shellcode

osusec

monday, 2/24

Capture The Flag League

da playa’s guide to running code that isn’t there

  • streaming
  • unmuted

review

smashing the stack

  • how?
  • writing past a buffer
  • why?
  • to overwrite the return address
  • where? (temporally)
  • the return address is pushed right before a function is called
  • where? (spatially)
  • right after the base pointer
  • what?
  • when ret is called, the program goes somewhere you control :D

where do we return to?

  • somewhere good in the code
  • like win() :D :D

why limit ourselves?

  • we can return anywhere
  • even our own buffer…
  • ….

arbitrary code execution

  • not many limits here
  • find where the buffer begins, return to it
  • instructions in your buffer start executing

which means ur gonna have to handwrite some assembly

  • pwntools is good at this
  • asm("xor ecx, ecx") will compile assembly into machine code
  • make sure you’re using the right architecture!

what kind of assembly code are we gonna write?

  • classic idea: just handwrite the win function.
read(open("flag.txt"), buffer, 32);
write(stdout, buffer, 32);
  • kinda a pain to do that in assembly

what it actually would be

  • each call to read/open/write represents a syscall
  • you can’t open a file, but the operating system can
  • so each of these library calls is actually a system call

system calls

  • interrupt program to do a syscall
  • on x86 32 bit: set yr registers, then use the instruction int 0x80
  • interrupts program, asking the Linux kernel to do some work

man 2 syscalls

syscalls(2)      System Calls Manual      syscalls(2)

NAME
       syscalls - Linux system calls

SYNOPSIS
       Linux system calls.

DESCRIPTION
       The  system  call is the fundamental interface
       between an application and the Linux kernel.

   System calls and library wrapper functions
       System calls are  generally  not  invoked  di‐
       rectly,  but  rather  via wrapper functions in
       glibc (or perhaps some  other  library).   For
       details of direct invocation of a system call,
       see intro(2).  Often, but not always, the name
       of  the  wrapper  function  is the same as the
       name of the system call that it invokes.   For
       example,  glibc  contains  a  function chdir()
       which invokes the  underlying  "chdir"  system
       call.

basic assembly

  • mov eax, 0x23 sets eax to 0x23
  • xor eax,eax clears eax
  • push eax puts whatever’s in eax to the top of the stack
  • int 0x80 does an interrupt

the flow

  1. write some assembly
  2. compile it to machine code
  3. write it to a buffer
  4. overwrite the return address with the start of that buffer

stuff to keep in mind

  • return address right after (+4/+8) the base pointer
  • SIGSEV invalid address 0xdeadbeef means you overwrote the return address!
  • sometimes, instructions will compile to bytes that get parsed wrong
  • ie, 0x0 or whatever a newline is
  • if your code acts weird, maybe it’s getting read in an unexpected way!
  • this technique is called ‘shellcode’ because…
  • syscalling execve on a shell is flexible and portable