Qual
ASCIS 2023 QUAL
CRYPTOGRAPHY WRITEUP
Author:
Pham Quoc Trung
Used Language:
Python3
Problem Solving
Crypto Gym
Welcome to crypto gym. First thing first, do 10 pushup
Attachment: pushup.sage
from Crypto.Util.number import *
flag = b"ASCIS{W3llDone_hitting_the_crypto_gym}"
p = random_prime(2^64,False,2^63)
k = 100
N = p^k
R.<x> = PolynomialRing(Zmod(N), implementation="NTL")
pol = R([getrandbits(303) for _ in range(8)])
rem = pol(bytes_to_long(flag))
pol2 = pol - rem
print(p)
print(pol2)
output.txt
11297687362481059303
13610397498137460052595710607775600966440673986561720083617038392214152560062011019976773770*x^7 + 3566392303389726626006032793588065859583087165101596345460586029577767956788324980852746288*x^6 + 7227318468293576946551014881082996672111192766111924180025635102400282562890972644421351500*x^5 + 7771302680925353252595662292109560220768956546753457049454904993425020919927767061221486221*x^4 + 139083310005991713122570444648981888435044361344964087355309478527640012858625517580301911*x^3 + 10431965883129539716182417642690446218733007501683833779007525409139657460951379770712373102*x^2 + 2655891997688433325155635727515206873804011670907688662530856511275429726187800190339210214*x + 1990468213382663050992514193186549986027466683418508635770777413817551279002416425502329820086861584095472837291418005624773513401408758670436382582234048163799788806226626593153501000046514398963951902046012093096889627829382025385675885186988109953010009115770485200550815315808412991631351114821645247484757612802395935646091741255310372634948676346139337203740284867648614092382676490768142323752125479973383639263480304615000184481073131150356830470611732683436270896044490259474247417693471208508957222774925150961910011882960781392579006359531632257744162604999333815810546399453824586710812096069645634464088126006346744764154042984373078867489476719514098331516466106097935211336674536065610816999665679040973651579582751231452003697987383534147985850684095100628612367594611200815680857874889854961710361062023098850129552718682182379299432474772126322312705937896898977384049986981576727484443307309856882552658648662622011836915288387316856549038216691517631404710419267570370185868331551998817164408824273037138508139872246840469178118447891408840689533252470570577069433326089871730774552442047182123932923084697422550196675689928558048170639744494377903971022314792618672680983240190918645044793065660686668847439068894202593794701984461427031780284501758478606643641114708694491715239872860200373088774910354567584766353453900023065619777887852835339101628894266209543584386397885981697802413486043807559982651878851431362770011433278158871282099680537195876295632087913919009624832811111375020850262854356800201139600896028683597688967045073054430644328634631654532540097138840888709833107492434165723295378716876382870562787875916326125400715648718443161316211216677436938376005080710347157377831498391277043220453740841631935922506793862323094941018556991395626031998291221412221183144473483101854286315619799724635496211825342536058324502706123278966607771777568594929815999891921492775
Bài này flag nằm luôn trên file source nên mình cũng chả cần phải làm gì :v. Sẽ nghiên cứu sau.
Flag: ASCIS{W3llDone_hitting_the_crypto_gym}
I_dont_know_how_to_name_this_chall
This is a description. Good luck
Attachments: chall_fixed.sage
from Crypto.Random.random import getrandbits
from Crypto.Util.number import bytes_to_long
nbits = 128
while True:
mul = getrandbits(nbits)
add = getrandbits(nbits)
modulus = getrandbits(nbits)
if mul < modulus and add < modulus:
break
def gen_num(bits):
truncate = bits
seed = getrandbits(511)
gen_num = 41
xx = []
yy = []
for _ in range(gen_num):
seed = (mul * seed + add) % modulus
xx.append(seed)
yy.append(seed >> (nbits-truncate))
return xx, yy
_, ee = gen_num(18)
_, ff = gen_num(20)
a = ee[-1]
b = ff[-1]
c = getrandbits(1024)
p = next_prime(a * c + getrandbits(512))
q = next_prime(b * c + getrandbits(512))
flag = '<REDACTED>'
N = p * q
e = 65537
m = bytes_to_long(flag.encode())
enc = pow(m, e, N)
print(f'enc = {enc}')
print(f'N = {N}')
print(f'ee = {ee[:-1]}')
print(f'ff = {ff[:-1]}')
print(f'a = {mul}')
print(f'c = {add}')
print(f'm = {modulus}')
output.txt
enc = 4782207738169357679017263311695366580149461241803922088835452812820137537830281562950634059939171784035642202164746425519370563906663225547286363495366866588141853586109553019469599011984795232666657032457349167541183811442599555965876853759790930565452169138123206051344200109808603093521161556603615660329142949615063443855551027286822234646698015310643407246009689006200152818931447476595216569044114220319818061396623338764899012025923470408152189436065437542065068815744124506169026323905222443334212867601172364249248963768649488580249031694113977946046461290930755706144535271632419505875554486279354334709794323960679
N = 3964970058588757148381961704143056706462468814335020245520977895524549102412775370911197710398920529632256746343939593559572847418983212937475829291172342816906345995624544182017120655442222795822907477729458438770162855927353619566468727681852742079784144920419652981178832687838498834941068480219482245959017445310420267641793085925693920024598052216950355088176712030006651946591651283046071005648582501424036467542988971212512830176367114664519888193885765301505532337644978456428464159474089450883733342365659030987687637355512103402573155030916404165387863932234088255017821889649456947853403395704387479968208359004918561
ee = [167323, 194700, 130745, 7156, 65616, 200175, 106106, 4410, 94204, 121719, 176084, 168449, 206162, 19151, 165232, 149276, 151372, 64105, 162906, 92391, 69021, 200382, 22272, 14195, 200195, 70505, 46059, 194712, 177080, 209749, 112239, 9882, 23285, 45783, 117745, 31663, 51641, 148822, 169539, 142669]
ff = [300710, 494582, 107979, 208491, 285026, 638043, 525064, 566864, 36622, 212388, 374138, 220683, 193612, 532230, 75887, 548412, 650282, 195040, 74550, 158762, 797511, 322315, 821880, 484339, 76864, 64394, 101586, 815915, 762307, 410750, 115213, 726390, 378350, 800132, 379035, 797320, 413506, 284265, 537835, 226489]
a = 43787291635671214792919526096167649451
c = 156497500579206068939331641182566791023
m = 273364800599018888270443304662600024273
Nhìn vào code của chương trình, ta có thể nhận ra ban đầu nó đã sử dụng LCG (Linear congruential generator) để tạo ra các số giả ngẫu nhiên. Ở đây ngoài các thông số của LCG như $m$, $a$ và $c$ ra, ta còn thấy sự xuất hiện của biến truncate
, phục vụ cho phép dịch phải. Đây là biểu hiện của dạng Truncated LCG.
Vì các biến phục vụ cho mã hóa RSA đằng sau phụ thuộc vào phần tử cuối của mảng được sinh ra từ LCG, thứ mà ta không biết. Để lấy được, ta phải gen lại cả mảng bằng cách break được thuật toán Truncated LCG này. Ở đây mình tìm được 2 nguồn giúp mình thực hiện điều này
https://github.com/jvdsn/crypto-attacks/tree/master/attacks/lcg
https://gist.github.com/maple3142/c7c31d2e5893d524e71eb5e12b0278f0#file-truncated_lcg-py
let's duel
I really want to play MTG with someone.
Attachments: chall_fixed_final.py
from hashlib import *
import os
from Crypto.Util.number import *
q = 2^32 - 5
n = 256
def bytes_to_seedlist(seedbytes):
seedlist = []
for i in range(16):
seedlist.append(bytes_to_long(seedbytes[i*4:i*4+4]))
return seedlist
def sample_poly(seed , lower , upper):
prng = PRNG(seed)
polylist = []
for i in range(n):
polylist.append((prng.raw_rand() % (upper - lower)) + lower)
return polynomial(polylist)
def encode_m(m):
m = bytes_to_long(m)
flist = []
for i in range(n):
flist = [m&1] + flist
m >>= 1
return polynomial(flist)
class PRNG:
def __init__(self , seed):
self.state = bytes_to_seedlist(seed)
self.m = 8723550600886591460
# f = [randint(0 , self.m) for _ in range(16)]
self.f = [385590684360, 111617452318, 131804337312, 300824916689, 419524791075, 690238874924, 160408772216, 63764520785, 50573686124, 688400902026, 333066488215, 270710580449, 107293144053, 703516825252, 541402940593, 624566048630]
self.d = 16
for i in range(self.d):
self.generate()
def generate(self):
res = 0
for i in range(self.d):
res += self.f[i] * self.state[i]
res %= self.m
self.state = self.state[1:] + [res]
def raw_rand(self):
temp = self.state[0]
self.generate()
return temp
class polynomial:
def __init__(self,flist):
n = 256
if type(flist) == list:
assert len(flist) == n
self.f = [flist[i] % q for i in range(n)]
def __add__(self , other):
assert type(other) == polynomial
return polynomial([(self.f[i] + other.f[i])%q for i in range(n)])
def __sub__(self , other):
assert type(other) == polynomial
return polynomial([(self.f[i] - other.f[i])%q for i in range(n)])
def __mul__(self , other):
assert type(other) == polynomial
res = [0 for _ in range(n)]
for i in range(n):
for j in range(n-i):
res[i+j] += self.f[i] * other.f[j]
res[i+j] %= q
for j in range(1, n):
for i in range(n-j, n):
res[i+j-n] -= (self.f[i] * other.f[j])
res[i+j-n] %= q
return polynomial(res)
flag = b'<REDACTED>'
assert flag[:8] == b'ASCIS{it' and flag[-1:] == b'}' and len(flag) == 32
print(f'hash_list: {list(map(lambda x: sha256(x).digest(), [flag[i:i+5] for i in range(0, len(flag), 5)][:-1]))}')
A = sample_poly(os.urandom(64) , 0 , 2**32 - 5)
e = sample_poly(os.urandom(64) , -4 , 4)
s = encode_m(flag)
b = A*s + e
print(b.f)
print(A.f)
output.txt
hash_list: [b'\xb6\xb1\xdahR\xef\xb5\xc4\x96\xc9\x87\xe3;K\xf2|(\xc2?\x8b\xd3B\xdc\xc7\x13\xd2\x82[=\xa9\xc3\xfb', b'\xb0"\x8fl8\xc0Z1\x97\x88ct\x8a\xf1\xea\xc8.\xe0Q=\x0e\xd9\x86\xbc\x89\xc2\xbb\x9dT\xc6}Z', b'\xc1\x9d\x81\xe4\xed\xaa\x8a\xa0\xb6\xcb\x15\xc6\xd2yv\x1f\x8f\xac\x839\xa4&}\x1c\xa8\xc3\x15"\x87r!\xe2', b'\xf26\x95*\x0c\xd2\xca\xd8xE\xbf\xf3P \xcc\xd7l\xebx\xdcW\xb2\x8e\x06\xfa\xd7r\xc0~\xdf\x18`', b'\x1f\xfa>\xea\xe2{-\x13:\xfe,`\x01j\xec\xa0\x15hl\xa5\\\x88\x9eQ[\x12\x1es7\xe3w\xa5', b"'cE\x04\xae\x04\x88\xdb\xe6\x0b\x9b}\xf7\x1d]\xedH\xf3:|\x12s\x0f\xc2\xa1v\xa2k\xf4\xbazJ"]
[4283545680, 646834737, 741988181, 3020304857, 3100253413, 1065061328, 3013693513, 3106959241, 2155350166, 1545834191, 790968817, 2015602796, 2973360521, 1871688489, 2744199016, 3790735376, 137555270, 1278025029, 3802308861, 3114891940, 3957760227, 2039267510, 2555990791, 564591932, 844115070, 709763793, 1413511597, 3223782810, 3762408596, 3237568557, 1506656324, 640118751, 3457884507, 2042392508, 3621570353, 2618427178, 3143980384, 4179375357, 2455473338, 3743578199, 1107663085, 1166269545, 349593668, 4275247796, 1262422354, 1739848908, 614386809, 3276667439, 1909302811, 2207910705, 3672171769, 1892473412, 2106619998, 3509534363, 4127643740, 3112406324, 717870202, 2851994732, 3003228494, 4016914585, 570223354, 3624435932, 205090202, 2012416867, 192505113, 3114220319, 1331292762, 479841116, 3516641914, 3685321945, 2143251094, 2590283404, 9811749, 2657687045, 4259037014, 1860067004, 2127021357, 3299398789, 3177792605, 3096187832, 617393158, 3105265865, 3200579500, 2180602657, 405538436, 2523765308, 4240756384, 1314900414, 583358099, 3101348135, 136786442, 2140102983, 360275303, 753809702, 2492856611, 2824277079, 2542382957, 304365097, 1407108023, 179330351, 3572907626, 2987119926, 1837821380, 4255503888, 4150911130, 1079223198, 382550547, 440445936, 429398418, 4269223853, 4293378325, 831535779, 1122173200, 916028602, 2063630491, 397805198, 1714268681, 3482358218, 1527006125, 972019432, 1178792742, 321122436, 1198282426, 4248922335, 1636504259, 1182244646, 1110957456, 3147355806, 2131582789, 816066497, 4212311714, 4189493964, 2888766800, 23922410, 988643330, 1734233855, 3610553547, 2881678944, 413335320, 605483264, 1226557747, 3998585106, 2761250861, 1388516116, 348565449, 1310945281, 2665014408, 3904323348, 3116210769, 371569431, 859621792, 3873282560, 3657629936, 2165332329, 3648500937, 1596125288, 4030977678, 3234029944, 3045811717, 495499658, 2773559501, 2326382782, 3221402806, 3005901931, 977057418, 2320593952, 2794811414, 711422896, 4281286089, 3466560539, 190173095, 3948641737, 1556799426, 3931257454, 1354240466, 2986326087, 4256860762, 3241117779, 640856507, 3473767594, 1713562536, 3684876849, 4017806788, 3077145772, 2824616513, 2935055408, 1623945766, 315873716, 102609950, 419009459, 1963388852, 3699184121, 794095422, 1786769052, 1636765552, 1268289826, 3988009796, 3507703205, 277522927, 3281391735, 3061479622, 2054288077, 320590104, 1155984065, 2345911582, 1311189685, 2417274203, 3663636979, 1355104029, 954525006, 1565182940, 2623166114, 2244058414, 4169012576, 3794090017, 3378386621, 3977599826, 2957395261, 2268921055, 1035839318, 39266986, 4127340185, 3213795177, 2648382777, 2574807466, 1859819418, 724070108, 2468329063, 519293835, 3786683045, 2138218831, 1129997749, 3957889649, 1690256184, 1279827160, 906462778, 337831463, 3731171015, 3668852053, 220581961, 288435651, 2016496414, 4130330054, 1731113030, 1951965858, 10770410, 639445397, 3043395505, 1900552693, 389764505, 902374272, 2347510467, 4180730265, 1161045967, 3252278061, 1005098266]
[287970464, 2164888233, 3900314872, 2803578471, 2100597265, 1816431874, 3107577409, 2442807705, 521828921, 3057968421, 4139887361, 4264789592, 2948288356, 804210161, 669029890, 3126041531, 1423738442, 590110291, 1673973318, 295613802, 3783064449, 901463863, 3903514026, 1296050662, 4273758939, 4100859588, 668993132, 64546990, 131928633, 2595095688, 610213244, 3054956557, 2993694188, 2498770917, 1402362082, 3632530868, 649841672, 1843661157, 786836159, 2485753489, 2839031237, 3731848071, 2817378681, 3403169521, 2015560787, 1822700770, 161085328, 286530859, 4130325360, 1390298514, 865328090, 60541228, 655193450, 3851091442, 4281910285, 745346163, 50447794, 3922986170, 2367251329, 988621856, 3722976714, 3538009554, 213747765, 1299739489, 3466643630, 370290663, 2976632085, 3044010057, 3168989507, 2278979483, 922376384, 2082045756, 784991240, 2824840459, 1611316601, 1606912636, 136325361, 1489816993, 3045086708, 3764326204, 1475244981, 629654012, 1988643969, 3286999466, 3195304933, 1606659017, 736848220, 2158974982, 347685569, 332414878, 207979890, 3372005421, 298012257, 2758990980, 3310277688, 349598758, 2378166773, 1464638028, 3273217830, 3763703130, 1389744097, 714695881, 1685453463, 3570078034, 1037471531, 3873616449, 951661170, 2805305208, 2306223616, 3687866993, 3305452882, 4260765485, 1742500231, 2390392028, 2943743112, 1502774651, 2456351616, 3308830006, 4192023258, 932695074, 1267048809, 2563600344, 3204565645, 4149110498, 2804299962, 163720842, 3742370816, 3487079987, 3312120468, 2779130485, 2412143335, 154330399, 3282001667, 494563132, 299113042, 4027004917, 328155934, 2637548213, 1565335384, 3995545006, 1061013616, 3931901355, 2526277849, 63039371, 947719144, 4204710772, 2705806345, 2725325172, 3596618182, 4263518096, 3004287726, 3480546848, 366296462, 2582223187, 873083062, 3035068564, 129826698, 682624376, 1041985948, 2300167185, 1985311187, 2158495582, 2574786951, 3239489764, 2005786117, 2399685911, 2157700060, 2548490153, 4165961385, 1864494416, 4267425571, 4023585511, 4032607081, 1740596122, 971654485, 4271206296, 1727985879, 770751334, 3357701211, 3406246261, 1758771097, 3755060295, 2398178683, 3380424195, 2048522566, 715325180, 3534765975, 3742183516, 4151425923, 1443702979, 3872154918, 3447970632, 2972193585, 1095301588, 1136514912, 3016628000, 3411626743, 1491689975, 3149230417, 1602027685, 1683352963, 3846848863, 3139684322, 62856240, 2244885460, 2895665432, 297531570, 1074403985, 1653386664, 95133646, 3476903462, 3606247651, 2399138344, 3186466372, 1956121684, 870920533, 3595320696, 3247874941, 3529506430, 2118652780, 2130399537, 2721787296, 1790856026, 4003100801, 1459989599, 437063189, 3567935321, 3982325641, 4200813095, 2636797818, 2761217793, 1932041321, 4210924853, 820967441, 2149054035, 3282837586, 1788349923, 3048451834, 1806983435, 4088507730, 3240976625, 564703315, 237694859, 2591207021, 4175049748, 2906348858, 106898972, 2915350214, 1266855510, 1321452064, 178409141, 3979906468, 1672294316, 1497714995, 1682915718, 968837565]
Vì hiện tại mình vẫn khá ngu về Lattice nên mình đã thử copy 1 số đoạn code để paste lên Github, và mình tìm được một challenge tương tự của giải D^3CTF 2023
https://github.com/shal10w/d3ctf2023-d3bdd/tree/main
Ngoài ra thì còn một cách khác. Ở đây, ta được cho 6 mảnh của flag, mỗi mảng là mã hóa SHA256 của 5 kí tự flag. Mình có thể brute-force SHA256 từng mảnh.
Ở đây mình sử dụng code C:
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <atomic>
#include <cstring>
#include <cmath>
#include <openssl/sha.h>
const char charset[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~";
std::string target_hash;
std::atomic<bool> found(false);
std::string yepassword;
void crack(int start, int end){
// just to c5 only
if (end > strlen(charset)) {
end = strlen(charset);
}
for (int c1 = 0; c1 < (strlen(charset)); ++c1) {
for (int c2 = 0; c2 < strlen(charset); ++c2) {
for (int c3 = 0; c3 < strlen(charset); ++c3) {
for (int c4 = 0; c4 < strlen(charset); ++c4) {
for (int c5 = start; c5 < end; ++c5) {
if (found) {
return;
}
std::string password = "";
password += charset[c1];
password += charset[c2];
password += charset[c3];
password += charset[c4];
password += charset[c5];
// std::cout << password << std::endl;
// generate hex of sha256
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, password.c_str(), password.size());
SHA256_Final(hash, &sha256);
std::stringstream ss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
ss << std::hex << (int)hash[i];
}
std::string sha256_hash = ss.str();
// std::cout << sha256_hash << std::endl;
if (sha256_hash == target_hash) {
found = true;
yepassword = password;
return;
}
}
}
}
}
}
}
int main(int argc, char *argv[]) {
target_hash = argv[1];
int num_threads = 8;
std::vector<std::thread> threads;
uint64_t workload = strlen(charset);
uint64_t work_per_thread = workload / num_threads + 1;
for(int i = 0; i < num_threads; i++) {
int start = i * work_per_thread;
int end = start + work_per_thread;
// std::cout << start << " " << end << std::endl;
threads.push_back(std::thread(crack, start, end));
}
for(auto& t : threads) {
t.join();
}
if(found) {
std::cout << "Password found: " << yepassword << std::endl;
}
else {
std::cout << "Password not found" << std::endl;
}
return 0;
}
Last updated