Crypto

BASE ALL


题目描述:哇!怎么这么多,搁这套娃呢?


下载文件,打开是一堆编码:

1
JJFEIRKNKJFUYS2KIZKTIVCDJJGEUQ2VJ5KTEVCLGVDFMRKTGJDEWTSMIVLVIQ2MJJNEIRSNKRFVOS2OIVKVKUSTJJFVURKWI5KTESKKJZBVMVKWKNIEWSK2IRCVEMSLJFHEWVSTKUZEYR2KIVKEWU2TKVFFMSKUIVKEWS2MJJDFMSKSJNLUWTSMIVHVMU2EJFLEIVSJKVNFGSSOJRCUOUSLJRFVKWSFJFJUWS2KIZBVKS2VLJJUWNKGIU2FGMSGJFLEYVKHKRJUQS22IVCUWVBSKZGEUSSVKNKFGRSJKVNEMT2VKNLEUTSOIVKVMQ2MJNGVURSRKNFFMSK2INLE6VKTGJFTKRCVGRJTERSLIZFFIRKRGJFUSWSGKZFVMMSPJNHEGRKXKNJUQS22JNLEGVJSLFFE4RCFKFJFGSSLGVFFKVKTKNFUUVSMIU3FMUSTJNHEKVJUKJFVMSZVJFLEOUSLJRDVMR2GJFKEWVCHJJGEKVKOJNEUSWSGKZHVCMSRJJHEYRKPKJJUYS2OIZKU6VCDI5EVMQ2UIVLEGVCJJZDFIS2SGJLEOUSMKVLVEU2KJNLE4RKJKIZFISKOIZKVKU2TI5EVMSCWIVJTEUCKJZEVMVKSJJJUWWSKIZEVGMSTJE2UYRJWKZFVIR2KIZCTIUSLK5FU4TCGI5KVGSCLLJCEMS2WGJKUOSSIKVKVGU2EJFLEMVSLKMZE2SSKIRCU2USLIZFTKQSVJNJUUVKMJJCEKS2WKNCEUVSGIVKVIS2WJJLEWVSVKZJUQSS2IJKUWTKTKNFU4SCVKNKVGRKLKJDFKMSNKNJEURJSKVGVEQ2GJNNEEVSFKRBUOSK2JNKEKVSDKRFDKRCVKVITEV2JJZEEKR2VGJGEOVSDIZFVMS2TJNHEWVKVJZFU2S2WIRLEKVJSJNFE4RSFKVJFGTCLJVNEMS2TGJHUUSSLKU3FKMSUJNHEMVSNKNFVOSSOI5LEOVJSJREUURCFJVITEV2LJZFEKWKTKNBUSWSIKZDVGMSMJJDEMRJSKJJUIS22IZLESU2KKZEVETCFJNKVGVCJKZCVIS2UJNKUSVSKIVDVKQ2MJRFEEVKNKVFVOSSOJBKVGU2TJNFVKMSGIVKTEVCKJZFEKU2WKNGEWVK2IZGVGU2LJFFEGVKTKZJUIS2KIZKVKUKTI5FVMS2GI5KDETCKJJDFMS2NKNHEWSSLIVLU4S2IJFLEUVJSJVJUQSSGINKEKVSDJBFTKRSVGJJUWS2JLJCEKV2VKJJUYQSGKU2FIU2GJNHEURSHKUZEWSKKIZDEWTKTJZFU4S2VKNHEEU2LKZFFMT2RGJFUUTJSKVKVEU2KJNEVURSPKMZE6SKSINKE2VSLKRFVMRKWIVJEWRSJJZGFKV2XINFEUVK2KVGVEMSYJJHEQVKVKZFTES22I5LE2U2TKVFE4SSFGJJFGQSLJJFFKV2TGJLUSUSMIUZFISSTJM2UMRSNKNBUMSKWJJKUOUSDJRGEURSGJNJUWVKHJJFFKV2TKNGESVJTIZGVCMSVJJJEIRKNKZFVMS2OIJKVCU2LJ5FFEQ2VJ5KUWVCKKJCVMVKTKNLUURSKIVLVOU2LJNFEEVKLJZBVGS2OIVCVOVSTINFVUSCWI5KTEVKKIUZFKU2WINEEWTSCKU2FGMSPJFHEIRSLKZBTES22IZCTIUSDK5ETKSCFK5LEWTCJLJBVMS2WJNMESTSFIVKU4S2MJNLE2VSLKUZFCSSOJZCU2USLJJFUSWSFGZJTEU2JJJFVKNSWKNFUWUSFKRFVGMSXJFLEYRKHKVFUWR2WIVCUWURSKNDUURSFJ5LVGS2JLJDFMR2TGJMEUTSIIUZFES2MJNIVURJSKMZEGSJVJRCTEVKTIREVMRSVJVJUWVSMIZFFMR2UINEEWWSFKZGVKS2TJJFEWVKXKNJU4SKVGJDEKVJSKBFEMTSFJ5LFGTSLJZFFMR2TKNFUUUSEIVJVMU2EJJJEIVSVKMZEOSJVJJLEOUJSJRFEUQ2VJNJTEVKKJZFUKV2OJNEESVSDKZCVCMSHJJJEGVCFKZBUQS2WIZLECU2TGJFFETCGINKTETCLKZDFKNCRGJDEOSSLIZCVMS2KI5IVURKNKNFVGSKNLJCVOUKTIVEVURCWI5ITER2KJZFEKVKWJNNEWTSKKZHVGU2PJFHEWVKXKRJUYSKSIZLE2USLK5EVMTCGI5JDESSJLJDEMS2SGJLUSTSFIVLVOU2IJNNEOVSDJVJVKSJVIZCUSVSLKZFVMSSVI5JVGQ2JJJFUKT2UJNKEWQSFKRFVGQ2GJNHEYRSVKUZE2SSGJZDE2U2LKNDUSWSFJ5KFGTKLKZEFMT2TLJJUUUSGIVIVMSSVJNGVURSFKNBVMR22JNCEKVKDJJEFKPJ5HU6T2PI=

