NahamCon CTF 2024

NAHAMCON CTF 2024

CRYPTOGRAPHY WRITEUP

Author:

  • Pham Quoc Trung

Used Language:

  • Python3

Problem Solving:

MagicRSA

Description:

Here's an RSA challenge using the most magical number of all.

Attachment:

rsa_with_a_magic_number.py

from secrets import randbits
from sympy import nextprime

e = 3

def encrypt(inp):
	p = nextprime(randbits(2048))
	q = nextprime(randbits(2048))
	n = p * q
	enc = [pow(ord(c), e, n) for c in inp]
	return [n, enc]

plaintext = open('flag.txt').read()

with open('output.txt', 'w') as f:
    data = encrypt(plaintext)
    f.write(f'Semiprime:\nN: {data[0]}\nCiphertext:\n')
    f.write(''.join(f'{b} ' for b in data[1]))
    f.write('\n\n')

output.txt

Semiprime:
N: 292661735803169078279687796534368733968232055929694715453717384181208539846645017378459508481927733219065809706996972833902743250671173212610674572380079245835772007065919936022084401497853611610920914306013040436502207047619016113234947051878549793269852855316328078769491183468515501156324665790842023112309668506350354977653838139155232422868462129041940364012648613391176971689126513558396465218392059219609662829793402841289708970576750698757213264731256720405308346659459733504680423032430634001779369250142543104703669906030549585514247663929431837546466696121103600101025434247152431200408744676625328330247569014313252820778269086840631297075563756934662979588351413726196027845505808290890109883253252054958997436359016852222176230489468164288277709046892991459049248340800616885136366469783271661343653314539194467688757972713531491290238432270971346559967725437118531023032768463200227986539449334624183071042562539584305305367245588508498775214112729500313280502474837332653452065755426475638743763861804587979560695676963674789819860296303566053542883415223272958687917330474367563315425617320128680682444959701586681495270336801802382200546403246134181793704030611664095075430115127507174884551339452808218398863888817
Ciphertext:
1061208 1259712 912673 1092727 1860867 175616 166375 941192 185193 1030301 941192 185193 912673 140608 175616 185193 140608 941192 970299 1061208 175616 912673 117649 912673 185193 148877 912673 125000 110592 1030301 132651 132651 1061208 117649 117649 1061208 166375 1953125 

Solution:

Đây là một bài liên quan tới RSA. Với e = 3 và việc mã hóa từng kí tự một của flag (m rất nhỏ) thì đây là đặc điểm của lỗ hổng small e, small n điển hình. Để giải thì ta chỉ cần lấy căn bậc 3 của từng c để ra được flag.

from sage.all import *
from Crypto.Util.number import *


N = 292661735803169078279687796534368733968232055929694715453717384181208539846645017378459508481927733219065809706996972833902743250671173212610674572380079245835772007065919936022084401497853611610920914306013040436502207047619016113234947051878549793269852855316328078769491183468515501156324665790842023112309668506350354977653838139155232422868462129041940364012648613391176971689126513558396465218392059219609662829793402841289708970576750698757213264731256720405308346659459733504680423032430634001779369250142543104703669906030549585514247663929431837546466696121103600101025434247152431200408744676625328330247569014313252820778269086840631297075563756934662979588351413726196027845505808290890109883253252054958997436359016852222176230489468164288277709046892991459049248340800616885136366469783271661343653314539194467688757972713531491290238432270971346559967725437118531023032768463200227986539449334624183071042562539584305305367245588508498775214112729500313280502474837332653452065755426475638743763861804587979560695676963674789819860296303566053542883415223272958687917330474367563315425617320128680682444959701586681495270336801802382200546403246134181793704030611664095075430115127507174884551339452808218398863888817

c = [1061208,1259712,912673,1092727,1860867,175616,166375,941192,185193,1030301,941192,185193,912673,140608,175616,185193,140608,941192,970299,1061208,175616,912673,117649,912673,185193,148877,912673,125000,110592,1030301,132651,132651,1061208,117649,117649,1061208,166375,1953125]

flag = b''
for i in c:
    m = int(i**(1/3))
    flag += chr(m).encode()

print(flag)

Flag: flag{87b9eb9a4894bcf8a1a95a20e33f11f7}

Encryption Server

Description:

I read online it's bad to re-use the prime numbers in RSA. So, I made this server that randomly generates them for me.

Attachment:

RSA_Encryption_Server.py

#!/usr/bin/python3

from secrets import randbits
from sympy import nextprime
import random

e = random.randint(500,1000)

def encrypt(inp):
	p = nextprime(randbits(1024))
	q = nextprime(randbits(1024))
	n = p * q
	c = [pow(ord(m), e, n) for m in inp]
	return [n, c]

def main():
	
	while True:
		print('Welcome to the Really Shotty Asymmetric (RSA) Encryption Server!')
		print('1: Encrypt a message')
		print('2: View the encrypted flag')
		print('3: Exit')
		
		inp = ''
		while (not ('1' in inp or '2' in inp or '3' in inp)):
			inp = input('> ')
		
		if('3' in inp):
			print('Goodbye!')
			exit()

		elif('1' in inp):
			plain = input('Enter a message, and the server will encrypt it with a random N!\n> ')
			encrypted = encrypt(plain)

		elif('2' in inp):
			data = open('flag.txt', 'r').read()
			data = data.strip()
			encrypted = encrypt(data)

		print('Your randomly chosen N:')
		print(f'> {encrypted[0]}')
		print('Your encrypted message:')
		print(f'> {encrypted[1]}')
		print('\n')

if(__name__ == '__main__'):
	main()

Recon:

Ở bài này, trước tiên, một số e sẽ được lấy random từ 500-1000 thông qua dòng này:

e = random.randint(500,1000)

Hàm encrypt thực hiện mã hóa RSA từng kí tự của input truyền vào giống bài trước:

def encrypt(inp):
	p = nextprime(randbits(1024))
	q = nextprime(randbits(1024))
	n = p * q
	c = [pow(ord(m), e, n) for m in inp]
	return [n, c]

Đến với hàm main, ta sẽ có các chức năng như sau:

  • Chức năng 1: Tiến hành mã hóa input người dùng, in ra ciphertextN sử dụng để mã hóa.

  • Chức năng 2: Tiến hành mã hóa flag, in ra ciphertextN sử dụng để mã hóa.

  • Chức năng 3: Thoát chương trình.

Solution:

Ban đầu thì mình cũng chưa nghĩ ra cách giải, chỉ là mình thấy từ chức năng 1, mình có thể khôi phục được e nên mình đã tiến hành tìm luôn.

Cụ thể, mình sẽ truyền input là \x02. Khi đó, c = pow(2, e, n) và do e chỉ nằm trong khoảng 500-1000, mình có thể dễ dàng factor c để ra được lũy thừa của 2. Và số mũ đó chính là e.

Giờ thì đã có e. Sau khi nghĩ mất một khoảng thời gian, mình nhận ra từ chức năng số 2 mình có thể lấy ra nhiều cặp c, n tùy ý, và đặc điểm của chúng là đều có chung số mũ e. Từ đó, mình nghĩ ra việc sử dụng Hastad Broadcast Attack. Về kĩ thuật thì các bạn có thể xem ở đây: link.

Nôm na là ở đây mình sẽ lấy ra 3 cặp c, n. Khi đó, mình sẽ có 3 phương trình như sau:

Sử dụng Định lý thặng dư Trung Hoa, mình sẽ tìm ra được giá trị m^e mod(n1*n2*n3). Nếu m đủ nhỏ và tích của n1, n2, n3 đủ lớn (do m chỉ là một kí tự nên mình đã test và khi e < 800 thì vẫn vô tư), ta có thể tìm được m bằng cách lấy căn bậc e của m.

Vậy ta sẽ kết nối tới server, tìm e, nếu e < 800 thì sẽ tiến hành tấn công Hastad Broadcast Attack trên từng kí tự để tìm được flag

from pwn import *
from sage.all import *
from Crypto.Util.number import *

while(True):
    conn = remote('challenge.nahamcon.com', 31880)
    #conn = process(['RSA_Encryption_Server.py'])

    def recvLine(n):
        for _ in range(n):
            conn.recvline()

    recvLine(4)

    conn.sendline(b'1')
    conn.sendline(b'\x02')

    recvLine(4)
    c = int(conn.recvline().decode().strip()[3:-1])

    e = int(str(factor(c))[2:])
    print("e = ", e)
    if e > 800:
        continue

    recvLine(6)

    print("[*] Getting Cs and Ns for Hastad Broadcast Attack")

    Cs = []
    Ns = []

    for _ in range(3):
        conn.sendline(b'2')

        recvLine(1)
        N = int(conn.recvline().decode().strip()[2:])
        print("N = ", N)
        Ns.append(N)

        recvLine(1)

        C = eval(conn.recvline().decode().strip()[2:])
        Cs.append(C)

        recvLine(6)

    assert len(Cs[0]) == len(Cs[1])

    flag = b''

    print("[*] Getting Flag...")

    for i in range(len(Cs[0])):
        c1 = Cs[0][i]
        c2 = Cs[1][i]
        c3 = Cs[2][i]

        m_e = crt([c1, c2, c3], Ns)
        m = m_e.nth_root(e)
        flag += long_to_bytes(int(m))
    
    break

print(flag)

Flag: flag{29070b0688f398587d41041f4b25d8a3}

Another way:

Cả 2 bước là lấy e và tìm ra m đều có thể được thực hiện bằng cách brute-force.

Đối với e , chỉ cần brute pow(m, e, n) với m là các kí tự đã biết "f, l, a, g, {", so sánh với ciphertext lấy được từ 2 để tìm được e đúng.

Tương tự với flag, chỉ cần brute pow(m, e, n) nhưng lần này là brute m. Nếu kết quả giống với trong ciphertext thì đó là kí tự đúng.

ciphertext_fl = [2845861777458711081285915326988338985743730999527118107203218292590482876126771640993767744378673311759111413636605606110421394748830107061641906596339045188086747491073274955252868760300906325061420000738148492330291196037401909122962683278381547408836248978852015904394621683658372934817194028530518446825031802525512682521353842074195961755512222666780207118946427171769618919880561426997137552992847684761319604713638803640694937665502650731213697070140308882556747092629301392850673735397904412530235046672784407389499493156368119349908716924754714857345990831342313207232004416498280804945586113762383026554002, 2805890269333072470208591258487553989034795359432421658708582474905413969103487472537071097034153838789167985283484253874142182991932492834999818617883543786579827593374012249984010887241145323385899009615612729724056742625273578099692560459861700063220691619145025109412244898326635121438617464353869114646077011853606382618463503786557216721930629983595460760523841730608693268027816793601411324981497931693365448703519732050192341945516118443772492022854842354042986850969724665267705856595076039273464728269983181692054073602833109503351924218720512878251360136970290247408724719952603560425934514843665385462474]
N = 3189114686224168527832331594922454956130813095678500091837003591252581589062448982723246876196017944847100818244381832468383363405845911023963060518988016928538755279709811123903342192509780913173428723886393253482859769115568498425217420047666488898487353815066472059082290797546861177320701802469167877671417071641160054157961123316709837879746006591255937485506228981534802657551533225645035775724152887077617722220015769980939338494248274632855471433642146347951726131771323868101240008040640059677232340041423789617615705270452301423174772159475723086187149237364733296047140690284751569807669233727054962069009

plaintext = ['f', 'l']

for i in range(0,2):
  for j in range(500,1000):
    if(pow(ord(plaintext[i]),j,N) == ciphertext_fl[i]):
      print("e = ", j)

