第五届大学生信息安全竞赛-部分WP

debu8ger Lv3

Crypto

BASE ALL


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


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

JJFEIRKNKJFUYS2KIZKTIVCDJJGEUQ2VJ5KTEVCLGVDFMRKTGJDEWTSMIVLVIQ2MJJNEIRSNKRFVOS2OIVKVKUSTJJFVURKWI5KTESKKJZBVMVKWKNIEWSK2IRCVEMSLJFHEWVSTKUZEYR2KIVKEWU2TKVFFMSKUIVKEWS2MJJDFMSKSJNLUWTSMIVHVMU2EJFLEIVSJKVNFGSSOJRCUOUSLJRFVKWSFJFJUWS2KIZBVKS2VLJJUWNKGIU2FGMSGJFLEYVKHKRJUQS22IVCUWVBSKZGEUSSVKNKFGRSJKVNEMT2VKNLEUTSOIVKVMQ2MJNGVURSRKNFFMSK2INLE6VKTGJFTKRCVGRJTERSLIZFFIRKRGJFUSWSGKZFVMMSPJNHEGRKXKNJUQS22JNLEGVJSLFFE4RCFKFJFGSSLGVFFKVKTKNFUUVSMIU3FMUSTJNHEKVJUKJFVMSZVJFLEOUSLJRDVMR2GJFKEWVCHJJGEKVKOJNEUSWSGKZHVCMSRJJHEYRKPKJJUYS2OIZKU6VCDI5EVMQ2UIVLEGVCJJZDFIS2SGJLEOUSMKVLVEU2KJNLE4RKJKIZFISKOIZKVKU2TI5EVMSCWIVJTEUCKJZEVMVKSJJJUWWSKIZEVGMSTJE2UYRJWKZFVIR2KIZCTIUSLK5FU4TCGI5KVGSCLLJCEMS2WGJKUOSSIKVKVGU2EJFLEMVSLKMZE2SSKIRCU2USLIZFTKQSVJNJUUVKMJJCEKS2WKNCEUVSGIVKVIS2WJJLEWVSVKZJUQSS2IJKUWTKTKNFU4SCVKNKVGRKLKJDFKMSNKNJEURJSKVGVEQ2GJNNEEVSFKRBUOSK2JNKEKVSDKRFDKRCVKVITEV2JJZEEKR2VGJGEOVSDIZFVMS2TJNHEWVKVJZFU2S2WIRLEKVJSJNFE4RSFKVJFGTCLJVNEMS2TGJHUUSSLKU3FKMSUJNHEMVSNKNFVOSSOI5LEOVJSJREUURCFJVITEV2LJZFEKWKTKNBUSWSIKZDVGMSMJJDEMRJSKJJUIS22IZLESU2KKZEVETCFJNKVGVCJKZCVIS2UJNKUSVSKIVDVKQ2MJRFEEVKNKVFVOSSOJBKVGU2TJNFVKMSGIVKTEVCKJZFEKU2WKNGEWVK2IZGVGU2LJFFEGVKTKZJUIS2KIZKVKUKTI5FVMS2GI5KDETCKJJDFMS2NKNHEWSSLIVLU4S2IJFLEUVJSJVJUQSSGINKEKVSDJBFTKRSVGJJUWS2JLJCEKV2VKJJUYQSGKU2FIU2GJNHEURSHKUZEWSKKIZDEWTKTJZFU4S2VKNHEEU2LKZFFMT2RGJFUUTJSKVKVEU2KJNEVURSPKMZE6SKSINKE2VSLKRFVMRKWIVJEWRSJJZGFKV2XINFEUVK2KVGVEMSYJJHEQVKVKZFTES22I5LE2U2TKVFE4SSFGJJFGQSLJJFFKV2TGJLUSUSMIUZFISSTJM2UMRSNKNBUMSKWJJKUOUSDJRGEURSGJNJUWVKHJJFFKV2TKNGESVJTIZGVCMSVJJJEIRKNKZFVMS2OIJKVCU2LJ5FFEQ2VJ5KUWVCKKJCVMVKTKNLUURSKIVLVOU2LJNFEEVKLJZBVGS2OIVCVOVSTINFVUSCWI5KTEVKKIUZFKU2WINEEWTSCKU2FGMSPJFHEIRSLKZBTES22IZCTIUSDK5ETKSCFK5LEWTCJLJBVMS2WJNMESTSFIVKU4S2MJNLE2VSLKUZFCSSOJZCU2USLJJFUSWSFGZJTEU2JJJFVKNSWKNFUWUSFKRFVGMSXJFLEYRKHKVFUWR2WIVCUWURSKNDUURSFJ5LVGS2JLJDFMR2TGJMEUTSIIUZFES2MJNIVURJSKMZEGSJVJRCTEVKTIREVMRSVJVJUWVSMIZFFMR2UINEEWWSFKZGVKS2TJJFEWVKXKNJU4SKVGJDEKVJSKBFEMTSFJ5LFGTSLJZFFMR2TKNFUUUSEIVJVMU2EJJJEIVSVKMZEOSJVJJLEOUJSJRFEUQ2VJNJTEVKKJZFUKV2OJNEESVSDKZCVCMSHJJJEGVCFKZBUQS2WIZLECU2TGJFFETCGINKTETCLKZDFKNCRGJDEOSSLIZCVMS2KI5IVURKNKNFVGSKNLJCVOUKTIVEVURCWI5ITER2KJZFEKVKWJNNEWTSKKZHVGU2PJFHEWVKXKRJUYSKSIZLE2USLK5EVMTCGI5JDESSJLJDEMS2SGJLUSTSFIVLVOU2IJNNEOVSDJVJVKSJVIZCUSVSLKZFVMSSVI5JVGQ2JJJFUKT2UJNKEWQSFKRFVGQ2GJNHEYRSVKUZE2SSGJZDE2U2LKNDUSWSFJ5KFGTKLKZEFMT2TLJJUUUSGIVIVMSSVJNGVURSFKNBVMR22JNCEKVKDJJEFKPJ5HU6T2PI=

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

BHFgBMg4QRUjtBi47cgDZ2ixKm5Ztbnh2HAxUUL7gZihGfyYuV2TongPQExQfCh6yBqkDHPGkyTsiwQtApv46cpBkgJRb6zew6Z9R1XuJsR2AHHn3j3ZpYwcaZ3wo2u8aLktHr62K7XEDcENR2cHSQzaXd6BCxRF4J3cCuGz42ic8RTHG8D9kcFkvZ6PwxXSCZYAby3S7QtZ35dWFc81azXk7ZnwySCWucBqVCtc7NXRNaTAQe2aciMAY246vHywTivpBngQquR36b56jFosDdz4Eer9oeF8AiWarr7iZVU1Mg5zrHbr2VXFLwpsmtNCcxnLyydrNKMTBtTDjPHS5YQKFLBqoN3Qmgs6wcc9sU

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

VmpCV1IxWnNXa1pVYkZaVFltNVNWVlJWV1RWbGJVbDRUMVpTVGxKcWJEQlVhMk14VjJ4bmVsVnJjR2xXTVZvMlUxWm5kMUJSUFQwPQ==

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

RSA Level 1


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


下载附件,

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:

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相同,咋办呀


打开附件:

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:

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的是什么加密算法吗?


打开附件:

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:

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查看源代码,得到核心加密逻辑:

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:

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反编译:

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就是把以上过程逆着来一遍:

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函数即为主逻辑,

{
__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:

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

__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加密,

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:

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一样的操作解包,在在线网站反编译,直接得到了源码

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:

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}
评论