放进CyberChef,看到最后的一个=,先用base32解码解4次,得到了:

1
BHFgBMg4QRUjtBi47cgDZ2ixKm5Ztbnh2HAxUUL7gZihGfyYuV2TongPQExQfCh6yBqkDHPGkyTsiwQtApv46cpBkgJRb6zew6Z9R1XuJsR2AHHn3j3ZpYwcaZ3wo2u8aLktHr62K7XEDcENR2cHSQzaXd6BCxRF4J3cCuGz42ic8RTHG8D9kcFkvZ6PwxXSCZYAby3S7QtZ35dWFc81azXk7ZnwySCWucBqVCtc7NXRNaTAQe2aciMAY246vHywTivpBngQquR36b56jFosDdz4Eer9oeF8AiWarr7iZVU1Mg5zrHbr2VXFLwpsmtNCcxnLyydrNKMTBtTDjPHS5YQKFLBqoN3Qmgs6wcc9sU

没一个或者两个=,说明不是64或者32,都尝试一下,得到是base58,用其解码4次:

1
VmpCV1IxWnNXa1pVYkZaVFltNVNWVlJWV1RWbGJVbDRUMVpTVGxKcWJEQlVhMk14VjJ4bmVsVnJjR2xXTVZvMlUxWm5kMUJSUFQwPQ==

两个=,说明是base64,最后解4次码得到flag:XAUTCTF{S0_so_S0_m4nY_tImes!}

RSA Level 1


题目描述:摊牌了,全给你吧!


下载附件,

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

p = getPrime(1024)
q = getPrime(1024)
e = 65537
m = bytes_to_long(flag)

print("p =", p)
print("q =", q)
print("c =", c)

'''
p = 177697410100406841991504486132480651434938805026060299904296103502746236101989391431404888013494476256376973503464918628752199515631040587743660729882489841554248617197097542499506348204018092806038301247454895130391741840954658391561541182921978025116693987995964220399091076462997685125730245187655200335183
q = 179434016998140031014368067904766081797986046197796143005154180586375739721169434781338336010438890164727776935390319878190484756530606555575566145849600611045908804661009299426088268999760269961430672640255341016386574914749521369064082756920181913030489172136557795523587135738615158374227952275819162957527
c = 28502957797327045767985236917760422196161961427609288501040821148578184890255528094925680917559890025155665851157310930601925216950553360053457655219378488534569091874119224665465564602479111367175108424055994961443368844256802504075949400191163184395696420192135775548413524183946302686864401083925251821992176479498256509277106306292961652379024856772746376842003779195106840973987122624555023876915779125969908294235750383404947046876892761276140432773813581856906409298780829601981625721630520583111943510355274379523760918502531060590060878780704586079788208139072053734418994815689327092740873631199305764701101
'''

是最经典的RSA,给了pqce=65537,直接写exp:

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

p = 177697410100406841991504486132480651434938805026060299904296103502746236101989391431404888013494476256376973503464918628752199515631040587743660729882489841554248617197097542499506348204018092806038301247454895130391741840954658391561541182921978025116693987995964220399091076462997685125730245187655200335183
q = 179434016998140031014368067904766081797986046197796143005154180586375739721169434781338336010438890164727776935390319878190484756530606555575566145849600611045908804661009299426088268999760269961430672640255341016386574914749521369064082756920181913030489172136557795523587135738615158374227952275819162957527
c = 28502957797327045767985236917760422196161961427609288501040821148578184890255528094925680917559890025155665851157310930601925216950553360053457655219378488534569091874119224665465564602479111367175108424055994961443368844256802504075949400191163184395696420192135775548413524183946302686864401083925251821992176479498256509277106306292961652379024856772746376842003779195106840973987122624555023876915779125969908294235750383404947046876892761276140432773813581856906409298780829601981625721630520583111943510355274379523760918502531060590060878780704586079788208139072053734418994815689327092740873631199305764701101
e = 65537