ciphertext = [2845861777458711081285915326988338985743730999527118107203218292590482876126771640993767744378673311759111413636605606110421394748830107061641906596339045188086747491073274955252868760300906325061420000738148492330291196037401909122962683278381547408836248978852015904394621683658372934817194028530518446825031802525512682521353842074195961755512222666780207118946427171769618919880561426997137552992847684761319604713638803640694937665502650731213697070140308882556747092629301392850673735397904412530235046672784407389499493156368119349908716924754714857345990831342313207232004416498280804945586113762383026554002, 2805890269333072470208591258487553989034795359432421658708582474905413969103487472537071097034153838789167985283484253874142182991932492834999818617883543786579827593374012249984010887241145323385899009615612729724056742625273578099692560459861700063220691619145025109412244898326635121438617464353869114646077011853606382618463503786557216721930629983595460760523841730608693268027816793601411324981497931693365448703519732050192341945516118443772492022854842354042986850969724665267705856595076039273464728269983181692054073602833109503351924218720512878251360136970290247408724719952603560425934514843665385462474, 345049340451699554007948763472893858069411074537199267556380516213734827871614442990536926350227584616252255045051744656658724729921391320513975448747866674731393989824816278253531731559615988365176956553948361741230399671929627311399657205635358188611855896981664987554010070048005180840005056436207539387449042369726304130418877417881364189259973633455724018939019191261925159303420250412390007010119147742488855420323873249301367316063804185927827524896427158951883596368737320448679598208240720659999317773937210898039147175668295346147218816545703112535909878232871373805727402265504548979315089528552745595697, 951163298345106231474965268208628957560219827343318469058594011214334907230708192966701434830239592607901230972125289759116778952718867152714673055156978415240844637092217615193683643441644710454365038159550862939209430473121277046234408508854805432587143690283399051889768700057669176809672637598759051517189918283013574918656032509526960299262696076915519384365007763770641009908429501397555619670029586938706763117479503165045356713874312445207595800339533912979658929330131578873516177465080105547702507295249779825666736757137298102812985083322667530164240990764773702433458491924992074240962884982274564568042, 2479740182999776804236008771087148553401180682610638938146084980344936940119492223862551282276185760469838774084821912305124124460275464842954477157399928256728277919043903943283684790617368819888418898754386175589677609172316868328189627957990265910903124804013463273031433067144372013213246768872278204181654312859179538915959094078445808285939843228263076180534914063668466731115577912318534413682290450045060127045330214188441581955638321469296811020710362645547033091994820234286586177226310069842056675435949953801865401798723082728308585082466783600901592974673165385121898944298025808889394130914931944174229, 1689648263690978778280170131450402539775056061067679151878561766159974416266729509392796827284280021114585143550272850553055947734392514548158687802346790714671470092057937163907789464017686363954964313625028846561605112921624275653838037238634867350561640932180755566024487316152259454353638830953487690089823845294888935653243560336802066211749736208394089320838051100685395305339300589018398810678283489041640663014789560080276320746223393434143652293446825746170769913805390960532534009682085721943696669610692920491082604004553026481265980479989159102201997507755264683603620375248250900657077159135913451475885, 1366265827726126356918913585024756485780435967256934245227562733065480167819880351305246951658964544613584070695752446892678824755899460089833139021634748263140167813790154552259800633189983090549953889604223027803342384439274709345584697554533577244637989592702173073532674527198681364164503021195270185894343355477553262666249315566674897748952144566851726429761160447044620354972047592165189091120374972648855042489789434055288450746687672289055011436685398085713382399844263579889952627226779408321023445016879555892307400296333734534585309043169678564257735058793357233406805237328776527846600882076903331621597, 1880986832723421995542331916276862609832710080821311021126193135130466468781046737384926415171473223417033002143569057118735414797058210868444342450451998472450675991431920644445767093008895225775331188675006434091188583890544406559752931519322823526034317979433859471268682724992239124339743776093619711411904783199970153237719782718807980965232535516306426899265343685689616945036774619408517193964770529813106017816818171225102814472420096407054689765934355621632742197439866839107501574533427757596992555703030987509779785289344475334209600587720610173392201510433795814155974605297309697094057625010692237992916, 447082459991133744898907089075375352292647403135626491589460690183256508370824774284013192023078727444876061065103019989794749220777810120216238379257625151547210011508048571858695019024528903607306443511742130484786824482766215774084738884759134952438739435418555890671646396282187515454410798071217424747025416582198003938572360105929490369879128733445529876133449964023814061929288535292138174771469414176930488932687917478017771230431142811940300118764993211347452731125058983435131302934226927647160815537980274550652722924832989338994546715962312554567887655175806262610551488067005093143845165595351011535046, 1880986832723421995542331916276862609832710080821311021126193135130466468781046737384926415171473223417033002143569057118735414797058210868444342450451998472450675991431920644445767093008895225775331188675006434091188583890544406559752931519322823526034317979433859471268682724992239124339743776093619711411904783199970153237719782718807980965232535516306426899265343685689616945036774619408517193964770529813106017816818171225102814472420096407054689765934355621632742197439866839107501574533427757596992555703030987509779785289344475334209600587720610173392201510433795814155974605297309697094057625010692237992916, 657531892116865015142394761686088155049562374838297052228520378422680338587486406531979861057659734879903815233207708117380133428703716981680650285276224325322438187176524500130763964760465650615713803716318611821687689852199541790168405701892817077531322995908823672231046818763668024654790829827656211534313826615071273919270061272218257895216173068084980116013395247872977107781645683609941220716456301742125138182120724068859552216850363822565319506568992865360794905224578157391381472852393192349908122159934353098111521293102108708455823289990396357737686400482466929223352252310227462412425488002625451459616, 1880986832723421995542331916276862609832710080821311021126193135130466468781046737384926415171473223417033002143569057118735414797058210868444342450451998472450675991431920644445767093008895225775331188675006434091188583890544406559752931519322823526034317979433859471268682724992239124339743776093619711411904783199970153237719782718807980965232535516306426899265343685689616945036774619408517193964770529813106017816818171225102814472420096407054689765934355621632742197439866839107501574533427757596992555703030987509779785289344475334209600587720610173392201510433795814155974605297309697094057625010692237992916, 931252500634441514616497679620051626217605365233679725051001206600034724152803746687940344729566093531275725080374938709126325168920365222032779304110863268497748886886843887387483633987124058566767668905862301341451661011482425906905418463431445584026807512410307727260551923867715741887504764424483991456831860134171099554794290686427452074841226324156456225827039952387715243745898645798191821048476456977943872538420959086785932613424632169412971609634657649512551652299626480695988623445043341380977574013519984162449844026080767169098052768982064746292758195314327865381760093388486686866860285907899797262088, 1516108394291563581129402757918441429103374282540273242535574001686808809056278753069427188395830088378688414390073229867838020209913041172365104049292611891822922405699792228824982320081408133615649588115855890512325779090710043445082538224451754606617750503661325473727213169075371602269467764343908061812510109618078253018279688326849900067366848210517579848333960452975012649436612670651848997870043639151181860894641518880479989748538477173553953687103113277529109777027218496246543551681896161811075929695362823665844770413650851610700668138703783542611069459838985646311963152663040630742739994022184468951693, 1516108394291563581129402757918441429103374282540273242535574001686808809056278753069427188395830088378688414390073229867838020209913041172365104049292611891822922405699792228824982320081408133615649588115855890512325779090710043445082538224451754606617750503661325473727213169075371602269467764343908061812510109618078253018279688326849900067366848210517579848333960452975012649436612670651848997870043639151181860894641518880479989748538477173553953687103113277529109777027218496246543551681896161811075929695362823665844770413650851610700668138703783542611069459838985646311963152663040630742739994022184468951693, 2845861777458711081285915326988338985743730999527118107203218292590482876126771640993767744378673311759111413636605606110421394748830107061641906596339045188086747491073274955252868760300906325061420000738148492330291196037401909122962683278381547408836248978852015904394621683658372934817194028530518446825031802525512682521353842074195961755512222666780207118946427171769618919880561426997137552992847684761319604713638803640694937665502650731213697070140308882556747092629301392850673735397904412530235046672784407389499493156368119349908716924754714857345990831342313207232004416498280804945586113762383026554002, 2310127393424955205107098753990740358616986137235523761428262577027025221085993167331127781046303783394387937006140407932458365609661360072106720211912369678829021097399331475604691187882409665300952366321289612227771815985404013084073477199260101972484084154567987647887377325483499340128094102430928953352662945461142995341584089062204341970339034221703457214832763736835220434547067732740206252238614354577428802536954307484724292316946308032286724679045981289044117505581194462938042596730344914183773705642632211684448859729662063800386303640529418370614292346515567013769130105736509067539211154067603076086189, 1366265827726126356918913585024756485780435967256934245227562733065480167819880351305246951658964544613584070695752446892678824755899460089833139021634748263140167813790154552259800633189983090549953889604223027803342384439274709345584697554533577244637989592702173073532674527198681364164503021195270185894343355477553262666249315566674897748952144566851726429761160447044620354972047592165189091120374972648855042489789434055288450746687672289055011436685398085713382399844263579889952627226779408321023445016879555892307400296333734534585309043169678564257735058793357233406805237328776527846600882076903331621597, 1516108394291563581129402757918441429103374282540273242535574001686808809056278753069427188395830088378688414390073229867838020209913041172365104049292611891822922405699792228824982320081408133615649588115855890512325779090710043445082538224451754606617750503661325473727213169075371602269467764343908061812510109618078253018279688326849900067366848210517579848333960452975012649436612670651848997870043639151181860894641518880479989748538477173553953687103113277529109777027218496246543551681896161811075929695362823665844770413650851610700668138703783542611069459838985646311963152663040630742739994022184468951693, 2825042302849856182284872811744811851303458709453114059362272060068512267538225413672354029466562884251929086090506718793766519094780957785264121916464366198247607907977936981194431588706166261133311195088312650094024949559791378239797230300129221749262929881181940740248368825139119795735889170215292788056972581404694082220855455649236193628823860271638426760590881522270205098323115629369841602830473153490864105692494513874244443421117783300861975364144568599970418552392058660723035379863919183943374528199975123570861634795494088933270814595952418757886991216069017712289797754734682455842143958305877491065308, 1516108394291563581129402757918441429103374282540273242535574001686808809056278753069427188395830088378688414390073229867838020209913041172365104049292611891822922405699792228824982320081408133615649588115855890512325779090710043445082538224451754606617750503661325473727213169075371602269467764343908061812510109618078253018279688326849900067366848210517579848333960452975012649436612670651848997870043639151181860894641518880479989748538477173553953687103113277529109777027218496246543551681896161811075929695362823665844770413650851610700668138703783542611069459838985646311963152663040630742739994022184468951693, 447082459991133744898907089075375352292647403135626491589460690183256508370824774284013192023078727444876061065103019989794749220777810120216238379257625151547210011508048571858695019024528903607306443511742130484786824482766215774084738884759134952438739435418555890671646396282187515454410798071217424747025416582198003938572360105929490369879128733445529876133449964023814061929288535292138174771469414176930488932687917478017771230431142811940300118764993211347452731125058983435131302934226927647160815537980274550652722924832989338994546715962312554567887655175806262610551488067005093143845165595351011535046, 911952661268613740583322997565412200914100502692357718437769466553003571267254639495161904160210650878940573803570850454621528713203365998436143695790546494901722250097991645848066686529879779990669014240227068002247584740881790026584221414251618906534958486397391687640947173344606419090340298923474444182516380607114649841952081489454956417542971671362961862642629115262583713292974344395338435404501794644438854646632565285640653797991087106823104952723282567247576478901710217187696256883106377762131777502200827895165209409875271987670024104226318541141456416006467124909526742250444801039181096325252980787937, 404953586124003713338094403824158076005487244392998242685509201327153305278954249039089984119775592321546283058278853313006332417730624875758884377551900046823033187266935812650505269250683845308747958368228419508173793699342704392907950014556812234110901800665251816896866317438756274009173828660344643880065244670967241154994170561756893223405112315769965926671415121445324858529519864795021415136180118485244749112441409398878171724578073635858057757284866247813421619605117907554732297911373096632500385347174349766094732800236684128079209645166435698882303614752359575832337798752667862475104063845009162911123, 905685771497468383707579661844517741131510146624065231016488522358591867392805435992637943183729559574110814536030841880160952126265038473173024062448851717036910638420337304168080133588944925865114215245944974991705439823897729116691937883749053899858403745246985614768892782108588241187122190260786564856012774733521266154949552017246439829318354606757306096013302253546964428485920620447844988938649711057865207734651104360867713093742305925508951994576164468480597387880351900638406381052307766144060496369997796375270344203820789125077580002531993616040845690994618971720151149188440949809688479761737824788097, 1880986832723421995542331916276862609832710080821311021126193135130466468781046737384926415171473223417033002143569057118735414797058210868444342450451998472450675991431920644445767093008895225775331188675006434091188583890544406559752931519322823526034317979433859471268682724992239124339743776093619711411904783199970153237719782718807980965232535516306426899265343685689616945036774619408517193964770529813106017816818171225102814472420096407054689765934355621632742197439866839107501574533427757596992555703030987509779785289344475334209600587720610173392201510433795814155974605297309697094057625010692237992916, 404953586124003713338094403824158076005487244392998242685509201327153305278954249039089984119775592321546283058278853313006332417730624875758884377551900046823033187266935812650505269250683845308747958368228419508173793699342704392907950014556812234110901800665251816896866317438756274009173828660344643880065244670967241154994170561756893223405112315769965926671415121445324858529519864795021415136180118485244749112441409398878171724578073635858057757284866247813421619605117907554732297911373096632500385347174349766094732800236684128079209645166435698882303614752359575832337798752667862475104063845009162911123, 905685771497468383707579661844517741131510146624065231016488522358591867392805435992637943183729559574110814536030841880160952126265038473173024062448851717036910638420337304168080133588944925865114215245944974991705439823897729116691937883749053899858403745246985614768892782108588241187122190260786564856012774733521266154949552017246439829318354606757306096013302253546964428485920620447844988938649711057865207734651104360867713093742305925508951994576164468480597387880351900638406381052307766144060496369997796375270344203820789125077580002531993616040845690994618971720151149188440949809688479761737824788097, 2845861777458711081285915326988338985743730999527118107203218292590482876126771640993767744378673311759111413636605606110421394748830107061641906596339045188086747491073274955252868760300906325061420000738148492330291196037401909122962683278381547408836248978852015904394621683658372934817194028530518446825031802525512682521353842074195961755512222666780207118946427171769618919880561426997137552992847684761319604713638803640694937665502650731213697070140308882556747092629301392850673735397904412530235046672784407389499493156368119349908716924754714857345990831342313207232004416498280804945586113762383026554002, 404953586124003713338094403824158076005487244392998242685509201327153305278954249039089984119775592321546283058278853313006332417730624875758884377551900046823033187266935812650505269250683845308747958368228419508173793699342704392907950014556812234110901800665251816896866317438756274009173828660344643880065244670967241154994170561756893223405112315769965926671415121445324858529519864795021415136180118485244749112441409398878171724578073635858057757284866247813421619605117907554732297911373096632500385347174349766094732800236684128079209645166435698882303614752359575832337798752667862475104063845009162911123, 657531892116865015142394761686088155049562374838297052228520378422680338587486406531979861057659734879903815233207708117380133428703716981680650285276224325322438187176524500130763964760465650615713803716318611821687689852199541790168405701892817077531322995908823672231046818763668024654790829827656211534313826615071273919270061272218257895216173068084980116013395247872977107781645683609941220716456301742125138182120724068859552216850363822565319506568992865360794905224578157391381472852393192349908122159934353098111521293102108708455823289990396357737686400482466929223352252310227462412425488002625451459616, 1689648263690978778280170131450402539775056061067679151878561766159974416266729509392796827284280021114585143550272850553055947734392514548158687802346790714671470092057937163907789464017686363954964313625028846561605112921624275653838037238634867350561640932180755566024487316152259454353638830953487690089823845294888935653243560336802066211749736208394089320838051100685395305339300589018398810678283489041640663014789560080276320746223393434143652293446825746170769913805390960532534009682085721943696669610692920491082604004553026481265980479989159102201997507755264683603620375248250900657077159135913451475885, 2825042302849856182284872811744811851303458709453114059362272060068512267538225413672354029466562884251929086090506718793766519094780957785264121916464366198247607907977936981194431588706166261133311195088312650094024949559791378239797230300129221749262929881181940740248368825139119795735889170215292788056972581404694082220855455649236193628823860271638426760590881522270205098323115629369841602830473153490864105692494513874244443421117783300861975364144568599970418552392058660723035379863919183943374528199975123570861634795494088933270814595952418757886991216069017712289797754734682455842143958305877491065308, 911952661268613740583322997565412200914100502692357718437769466553003571267254639495161904160210650878940573803570850454621528713203365998436143695790546494901722250097991645848066686529879779990669014240227068002247584740881790026584221414251618906534958486397391687640947173344606419090340298923474444182516380607114649841952081489454956417542971671362961862642629115262583713292974344395338435404501794644438854646632565285640653797991087106823104952723282567247576478901710217187696256883106377762131777502200827895165209409875271987670024104226318541141456416006467124909526742250444801039181096325252980787937, 1516108394291563581129402757918441429103374282540273242535574001686808809056278753069427188395830088378688414390073229867838020209913041172365104049292611891822922405699792228824982320081408133615649588115855890512325779090710043445082538224451754606617750503661325473727213169075371602269467764343908061812510109618078253018279688326849900067366848210517579848333960452975012649436612670651848997870043639151181860894641518880479989748538477173553953687103113277529109777027218496246543551681896161811075929695362823665844770413650851610700668138703783542611069459838985646311963152663040630742739994022184468951693, 345049340451699554007948763472893858069411074537199267556380516213734827871614442990536926350227584616252255045051744656658724729921391320513975448747866674731393989824816278253531731559615988365176956553948361741230399671929627311399657205635358188611855896981664987554010070048005180840005056436207539387449042369726304130418877417881364189259973633455724018939019191261925159303420250412390007010119147742488855420323873249301367316063804185927827524896427158951883596368737320448679598208240720659999317773937210898039147175668295346147218816545703112535909878232871373805727402265504548979315089528552745595697, 2310127393424955205107098753990740358616986137235523761428262577027025221085993167331127781046303783394387937006140407932458365609661360072106720211912369678829021097399331475604691187882409665300952366321289612227771815985404013084073477199260101972484084154567987647887377325483499340128094102430928953352662945461142995341584089062204341970339034221703457214832763736835220434547067732740206252238614354577428802536954307484724292316946308032286724679045981289044117505581194462938042596730344914183773705642632211684448859729662063800386303640529418370614292346515567013769130105736509067539211154067603076086189, 260103909934101734536962369349227910737941229676355629033234214156269594943514773423475990016988081886527609702651915199269149400381634311486797884863469442738377631198605297328240657294126185806275220201520185922158666416638929182005650012419901316367524983201785784243504188316736709689328878602689716382200845553376605467447386204662988107092580795936646455346850407094699708770087824573768242252865671229952401642055406014325968496131314289528932191878614864330913120994685365723644918001169807548626702912355139857537404378099007036012070824841803771589907014266992233954712642256908443894447198510324151722807]
e = 629
N = 3189114686224168527832331594922454956130813095678500091837003591252581589062448982723246876196017944847100818244381832468383363405845911023963060518988016928538755279709811123903342192509780913173428723886393253482859769115568498425217420047666488898487353815066472059082290797546861177320701802469167877671417071641160054157961123316709837879746006591255937485506228981534802657551533225645035775724152887077617722220015769980939338494248274632855471433642146347951726131771323868101240008040640059677232340041423789617615705270452301423174772159475723086187149237364733296047140690284751569807669233727054962069009

possiblechr = "{}abcdefghijklmnopqrstuvwxyz0123456789"
plaintext = ""

for i in ciphertext:
  for j in possiblechr:
    if(pow(ord(j),e,N) == i):
      plaintext += j

print(plaintext)

Rigged Lottery

Description:

I found out that somebody has been able to guarantee to win a prize everytime in this lottery. I can't figure it out how they were able to do that. Can you?

Attachment:

server.py

from inputimeout import inputimeout, TimeoutOccurred
import random, sys

with open('flag.txt') as f:
	flag = f.read()

def main():
	print("Here is how the lottery works:")
	print("- Players purchase tickets comprising their choices of six different numbers between 1 and 70")
	print("- During the draw, six balls are randomly selected without replacement from a set numbered from 1 to 70")
	print("- A prize is awarded to any player who matches at least two of the six drawn numbers.")
	print("- More matches = higher prize!")
	while True:
		print("\n********************\nHow many tickets would you like to buy? There is a limit of 50 tickets per person")
		try:
			reply = int(inputimeout(prompt='>> ', timeout=60))
		except ValueError:
			reply = 0
		except TimeoutOccurred:
			print("Oof! Not fast enough!\n")
			sys.exit()
		if reply > 50 or reply < 1:
			print("That is an invalid choice!\n")
		else:
			break
	tickets = []
	for x in range(reply):
		ticket = []
		print(f"\n********************\nPlease give the numbers for ticket {x+1}:")
		for _ in range(6):
			while True:
				try:
					number = int(inputimeout(prompt='>> ', timeout=60))
				except TimeoutOccurred:
					print("Oof! Not fast enough!\n")
					sys.exit()
				except ValueError:
					number = 0
				if number > 70 or number < 1:
					print("That is an invalid choice!\n")
				else:
					break
			ticket.append(number)
		tickets.append(ticket)
	winnings = [0, 0, 1, 100, 1000, 100000, 10000000]
	print(f"\n********************\nLet's see if you can win in {10**6} consecutive rounds of the lottery and make a profit at the end of it!")
	profit = 0
	for i in range(10**6):
		draw = set([])
		while len(draw) != 6:
			draw.add(random.randint(1,70))
		won_prize = False
		for ticket in tickets:
			profit -= 1
			matches = len(draw.intersection(set(ticket)))
			if matches > 1:
				won_prize = True
			profit += winnings[matches]
		if won_prize:
			if (i+1)%(10**5) == 0:
				print(f"You made it through {i+1} rounds! Profit so far is ${profit}")
		else:
			print(f"Draw {i+i}: {draw}, profit: ${profit}")
			print(f"\n********************\nAh shucks! Look's like you did not win any prizes this round. Better luck next time")
			sys.exit()
	if profit > 0:
		print(f"\n********************\nWow! You broke the lottery system! Here's the well-deserved flag --> {flag}")

if __name__ == "__main__":
	main()

Solution:

Bài này..., thôi bỏ đi :v. All you need is here: link

from pwn import *

tickets = ((1, 2, 3, 26, 27, 28),
			(1, 4, 26, 30, 31, 34),
			(3, 4, 28, 29, 30, 33),
			(2, 4, 5, 27, 30, 32),
			(3, 5, 28, 31, 32, 34),
			(1, 5, 26, 29, 32, 33),
			(2, 27, 29, 31, 33, 34),
			(6, 35, 36, 42, 7, 37),
			(6, 35, 41, 43, 9, 39),
			(7, 37, 8, 38, 9, 39),
			(6, 35, 10, 40, 8, 38),
			(7, 37, 10, 40, 41, 43),
			(9, 39, 10, 40, 36, 42),
			(36, 42, 8, 38, 41, 43),
			(11, 44, 49, 51, 12, 47),
			(11, 44, 14, 45, 13, 46),
			(12, 47, 50, 52, 13, 46),
			(12, 47, 15, 48, 14, 45),
			(11, 44, 15, 48, 50, 52),
			(13, 46, 15, 48, 49, 51),
			(49, 51, 50, 52, 14, 45),
			(16, 53, 17, 54, 18, 55),
			(16, 53, 58, 61, 20, 59),
			(16, 53, 57, 60, 19, 56),
			(18, 55, 57, 60, 58, 61),
			(18, 55, 19, 56, 20, 59),
			(20, 59, 57, 60, 17, 54),
			(17, 54, 19, 56, 58, 61),
			(21, 62, 63, 69, 25, 64),
			(21, 62, 24, 65, 67, 70),
			(21, 62, 22, 68, 23, 66),
			(25, 64, 67, 70, 22, 68),
			(25, 64, 24, 65, 23, 66),
			(23, 66, 67, 70, 63, 69),
			(63, 69, 24, 65, 22, 68))

if __name__ == '__main__':
	#server = process(['python3','server.py'])
	server = remote("challenge.nahamcon.com", 30392)
	server.recvuntil(b'>> ')
	server.sendline(str(len(tickets)).encode())
	for ticket in tickets:
		for x in ticket:
			server.recvuntil(b'>> ')
			server.sendline(str(x).encode())
	for _ in range(16):
		print(server.recvline())

Flag: <ditme tat me server roi>

Blackjack

Description:

Can you make a killing by playing blackjack?

Attachment:

server.py

# A lot of this code is taken from https://github.com/rishimule/blackjack-python
from inputimeout import inputimeout, TimeoutOccurred
import os, sys

suits = ("Hearts", "Clubs", "Diamonds", "Spades")
ranks = ("Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King", "Ace")
values = {"Two" : 2, "Three" : 3, "Four" : 4, "Five" : 5, "Six" : 6, "Seven" :7, "Eight" : 8, "Nine" : 9, "Ten" : 10, "Jack" : 10, "Queen" : 10, "King" : 10, "Ace" : 11}

class PRNG:
	def __init__(self, seed = int(os.urandom(8).hex(),16)):
		self.seed = seed
		self.state = [self.seed]
		self.index = 52
		for i in range(51):
			self.state.append((3 * (self.state[i] ^ (self.state[i-1] >> 6)) + i+1)%512)

	def __str__(self):
		return f"{self.state}"

	def getnum(self):
		if self.index >= 52:
			for i in range(52):
				y = (self.state[i] & 0x40) + (self.state[(i+1)%52] & 0x3f)
				val = y >> 1
				val = val ^ self.state[(i+9)%52]
				if y & 1:
					val = val ^ 69
				self.state[i] = val
			self.index = 0
		seed = self.state[self.index]
		self.index += 1
		return (seed*13 + 17)%(2**7)

class Card:
	def __init__(self,rank,suit):
		self.rank = rank
		self.suit = suit
		self.value = values[rank]

	def __str__(self):
		return self.rank + " of " + self.suit

class Deck:
	def __init__(self):
		self.cardlist = []
		for suit in suits:
			for rank in ranks:
				current_card = Card(rank,suit)
				self.cardlist.append(current_card)
	
	def __str__(self):
		deck_cards = ''
		for x in range(len(self.cardlist)):
			deck_cards += str(self.cardlist[x]) + "\n"
		return f"This Deck has {str(len(self.cardlist))} Cards.\n" + deck_cards
	
	def shuffle_deck(self):
		new_deck = []
		for i in range(len(self.cardlist)):
			x = rng.getnum() % 52
			if self.cardlist[x] not in new_deck:
				new_deck.append(self.cardlist[x])
			elif self.cardlist[i] not in new_deck:
				new_deck.append(self.cardlist[i])
			else:
				for card in self.cardlist:
					if card not in self.cardlist:
						new_deck.append(card)
						break
		self.cardlist = new_deck
	
	def deal_one(self):
		return self.cardlist.pop(0)

class Player:
	def __init__(self,name,chips):
		self.name = name
		self.chips = chips
		self.bet = 0
	
	def __str__(self):
		return 'Player {} has {} chips\n'.format(self.name,self.chips)
	
	def add_chips(self,chips):
		self.chips += chips
	
	def remove_chips(self,chips):
		if chips > self.chips or chips < 1:
			print("Invalid amount of Chips.")
			print("Current balance = {}".format(self.chips))
			
		else:
			self.chips -= chips
			print("Current balance = {}".format(self.chips))

class Hand:
	def __init__(self):
		self.cards = []
		self.value = 0
		self.ace_count = 0
	
	def __str__(self):
		cards_in_hand = ''
		for x in range(len(self.cards)):
			cards_in_hand += "  " + str(self.cards[x]) + "\n"
		return cards_in_hand + "This hand has a value of {}.".format(self.value)
	
	def add_card(self,card):
		self.cards.append(card)
		self.value += card.value
		if card.rank == "Ace":
			self.ace_count += 1
		while self.value > 21 and self.ace_count > 0:
			self.value -= 10
			self.ace_count -= 1

def take_bet(player):
	while True:
		try:
			current_bet = int(inputimeout(prompt="Amount of chips to bet: ", timeout=60))
			if current_bet > player.chips or current_bet < 1:
				print("Invalid amount. Please try again\n")
			else:
				player.bet += current_bet
				player.chips -= current_bet
				break
		except ValueError:
			print("That is an invalid option! Please try again\n")
		except TimeoutOccurred:
			print("Oof! Not fast enough!\n")
			sys.exit()

def create_player():
	global player
	while True:
		try:
			player_name = inputimeout("Please enter your name: ", timeout=60)
			if player_name != '':
				break
			else:
				print("Please enter a valid name\n")
		except TimeoutOccurred:
			print("Oof! Not fast enough!\n")
			sys.exit()
	player = Player(player_name,1000)

