Skip to content

Instantly share code, notes, and snippets.

@lightdiscord
Last active October 3, 2021 12:13
Show Gist options
  • Save lightdiscord/f76a5c881e2a04f3f0238cde0323abfc to your computer and use it in GitHub Desktop.
Save lightdiscord/f76a5c881e2a04f3f0238cde0323abfc to your computer and use it in GitHub Desktop.
Writeup TSG2021 - Begginer's reverse

writeup-tsg-2021

beginner's reverse

The challenge is a crackme, it asks for an argument of 32 chars and gives it to a check function.

This check function fork the program multiple times and redirect the stdout of the child to /dev/null.

do {
	_Var1 = fork();
	iVar3 += 1;
	if (_Var1 == 0) {
		iVar3 = 0;
		uVar4 |= 1 << ((byte)iVar2 & 0x1f);
		fd = open("/dev/null",1);
		dup2(fd,1);
	}
	iVar2 += 1;
} while (iVar2 != 5);

For each fork, it create an index (uVar4) and gives it to a function which will test if the password[index] is correct.

is_correct(password[uVar4], uVar4);

One way to crack the password is to test the function is_correct for each char in each position.

The easiest way to do it without extracting the function is to load a library with LD_PRELOAD which will call the function.

The first problem we find is that the binary is a PIE, so we need to find where it's loaded in memory. I didn't find a great way to do this so I'm using the entries in /proc/self/maps.

static unsigned long pie_base_address(void) {
	FILE *maps = fopen("/proc/self/maps", "r");

	while (1) {
		unsigned long from;
		int pgoff;
		char *lib;

		fscanf(maps, "%lx-%*lx %*4c %x %*x:%*x %*lu %ms", &from, &pgoff, &lib);
		bool check = strstr(lib, "beginners_rev") && pgoff == 0;

		free(lib);
		if (check) {
			return from;
		}
	}

	abort();
}

Now we need to write the code to crack each character of the password.

static __attribute__((constructor)) void init(void) {
	void *base_address = (void*)pie_base_address();

	printf("[*] Base address is %p\n", base_address);

	puts("[*] Cracking password");

	bool (*is_correct)(int value, int offset) = base_address + 0x1280;

	for (int offset = 0; offset < 32; offset++) {
		for (int i = 0; i < 256; i++) {
			if (is_correct(i, offset)) {
				putchar(i);
			}
		}
	}

	putchar('\n');
	exit(0);
}

Unfortunately, doing this will massively log errors about this function not able to being run inside a debugger.

Looking inside this function we can find the code responsible of telling us that.

if (in_stack_00000000 != 0x1031cf) {
	fwrite("This function may not work properly with a debugger.",1,0x34,stderr);
}

This check if the return address is equals to 0x1031cf or looking at the assembly, if it is equals to check's address + 0x5f.

So to lead the program into thinking its return address is what it want we will patch the .text section with our library. To do this we will use mprotect to be able to write and we will replace the instruction at the return address with a ret and instead of directly calling the function we will call this gadget.

mprotect(base_address, 0x4000, PROT_READ | PROT_WRITE | PROT_EXEC);
*(char*)(base_address + 0x031cf) = 0xc3;

Adding that to our library and running the program don't show the warning message anymore and shows us the flag.

#include <stdbool.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
static unsigned long pie_base_address(void) {
FILE *maps = fopen("/proc/self/maps", "r");
while (1) {
unsigned long from;
int pgoff;
char *lib;
fscanf(maps, "%lx-%*lx %*4c %x %*x:%*x %*lu %ms", &from, &pgoff, &lib);
bool check = strstr(lib, "beginners_rev") && pgoff == 0;
free(lib);
if (check) {
return from;
}
}
abort();
}
static __attribute__((constructor)) void init(void) {
void *base_address = (void*)pie_base_address();
printf("[*] Base address is %p\n", base_address);
puts("[*] Patching instruction");
mprotect(base_address, 0x4000, PROT_READ | PROT_WRITE | PROT_EXEC);
*(char*)(base_address + 0x031cf) = 0xc3;
puts("[*] Cracking password");
bool (*is_correct)(int value, int offset) = base_address + 0x31ca;
for (int offset = 0; offset < 32; offset++) {
for (int i = 0; i < 256; i++) {
if (is_correct(i, offset)) {
putchar(i);
}
}
}
putchar('\n');
exit(0);
}
$ cc -O3 -shared -o libcracker.so -fPIC cracker.c && env LD_PRELOAD=./libcracker.so ./beginners_rev
[*] Base address is 0x5613164bd000
[*] Patching instruction
[*] Cracking password
TSGCTF{y0u..................015}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment