一、引言
百度的OpenRASP将Gartner在2014年提出的RASP(Runtime Application Self-Protection)安全防护技术进行了开源实现,使其迅速成为企业Web安全防护中的一个重要武器,有效增强防御体系纵深和对漏洞防护的适应能力。OpenRASP相较与传统WAF具有误报率低、高性能等优点。Django是Python实现的Web开发框架,最初被设计用于具有快速开发需求的新闻类站点,目的是要实现简单快捷的网站开发。
本文介绍了OpenRASP和Django的一些基本内容,在搭建好OpenRASP测试实验环境的基础上编写官方测试用例的自动化漏洞验证脚本,最后通过Django快速开发报警接收Web应用。
二、OpenRASP和Django概述
1. RASP(Runtime Application Self-Protection)
开发人员常常倾向于采用静态和传统的AppSec方法,而不是解决应用程序的设计缺陷,这些方法在面对复杂的安全威胁时往往会失败。这种完全不同的安全控制层常常成为应用程序、基础设施和安全层的多个组件的瓶颈,但随着RASP解决方案的出现,应用程序安全不再是对威胁的一种随意反应。RASP是应用程序安全生态系统中的一项创新,通过提供对隐藏的漏洞的更多可见性来处理运行时对软件应用层的攻击。它本质上是与应用程序或其运行时环境集成的安全软件,并不断拦截对应用程序的调用,以检查其安全性。RASP软件不会等待威胁影响应用程序。相反,它会在进入应用程序的流量中主动搜索恶意软件,防止欺诈性调用在应用程序内部执行。通过留在应用程序内,RASP解决方案中和已知的漏洞,并保护应用程序免受未知的0day攻击,无需任何人工干预。因此,RASP提供了一种与传统安全方法(如web应用程序防火墙(WAF))在概念上不同的安全范式,后者通过阻止所有可疑流量来保护应用程序。
RASP已经发展成为一种成熟的应用程序内安全概念,它允许开发者以多种方式对威胁进行防御。根据开发人员想要在应用程序或服务器中实现RASP安全层的方式,有四种方法可供选择:
(1). Servlet filters, SDKs and plugins
这种方法适用于监控和检查到达应用程序代码之前Apache Tomcat或其他Web服务器传入的HTTP请求和数据。
(2). Binary instrumentation
该方法适用于在应用程序中构建监视和控制元素,前者标识正在运行的应用程序中的安全事件,而后者记录此类事件的日志并阻止它们。
(3). JVM replacement
此方法采用RASP层替换标准库(JAR或JVM(对于Java))来侦听对支持库的调用,并在调用被拦截时的应用规则。因此RASP对app代码库和系统调用路由框架有一个整体的了解,这使得RASP可以通过对应用调用的被动监控来了解机器行为和序列流。
(4). Virtualization
Virtualization,或者叫做containerized runtime protection,它创建一个应用程序副本,并通过使用规则来控制应用程序该如何被保护,同时控制应用程序在副本上的运行时行为。RASP监视和学习应用程序代码路径、逻辑构造、参数化和生成的输出等,然后应用于应用程序请求。这种方法有助于区分清楚的请求和恶意请求,并允许采取适当的补救措施。
2. OpenRASP
OpenRASP是百度安全推出的一款免费、开源的应用运行时自我保护产品。
官网地址为:https://rasp.baidu.com
若要了解更多细节,请阅读 谢幺 – 百度安全的 OpenRASP 项目,究竟是什么?以及 OpenRASP 最佳实践
OpenRASP目前支持Java和PHP两种类型的服务器,其快速上手部署请参考官方文档:https://rasp.baidu.com/doc/install/software.html
本文中,通过采用CentOS 8 + Tomcat在VM虚拟机中快速搭建好实验环境,使用OpenRASP v1.3.5进行实验。
3. Django
Django是一个由Python编写的具有完整架站能力的开源Web框架。使用Django,只要很少的代码,开发人员就可以轻松地完成一个正式网站所需要的大部分内容,并进一步开发出全功能的Web服务。Django本身基于MVC架构,即Model(模型)+View(视图)+ Controller(控制器)设计模式,因此天然具有MVC的出色基因:开发快捷、部署方便、可重用性高、维护成本低等优点。除此之外,Django还具备自己的admin后台,开发人员只需要通过简单的几行配置和代码就可以实现一个完整的后台数据管理控制平台,是Django的亮点之一。但是Django由于Python性能的限制,无法作为大流量的服务器使用。这里我们只需要在内网中监控OpenRASP的报警,从业务场景上可以使用Django。
三、OpenRASP示例的自动化攻击脚本
1. 搭建OpenRASP测试用例
在搭建好OpenRASP环境中,可以将官方给的测试用例部署在服务器上,这里笔者采用Java服务器的测试用例:https://rasp.baidu.com/doc/install/testcase.html
重启Tomcat服务器后我们可以看到OpenRASP 官方测试用例集界面:
单击进入每一个测试用例可以获取到不同攻击的完整URL:
2. 编写自动化攻击脚本
这里我们使用Python来编写自动化攻击脚本,编写该脚本的目的是方便后续开发报警接收应用时能够更加高效率地去模拟攻击并获取报警信息。
首先,单击每个非正常调用URL,异常调用会被OpenRASP拦截下来:
这样我们可以将需要的攻击URL(仅含参数)放入数组中:
class OpenRASPTest:def__init__(self, host):self.headers = {“User-Agent”: “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ““Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0”}self.host = host# 攻击Payload URLself.AttackUrl =[‘/vulns/001-dir-1.jsp?dirname=../../../../../../../../../../../../../../../var/log/’,‘/vulns/002-file-read.jsp?file=../../../../../../../../../../../../../../../etc/passwd’,‘/vulns/002-file-read.jsp?file=../../../conf/tomcat-users.xml’,‘/vulns/004-command-2.jsp?cmd=ls+-la+/’,‘/vulns/005-file-write.jsp?filename=reports/../123.jsp&filedata=some-webshell-data’,‘/vulns/008-file-upload.jsp’,‘/vulns/009-deserialize.jsp?id=whoami’,‘/vulns/010-jstl-import.jsp?url=file:///etc/’,‘/vulns/010-jstl-import.jsp?url=http://192.168.1.1’,‘/vulns/011-ssrf-commons-httpclient.jsp?url=http://www.baidu.com’,‘/vulns/011-ssrf-httpclient.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/011-ssrf-httpclient.jsp?url=http://uee.me/cFas3’,‘/vulns/011-ssrf-urlconnection.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/011-ssrf-okhttp.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/011-ssrf-okhttp3.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/019-file-delete.jsp?filename=reports/../testfile.txt’,‘/vulns/020-random-file.jsp?filename=reports/../123.jsp&filedata=some-webshell-data’,‘/vulns/020-random-file.jsp?file=../../../../../../../../../../../../../../../etc/passwd’,‘/vulns/021-nio-file.jsp?filename=reports/../123.jsp&filedata=some-webshell-data&mode=write’,‘/vulns/021-nio-file.jsp?file=../../../../../../../../../../../../../../../etc/passwd&mode’‘=read’,‘/vulns/021-nio-file.jsp?filename=reports/../testfile.txt&mode=delete’,‘/vulns/021-nio-file.jsp?filename=reports/../testfile.txt&dst=reports/../testfile.jsp&mode’‘=link’,‘/vulns/021-nio-file.jsp?dirname=../../../../../../../../../../../../../../../var/log/&mode’‘=list’,‘/vulns/021-nio-file.jsp?filename=reports/../rename.txt&dst=reports/../rename.jsp&mode=rename’]
def get_url(self, url):req = urllib.request.Request(self.host + url, headers=self.headers)html = urllib.request.urlopen(req).read().decode(‘utf-8’)content = etree.HTML(html)print(self.load_page(content) +’ 攻击已被拦截’)defpost_url(self, url):files = {‘file’: open(‘1.jsp’, ‘rb’)}data = {}res = requests.post(self.host + url, data=data, files=files)reg = re.compile(r’400 – Request blocked by OpenRASP’)resstr = reg.search(res.text)print(resstr)
load_page
方法,在该方法中使用上面复制的xpath获取关键标签中的内容。def load_page(self, con):xpath = ‘/html/body/div[2]/div/div[2]/h2’down = con.xpath(xpath)try:result = down[0].textexceptIndexError:result = “ERROR”print(“攻击失败”)return result
import urllib.requestfrom lxml import etreeimport requestsimport reimport datetimeclass OpenRASPTest:def__init__(self, host):self.headers = {“User-Agent”: “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ““Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0”}self.host = host# 攻击Payload URLself.AttackUrl =[‘/vulns/001-dir-1.jsp?dirname=../../../../../../../../../../../../../../../var/log/’,‘/vulns/002-file-read.jsp?file=../../../../../../../../../../../../../../../etc/passwd’,‘/vulns/002-file-read.jsp?file=../../../conf/tomcat-users.xml’,‘/vulns/004-command-2.jsp?cmd=ls+-la+/’,‘/vulns/005-file-write.jsp?filename=reports/../123.jsp&filedata=some-webshell-data’,‘/vulns/008-file-upload.jsp’,‘/vulns/009-deserialize.jsp?id=whoami’,‘/vulns/010-jstl-import.jsp?url=file:///etc/’,‘/vulns/010-jstl-import.jsp?url=http://192.168.1.1’,‘/vulns/011-ssrf-commons-httpclient.jsp?url=http://www.baidu.com’,‘/vulns/011-ssrf-httpclient.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/011-ssrf-httpclient.jsp?url=http://uee.me/cFas3’,‘/vulns/011-ssrf-urlconnection.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/011-ssrf-okhttp.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/011-ssrf-okhttp3.jsp?url=http://127.0.0.1.xip.io’,‘/vulns/019-file-delete.jsp?filename=reports/../testfile.txt’,‘/vulns/020-random-file.jsp?filename=reports/../123.jsp&filedata=some-webshell-data’,‘/vulns/020-random-file.jsp?file=../../../../../../../../../../../../../../../etc/passwd’,‘/vulns/021-nio-file.jsp?filename=reports/../123.jsp&filedata=some-webshell-data&mode=write’,‘/vulns/021-nio-file.jsp?file=../../../../../../../../../../../../../../../etc/passwd&mode’‘=read’,‘/vulns/021-nio-file.jsp?filename=reports/../testfile.txt&mode=delete’,‘/vulns/021-nio-file.jsp?filename=reports/../testfile.txt&dst=reports/../testfile.jsp&mode’‘=link’,‘/vulns/021-nio-file.jsp?dirname=../../../../../../../../../../../../../../../var/log/&mode’‘=list’,‘/vulns/021-nio-file.jsp?filename=reports/../rename.txt&dst=reports/../rename.jsp&mode=rename’]defstart_attack(self):print(“当前时间为 {0} 攻击开始…”.format(datetime.datetime.now()))print(“0x00. 完成File.listFiles 遍历目录攻击,响应结果如下:”)self.get_url(self.AttackUrl[0])print(“0x01. 完成任意文件下载/读取漏洞攻击,读取passwd文件,响应结果如下:”)self.get_url(self.AttackUrl[1])print(“0x02.完成任意文件下载/读取漏洞攻击,读取tomcat-users文件,响应结果如下:”)self.get_url(self.AttackUrl[2])print(“0x03. 完成命令执行后门攻击,响应结果如下:”)self.get_url(self.AttackUrl[3])print(“0x04. 完成任意文件写入攻击,响应结果如下:”)self.get_url(self.AttackUrl[4])print(“0x05. 完成任意文件上传漏洞攻击,采用commons.io 方式,响应结果如下:”)self.post_url(self.AttackUrl[5])print(“0x06. 完成使用 InvokerTransformer 反序列化并执行命令攻击,响应结果如下:”)self.get_url(self.AttackUrl[6])print(“0x07. 完成JSTL import 任意文件包含/SSRF攻击,file 协议读取目录,响应结果如下:”)self.get_url(self.AttackUrl[7])print(“0x08. 完成JSTL import 任意文件包含/SSRF攻击,http 协议 SSRF,响应结果如下:”)self.get_url(self.AttackUrl[8])print(“0x09. 完成SSRF攻击,通过commons.httpclient 方式,响应结果如下:”)self.post_url(self.AttackUrl[9])print(“0x0A. 完成SSRF攻击,通过HttpClient调用方式,响应结果如下:”)self.get_url(self.AttackUrl[10])print(“0x0B. 完成SSRF攻击,通过HttpClient重定向方式,响应结果如下:”)self.get_url(self.AttackUrl[11])print(“0x0C. 完成SSRF攻击,通过jdk 中的 URL.openConnection 调用方式,响应结果如下:”)self.post_url(self.AttackUrl[12])print(“0x0D. 完成SSRF攻击,通过okhttp方式,响应结果如下:”)self.get_url(self.AttackUrl[13])print(“0x0E. 完成SSRF攻击,通过okhttp3方式,响应结果如下:”)self.get_url(self.AttackUrl[14])print(“0x0F. 完成任意文件删除攻击,响应结果如下:”)self.get_url(self.AttackUrl[15])print(“0x10. 完成RandomAccessFile 文件读写攻击,响应结果如下:”)self.get_url(self.AttackUrl[16])print(“0x11. 完成RandomAccessFile 文件读写攻击,读取linux下的passwd文件,响应结果如下:”)self.get_url(self.AttackUrl[17])print(“0x12. 完成NIO 文件调用攻击,响应结果如下:”)self.get_url(self.AttackUrl[18])print(“0x13. 完成linux下的NIO 文件读取调用攻击,响应结果如下:”)self.get_url(self.AttackUrl[19])print(“0x14. 完成NIO 文件删除攻击,响应结果如下:”)self.get_url(self.AttackUrl[20])print(“0x15. 完成NIO 文件硬链接攻击,响应结果如下:”)self.get_url(self.AttackUrl[21])print(“0x16. 完成linux下的NIO 文件目录遍历攻击,响应结果如下:”)self.get_url(self.AttackUrl[22])print(“0x17. 完成NIO 文件重命名攻击,响应结果如下:”)self.get_url(self.AttackUrl[23])defget_url(self, url):req = urllib.request.Request(self.host + url, headers=self.headers)html = urllib.request.urlopen(req).read().decode(‘utf-8’)content = etree.HTML(html)print(self.load_page(content) +’ 攻击已被拦截’)defpost_url(self, url):files = {‘file’: open(‘1.jsp’, ‘rb’)}data = {}res = requests.post(self.host + url, data=data, files=files)reg = re.compile(r’400 – Request blocked by OpenRASP’)resstr = reg.search(res.text)print(resstr)defload_page(self, con):xpath = ‘/html/body/div[2]/div/div[2]/h2’down = con.xpath(xpath)try:result = down[0].textexceptIndexError:result = “ERROR”print(“攻击失败”)return resultif __name__ == “__main__”:ORT= OpenRASPTest(“http://192.168.xx.xx:80xx”)ORT.start_attack()
四、OpenRASP报警推送数据分析
字段 | 说明 |
---|---|
rasp_id | RASP agent id |
app_id | 应用ID |
event_type | 日志类型,固定为 attack 字样 |
event_time | 事件发生时间 |
request_id | 当前请求ID |
request_method | 请求方法 |
intercept_state | 拦截状态 |
attack_source | 攻击来源 IP |
target | 被攻击目标域名 |
server_hostname | 被攻击的服务器主机名 |
server_ip | 被攻击目标 IP |
server_type | 应用服务器类型 |
server_version | 应用服务器版本 |
…… | …… |
详情请参考:OpenRASP日志说明
五、基于Django的报警接收Web应用开发
1. 安装Django
执行
pip install django
安装Django
2. 新建Django项目
打开Pycharm,点击new project。选择Django,输入项目名之后点击CREATE按钮新建Django项目:
Pycharm会自动帮我们把新建好的Django项目目录结构初始化,这时我们需要自己在settings.py中将ALLOWED_HOSTS修改为,注意不要漏掉“,”:
ALLOWED_HOSTS = [‘*’, ]
‘django.middleware.csrf.CsrfViewMiddleware’,
给注释掉
最后,在Django configuration中将host改为0.0.0.0
,重启Django服务器之前记得在主机的防火墙中添加8000端口
3. 接收POST路由
在项目目录下新建views.py,获取POST请求
def openraspalarm(request):if request.method ==’POST’:postBody = request.body
之后在urls.py中添加路由:
path(‘alarm/’, openraspalarm),
4. 读取报警信息
使用JSON读取POST请求体中的报警信息。首先引入json库:
import json
然后使用json.loads
方法将json格式数据转换为字典
json_result = json.loads(postBody)print(‘完整的JSON字符串如下:\n {0}’.format(json_result))
并且可以直接输出app_id键的值
print(json_result[‘app_id’])
由于每隔120秒Agent会将所有还没报警的事件进行推送,所有推送的数据包中可能会包含多个事件,这些事件的报警均在data键内。最后,我们循环输出每个事件的json标签内容:
data = json_result[‘data’]print(‘data长度为{0}’.format(len(data)))for i in range(len(data)):print(‘\033[45m第 {0} 个攻击\033[0m’.format(i))print(‘攻击源IP地址:{0}’.format(data[i][‘attack_source’]))print(‘攻击类型:{0}’.format(data[i][‘attack_type’]))print(‘攻击发生时间:{0}’.format(data[i][‘event_time’]))print(‘事件类型:{0}’.format(data[i][‘event_type’]))print(‘攻击向量头部:{0}’.format(data[i][‘header’]))print(‘拦截状态:{0}’.format(data[i][‘intercept_state’]))print(‘当前URL:{0}’.format(data[i][‘url’]))print(‘攻击应用ID:{0}’.format(data[i][‘app_id’]))print(‘攻击定位:{0}’.format(data[i][‘attack_location’]))print(‘攻击变量信息:{0}’.format(data[i][‘attack_params’]))print(‘插件检测算法:{0}’.format(data[i][‘plugin_algorithm’]))print(‘检测准确率:{0} %’.format(data[i][‘plugin_confidence’]))print(‘检测报告:{0}’.format(data[i][‘plugin_message’]))print(‘RASP agent ID:{0}’.format(data[i][‘rasp_id’]))print(‘当前请求ID:{0}’.format(data[i][‘request_id’]))print(‘请求方法:{0}’.format(data[i][‘request_method’]))print(‘被攻击服务器主机名:{0}’.format(data[i][‘server_hostname’]))print(‘被攻击目标IP及网卡接口名称:{0}’.format(data[i][‘server_nic’]))print(‘应用服务器类型:{0}’.format(data[i][‘server_type’]))print(‘应用服务器版本:{0}’.format(data[i][‘server_version’]))print(‘被攻击目标域名:{0}’.format(data[i][‘target’]))
这时我们可以运行自动化攻击脚本,为OpenRASP后台创造报警数据,当一个报警周期(120秒)过后,就能接收到OpenRASP后台传来的报警数据:
我们可以将接收到的报警数据根据实际需要存入数据库或做进一步的分析处理。
六、总结
有关RASP的理念,早在2014年就已经被提出,并且被世界顶级咨询公司Gartner列为应⽤安全领域的“关键趋势”。OpenRASP作为其落地的项目已经做到相对成熟的地步,尽管它还存在一些问题,但是相信在未来几年我们能看到OpenRASP能够带来更好的表现。本文在搭建好OpenRASP测试实验环境的基础上编写官方测试用例的自动化漏洞验证脚本,最后通过Django快速开发报警接收Web应用。本文的主要目的在于更好地去使用和研究OpenRASP技术,希望这篇文章能够给大家提供有用思路和方法。
附录
参考:
https://www.freebuf.com/articles/web/217421.htmlhttps://www.freebuf.com/articles/web/164413.htmlhttps://www.appsealing.com/what-is-runtime-application-self-protection/https://rasp.baidu.com/download/OpenRASP%20Internals.pdf?from=headerhttps://rasp.baidu.com/doc/install/software.htmlhttps://rasp.baidu.com/doc/install/testcase.htmlhttps://rasp.baidu.com/doc/setup/log/main.html#format
来源:freebuf.com 2020-11-02 19:59:12 by: SHXiGi
请登录后发表评论
注册