def adjust_winnings(winner):
	if winner == "player":
		player.chips += int(player.bet*1.5)
		player.bet = 0
	elif winner == "tie" :
		player.chips += player.bet
		player.bet = 0
	else:
		player.bet = 0

def hit_or_stand(player_hand,deck_1):
	while True:
		try:
			temp = inputimeout(prompt="HIT OR STAND? : ", timeout=60)
			if temp == '':
				print("Please choose a valid option\n")
			elif temp[0].lower() == 'h':
				player_hand.add_card(deck_1.deal_one())
				break
			elif temp[0].lower() == 's':
				break
			else:
				print("Please choose a valid option\n")
		except TimeoutOccurred:
			print("Oof! Not fast enough!\n")
			sys.exit()
	if temp[0].lower() == 'h':
		return "h"
	else:
		return "s"

def player_busted():
	global winner	
	print("\nPlayer Busted.")
	print("Dealer Wins!\n")
	winner = "dealer"

def dealer_busted():
	global winner
	print("\nDealer Busted.")
	print("Player Wins!\n")
	winner = "player"

def player_dealer_tie():
	global winner	
	print("IT'S A TIE!!\n")
	winner = "tie"

def player_wins():
	global winner	
	print("Player Wins!\n")
	winner = "player"
	
def dealer_wins():
	global winner
	print("Dealer Wins!\n")
	winner = "dealer"	

def show_some_cards(player_hand, dealer_hand):
	print("\nPlayer Cards are : ")
	print(str(player_hand))
	print("\nDealer Cards are : ")
	print("  " + str(dealer_hand.cards[0]))
	print("**Card is Hidden.**")
	print(50*'*')

def show_all_cards(player_hand, dealer_hand):
	print("\nPlayer Cards are : ")
	print(str(player_hand))
	print("\nDealer Cards are : ")
	print(str(dealer_hand))
	print(50*'*')

def main(player):
	deck_1=Deck()
	deck_1.shuffle_deck()
	player_hand = Hand()
	dealer_hand = Hand()
	print(50*'*')
	print(player)
	take_bet(player)
	player_hand.add_card(deck_1.deal_one())
	player_hand.add_card(deck_1.deal_one())
	dealer_hand.add_card(deck_1.deal_one())
	dealer_hand.add_card(deck_1.deal_one())
	show_some_cards(player_hand, dealer_hand)
	while True:
		if player_hand.value == 21:
			break
		elif player_hand.value > 21:
			player_busted()
			break
		req = hit_or_stand(player_hand, deck_1)
		if req == 's':
			break
		show_some_cards(player_hand, dealer_hand)
	show_all_cards(player_hand, dealer_hand)
	dealer_playing = True
	while dealer_playing:
		if player_hand.value <= 21:
			while dealer_hand.value < 17 :
				print("\nDealer Hits......")
				dealer_hand.add_card(deck_1.deal_one())
				show_all_cards(player_hand, dealer_hand)
			dealer_playing = False
			if dealer_hand.value > 21:
				dealer_busted()
				break
			elif player_hand.value == dealer_hand.value:
				player_dealer_tie()
				break
			elif player_hand.value > dealer_hand.value:
				player_wins()
				break
			else:
				dealer_wins()
				break
		else:
			break
	adjust_winnings(winner)
	print("\n" + str(player))

def play_again():
	while True:
		print(50*'*')
		try:
			temp = inputimeout(prompt="\nWant to play again? : ", timeout=60)
			if temp[0].lower() == 'y':
				return True
			elif temp[0].lower() == 'n':
				print(50*'*')
				print("\nThank you for playing...\n")
				print(50*'*')
				return False
			else:
				print("Please choose a valid option\n")
		except TimeoutOccurred:
			print("Oof! Not fast enough!\n")
			sys.exit()

if __name__ == '__main__':
	playing = True
	create_player()
	global rng
	rng = PRNG()
	while playing:
		main(player)
		if player.chips >= 1000000:
			print(50*'*')
			print("Congratulations on winning this big! Here's a special reward for that...")
			with open('flag.txt', 'r') as f:
				print(f.read())
			print("\nThank you for playing...\n")
			print(50*'*')
			break
		elif player.chips == 0:
			print(50*'*')
			print("Sorry for losing everything. Better luck next time!")
			print(50*'*')
			break
		playing=play_again()

Recon:

Bài này thì nó chính là một code game Blackjack luôn. Mục tiêu là ta phải thắng đủ 1.000.000 chips để có thể lấy đươc flag. Có một số điểm cần lưu ý:

  • Nếu nhà cái có số điểm >= 17 thì sẽ auto STAND.

  • Mỗi lần thắng, nếu all in ta sẽ lãi 50% vốn.

  • Bộ bài được shuffle sẽ là thứ tự bốc, mình sẽ được phát 2 con đầu và nhà cái là 2 con sau (cái này cứ print ra là thấy chứ đọc code chết)

=> Chỉ cần biết trước được bộ bài đã shuffle, ta có thể HIT or STAND một cách thuận lợi để lời nhiều nhất và lỗ ít nhất. Đơn giản là nếu không thắng được, ta sẽ biết trước và cược 1 chips only.

Solution:

Ý tưởng giải bài này: link

Nôm na thì state thực sự chỉ dựa vào 15 bit cuối của seed nên mình có thể bruteforce seed trong khoảng 2**15. Sau đó mình hoàn toàn có thể lấy được shuffled desk của từng ván, từ đó quyết định HIT or STAND.

Bằng cách đầu hàng ván đầu (dùng 1 chips), mình hoàn toàn có thể lấy được tối thiểu 4 lá bài đầu của bộ shuffled (sẽ cho vào file input.txt). Nếu seed nào cho ra outputs có 4 lá đó liền nhau, đó chính là seed đúng. Đây là code để lấy ra seed và hiển thị bộ bài (mình không hiển thị các bài đã trên tay để cho mục đích cá nhân: chơi cho dễ).

from inputimeout import inputimeout, TimeoutOccurred
import os
import sys
from tqdm import tqdm
from pwn import *

suits = ("Hearts", "Clubs", "Diamonds", "Spades")
ranks = ("Two", "Three", "Four", "Five", "Six", "Seven",
         "Eight", "Nine", "Ten", "Jack", "Queen", "King", "Ace")
values = {"Two": 2, "Three": 3, "Four": 4, "Five": 5, "Six": 6, "Seven": 7,
          "Eight": 8, "Nine": 9, "Ten": 10, "Jack": 10, "Queen": 10, "King": 10, "Ace": 11}


class PRNG:
    def __init__(self, seed=int(os.urandom(8).hex(), 16)):
        self.seed = seed
        self.state = [self.seed]
        self.index = 52
        for i in range(51):
            self.state.append(
                (3 * (self.state[i] ^ (self.state[i-1] >> 6)) + i+1) % 512)

    def __str__(self):
        return f"{self.state}"

    def getnum(self):
        if self.index >= 52:
            for i in range(52):
                y = (self.state[i] & 0x40) + (self.state[(i+1) % 52] & 0x3f)
                val = y >> 1
                val = val ^ self.state[(i+9) % 52]
                if y & 1:
                    val = val ^ 69
                self.state[i] = val
            self.index = 0
        seed = self.state[self.index]
        self.index += 1
        return (seed*13 + 17) % (2**7)


