$> shellcode
/bin/////////sh
NOP
sleds“These courses expects a high standard of professionalism from its students with regard to how security testing is conducted. We expect all students to act in good faith at all times […]”
TL;DR Don’t be mean
Your common assembly instructions
mov a, b # a = b
add a, value # a = a + value
sub a, value # a = a - value
xor a, b # a = a ^ b
and a, b # a = a & b
push a # push a onto the stack, then dec esp - 4
pop a # pop into a from the stack, then add esp + 4
int 0x80 # syscall
void mycoolfunc(char *a, int b, char *c)
What assembly would I write to call this function?
push address_c
push value_b
push address_a
call mycoolfunc
Shellcode is a sequence of assembly instructions that carry out a task. If we can make the instruction pointer (EIP
) point to our shellcode, we have code execution!
Generally we want to pop a shell
./runner
Sometimes we do not have enough space in an execute-vulnerable buffer to inject our payload.
Instead, we put our payload (the egg) somewhere else, and write an ‘egg hunter’ - assembly instructions that finds and execute the egg.
Demo time!
#include <stdio.h> // Compile with:
#include <stdlib.h> // gcc -o eggHunterDemo -z execstack -m32 -g eggHunterDemo.c
#include <time.h> // \__________/
#include <unistd.h> // -- Andrew | allow stack execution
int main() {
char mem[256] = { 0 }, shellcode[512] = { 0 };
srand(time(NULL));
// Set some random position in mem to [0, 255]
mem[(u_int8_t)rand()] = 0xFF; // eggu desu ~
puts("Find that egg!\nEnter up to 512 bytes of shellcode");
read(0, shellcode, 512);
// Your shellcode should accept a buffer (esp+4), and return an index via eax
u_int8_t i = ((u_int8_t(*)(u_int8_t * a)) shellcode)(mem);
printf("mem[i = %hhu] = 0x%2x\n", i, mem[i] & 0xFF);
puts(mem[i] & 0xFF == 0xFF ? "nice!" : "nope.");
}
A fancy egghunter that finds multiple payloads / eggs and combines them together.
Useful when we have multiple regions of controllable memory that can collectively hold the entire payload.
/bin/////////sh
Sometimes we cannot inject /bin/sh
directly.
Why?
NULL
characterNULL
character !! uh oh, null char!
vv
_hs/ | push 0x0068732f | 68 2f 73 68 [00]
nib/ | push 0x6e69622f | 68 2f 62 69 6e
We have ways around this!
Pad our /bin/sh
to /bin//sh
// BEFORE
_hs/ | push 0x0068732f | 68 2f 73 68 00
nib/ | push 0x6e69622f | 68 2f 62 69 6e
// AFTER
hs// | push 0x68732f2f | 68 2f 2f 73 68
nib/ | push 0x6e69622f | 68 2f 62 69 6e
some shellcode yadda yadda / b i n / / s h ... int 0x80
How do we push
0
's onto the stack?
xor eax, eax
push eax
etc…
Sometime in the future…
Maybe /bin/sh
is already in the program???
idk ¯\_(ツ)_/¯
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
In order to execute our shellcode, we need to know the exact start address of it… sometimes we can’t do that, but we can jump near it and nop
-sled away.
The
nop
instruction (\x90
) is a single byte instruction that does nothing
Where we start execution Where our shellcode actually is
| |
v v
\x90 \x90 \x90 \x90 \x90 \x90 \x68 \x2f \x2f \x73 \x68 \x68..
Lab 2 - Shellcode Exercices