强网杯2020 部分writeup

简单记录一下做出的几道题目,以后还是科研为主科研为主

babyCRT#

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
# task.py
from Crypto.Util.number import getPrime, long_to_bytes, getStrongPrime
from hashlib import sha1
from random import randint
from secret import flag, p, q
import libnum

def gen_t(d):
while True:
t = getPrime(16)
if t % 4 == 3 and libnum.gcd(d, t - 1) == 1:
break
return t

def sign(m, params):
d, p, q, n, t1, t2, e1, e2 = params
dp = d % ((p - 1) * (t1 - 1))
dq = d % ((q - 1) * (t2 - 1))
k = getPrime(16)
Sp = pow(m + k, dp, p * t1)
Sq = pow(m, dq, q * t2)
Cp = q * t2 * libnum.invmod(q * t2, p * t1)
Cq = p * t1 * libnum.invmod(p * t1, q * t2)
S = (Cp * Sp + Cq * Sq) % (n * t1 * t2)
c1 = (m - pow(S, e1, t1) + 1) % t1
c2 = (m - pow(S, e2, t2) + 1) % t2
return pow(S, c1 * c2, n)

e = 65537
assert p < q
assert flag == "flag{" + sha1(long_to_bytes(p)).hexdigest() + "}"

n = p*q
print(n)
d = libnum.invmod(e, (p - 1) * (q - 1))
t1 = gen_t(d)
et1 = libnum.invmod(d, t1 - 1)
t2 = gen_t(d)
et2 = libnum.invmod(d, t2 - 1)
params = (d, p, q, n, t1, t2, et1, et2)
m = randint(1, n-1)
print(m)
sig = sign(m, params)
print(sig)

论文题:http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.510.3146&rep=rep1&type=pdf

结论:$gcd(m^{c_1} - {Sig}^e,N)=p$

所以爆破$c_1$就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from hashlib import sha1
from libnum import gcd
from Crypto.Util.number import long_to_bytes

e = 65537
n = 26318358382258215770827770763384603359524444566146134039272065206657135513496897321983920652242182112479484135343436206815722605756557098241887233837248519031879444740922789351356138322947108346833956405647578838873425658405513192437479359531790697924285889505666769580176431360506227506064132034621123828090480606055877425480739950809109048177976884825589023444901953529913585288143291544181183810227553891973915960951526154469344587083295640034876874318610991153058462811369615555470571469517472865469502025030548451296909857667669963720366290084062470583318590585472209798523021029182199921435625983186101089395997
m = 26275493320706026144196966398886196833815170413807705805287763413013100962831703774640332765503838087434904835657988276064660304427802961609185997964665440867416900711128517859267504657627160598700248689738045243142111489179673375819308779535247214660694211698799461044354352200950309392321861021920968200334344131893259850468214901266208090469265809729514249143938043521579678234754670097056281556861805568096657415974805578299196440362791907408888958917063668867208257370099324084840742435785960681801625180611324948953657666742195051492610613830629731633827861546693629268844700581558851830936504144170791124745540
s = 20152941369122888414130075002845764046912727471716839854671280255845798928738103824595339885345405419943354215456598381228519131902698373225795339649300359363119754605698321052334731477127433796964107633109608706030111197156701607379086766944096066649323367976786383015106681896479446835419143225832320978530554399851074180762308322092339721839566642144908864530466017614731679525392259796511789624080228587080621454084957169193343724515867468178242402356741884890739873250658960438450287159439457730127074563991513030091456771906853781028159857466498315359846665211412644316716082898396009119848634426989676119219246

for c1 in range(2**16):
p = gcd(pow(m, c1, n)-pow(s, e, n), n)
if(p != 1 and n % p == 0):
q = n//p
print(p*q==n)
print("flag{" + sha1(long_to_bytes(p)).hexdigest() + "}")
print("flag{" + sha1(long_to_bytes(q)).hexdigest() + "}")

bank#

nc看了下可以知道是ECB模式加密了sender+receiver+money,所以通过加密可以知道自己的账号对应的密文,同时在recorder里可以看到哪些人在相互转钱,题目让我们可以提供recorder来伪造其他账户转钱给自己,所以思路就很简单了:

  1. 加密一次,得到自己的账号
  2. 得到所有已有的其他账户信息
  3. 伪造recorder让其他账户给自己打钱
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
from pwn import *
import string
from hashlib import sha256
import itertools

#context.log_level = 'debug'
p = remote('39.101.134.52', 8005)

def proof_of_work(token):
p.recvuntil("sha256(XXX+")
pad = p.recvuntil(")")[:-1]
p.recvuntil(" == ")
target = bytes.fromhex(p.recvline().strip().decode())
for s in itertools.product(string.printable, repeat=3):
if sha256(''.join(s).encode()+pad).digest() == target:
p.sendlineafter("Give me XXX:", ''.join(s))
p.sendlineafter("teamtoken:", token)
return

