目录
这个题5层RSA加密,很简单就是要带条件爆破5组p,q,一开始看错了,对为5组是一一对应的,回头发现后边两对不是对应的。
- from Crypto.Util.number import getPrime, isPrime, bytes_to_long
-
-
- def getSuperPrime(nbits):
- while True:
- p = getPrime(nbits)
- pp = bytes_to_long(str(p).encode())
- if isPrime(pp):
- return p, pp
-
-
- p1, q1 = getSuperPrime(512) #ok
- p2, q2 = getSuperPrime(512)
- p3, q3 = getSuperPrime(512)
- p4, q4 = getSuperPrime(512)
- p5, q5 = getSuperPrime(512)
-
- n1 = p1 * q1
- n2 = p2 * p3 #明显很小,不是 p2*q2是p2*q3
- n3 = q2 * q3
- n4 = p4 * q5
- n5 = p5 * q4
-
- e = 65537
- c = bytes_to_long(open("flag.txt", "rb").read().strip())
- for n in sorted([n1, n2, n3, n4, n5]):
- c = pow(c, e, n)
-
- print(f"{n1 = }")
- print(f"{n2 = }")
- print(f"{n3 = }")
- print(f"{n4 = }")
- print(f"{n5 = }")
- print(f"{e = }")
- print(f"{c = }")
对三种情况对应3种爆破姿势。
数据部分,方便哪们想复现的话可以用。hitcon的题目会放到googleapis上,但这个地址对国内极不稳定,明通明不通
- n1 = 132240475872174910020944408159013384770525986234801028624784519134365862704105251340824787510945183963356820885920367304711310957365047441178683686926111455575911962257698539064559510444855775549001648292058855493337857073693460061212792795075263084221929517773754699732129582794061997056827998985829666251060653380798686353779510948629280009197715644814616657550158740378670095210797455828266323922570838468050733341304227070902756780052159113811360169205531739117518635829837403006788948761106892086004133969899267757339921
- n2 = 95063555614573541810575593850289506856925979977609991181205616159125089261546784721154599484613262518469706157215924537125160406418217535531993036958388330505871763176297570429533467696205928686731756713059807727405313286020007347211892135226632724359291407913539632339885950358476265995466145680878334722001
- n3 = 59077122528757446350604269162079270359932342538938986760275099248290981958441838384256597839386787448447136083450980256330743221155636885358548541847176342745397373638152767362253944731433134474562146358334422503033973244936835557423934491676324297243326613498319086748647812745223753746779568080090592100960499863677438403657325762852705171109382084916335379889394829715777901290096314487661584614712488781379507151355301063123233880909931925363322846957197537676660047824476129446066149857051131731840540157488590899311381370266592295206055792990886734933291304077440476730373491475852882163732120626849448728573574411786320772125534383707413572678316508826450778346723441956945169297689138799298561759843280317867927205551400065163199599457
- n4 = 24589423756497058585126900932611669798817346035509889383925628660158156567930038333401661451846451875869437263666365776498658699865323180836374906288949824205543130261556051807217164348291174483234810669420041361857307271050079366739157441129916338485838528114129985080841445467007786565727910355311119650431197742495274527401569906785121880408809802492383216836691265423297722021017515667257863302820657924121913047547741420413553737917632809270380269758313556777803344394624408862183672919570479289614998783678080936272369083
- n5 = 185885020243714550225131939334004568560534422416697599024696590344782893162219788079305752632863387855011040772104676488940707663157284194641170875157382507202789029285286466326803699701161968587945867047101502048926016515139728368809523009828247173096909917611001113266938209226483162533302629909322412013492978440863258135181226831155024690292336026753678424906151360739424148666951389956182136072508650529271179749569637083537783283360860102371562796635391549934474381821125255176073752645643893294533330184238070085333427
- e = 65537
- c = 44836759088389215801662306050375432910426695023654894661152471598197009644316944364461563733708795401026569460109604554622161444073404474265330567406370705019579756826106816505952084633979876247266812002057927154389274998399825703196810049647324831928277737068842860115202258059693760003397831075633707611377854322143735834890385706873765241863615950449707047454133596389612468366465634011925228326638487664313491916754929381088396403448356901628825906815317934440495749705736715790281606858736722493438754469493049523175471903946974639097168758949520143915621139415847104585816466890751841858540120267543411140490236193353524030168152197407408753865346510476692347085048554088639428645948051171829012753631844379643600528027854258899402371612
-
- from Crypto.Util.number import getPrime, isPrime, bytes_to_long,long_to_bytes
- from gmpy2 import invert, iroot
-
- def getSuperPrime(nbits):
- while True:
- p = getPrime(nbits)
- pp = bytes_to_long(str(p).encode())
- if isPrime(pp):
- return p, pp
第1种,最简单,因为q = bytes_to_long(str(p)),p,q是相关的可以直接爆破,原先经常用的是2进制的,现在这个是10进制的,就乘pow(10,i)
- #1,
- #n1 = p1 * q1
- def get_sq(n, l):
- p = 0
- for i in range(l,-1,-1):
- for j in range(9,-1,-1):
- sp = p + j*pow(10, i)
- sq = bytes_to_long(str(sp).encode())
- if sp*sq<= n:
- p = sp
- print("", i, j)
- break
- print(p)
- return p
-
- p1 = get_sq(n1, 220)
- #p1 = 8146548592442976266345996123132853490697005499246649457977706700220974227149533573761967281334961993159106889103915430835029497970085237349414587895387361
- q1 = bytes_to_long(str(p1).encode())
对于n2,n3来说由于p,q并不对应,所以这里从后向前爆破,正好通过n3尾部判断。如果没有这人实际上只通过n2尾部的话是不能爆破的,有数不清的组合。
从后爆破的话还有一个问题,就是不足位时前被0,但如果是最后一位就不再被0,所以这里对小的做了能分解直接退出,避免无法判断的补0出现。
- #2,
- #n2 = p2 * p3
- #n3 = q2 * q3
- def get_tail(p2,p3, idx):
- print(f"{idx}\n{p2=}\n{p3=}")
- tn2 = p2*p3
- if tn2>n2:
- return False
- if p2>1 and n2%p2 == 0:
- print(f"OK\n{p2=}\n{n2//p2}")
- exit()
- for i in range(10):
- for j in range(10):
- tp2 = p2+i*pow(10,idx)
- tp3 = p3+j*pow(10,idx)
- if str(tp2*tp3)[-(idx+1):] == ('000'+str(n2))[-(idx+1):]:
- if idx == 154:
- print('x', str(tp2*tp3)[-(idx+1):], ('000'+str(n2))[-(idx+1):])
- #爆到的 idx 字节 * 8 位 与n3 比较
- sq2 = bytes_to_long(str(tp2).zfill(idx+1).encode())
- sq3 = bytes_to_long(str(tp3).zfill(idx+1).encode()) #当不足时补0,当足时补0错
- mask = (1<<((idx+1)*8))-1
- if ((sq2*sq3)^n3) & mask == 0:
- #print(hex(mask), tp2,tp3)
- get_tail(tp2,tp3, idx+1)
-
- get_tail(0,0,0)
- p2 = 8896291584885417569104339023688932443326753617531842711599106401724528341937087331194574622599888534531753509912922572906401573640791655490141830263538581
- q2 = bytes_to_long(str(p2).encode())
- p3 = 10685750878049478986600454022422733804784834227531623991827538970867377925593354382775253050419846972347584519245766235538419501021140939003899401773087821
- q3 = bytes_to_long(str(p3).encode())
第3种由于p4*q5没有尾部特征,只能从头开始爆破。需要判断上下边界,即后部全0大于n和后部全9小于n的情况剪掉。
- #n4 = p4 * q5
- #n5 = p5 * q4
- def get_45(p4,p5,idx):
- if idx<0:
- return False
- if idx<153 and (p4==0 or p5 == 0): #154-155位10进制
- return False
- if p4>1 and n4%p4 == 0:
- print(f'OK\n{p4 = }\np5 = {long_to_bytes(n4//p4)}')
- exit()
- #print(idx,p4,p5)
- q4 = bytes_to_long(str(p4).encode())
- q5 = bytes_to_long(str(p5).encode())
- if p4*q5 > n4 or p5*q4 > n5:
- #print('>')
- return False
- if idx>0:
- sp4 = str(p4).encode()[:-idx]+b'9'*(idx)
- sp5 = str(p5).encode()[:-idx]+b'9'*(idx)
- #if idx<2:
- # print(idx,sp4,sp5)
- rp4 = int(sp4)
- rp5 = int(sp5)
- rq4 = bytes_to_long(sp4)
- rq5 = bytes_to_long(sp5)
- if idx<154 and p4>0 and p5>0 and (rp4*rq5
or rp5*rq4 - #print(f"{idx} ,{rp4} ,{rp5} , {rq4}, {rq5}, {n4}, {n5}, {p4*rq5
- return False
-
- for i in range(10):
- for j in range(10):
- #print('>>>>>',idx,i,j)
- tp4 = p4+i*pow(10,idx-1)
- tp5 = p5+j*pow(10,idx-1)
- get_45(tp4,tp5, idx-1)
-
- #get_45(0,0,155)
- p4 = 6759224678814800913204473280361658486772650199941114505283409645622497866148765146601841353932633241398607040792961131806556756943022446601137737571037341
- p5 = 11868750061342011267437975338788313730068511026231254554820987614699325962867540061083226545014725808842166519144882448332395484715124334891963558447955747
- q4 = bytes_to_long(str(p4).encode())
- q5 = bytes_to_long(str(p5).encode())
- #print(n4%p4, n5%p5)
最后是5个已经分解n的RSA按从大到小顺序解密
- d1 = invert(e, (p1-1)*(q1-1))
- d2 = invert(e, (p2-1)*(p3-1))
- d3 = invert(e, (q2-1)*(q3-1))
- d4 = invert(e, (p4-1)*(q5-1))
- d5 = invert(e, (p5-1)*(q4-1))
-
- #加密顺序 2,1,5,4,3
- m = pow(pow(pow(pow(pow(c,d3,n3),d4,n4),d5,n5),d1,n1),d2,n2)
- print(long_to_bytes(m))
- #b"hitcon{using_different_combinations_of_primes_still_doesn't_make_this_bad_prime_generation_method_any_safer...}"
Reverse Meow_way
这个题一看就用了复杂的东西。
- int __cdecl main(int argc, const char **argv, const char **envp)
- {
- char v4; // [esp+0h] [ebp-24h]
- int v5; // [esp+0h] [ebp-24h]
- int v6; // [esp+14h] [ebp-10h]
- int v7[2]; // [esp+18h] [ebp-Ch] BYREF
-
- v7[0] = -1;
- v7[1] = -1;
- if ( argc < 2 )
- {
- sub_401340("Usage: %s
\n" , (char)*argv); - exit(1);
- }
- if ( strlen(argv[1]) != 48 )
- {
- sub_401340("Wrong length\n", v4);
- exit(1);
- }
- v6 = (int)argv[1];
- dword_40544C(v6, v6 >> 31, v6, v6 >> 31, 196, 0, v7, (int)v7 >> 31);
- ++v6;
- ......
- dword_4053F4(v6, v6 >> 31, v6, v6 >> 31, 152, 0, v7, (int)v7 >> 31);
- dword_405438(v6 + 1, (v6 + 1) >> 31, v6 + 1, (v6 + 1) >> 31, 101, 0, v7, (int)v7 >> 31);
- v5 = memcmp(&unk_405018, argv[1], 0x30u); // 将0x30依次修改为1,2,...仅判断1个字节,爆破得到flag
- if ( v5 )
- {
- sub_401340("Wrong\n", v5);
- exit(-1);
- }
- sub_401340("I know you know the flag!\n", 0);
- return 0;
- }
用了48个函数,和参数,每个函数又都是指针,还被隐藏了。
不过最后有个问题memcmp对全部进行比较,这里如果将0x30改为1,他就仅对第1个字符比较。这样通过修改比较的长度就可以实现爆破了。
这个字节在0x401bf5在文件里的偏移是0xff5
后来看了别人的帖子,这里用push 0x33;retf将32位转64位执行,可惜没有get到出题人的用心。
- import subprocess
-
- data = list(open('meow_way.exe', 'rb').read())
-
- flag = ''
- for i in range(1, 0x31):
- fname = f'meow_{i}.exe'
- data[0xff5] = i
- open(fname, 'wb').write(bytes(data))
- for v in range(0x21, 0x7f):
- tmp = (flag+chr(v)).ljust(0x30, '0')
- rc,out= subprocess.getstatusoutput(f"{fname} {tmp}")
- if 'I know you know the flag!' in out:
- flag += chr(v)
- print(flag)
- break
-
- print(flag)
- #hitcon{___7U5T_4_S1mpIE_xB6_M@G1C_4_mE0w_W@y___} 提交不正确,把两头的下划开线删掉
- #hitcon{7U5T_4_S1mpIE_xB6_M@G1C_4_mE0w_W@y}
BabySSS
看到一个大牛博客 ,里边有3道,说是后两道以后上,关注中。
这个题我用的crt方法,他还提到格基约减法。
M = [ 1 1 . . . 1 1 . . . x 1 x 2 . . . x 8 1 . . . . . . . . . . . . . . . . . . . . . . . . x 1 128 x 2 128 . . . x 8 128 1 − y 1 − y 2 . . . − y 8 1 ] " role="presentation" style="position: relative;">
由于并没有取模,只是限制在64位,所以把右部单位阵的1部分改为2^-63
然后进行约减,结果中前8位为0的行对应的值再乘2**63就得到对应的一组v
- #LLL法
- V = matrix(QQ, 130,8+130)
- for i in range(8):
- for j in range(129):
- V[j,i] = pow(a[i][0], j)
- V[129,i] = -a[i][1]
-
- for i in range(129):
- V[i, 8+i] = pow(2, -63)
- V[129,8+129] = 1
-
- k = V.LLL()
- #前8位全0的行
- v = k[1][8:-1]*9223372036854775808 #2**63
Secret
看上去挺简单,就是个共模攻击,由于共模攻击时可以两边共同除其中一项m^(p+e1) / m^(p+e0) = m^(e1-e0) 所以这里的p可以解决掉。
麻烦的就是模未知。
“取一组核空间的基构成的矩阵,在这个矩阵上进行LLL算法即可得到符合条件的小系数 k i " role="presentation" style="position: relative;"> 。因为我们不能求逆,把正负号分两边进行计算,即可得到n的整数倍 K n " role="presentation" style="position: relative;"> , 利用多组这样的倍数求一个最大公倍数即可恢复n。” 一时没理解,原样复制。
- from output import es,cs
-
- B = matrix(ZZ, 2, 64)
- B[0] = es
- B[1] = [1 for _ in range(64)]
-
- M = B.right_kernel_matrix()
- L = M.LLL()
-
- #求n
- def compute_kn(coff):
- res_right = 1
- res_left = 1
- for i ,cof in enumerate(coff):
- if cof > 0:
- res_right = res_right * cs[i]**cof
- else:
- res_left = res_left * cs[i]**(-cof)
- return res_left - res_right
-
- n = compute_kn(L[0])
- #再求公约数
- for l in L[1:]:
- n = gcd(compute_kn(l),n)
- n = factor(n,limit = 2**20)[-1][0]
- if n.nbits() <= 2048:
- break
- print(n)
得到n后先处理一下p,然后用共模攻击
- n = 17724789252315807248927730667204930958297858773674832260928199237060866435185638955096592748220649030149566091217826522043129307162493793671996812004000118081710563332939308211259089195461643467445875873771237895923913260591027067630542357457387530104697423520079182068902045528622287770023563712446893601808377717276767453135950949329740598173138072819431625017048326434046147044619183254356138909174424066275565264916713884294982101291708384255124605118760943142140108951391604922691454403740373626767491041574402086547023530218679378259419245611411249759537391050751834703499864363713578006540759995141466969230839
-
- from Crypto.Util.number import *
- mpe1_inv = inverse(cs[0],n)
- _es = [e-es[0] for e in es[1:]] # _c = m^(e1-e0)
- _cs = [c*mpe1_inv%n for c in cs[1:]] #
-
- #找两个互素的e进行共模攻击 find gcd(_ei,_ej) = 1
- find = False
- for i in range(len(_es)):
- for j in range(len(_es)):
- if gcd(_es[i],_es[j]) == 1:
- find = True
- break
- if find:
- break
- print(i,j)
-
- e1,e2 = _es[i] , _es[j]
- c1,c2 = _cs[i] , _cs[j]
- g, x1, x2 = xgcd(e1,e2)
- m = pow(c1,x1,n)*pow(c2,x2,n) % n
- print(long_to_bytes(int(m)))
- #hitcon{K33p_ev3rythIn9_1nd3p3ndent!}