狗儿

热爱的话就坚持吧~

0%

swpu

中午才起床,舍友喊我起床恰烂钱。ak了密码。逆向只做了了一题。没时间了。不到五小时做了500分我个人感jio还行吧。

crypto

rsa

1
2
3
4
('c=', '0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9eL')
('e=', '0x872a335')
#q + q*p^3 =1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
#qp + q *p^2 = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594

入门难度,通过给出表达式轻松求出p和q

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.Util.number import *
from gmpy2 import *

a = 1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
b = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
e = 0x872a335
c = 0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9e


gcd_ = gcd(a, b) # q*(1+p)

p = b // gcd_
q = b // (p*(p+1))

n = p * q
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, n)
print(long2str(m))

Yusa_cbc

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
from Crypto.Cipher import AES
import os
flag='flag{********************************}'
BLOCKSIZE = 16



def pad(data):
pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if len(data) % BLOCKSIZE != 0 else 0
return data + "=" * pad_len

def unpad(data):
return data.replace("=","")


def enc(data,key,iv):
cipher = AES.new(key,AES.MODE_CBC,iv)
encrypt = cipher.encrypt(pad(data))
return encrypt


def dec(data,key,iv):
try:
cipher = AES.new(key,AES.MODE_CBC,iv)
encrypt = cipher.decrypt(data)
return unpad(encrypt)
except:
exit()


def task():
try:
key = os.urandom(16)
iv = os.urandom(16)
pre = "yusa"*4
for _ in range(3):
choice = raw_input(menu)
if choice == '1':
name = raw_input("What's your name?")
if name == 'admin':
exit()
token = enc(pre+name,key,iv)
print "Here is your token(in hex): "+iv.encode('hex')+token.encode('hex')
continue
elif choice == '2':
token = raw_input("Your token(in hex): ").decode('hex')
iv = token[:16]
name = dec(token[16:],key,iv)
print iv.encode('hex')+name.encode('hex')
if name[:16] == "yusa"*4:
print "Hello, "+name[16:]
if name[16:] == 'admin':
print flag
exit()
else:
continue
except:
exit()
menu='''
1. register
2. login
3. exit
'''
if __name__ == "__main__":
task()

cbc bit flipping攻击

两个密文块,通过改第一个密文块,可以使得第二个密文块解密出admin.

但是这会使得第一个密文块解密出乱码。而题目也需要第一个密文块的值为yusayusayusayusa.

好在题目给出了三次交互的机会,第一次用于登陆,第二次用于改第一个密文块,从而使第二个密文块解密出admin。

第三次交互,需要从第二次交互的输出中提取第一个密文块的明文,与yusayusayusayusa异或后,再与iv进行异或,作为新的iv。这样aes cbc解密出乱码也没关系,因为会被iv抵消掉乱码。

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
from binascii import *
import struct

def bstr_xor(s1, s2):
l = min(len(s1), len(s2))
res = b''
for i in range(l):
tmp = s1[i] ^ s2[i]
res += struct.pack('B', tmp)
return res


token = unhexlify('9b41cb6addcea48f7f2b682afd6b5e75a2c94d578c9a7050fd5c51883d6a238e0df403bcb027bab1c36accccac29cd0e')
iv, enc1, enc2 = token[:16], token[16:32], token[32:]

n_enc1 = bstr_xor(enc1, bstr_xor(b'iyzyi', b'admin')) + enc1[5:]
print(enc1)
print(n_enc1)

result = iv + n_enc1 + enc2
print(result)
print('第一次登陆:', hexlify(result))
print('\n\n\n\n')


token2 = unhexlify('9b41cb6addcea48f7f2b682afd6b5e759b55c130fc13ab03f31c142883099e3161646d696e')
enc1_2 = token2[16:32]
print(enc1_2)
n_iv = bstr_xor(iv, bstr_xor(enc1_2, b'yusayusayusayusa'))
print(n_iv)
result2 = n_iv + n_enc1 + enc2
print('第二次登陆:', hexlify(result2))

Snipaste_2020-12-06_13-28-02

Yusa_ecb

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
from Crypto.Cipher import AES
import os
BLOCKSIZE = 16
flag='flag{********************************}'


def pad(data):
pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if len(data) % BLOCKSIZE != 0 else 0
return data + chr(pad_len) * pad_len

def unpad(data):
num = ord(data[-1])
return data[:-num]


def enc(data,key):
cipher = AES.new(key,AES.MODE_ECB)
encrypt = cipher.encrypt(pad(data))
return encrypt


def dec(data,key):
try:
cipher = AES.new(key,AES.MODE_ECB)
encrypt = cipher.decrypt(data)
return unpad(encrypt)
except:
exit()


def task():
try:
key = os.urandom(16)
while True:
plaintext = raw_input("Amazing function: ").decode('hex')
yusa = plaintext+flag
print enc(yusa,key).encode('hex')
except Exception as e:
print str(e)
exit()
if __name__ == "__main__":
task()

byte at a time 攻击。