n = p * q
phi = (p - 1) * (q - 1)
d = invert(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)

print("flag:", flag.decode())

#flag:XAUTCTF{B4sic_rsa}

RSA Level 2


题目描述:如果N相同,咋办呀


打开附件:

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 secret import flag
flag = ''

p = getPrime(1024)
q = getPrime(1024)
e1 = 65537
e2 = 17
m = bytes_to_long(flag)

print("N =", N)
print("c1 =", c1)
print("c2 =", c2)

'''
N = 17742883093375430209933780827720373184192033032113850848290259626753776160310652775194394280077879399470438225584966759302605436714424041654119002336706046920556981531478522358960683046640263531845198616499455513888753814470704084612516302118614717589777646437105634806046555639001958185915128803184308793660980485033198339303770540170649651576734290591868935037134313634769082038219339944754965791948071305212832936342477572279979839259168234256451878840424055187258963042166563687998648838088445249323114374159905431396079566655358241227264130828452609382289050758685852838091113549741684909677228556491103704648233
c1 = 4209524713291018361207432630163969790398614710361573691639925490967143757579042703893521982159350347316340633712913968872194655072092495881088889617393240783996273950275785937844281745666761736642553118553803256001578129898850803172873792675951325758523960546783494070910276621781768702688046958633813763371323199565035207534169507937047513688009294562101517999274218767449099312518853277302151459928243689399073592003694723545484333679529436771029977915304646275571324346968442115352514920207004046996538380627267473050156819585731327426891702087017767805096175987261617671398594091749112554247713345354526089528704
c2 = 5121911425923282820844079080731922537971303651770938553190884199965858259287926941333623045676843064688657554610105219525386188669290350482072684260928497862056089076852705060413881338428627384679674509758016510111760562829543256630437025837081758958357475038562656027789326545769354046462070447374575449873061448254780009787028305445541324529564117869788432974956204444305714512756435236434923127529028205572971125902616542476757052054065046734257840419969212063395501327245161396123771804520958713818591018141479564553526050926745048456932295209491950218526112466119588740622700366942385099638519546146399285888806
'''

给了两个c和两个e,e1e2c1c2,还有一个共同的N,结合RSA相关,知道是共模攻击

核心思路是利用扩展欧几里得算法,求s1&s2,用m = (c1^s1 * c2^s2) mod N解得最后的flag。

exp:

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

N = 17742883093375430209933780827720373184192033032113850848290259626753776160310652775194394280077879399470438225584966759302605436714424041654119002336706046920556981531478522358960683046640263531845198616499455513888753814470704084612516302118614717589777646437105634806046555639001958185915128803184308793660980485033198339303770540170649651576734290591868935037134313634769082038219339944754965791948071305212832936342477572279979839259168234256451878840424055187258963042166563687998648838088445249323114374159905431396079566655358241227264130828452609382289050758685852838091113549741684909677228556491103704648233
c1 = 4209524713291018361207432630163969790398614710361573691639925490967143757579042703893521982159350347316340633712913968872194655072092495881088889617393240783996273950275785937844281745666761736642553118553803256001578129898850803172873792675951325758523960546783494070910276621781768702688046958633813763371323199565035207534169507937047513688009294562101517999274218767449099312518853277302151459928243689399073592003694723545484333679529436771029977915304646275571324346968442115352514920207004046996538380627267473050156819585731327426891702087017767805096175987261617671398594091749112554247713345354526089528704
c2 = 5121911425923282820844079080731922537971303651770938553190884199965858259287926941333623045676843064688657554610105219525386188669290350482072684260928497862056089076852705060413881338428627384679674509758016510111760562829543256630437025837081758958357475038562656027789326545769354046462070447374575449873061448254780009787028305445541324529564117869788432974956204444305714512756435236434923127529028205572971125902616542476757052054065046734257840419969212063395501327245161396123771804520958713818591018141479564553526050926745048456932295209491950218526112466119588740622700366942385099638519546146399285888806
e1 = 65537
e2 = 17

g, s1, s2 = gcdext(e1, e2)
if s1 < 0:
c1 = invert(c1, N)
s1 = -s1
if s2 < 0:
c2 = invert(c2, N)
s2 = -s2

