IERAE CTF had one of the coolest pwn challenges I've done in the while. It was written by hugeh0ge.
Here's the full source:
// gcc chal.c -fno-stack-protector -static -o chal
#include <stdio.h>
#include
IERAE CTF had one of the coolest pwn challenges I've done in the while. It was written by hugeh0ge.
Here's the full source:
// gcc chal.c -fno-stack-protector -static -o chal
#include <stdio.h>
#include
#!/usr/bin/env python2 | |
# -*- coding: utf-8 -*- | |
# The 300 challenge was a heap challenge that allowed you to make allocations of size 0x300. | |
# You could free allocations and read/write to them even after they got freed. | |
# The tricky part about the challenge was that you don't control the size and can't for example use the usual fastbin techniques. | |
# This exploit overwrites the check_action variable so that the libc doesn't abort on errors anymore. | |
# Afterwards we can get a write-what-where primitive using unsafe unlink. |
This challenge gave parts of the points as soon as you find a crash in the binary, which was a forking network service. With a short LD_PRELOAD library, you can bypass all the networking code and fuzz the handler function directly with afl using the qemu mode.
The basic steps:
#include <signal.h> | |
#include <unistd.h> | |
typedef void (*sighandler_t)(int); | |
sighandler_t signal(int signum, sighandler_t handler) { | |
void (*fn)() = (void (*)())0x404310; | |
fn(); | |
_exit(0); | |
} |
SecuVPS was another pwning challenge (though it was marked as misc).
You had a website where you could download a patched ssh client including the sources and luckily they even told you the original source repo of the code they used. That made finding the diff easy: git clone the original repo, replace the code with the patched files and take a look at git diff. There were two changes:
Since we don't want to reimplement the ssh protocol, let's reuse the ssh code that we got. Compile your own sshd, run it with in verbose mode and connect against it with the vulnerable ssh binary. You'll see some messages abuot key exchange packets and one that prints "no match: $BANNER". So we can find these messages in the source and put our exploit code there. I.e. where it says "no match" we parse the info leak and in
Noted was a 32bit pwnable that read / write notes which are backed by files on the disk. Every file started with a 16 byte password and then you were able to write up to 0x400 bytes to the file. When editing notes, you were allowed to write as many bytes to the file as it contained previously, but the buffer had a fixed size. So if you'd find a way to create a file that is bigger than 0x400 bytes then you'd have a straight forward stack overflow. The bug was in the way the length check worked and the mandatory 16 byte password at the beginning. If you create a file that only contained the password, the length check would underflow and allow you to write (unsigned) -1 bytes to the file / local buffer. The same code would also leak the stack content to you.
From there it was slightly complicated rop since I didn't figure out how to use the plt on x86. First leak the libc address from the got by jumping to one of the puts calls in the binary. On the next return we can gain code execution again by having the ebp
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import struct | |
import sys | |
import struct | |
import pwn | |
from find_offset import get_libc_off, MyException |
with (true) { | |
// f() will allocate a buggy JSArray. The length is set to 24 but the capacity is only 16. | |
// take a look at JSCreateLowering::ReduceJSCreateArray to see why this is happening | |
function f(){ | |
var x = 8; | |
var y = 0xffffffff; | |
var ind = x & y; | |
x = 16; | |
y = 0xffffffff; | |
var ind2 = ind + (x&y); |