首先通过更改plaintext的长度,测出flag长度是38(plaintext长为10的时候,密文长度48,长为11的时候,密文长度64)

参考了这篇文章:ECB Byte at Time - scriptkid - 博客园 (cnblogs.com)

每次爆破一个字符即可。

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
from pwn import *
from binascii import *

context.log_level = 'debug'
p = remote('das.wetolink.com', 42887)

#while (b'flag' not in p.recvline()):
'''
p.sendlineafter(b'Amazing function: ', b'88' * 11)
r = p.recvline()
print((len(r)-1)//2) # 10 => 48, 11 = > 64, so flag's length is 38
'''

def n2b(n):
h = hex(n)[2:]
return struct.pack('B', ord(h[0])) + struct.pack('B', ord(h[1]))

enc = []
for i in range(38):
payload = b'88' * (47-i)
p.sendlineafter(b'Amazing function: ', payload)
enc.append(p.recvline()[64:96])
print(enc)


flag = b''
for i in range(38):
f = False
for c in range(32, 127):
payload = b'88' * (47-len(flag)//2) + flag + n2b(c)
p.sendlineafter(b'Amazing function: ', payload)
e = p.recvline()[:-1]
if e[64:96] in enc:
flag += n2b(c)
print(flag)
f = True
break
if not f:
exit()

print(unhexlify(flag))

逆向

RealEzRE

这题很有意思。

字符串都是加密过的了,走了一个类似base64的解码。

有两个反调试,一个是时间调试,另一个我没深入去看:

image-20201206184130092

看了看,跟进这个函数:

image-20201206184216905

里面是个smc,但我没找到具体的smc的解码代码。

索性直接解码后dump出来。虽然不能动调了,但是可以静态看。

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
dword_437FA0 = 825373492;
for ( i = 0; i < sub_40F3D0(*(_DWORD **)(a1 + 4)); ++i )
input[i] = *(_BYTE *)(*(_DWORD *)(a1 + 4) + i);
sub_40B3A0((__m128i *)v13, 0, 0x408u);
rc4_(v13, 8);
if ( sub_401460() )
{
strcpy((char *)&v23, "RGVidWdnaW5nISEh"); // debuging
prin1(&v23, &v19);
v1 = (void *)prin2(&off_4380C0, &v19);
prin3(v1, (int (__cdecl *)(void *))sub_402F00);
result = -1;
}
else
{
v3 = sub_40F3D0(input);
sub_401640(v13, (int)input, (int)v15, v3);
for ( j = 0; j < 13; ++j )
{
if ( v15[j] != byte_4370C8[j] )
{
strcpy((char *)&v22, "SW5jb3JyZWN0IGZsYWch");// incorrect flag
prin1(&v22, &v19);
v4 = (void *)prin2(&off_4380C0, &v19);
prin3(v4, (int (__cdecl *)(void *))sub_402F00);
return -1;
}
}
for ( k = 0; k < 6; ++k )
{
if ( v17[k] != byte_4370E8[k] )
{
strcpy((char *)&v21, "SW5jb3JyZWN0IGZsYWch");// incorrect flag
prin1(&v21, &v19);
v5 = (void *)prin2(&off_4380C0, &v19);
prin3(v5, (int (__cdecl *)(void *))sub_402F00);
return -1;
}
}
for ( l = 0; l < 13; ++l )
{
if ( v16[l] != byte_4370D8[l] )
{
strcpy((char *)&v20, "SW5jb3JyZWN0IGZsYWch");// incorrect flag
prin1(&v20, &v19);
v6 = (void *)prin2(&off_4380C0, &v19);
prin3(v6, (int (__cdecl *)(void *))sub_402F00);
return -1;
}
}
dword_437FA4 = 'abcd';
strcpy(&v18, "ZmxhZyBpcyAiZmxhZ3t5b3VyIGlucHV0fSIg");
prin1(&v18, &v19);
v7 = prin3(&off_4380C0, (int (__cdecl *)(void *))sub_402F00);
v8 = (void *)prin2(v7, &v19);
prin3(v8, (int (__cdecl *)(void *))sub_402F00);
sub_40F781(aPause);
result = 0;
}

稍微看了下,就一个rc4,没别的了。

解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Cipher import ARC4
from binascii import unhexlify, hexlify
import struct

def l2b(l):
t = b''
for i in l:
t += struct.pack('B', i)
return t

def rc4_decrypt(cipher, key):
rc4 = ARC4.new(key)
return rc4.decrypt(cipher)


rc4_key = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
cipher = [0x12, 0xA7, 0xF5, 0xDE, 0x75, 0x2A, 0x6E, 0x4A, 0x6E, 0x73, 0xE6, 0x62, 0x50] + [0xBF, 0x2A, 0x98, 0xFE, 0x2B, 0xDD, 0x7B, 0xBA, 0xB6, 0x05, 0x13, 0x63, 0x57] + [0x2D, 0xD4, 0x45, 0xB8, 0xFE, 0xBC]
cipher = l2b(cipher)
print(cipher)

result = rc4_decrypt(cipher, rc4_key)
print(result)