m = (pow(c1, s1, N) * pow(c2, s2, N)) % N
flag = long_to_bytes(m)
print("flag =", flag.decode())

#flag:XAUTCTF{pr0ceed_T0_lev3l_2}

Hello Elgamal


题目描述:你知道基于DLP的是什么加密算法吗?


打开附件:

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
from Crypto.Util.number import *
import random
from secret import flag

p = getPrime(512)
g = random.randint(2, p - 2)
x = random.getrandbits(32)
y = pow(g, x, p)

print(f'{p = }')
print(f'{g = }')
print(f'{y = }')

k = random.randint(2, p - 2)
m = bytes_to_long(flag)
c1 = pow(g, k, p)
c2 = m ^ pow(y, k, p)

print(f'{c1 = }')
print(f'{c2 = }')

'''
p = 10560464175631160709999383504944939280267067560378620626979040921315467798501630079655340663547895515812021911470304483075907600549587171358369476255124337
g = 5572911063894340974483734192541353411838868965361107134612465011908061780180242348779533324820127053271574799429894984956163372524626786431177292215721384
y = 2551976503972625362405323290468587787679347326045114894085518452627208422960190509410833573983206966744456211220857302778318665690771595372276106771043208
c1 = 9071965584576264923403086591232117827858384577456456793981072915555026112823425849396400204347722315236083995667089323229271125340514070188310355442538777
c2 = 159183163208726126854573937893634069311746313774681822974188715631240731794775157584781489466403748407493148663593792165690310529079522526949802954050789
'''

结合题目elgamal知道是elgamal的公钥加密,其中p是大素数、g是生成元、y = g^x mod p是公钥,x是私钥,计算c1c2

核心的解码公式是s = pow(c1, x, p)m = c2 ^ x

我们通过暴力破解得到x,利用XOR来得到最终的flag,exp采用多进程来提高爆破效率。

exp:

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
from Crypto.Util.number import long_to_bytes
import multiprocessing as mp
from multiprocessing import Manager
import time

p = 10560464175631160709999383504944939280267067560378620626979040921315467798501630079655340663547895515812021911470304483075907600549587171358369476255124337
g = 5572911063894340974483734192541353411838868965361107134612465011908061780180242348779533324820127053271574799429894984956163372524626786431177292215721384
y = 2551976503972625362405323290468587787679347326045114894085518452627208422960190509410833573983206966744456211220857302778318665690771595372276106771043208
c1 = 9071965584576264923403086591232117827858384577456456793981072915555026112823425849396400204347722315236083995667089323229271125340514070188310355442538777
c2 = 159183163208726126854573937893634069311746313774681822974188715631240731794775157584781489466403748407493148663593792165690310529079522526949802954050789

STEP = 1000000


def worker(start_x, end_x, result_queue):
print(f"[进程] 爆破区间 [{start_x}, {end_x})")
for x in range(start_x, min(end_x, 1 << 32)):
if pow(g, x, p) == y:
s = pow(c1, x, p)
m = c2 ^ s
try:
flag = long_to_bytes(m).decode('utf-8', errors='ignore')
except:
flag = str(long_to_bytes(m))
result_queue.put((x, flag))
return
if x % STEP == 0 and x > start_x:
print(f"[进程 {start_x}] 已尝试 {x - start_x} 个值...")
result_queue.put(None)


def main():
num_cores = mp.cpu_count()
print(f"检测到 {num_cores} 个 CPU")

total = 1 << 32
chunk_size = (total + num_cores - 1) // num_cores

manager = Manager()
result_queue = manager.Queue()

processes = []
start_time = time.time()

for i in range(num_cores):
start_x = i * chunk_size
end_x = start_x + chunk_size
p = mp.Process(target=worker, args=(start_x, end_x, result_queue))
p.start()
processes.append(p)

result = None
while result is None:
try:
tmp = result_queue.get(timeout=1)
if tmp is not None:
result = tmp
break
except:
pass

if result:
x, flag = result
print(f"\n找到私钥 x = {x}")
print(f"Flag: {flag}")
elapsed = time.time() - start_time
print(f"耗时: {elapsed:.2f} 秒")

for p in processes:
p.terminate()
p.join()
else:
print("未找到 x")


if __name__ == '__main__':
mp.set_start_method('spawn', force=True)
main()

#flag:XAUTCTF{31g4m41_D15cr373_fUn}

Reverse

JS_Enigma


题目描述:

啥也不会的debu8ger一个寒假没碰自己的博客,开学打开发现了一个神奇的网页! 请你定位到这个网页并收获属于你的first egg! 博客地址:https://incldue.github.io/

提示:flag在/flag


点开博客,根据提示直接拼接命令进入/flag.html,是一个flag加密界面:

re1

F12查看源代码,得到核心加密逻辑:

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
var key = 6;

var Cipher = "^GSRER@}R6jbYSYluYui6i6YC|||'{";

function log(msg) {
var box = document.getElementById("log");
box.innerHTML += msg + "\n";
box.scrollTop = box.scrollHeight;
}

function sleep(ms) {
return new Promise(r => setTimeout(r, ms));
}

function xorEncrypt(str) {
var res = "";
for (var i = 0; i < str.length; i++) {
res += String.fromCharCode(str.charCodeAt(i) ^ key);
}
return res;
}

async function start() {

document.getElementById("log").innerHTML = "";

var input = document.getElementById("inputFlag").value;

log("[*] Loading Encrypt Engine...");
await sleep(300);

log("[*] Using my secret...");
await sleep(500);

log("[*] Encrypting input...");
await sleep(700);

var encrypted = "";

for (var i = 0; i < input.length; i++) {
encrypted += String.fromCharCode(input.charCodeAt(i) ^ key);
log(" -> processing: " + input[i] + " => " + encrypted[i]);
await sleep(80);
}

将明文用6进行异或得到Cipher,解密直接逆着异或来得到原始flag:

1
2
3
4
5
6
7
8
9
10
cipher = "^GSRER@}R6jbYSYluYui6i6YC|||'{"
key = 6

flag = ""
for c in cipher:
flag += chr(ord(c) ^ key)

print(flag)

#flag:XAUTCTF{T0ld_U_js_so0o0_Ezzz!}

EzPy


题目描述:深夜一条披着羊皮的小蛇溜进了农场主的农场里, 请你找到这条小蛇并获得你的奖励吧!


根据题目,知道是用python打包的.exe文件,于是将exe文件解包,得到一堆东西

找到有和原文件同名的.pyc文件,用在线网站PyLingual反编译:

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
import base64
def Gen(key):
s = list(range(1024))
j = 0
for i in range(1024):
j = (j + s[i] + ord(key[i % len(key)])) % 1024
tmp = s[i]
s[i] = s[j]
s[j] = tmp
i = j = 0
data = []
for _ in range(50):
i = (i + 1) % 1024
j = (j + s[i]) % 1024
tmp = s[i]
s[i] = s[j]
s[j] = tmp
data.append(s[(s[i] + s[j]) % 1024])
return data
def encrypt(text, key):
result = ''
for c, k in zip(text, Gen(key)):
result += chr(ord(c) ^ k)
result = base64.b64encode(result.encode()).decode()
return result
text = input('Your flag: ')
key = 'welcome_to_our_5th_xautctf'
enc = encrypt(text, key)
if enc == 'xLnEqs+AwpLLpsqzzb/EnG3ImsSTKcuNxYkyz6LIrs+Rx5zLuMKYwp3Kgsaqw5bDis2Wx4I=':
print('You are the best!')
else:
print('Sorry, try again!')

整个流程就是将flag用Gen(key)生成的50字节密钥进行逐字节的XOR,然后再用base64编码得到密文。

S盒,说明是改造版的RC4加密,用key = 'welcome_to_our_5th_xautctf'循环打乱S盒PRGA算法生成密钥,XOR加密,最后base64编码。

最后的exp就是把以上过程逆着来一遍:

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
import base64

def gen(key):
s = list(range(1024))
j = 0
for i in range(1024):
j = (j + s[i] + ord(key[i % len(key)])) % 1024
s[i], s[j] = s[j], s[i]

i = j = 0
data = []
for _ in range(50):
i = (i + 1) % 1024
j = (j + s[i]) % 1024
s[i], s[j] = s[j], s[i]
data.append(s[(s[i] + s[j]) % 1024])
return data

def decrypt(enc, key):
cipher = base64.b64decode(enc).decode()
result = ''
for c, k in zip(cipher, gen(key)):
result += chr(ord(c) ^ k)
return result

key = 'welcome_to_our_5th_xautctf'
enc = 'xLnEqs+AwpLLpsqzzb/EnG3ImsSTKcuNxYkyz6LIrs+Rx5zLuMKYwp3Kgsaqw5bDis2Wx4I='
flag = decrypt(enc, key)
print(flag)

#flag:XAUTCTF{Y0u_cr5cked_0ur_py!}

test your asm


题目描述:来学习一下好玩的asm嘛?


下载附件,在DIE里检查:

re2

64位ELF文件,无壳,IDA打开

main函数即为主逻辑,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
__int64 i; // rcx
char v4; // al
__int64 j; // rdx
char v6; // al

scanf("%s", _TMC_END__);
for ( i = 0LL; ; ++i )
{
v4 = _TMC_END__[i];
if ( !v4 )
break;
_TMC_END__[i] = __ROL1__(i + (v4 ^ 0x13), 3) ^ 0x37;
}
for ( j = 0LL; ; ++j )
{
v6 = _TMC_END__[j];
if ( v6 != d1[j] )
break;
if ( !v6 )
return 0;
}
return 1;
}

将flag与0x13异或后循环左移3位,再异或0x37得到密文。

点进d1数组查看,发现一连串数据,即为密文数据

re3

最后exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cipher = [
0x6D,0xAD,0x75,0x65,0x95,0x55,0xED,0x4C,
0xE4,0x7C,0x73,0x8D,0x03,0x5C,0xE5,0x4C,
0xAE,0xDD,0x73,0xD4,0xDC,0xC4,0x24,0x53,
0x93,0xE4,0x04,0x3B,0x45,0x6B
]

def ror(x, r):
return ((x >> r) | (x << (8-r))) & 0xff

flag = []
for i, c in enumerate(cipher):
x = c ^ 0x37
x = ror(x, 3)
x = (x - i) & 0xff
x ^= 0x13
flag.append(x)

print(bytes(flag).decode())

#flag:XAUTCTF{asm_is_s0_ezzz_for_u!}

EzTea


题目描述:请你喝一杯淳朴的茶 ~~


[这题本来想考察TEA加密的,但是点进数据转hex可以直接出flag,这题没出好,我的错,道歉了 :( ]

老习惯,下载完DIE一下,

re4

没加壳,64位可执行文件,再IDA打开,

主函数入口在sub_140002900

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
__int64 sub_140002900()
{
_BYTE *v0; // rbx
_BYTE *v1; // rsi
_BYTE *v2; // rcx
__m128i si128; // [rsp+20h] [rbp-48h] BYREF
_OWORD v5[2]; // [rsp+30h] [rbp-38h] BYREF
_BYTE v6[24]; // [rsp+50h] [rbp-18h] BYREF

sub_140001590();
v0 = v5;
v1 = v5;
si128 = _mm_load_si128((const __m128i *)&xmmword_140004010);
v5[0] = _mm_load_si128((const __m128i *)&xmmword_140004020);
v5[1] = _mm_load_si128((const __m128i *)&xmmword_140004030);
do
{
v2 = v1;
v1 += 8;
sub_140001440(v2, &si128);
}
while ( v6 != v1 );
puts("Encrypted:");
do
{
v0 += 4;
sub_140002640("%08X");
}
while ( v6 != v0 );
return 0LL;
}

v5数组存储密文,函数sub_140001440对应TEA加密,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
v2 = *a1;
v3 = *(_DWORD *)(a2 + 4);
v4 = *(_DWORD *)(a2 + 8);
v6 = a1[1];
v8 = 0;
do
{
v9 = v8;
v8 += 1779033703;
v2 += (v3 + (v6 >> 5)) ^ (v6 + v9 + 1779038363) ^ (*(_DWORD *)(a2 + 4LL * ((v8 >> 11) & 3)) + 16 * v6);
result = (v2 + v9 + 1779055839) ^ (v4 + 16 * v2) ^ (*(_DWORD *)(a2 + 4LL * ((v8 >> 13) & 3)) + (v2 >> 5));
v6 += result;
}
while ( v8 != 1094503648 );
*a1 = v2;
a1[1] = v6;
return result;

每次对64 bit的数据块进行32轮运算,key128 bit

通过对常数进行进制转换,得到了常数0x6A09E667,为TEA算法的经典特征

v2 += F(v6, sum, key)v6 += G(v2, sum, key)进行32轮逆运算得到flag

密文则是通过运行程序得到:

re5

所需的key在数据xmmword_140004010中,

re6

编写最终exp:

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
import struct

cipher_hex = "80EF02004ED8294CBFB53E7FF6D7ECA70A7B97F3292FC805CBA06F4E60DFABD8"
v = []
for i in range(0, len(cipher_hex), 8):
v.append(int(cipher_hex[i:i+8], 16))
k = [
0x13572468,
0x24681357,
0xDEADBEEF,
0xCAFEBABE
]

delta = 0x6A09E667
rounds = 32

def Tea_dec(block):
v0, v1 = block
sum = (delta * rounds) & 0xffffffff
for _ in range(rounds):
v1 = (v1 - (
((v0 << 4) + k[2]) ^
(v0 + sum + 0x5678) ^
((v0 >> 5) + k[(sum>>13)&3])
)) & 0xffffffff

v0 = (v0 - (
((v1 << 4) + k[(sum>>11)&3]) ^
(v1 + sum + 0x1234) ^
((v1 >> 5) + k[1])
)) & 0xffffffff

sum = (sum - delta) & 0xffffffff

return [v0, v1]

for i in range(4):
v[2*i], v[2*i+1] = Tea_dec([v[2*i], v[2*i+1]])

plaintext = b''.join(struct.pack(">I", x) for x in v)
print(plaintext.decode())

#flag:XAUTCTF{Y0u_kn0w_tea_v3ry_much!}

贪吃蛇…吧


题目描述:你玩过贪吃蛇吗? 听说达到了50000分的勇者可以获得一把屠龙宝刀哦~

​ 提示:想想UPX的特征呢


照例,DIE一下,

re7

64位可执行文件,有UPX压缩壳,用UPX尝试脱壳,显示错误

re8

于是在010里面查看hex详情,

re9

可以看到在原本UPX特征位上的UPX字符不对,所以我们选中XUT,将其修改为UPX,替换所有的XUT,然后再进行UPX的脱壳,成功脱壳,得到原文件

点击,是贪吃蛇的游戏,根据题目猜测得打满50000分才能获得flag

re10

用IDA打开,查看字符串发现有Py...样式的字符,推测可以用python解包,

于是跟上面EzPy一样的操作解包,在在线网站反编译,直接得到了源码

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
import random
import sys
import time
import pygame
from pygame.locals import *
from collections import deque
import struct
Screen_Height = 480
Screen_Width = 600
Size = 20
Line_Width = 1
Area_x = (0, Screen_Width // Size - 1)
Area_y = (2, Screen_Height // Size - 1)
Food_Style_List = [(10, (255, 100, 100)), (20, (100, 255, 100)), (30, (100, 100, 255))]
Light = (100, 100, 100)
Dark = (200, 200, 200)
Black = (0, 0, 0)
Red = (200, 30, 30)
Back_Ground = (40, 40, 60)
F_flag = 'XAUTCTF{u_think_this_is_your_flag?}'
enc_flag = [1020552516, 2334011411, 2747013171, 3280201786, 693978663, 2011163427, 3195512570, 4073077514]
def gen_key(score, length):
k0 = score * 4919 ^ 3735928559
k1 = length << 5 ^ 2775296973
k2 = score << 3 ^ 1736282519
k3 = length * 4660 ^ 2993693404
return [k0 & 4294967295, k1 & 4294967295, k2 & 4294967295, k3 & 4294967295]
def tea_dec(v, k):
v0, v1 = v
delta = 2654435769
sum = delta * 32 & 4294967295
for _ in range(32):
v1 = v1 - ((v0 << 4) + k[2] ^ v0 + sum ^ (v0 >> 5) + k[3]) & 4294967295
v0 = v0 - ((v1 << 4) + k[0] ^ v1 + sum ^ (v1 >> 5) + k[1]) & 4294967295
sum = sum - delta & 4294967295
return (v0, v1)
def decrypt_flag(score, length):
k = gen_key(score, length)
data = []
for i in range(0, len(enc_flag), 2):
v = tea_dec((enc_flag[i], enc_flag[i + 1]), k)
data.append(v[0])
data.append(v[1])
out = b''
for x in data:
out += struct.pack('>I', x)
res = bytearray(out)
for i in range(1, len(res)):
res[i] ^= res[i - 1]
try:
return res.decode()
except:
return F_flag
def Print_Txt(screen, font, x, y, text, fcolor=(255, 255, 255)):
Text = font.render(text, True, fcolor)
screen.blit(Text, (x, y))
def init_snake():
snake = deque()
snake.append((2, Area_y[0]))
snake.append((1, Area_y[0]))
snake.append((0, Area_y[0]))
return snake
def Creat_Food(snake):
food_x = random.randint(Area_x[0], Area_x[1])
food_y = random.randint(Area_y[0], Area_y[1])
while (food_x, food_y) in snake:
food_x = random.randint(Area_x[0], Area_x[1])
food_y = random.randint(Area_y[0], Area_y[1])
return (food_x, food_y)
def Food_Style():
return Food_Style_List[random.randint(0, 2)]
def main():
pygame.init()
screen = pygame.display.set_mode((Screen_Width, Screen_Height))
pygame.display.set_caption('贪吃蛇')
font1 = pygame.font.SysFont('SimHei', 24)
font2 = pygame.font.SysFont(None, 72)
fwidth, fheight = font2.size('GAME OVER')
b = True
snake = init_snake()
food = Creat_Food(snake)
food_style = Food_Style()
pos = (1, 0)
game_over = True
game_start = False
score = 0
orispeed = 0.3
speed = orispeed
last_move_time = None
pause = False
flag_text = ''
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
else:
if event.type == KEYDOWN:
if event.key == K_RETURN:
if game_over:
game_start = True
game_over = False
b = True
snake = init_snake()
food = Creat_Food(snake)
food_style = Food_Style()
pos = (1, 0)
score = 0
flag_text = ''
last_move_time = time.time()
else:
if event.key == K_SPACE:
if not game_over:
pause = not pause
else:
if event.key in (K_UP, K_w):
if b and (not pos[1]):
pos = (0, (-1))
b = False
else:
if event.key in (K_DOWN, K_s):
if b and (not pos[1]):
pos = (0, 1)
b = False
else:
if event.key in (K_LEFT, K_a):
if b and (not pos[0]):
pos = ((-1), 0)
b = False
else:
if event.key in (K_RIGHT, K_d) and b and (not pos[0]):
pos = (1, 0)
b = False
screen.fill(Back_Ground)
for x in range(Size, Screen_Width, Size):
pygame.draw.line(screen, Black, (x, Area_y[0] * Size), (x, Screen_Height), Line_Width)
for y in range(Area_y[0] * Size, Screen_Height, Size):
pygame.draw.line(screen, Black, (0, y), (Screen_Width, y), Line_Width)
if not game_over:
curTime = time.time()
if curTime - last_move_time > speed and (not pause):
b = True
last_move_time = curTime
next_s = (snake[0][0] + pos[0], snake[0][1] + pos[1])
if next_s == food:
snake.appendleft(next_s)
score += food_style[0]
speed = orispeed - 0.03 * (score // 100)
food = Creat_Food(snake)
food_style = Food_Style()
if score >= 50000 and flag_text == '':
flag_text = decrypt_flag(score, len(snake))
if Area_x[0] <= next_s[0] <= Area_x[1] and Area_y[0] <= next_s[1] <= Area_y[1] and (next_s not in snake):
snake.appendleft(next_s)
snake.pop()
game_over = True
if not game_over:
pygame.draw.rect(screen, food_style[1], (food[0] * Size, food[1] * Size, Size, Size), 0)
for s in snake:
pygame.draw.rect(screen, Dark, (s[0] * Size + Line_Width, s[1] * Size + Line_Width, Size - Line_Width * 2, Size - Line_Width * 2), 0)
Print_Txt(screen, font1, 30, 7, f'速度: {score // 100}')
Print_Txt(screen, font1, 450, 7, f'得分: {score}')
if flag_text!= '':
Print_Txt(screen, font1, 200, 7, flag_text, (255, 255, 0))
if game_over and game_start:
Print_Txt(screen, font2, (Screen_Width - fwidth) // 2, (Screen_Height - fheight) // 2, 'GAME OVER', Red)
pygame.display.update()
if __name__ == '__main__':
main()

可以看到一眼假的flag,下面的便是真正的密文,有8个32bit整数,4个TEA加密块

后面的密钥生成依赖于你所得分数和最终蛇的长度

后面有TEA加密常数0x9E3779B9,进行32轮的解密

第二层是一个链式的XOR,res[i] ^= res[i - 1],解码只需逆着来

要解码,我们得估算到50000分时蛇的大概长度,当然也可以暴力破解直接拿到估计长度,逆向算法后通过暴力枚举参数来获得50000分时的长度。

最终exp:

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
import struct

enc_flag = [
0x3cd46544,0x8b1e3013,
0xa3bc1833,0xc383e83a,
0x295d4627,0x77dfeb23,
0xbe77a6fa,0xf2c63b0a,
]

order=[2,0,3,1]

def unshuffle(blocks):
res=[None]*4
for i,p in enumerate(order):
res[p]=blocks[i]
return res

def gen_key(score,length):
k0=(score*0x1337)^0xDEADBEEF
k1=(length<<5)^0xA56BABCD
k2=(score<<3)^0x677D9197
k3=(length*0x1234)^0xB27022DC
return [k0&0xffffffff,k1&0xffffffff,k2&0xffffffff,k3&0xffffffff]


def tea_dec(v,k):
v0,v1=v
delta=0x9E3779B9
sum=(delta*32)&0xffffffff
for _ in range(32):
v1=(v1-(((v0<<4)+k[2])^(v0+sum)^((v0>>5)+k[3])))&0xffffffff
v0=(v0-(((v1<<4)+k[0])^(v1+sum)^((v1>>5)+k[1])))&0xffffffff
sum=(sum-delta)&0xffffffff
return v0,v1

blocks=[]

for i in range(0,len(enc_flag),2):
blocks.append((enc_flag[i],enc_flag[i+1]))

blocks=unshuffle(blocks)
k=gen_key(50000,15)
data=b''
for b in blocks:
v=tea_dec(b,k)
data+=struct.pack(">II",v[0],v[1])
buf=bytearray(data)
for i in range(len(buf)-1,0,-1):
buf[i]^=buf[i-1]

print(buf.rstrip(b"\x00").decode())

#flag:XAUTCTF{u_c4ptured_littl3_sNake}
⬆︎TOP