这个比赛太难了,就作了4个题
Crypto Bedouin
题目非常短,就是先生成一个小素数,然后堆到一起l次再补个1,比如235就变成2352352351这样,一开始以为是2进制,一直没作出来,方式也没错。后来发现原来是按10进制作的。
#!/usr/bin/env python3from Crypto.Util.number import *
from secret import nbit, l, flagdef genbed(nbit, l):while True:zo = bin(getPrime(nbit))[2:] #将生成的素数按2进制展开OZ = zo * l + '1' #重复l次后补 1if isPrime(int(OZ)):return int(OZ) #按10进制返回p, q = [genbed(nbit, l) for _ in '01']
n = p * q
print(p,q,n)d = 1 ^ l ** nbit << 3 ** 3
phi = (p - 1) * (q - 1)
e = inverse(d, phi)
m = bytes_to_long(flag)
c = pow(m, e, n)if pow(c, d, n) == m:print(f'n = {n}')print(f'c = {c}')#n = 11121113123123225316356434558678774858078977276593397021624543840384563202155115058738121019496122867665089041531378765495378941511466657718894542904114559625642441128465120925869122510013821648504078756132678905746339918416164541967844556049129767198192120832242122152362554255476778746769978869981213179113423219879222189087301075677966655352464552361280530032139098871700688581383095249648153220815492192663813749608239655446091552718931797425166398881063388617148221988950883221751762196240326423538512655539718553076583064818193698890426088652913348728253613222688032199816839097468785655633345553434234332211221
#c = 5803843969579132819335011147316700126850138645040786164613358324092389257116809400026966450184769375312899614327409585905225984512416350357377317869970672798156364680892279582644858593231713523918843003132993052161445288600305597235814501843656650641435288766888570072089417279402327786422304840443072946105311935400719421676606837065330750119585868374198105257007769314552030416147375054014617867407120886709602787976009552494441839542161616895658128320828121588847607421594537828968601732104230218732437554934895126797258625829953684512887833584347693414306725103727114467326912748686785899766881841877099566330733
就卡在弄错的一个地方了。看明白就好办了,一定要细心
RSA题当然是分解了,这里先生成的数设为x则有
p = x*10**((l-1)*nbit+1) + x*10**((l-2)*nbit+1) + ... + x*10**1 + 1
也可以理解为
p = x * 1---1---1---1...---11
这里设这个数为m则有
p = x*m + 1
q = y*m + 1
n == p*q = mmxy + mx + my + 1
(n-1)%m**2//m = x+y
(n-1-m*(x+y))//m**2 = xy
但m的l和nbit未给出,不过这个不难,两个都不大而且相关,可以爆破。
for l in range(2,1000):for bits in range(2,512):m = int(('1'.rjust(bits,'0'))*l + '0') #K,这里是10进制if ((n-1)%m) == 0:print(l,bits,m)
爆破结果是2,4,7,14,28显然用最大一个其它都是它的因子。
l = 11
nbit = 28
m = int(('1'.rjust(nbit,'0'))*l + '0') #10进制
p_q = ((n-1)%m**2)//m
pq = (n-1-m*p_q )//m**2
print(f"{pq = }\n{p_q = }")
#pq = 1112111312312322531635643455645455223345433221332211011
#p_q = 1055505550550505605055555506
然后就好办了,直接用z3解出p,q
from z3 import *
p,q = Ints('p q')
s = Solver()
s.add(p+q == p_q)
s.add(p*q == pq)
if s.check() == sat:print(s.model())
'''
tq = 1100010100100000110100001011
tp = 1011001001001011100011110001
'''
最后根据pq求出m
p = m*tp +1
q = m*tq +1
print(p)
print(q)d = 1 ^ l ** nbit << 3 ** 3
m = pow(c,d,n)
print(bytes.fromhex(hex(m)[2:]))
#ASIS{B48y_CrYpT0_4_WaRm_Up_N3veR_TrU57_yOuR_3yEs!}
REV Deserve
一般会的题都不难,这个题比较新,我原来想过一个问题,如果加密的时候用的解密程序会是什么样。结果这题真是用解密程序作的加密。
符号表都删了,函数名都没有,不过很容易看到主函数里就一个加密一个输出。闲来无事给它改了一下名。
void __fastcall __noreturn sub_A80(int a1, const char **a2)
{__int64 v2; // [xsp+10h] [xbp+10h] BYREFsize_t len; // [xsp+18h] [xbp+18h] BYREFif ( a1 != 1 )sub_F74(*a2);len = read(&v2);enc(v2, &len);write_s(v2, len);exit(0);
}
加密函数前边是对原始数据作了个替换,符号和空格改成+n,++n,/
v8 = __ctype_b_loc(); // 字符类型v9 = 0;do{v10 = (unsigned __int8)a1[v7];size = v6;v11 = *v8;if ( ((*v8)[(unsigned __int8)a1[v7]] & 8) != 0 )// 数字{++v9;v5[v6] = v10;v6 = v9;size = v9;}else if ( v10 == 32 ) // 空格{if ( v9 > 1 && (v11[v5[v6 - 1]] & 0x200) != 0 && v5[v6 - 2] == '+' ){v38 = v5[v6 - 1];v5[v6 - 1] = (*__ctype_toupper_loc())[v38];}else{++v9;v5[v6] = '/'; // 空格/v6 = v9;size = v9;}}else{if ( !a1[v7] )goto LABEL_9;v33 = strchr("@$_!\"#%&'()*+,-./:;<=>?\n", v10);// 如果是这些符号替换为a-zif ( v33 ) // 符号{v34 = v9 + 1;v9 += 2;v5[v6] = '+';v6 = v9;size = v9; // +nv5[v34] = (_BYTE)v33 - (unsigned __int8)"@$_!\"#%&'()*+,-./:;<=>?\n" + 97;}else{v35 = strchr("[\\]^{|}~`\t", v10);if ( !v35 )
LABEL_9:sub_F30("Invalid input! Sorry!!", v11);v36 = v9 + 1;v37 = v9 + 2;v9 += 3;v5[v6] = '+';v6 = v9;v5[v36] = '+'; // ++nsize = v9;v5[v37] = (_BYTE)v35 - (unsigned __int8)"[\\]^{|}~`\t" + 97;}}++v7;}while ( *a2 > v7 );
后边一大堆用指针处理的原来是对base64解码。
do // base64 decode{v17 += 4LL;v31 = strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", *v16);if ( !v31 )sub_F30("Exception occurred! Sorry!!", v32);v18 = v16[1];*a1 = 4 * ((v31 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") & 0x3F);// 1v19 = 4 * ((v31 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") & 0x3F);// 1v20 = strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", v18);// 2if ( !v20 )sub_F30("Exception occurred! Sorry!!", v21);v22 = v16[2];*a1 = v19 | ((v20 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") >> 4);a1[1] = 16 * ((v20 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") & 0xF);v23 = 16 * ((v20 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") & 0xF);v25 = strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", v22);if ( !v25 )sub_F30("Exception occurred! Sorry!!", v24);v26 = v16[3];v16 += 4;a1[1] = v23 | ((v25 - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") >> 2);a1[2] = (((_BYTE)v25 - (unsigned __int8)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") & 3) << 6;v27 = (((_DWORD)v25 - (unsigned int)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") & 3) << 6;v28 = strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", v26);if ( !v28 )sub_F30("Exception occurred! Sorry!!", v29);v30 = v15 + (_DWORD)a1;a1[2] = v27 | ((_BYTE)v28 - (unsigned __int8)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");a1 += 3;}while ( *a2 > v17 );size = v30;}
那处理方法就简单了,先进行base64编码,再把一些东西替换回来。其实根本不用写脚本,一眼就看出来后边是flag把+c替换成_,两头改个括号就行。
from base64 import *data = open('flag.enc', 'rb').read()
a = b64encode(data)
print(a)
a=b'+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+m+xCompressing/short/messages/is/essential+Nso/ASIS/has/developed/new/one+xThe/flag/for/this/task/is+RASIS++ec0mprEs51nG+csHOr7+ct3xT+cmE5s49es+cASIS+d++g///'b = "@$_!\"#%&'()*+,-./:;<=>?\n"
c = "[\\]^{|}~`\t"
'''
+m +
+x \n
+c _
_d !
++e {
++d }
'''
flag = ''
i = 0
while i <len(a):if a[i] == ord('+'):if a[i+1] == ord('+'):flag += c[a[i+2]-97]i+=3else:flag += b[a[i+1]-97]i+=2else:if a[i] == ord('/'):flag += ' 'else:flag += chr(a[i])i+=1 print(flag)#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#Compressing short messages is essential+Nso ASIS has developed new one
#The flag for this task is:ASIS{c0mprEs51nG_sHOr7_t3xT_mE5s49es_ASIS!}
REV Rexy
这题用了些无用指令,故意捣乱的,还好不是花指令,恢复那个就比较麻烦了。这些年看着没用的就跳过就行。
有用的就是先转8进制,再按10进制打包成16进制,再反转。最后加个4个字符。
for ( i = 0; i < v18; ++i ){++v28;v11 = (v28 * v28) ^ 0x19;v10 = *(char *)(i + a1) ^ v11 ^ v17 ^ 0x11F0B8;// encsrc = (char *)malloc(8uLL);dest = (char *)malloc(8uLL);v7 = (char *)malloc(8uLL);*(_WORD *)dest = 48;sprintf(src, "%o", v10); // 8进制strcat(dest, src); // 前补0v4 = strtol(dest, 0LL, 10); // 按10进制,转16sprintf(v7, "%X", v4);v6 = (char *)malloc(8uLL); // v5,v6没用memset(v6, 0, 8uLL);for ( j = 0; j <= 7; ++j ){v5[0] = v7[j];v5[1] = 0;strncat(v6, v5, 1uLL);}strncat((char *)s, v7, 6uLL);free(src);free(dest);free(v7);}v15 = (char *)malloc(8uLL);v14 = (char *)malloc(8uLL);v13 = (char *)malloc(8 * v18);memset(v15, 0, 8uLL);memset(v14, 0, 8uLL);memset(v13, 0, 8uLL);v12 = v17 ^ 0xD417;sprintf(v15, "%X", v17 ^ 0xD417u);for ( k = 0; v15[k]; ++k );v24 = k - 1;for ( m = 0; m < k; ++m )v14[m] = v15[v24--];for ( n = 0; *((_BYTE *)s + n); ++n );v21 = n - 1;for ( ii = 0; ii < n; ++ii )v13[ii] = *((_BYTE *)s + v21--); //反转v13[ii] = 0;
最好的办法当然是写解法,但最快的方法就是爆破。
cipher = '3B41249CE22429D224A2F224EEA224B1C2248AB224A36224C782245C2224B422248D32246E9A141FAA1465AA14416A14787A144B6A14A22A14933A14492A14EBD91478D91429E914249B14858B14B2BB14D35B14564B14637B14226B14CA1B146E0B14623B14302B1458DA1481DA1446FA142BEA14711D14C10D14B92D14AC1D140FCC1443CC1429EC14B7DC14BC8C14528C1417AC147DAC14479C14B45C14D14C14384C14FC6C146C5C14F10E147B0E1486FD14B02E14D12E14A01E1456CD148DCD14F7BD146CBD1495ED14BDDD1468DD1449DD14F78D14DE8D142C7D143A7D1490AD1495AD14229D14BA9D14EA9D14674D14BC4D14384D141A3D146D3D14924D14FC3D14366D14F26D14566D14086D14445D14A35D14855D14E45D14E95D14E95D14AC5D140B5D144C5D14AC5D14995D145ADB'.lower()[::-1][4:]
#先反转再去掉头部4无用字符
print(cipher)
flag = ''
tsrc = ''
for v28 in range(1,100):v11 = ((v28*v28)^0x19) & 0xfffffffffor c in range(0x100):v10 = c^v11^27058^0x11F0B8src = tsrc + hex(int(f"0{v10:o}", 10))[2:]#print(src)if cipher.startswith(src) :flag += chr(c)print('--->',flag)tsrc = src break#ASIS{W00twootW00t_HappyNewYear}
Misc Basic
给了一个不知道什么程序打的包,看似无从下手,一点点看包里可见的字符
position
isflagchar
md5charsaltIs flag char?
md5(char + 'SALT')Z.N02c56c63b3488ed738c8788cc2d88259
......
从这里猜大概就是
for c in flag:md5( c+ 'SALT')
但拿一个md5测一下肯定不是c+SALT,又拿了几个试,其中一个结果是 s4LtA,得到salt和顺序就好办了。但出来的东西有227个字符,显然还着点。
把data里的东西全打印出来
02c56c63b3488ed738c8788cc2d88259 90 N
02c56c63b3488ed738c8788cc2d88259 113 N
02c56c63b3488ed738c8788cc2d88259 165 N
02c56c63b3488ed738c8788cc2d88259 218 N
07efbd85d388985546f790547b5af8ad 137 N
07efbd85d388985546f790547b5af8ad 222 N
0827a1505e5d9d1bd3719bf766a4083d 69 N
0827a1505e5d9d1bd3719bf766a4083d 70 N
......
这每段第1位应该是个序号,第3字节是N或Y,后边是md5值。所以要先按顺序排队,再将Y的结果列出来。
from hashlib import md5data = open('aaa.raw', 'rb').read()
a = [data[i+3: i+35].decode() for i in range(0, len(data), 35)] # md5(s4Lt+chr)
p1 = [data[i] for i in range(0, len(data), 35)] #idx
p2 = [chr(data[i+2]) for i in range(0, len(data), 35)] #Y,N 去掉N
for i in range(len(a)):print(f"{a[i]} {p1[i]} {p2[i]}")
print(''.join(p2))
#将md5值转为字符
flag = ''
for v in a:for i in range(0x20,0x7f):if v == md5(b's4Lt'+bytes([i])).hexdigest() :flag +=chr(i)breakprint(flag)#按序号排序
t2 = [0]*227
t3 = [0]*227
for i in range(227):t2[p1[i]-1] = flag[i]t3[p1[i]-1] = p2[i]#过滤出Y
t4 = ''
for i in range(227):if t3[i] == 'Y':t4+=t2[i]
print(t4)
#ASIS{U51nG_Stata_t0_0b5cUrE_7h3_fL4g!}