class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit
        self.value = values[rank]

    def __str__(self):
        return self.rank + " of " + self.suit


class Deck:
    def __init__(self):
        self.cardlist = []
        for suit in suits:
            for rank in ranks:
                current_card = Card(rank, suit)
                self.cardlist.append(current_card)

    def __str__(self):
        deck_cards = ''
        for x in range(9):
            deck_cards += str(self.cardlist[x]) + "\n"
        return f"This Deck has {str(len(self.cardlist))} Cards.\n" + deck_cards

    def shuffle_deck(self):
        new_deck = []
        for i in range(len(self.cardlist)):
            x = rng.getnum() % 52
            if self.cardlist[x] not in new_deck:
                new_deck.append(self.cardlist[x])
            elif self.cardlist[i] not in new_deck:
                new_deck.append(self.cardlist[i])
            else:
                for card in self.cardlist:
                    if card not in self.cardlist:
                        new_deck.append(card)
                        break
        self.cardlist = new_deck

    def deal_one(self):
        return self.cardlist.pop(0)


class Player:
    def __init__(self, name, chips):
        self.name = name
        self.chips = chips
        self.bet = 0

    def __str__(self):
        return 'Player {} has {} chips\n'.format(self.name, self.chips)

    def add_chips(self, chips):
        self.chips += chips

    def remove_chips(self, chips):
        if chips > self.chips or chips < 1:
            print("Invalid amount of Chips.")
            print("Current balance = {}".format(self.chips))

        else:
            self.chips -= chips
            print("Current balance = {}".format(self.chips))


class Hand:
    def __init__(self):
        self.cards = []
        self.value = 0
        self.ace_count = 0

    def __str__(self):
        cards_in_hand = ''
        for x in range(len(self.cards)):
            cards_in_hand += "  " + str(self.cards[x]) + "\n"
        return cards_in_hand + "This hand has a value of {}.".format(self.value)

    def add_card(self, card):
        self.cards.append(card)
        self.value += card.value
        if card.rank == "Ace":
            self.ace_count += 1
        while self.value > 21 and self.ace_count > 0:
            self.value -= 10
            self.ace_count -= 1


def take_bet(player):
    while True:
        try:
            current_bet = int(inputimeout(
                prompt="Amount of chips to bet: ", timeout=60))
            if current_bet > player.chips or current_bet < 1:
                print("Invalid amount. Please try again\n")
            else:
                player.bet += current_bet
                player.chips -= current_bet
                break
        except ValueError:
            print("That is an invalid option! Please try again\n")
        except TimeoutOccurred:
            print("Oof! Not fast enough!\n")
            sys.exit()


def create_player():
    global player
    while True:
        try:
            player_name = "TrungPQ"
            if player_name != '':
                break
            else:
                print("Please enter a valid name\n")
        except TimeoutOccurred:
            print("Oof! Not fast enough!\n")
            sys.exit()
    player = Player(player_name, 1000)


def adjust_winnings(winner):
    if winner == "player":
        player.chips += int(player.bet*1.5)
        player.bet = 0
    elif winner == "tie":
        player.chips += player.bet
        player.bet = 0
    else:
        player.bet = 0


def hit_or_stand(player_hand, deck_1):
    while True:
        try:
            temp = inputimeout(prompt="HIT OR STAND? : ", timeout=60)
            if temp == '':
                print("Please choose a valid option\n")
            elif temp[0].lower() == 'h':
                player_hand.add_card(deck_1.deal_one())
                break
            elif temp[0].lower() == 's':
                break
            else:
                print("Please choose a valid option\n")
        except TimeoutOccurred:
            print("Oof! Not fast enough!\n")
            sys.exit()
    if temp[0].lower() == 'h':
        return "h"
    else:
        return "s"


def player_busted():
    global winner
    print("\nPlayer Busted.")
    print("Dealer Wins!\n")
    winner = "dealer"


def dealer_busted():
    global winner
    print("\nDealer Busted.")
    print("Player Wins!\n")
    winner = "player"


def player_dealer_tie():
    global winner
    print("IT'S A TIE!!\n")
    winner = "tie"


def player_wins():
    global winner
    print("Player Wins!\n")
    winner = "player"


def dealer_wins():
    global winner
    print("Dealer Wins!\n")
    winner = "dealer"


def show_some_cards(player_hand, dealer_hand):
    print("\nPlayer Cards are : ")
    print(str(player_hand))
    print("\nDealer Cards are : ")
    print("  " + str(dealer_hand.cards[0]))
    print("**Card is Hidden.**")
    print(50*'*')


def show_all_cards(player_hand, dealer_hand):
    print("\nPlayer Cards are : ")
    print(str(player_hand))
    print("\nDealer Cards are : ")
    print(str(dealer_hand))
    print(50*'*')


def main(player):
    deck_1 = Deck()
    deck_1.shuffle_deck()
    return deck_1


def play_again():
    while True:
        print(50*'*')
        try:
            temp = inputimeout(prompt="\nWant to play again? : ", timeout=60)
            if temp[0].lower() == 'y':
                return True
            elif temp[0].lower() == 'n':
                print(50*'*')
                print("\nThank you for playing...\n")
                print(50*'*')
                return False
            else:
                print("Please choose a valid option\n")
        except TimeoutOccurred:
            print("Oof! Not fast enough!\n")
            sys.exit()


with open('input.txt', 'r') as file:
    lines = file.readlines()

c = ''
for line in lines:
    c += line

print(c)

for i in tqdm(range(2**15)):
    create_player()
    rng = PRNG(seed=i)
    m = str(main(player))
    if c in m:
        print("Found seed = ", i)
        print(m)
        break

while True:
    deck_1 = Deck()
    deck_1.shuffle_deck()
    player_hand = Hand()
    dealer_hand = Hand()
    player_hand.add_card(deck_1.deal_one())
    player_hand.add_card(deck_1.deal_one())
    dealer_hand.add_card(deck_1.deal_one())
    dealer_hand.add_card(deck_1.deal_one())
    print("Shuffled")
    print("You: ", player_hand.value)
    print("Dealer: ", dealer_hand.value)
    print(deck_1)
    c = input()

Dựa trên việc số chips sau khi all in sẽ bằng 1.5 lần số chips gốc, chỉ cần mình thắng all in khoảng 18 lần là sẽ thừa tiền lấy flag.

Do đếu viết được code solve bằng pwntools vì output mỗi lần đều khác và logic hơi phức tạp với mình để code, nên mình sẽ chơi bằng tay (18 lần bọ)

Flag: flag{49bfe61dce46fc826814208e020f58f3}

© 2024,Pham Quoc Trung. All rights reserved.

Last updated