token = ''
proof_of_work(token)

p.sendlineafter("give me your name:", "ycdxsb")
p.sendlineafter("> ", "transact")
p.sendlineafter("> ", "Mote 10")
receiver = p.recvline().strip()[:32]
p.sendlineafter("> ", "view records")
p.recvline()

senders = []
cashs = []
for i in range(10):
line = p.recvline().strip()
senders.append(line[32:-32])
cashs.append(line[-32:])
print(senders)
print(cashs)
for i in range(10):
payload = senders[i]+receiver+cashs[i]
p.sendlineafter("> ", "provide a record")
p.sendlineafter("> ", payload)

p.recvuntil('> ')
p.sendline('get flag')
import time
time.sleep(1)
print(p.recv())

modestudy#

是真的让人头大

六个Chanllege 分别对应:

  • CBC 字节翻转攻击
  • CBC预测iv
  • ECB 块加密,可以发现有两个块只差一个字节,可以通过覆盖修改admin=0 为admin=1(session:dfc684a3;timedl=1;admin=0;guess_cookie_ma=1;guess_mp_ab=1;guess_cookie_mb=0;hell_pad=233)
  • ECB padding oracle
  • 自己写的ECB块加密,两个字节为一个块,先建立明文和密文的字典,然后直接爆破
  • CBC padding oracle
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
import binascii
from zio import *
import string
import random
import hashlib
import pickle
from Crypto.Util.number import bytes_to_long, long_to_bytes

'''
# get Challedge dict
idx = 0
for key in d.keys():
if(ord(d[key][0])>=idx):
idx = ord(d[key][0])
for i in range(idx,256):
for j in range(32):
sendmsg = ""
for k in range(8):
sendmsg += chr(i)+chr(8*j+k)
io.read_until('your choice:')
io.writeline('1')
io.read_until('input(encode hex):')
io.writeline(sendmsg.encode('hex'))
line = io.readline().strip()
line = line.split(':')[1]
for k in range(8):
d[line[4*k:4*k+4]] = chr(i)+chr(8*j+k)
#print(d)
with open('challege5.pickle','wb') as f:
pickle.dump(d,f)
'''

def passpow(io, difficulty):
io.read_until("[+] sha256(")
prefix = io.read_until("+")[:-1]
while 1:
answer = ''.join(random.choice(
string.ascii_letters + string.digits) for i in range(8))
hashresult = hashlib.sha256(prefix+answer).digest()
bits = ''.join(bin(ord(j))[2:].zfill(8) for j in hashresult)
if bits.startswith('0'*difficulty):
io.read_until("=")
io.writeline(answer)
return

token = ''
ip = '139.224.254.172'
target = (ip, 7777)
io = zio(target, timeout=1000000, print_read=COLORED(
RAW, 'red'), print_write=COLORED(RAW, 'green'))
passpow(io, 5)
io.writeline(token)


# Challege 1
io.read_until('your choice:')
io.writeline('1')
line = io.readline()
line = io.readline()
message = io.readline().strip().split(' ')[1]
cookie = message.split(';checksum=')[0].split(':')[1]
checksum = message.split(';checksum=')[1]
target = cookie[:31]+'1'
print('\n')
print('cookie:'+cookie)
print('checksum:'+checksum)
print('target:'+target)
checksum = long_to_bytes(int(checksum, 16))
print([checksum], len(checksum))
checksum = checksum[0:15]+chr(0x49 ^ 0x48 ^ ord(checksum[15]))+checksum[16:]
result = target+';checksum='+binascii.b2a_hex(checksum)

print("Challege 1:", result)
io.writeline(result)


# Challege 2
io.read_until('your choice:')
io.writeline('2')
line = io.readline()
line = io.readline()
iv_sha256 = io.readline().strip().split('=')[1]

print(iv_sha256)
io.read_until('your choice:')
io.writeline('1')
A = '1'*16
B = '1'*16
io.read_until('c:')
io.writeline(A+B)
line = io.readline().strip().split(' ')[1]
plaintext = long_to_bytes(int(line,16))
D = bytes_to_long(b'1'*16)^bytes_to_long(plaintext[16:])
iv = D^bytes_to_long(plaintext[:16])
iv = long_to_bytes(iv)
print(iv)
print(hashlib.sha256(iv).hexdigest())
io.read_until('your choice:')
io.writeline('2')
io.read_until('iv(encode hex):')
io.writeline(iv.encode('hex'))


# Challege 3
io.read_until('your choice:')
io.writeline('3')
line = io.readline()
line = io.readline()
cookie = io.readline().strip()[11:]
ciphertext = io.readline().strip().split('(cookie):')[1]
print('\n')
print("cookie:"+cookie)
print("ciphtertext:"+ciphertext)

io.read_until('input your encrypted cookie(encode hex):')
ciphertext = list(ciphertext)
for i in range(32):
ciphertext[64+i] = ciphertext[128+i]
result = ''.join(ciphertext)
io.writeline(result)
print("Challege 3:", result)


# Challege 4
io.read_until('your choice:')
io.writeline('4')
line = io.readline()
line = io.readline()
line = io.readline()
secret_sha256 = line.split('=')[1]
print("sha256(secret):"+secret_sha256)
guess = ""
for i in range(16):
for ch in range(256):
io.read_until('your choice:')
io.writeline('1')
sendmsg = chr(ch)+guess+'\x00'*16
io.read_until('input(encode hex):')
io.writeline(sendmsg.encode('hex'))
line = io.readline()
ciphertext = io.readline().strip().split('msg: ')[1]
if(ciphertext[0:32] == ciphertext[64:]):
guess = chr(ch)+guess
break
# io.interact()
print(guess)
print("Challege 4:", guess)
io.read_until('your choice:')
io.writeline('2')
io.read_until('secret(encode hex):')
io.writeline(guess.encode('hex'))
# edd11570a9bad21c0d6d97d32cc36674



# Challege 5
io.read_until('your choice:')
io.writeline('5')
line = io.readline()
line = io.readline()
line = io.readline()
line = io.readline()
line = io.readline()
secret = line.strip().split('=')[1]
print("secret:"+secret)

with open('challege5.pickle','rb') as f:
d = pickle.load(f)

result = ""
for i in range(0, 8):
result += d[secret[4*i:4*i+4]]
print('Challege 5:'+result)
io.read_until('your choice:')
io.writeline('2')
io.read_until('secret(encode hex):')
io.writeline(result.encode('hex'))


# Challege 6
io.read_until('your choice:')
io.writeline('6')
line = io.readline()
line = io.readline()
line = io.readline()
line = io.readline()
line = io.readline()
line = io.readline().strip().split(':')[1]
iv = long_to_bytes(int(line[:32],16))
se_c = long_to_bytes(int(line[32:],16))

tmp_iv = map(ord,list(iv))
tmp_c = map(ord,list(se_c[:16]))
zero = '0'*16

ans = [0] * 16
for idx in range(16):
for num in range(0, 256):
io.read_until('your choice:')
io.writeline('1')
io.read_until('iv+c (encode hex):')
tmp_iv[-(1+idx)] = num
payload = zero + ''.join(map(chr, tmp_iv+tmp_c))
payload = ''.join(['%02x' % ord(ch) for ch in payload])
io.writeline(payload)
if 'error' not in io.readline():
ans[-(1+idx)] = num ^ (idx+1)
for j in range(idx+1):
tmp_iv[-(j+1)] = ans[-(1+j)] ^ (idx+2)
print(ans)
break
else:
raise Exception("unknow error")
ans = ''.join(['%02x' % (ch^0x31) for ch in ans])
io.read_until('your choice:')
io.writeline('2')
io.read_until('ecret(encode hex):')
io.writeline(ans)
io.interact()
# 974c3485c74af5a38c874d3c9d03b2c3

xx_warmup_obf#

应该是被我非预期了23333。

一道混淆的re,但我向来是一个不喜欢麻烦的人,所以我抱着侥幸的心理试了下pin的指令数目侧信道,前置知识可以看之前这篇博客(https://blog.ycdxsb.cn/c61763eb.html)

可以看到有bad passcode,you got ityou failed it三个不同的字符串

根据位置和经验猜测第一个bad passcode是判断输入长度的,所以试了下知道输入长度为28字节

然后试了下第一个字节,发现f是指令数最少的,又简单测试了一下第二个l也满足条件,所以直接侧信道走起,吃个饭回来拿flag岂不是美滋滋,可惜题目看的太迟了,第4个做出来,连3血都没拿到

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
import os
import sys
import subprocess

class Shell(object):
def runCmd(self, cmd):
res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
sout, serr = res.communicate()
return res.returncode, sout, serr, res.pid

def initPin(self, cmd):
res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.res = res

def pinWrite(self, input):
self.res.stdin.write(input)

def pinRun(self):
sout, serr = self.res.communicate()
return sout, serr

cmd = './pin -t ./source/tools/ManualExamples/obj-intel64/inscount0.so -- ./xx_warmup_obf'

shell = Shell()

s = "f"
import string
chs=string.printable
chs = string.digits+string.ascii_letters+'{}_'
for i in range(27):
min_num = 2**32
min_ch = ""
for ch in chs:
tmp = s + ch +(28-len(s)-1)*'a'+'\n'
shell.initPin(cmd)
shell.pinWrite(tmp)
sout,serr = shell.pinRun()
with open('inscount.out') as f:
count = f.readline().split(' ')[1]
count = int(count)
print(count,tmp,sout)
if(count<min_num):
min_num = count
min_ch = ch
s+=min_ch
print(min_num,min_ch)
print('flag:'+s)

评论