KEMBAR78
CNIT 127 Ch 3: Shellcode | PDF
CNIT 127: Exploit Development




Ch 3: Shellcode
Updated 2-22-21
Topics
• Protection rings


• Syscalls


• Shellcode


• nasm Assembler


• ld GNU Linker


• objdump to see contents of object files


• strace System Call Tracer


• Removing Nulls


• Spawning a Shell
Understanding System Calls
Shellcode
• Written in assembler


• Translated into hexadecimal opcodes


• Intended to inject into a system by
exploiting a vulnerability


• Typically spawns a root shell, but may do
something else
System Calls (or Syscalls)
• Syscalls directly access the kernel, to:


– Get input


– Produce output


– Exit a process


– Execute a binary file


– And more


• They are the interface between protected
kernel mode and user mode
Protection Rings
• Although the x86
provides four
rings, only rings 0
and 3 are used by
Windows or Unix


• Ring 3 is user-
land


• Ring 0 is kernel-
land


• Links Ch 3a-3c
Protecting the Kernel
• Protected kernel mode


– Prevents user applications from compromising
the OS


• If a user mode program attempts to
access kernel memory, this generates an
access exception


• Syscalls are the interface between user
mode and kernel mode
Libc
• C library wrapper


• C functions that perform syscalls


• Advantages of libc


– Allows programs to continue to function
normally even if a syscall is changed


– Provides useful functions, like malloc


– (malloc allocates space on the heap)


• See link Ch 3d
Syscalls use INT 0x80
1. Load syscall number into EAX


2. Put arguments in other registers


3. Execute INT 0x80


4. CPU switches to kernel mode


5. Syscall function executes
Syscall Number and Arguments
• Syscall number is an integer in EAX


• Up to six arguments are loaded into


– EBX, ECX, EDX, ESI, EDI, and EBP


• For more than six arguments, the first
argument holds a pointer to a data
structure
Demonstration
Using Debian 10 64-Bit
exit()
• The libc exit function does a lot of
preparation, carefully covering many
possible situations, and then calls SYSCALL
to exit
Disassembling exit
• gdb -q e


– disassemble main


– main calls exit


– exit calls
__run_exit_handlers


– __run_exit_handlers
calls _exit


– disassemble _exit


• int 0x80


– call *$gs:10


– int 0x80
Four Ways to Do Syscall
• Link Ch 3o
Disassembling _exit
• syscall 252 (0xfc), exit_group() (kill all threads)


• syscall 1, exit()
	
(kill calling thread)


– Link Ch 3e
Writing Shellcode for the
exit() Syscall
Shellcode Size
• Shellcode should be as simple and
compact as possible


• Because vulnerabilities often only allow a
small number of injected bytes


– It therefore lacks error-handling, and will
crash easily
sys_exit Syscall
• Two arguments: eax=1, ebx is return value
(0 in our case)


• Link Ch 3m
Simplest code for exit(0)
nasm and ld
• sudo apt install nasm


• nasm creates object file


• gcc links it, creating an executable ELF file
objdump
• Shows the contents of object files
C Code to Test Shellcode
• From link Ch 3k


• Textbook version explained at link Ch 3i
Compile and Run
• Textbook omits the "-z execstack" option


• It's required now or you get a segfault


• Next, we'll use "strace" to see all system
calls when this program runs


• That shows a lot of complex calls, and
"exit(0)" at the end
Using strace
• sudo apt install strace
Injectable Shellcode
Getting Rid of Nulls
• We have null bytes, which will terminate
a string and break the exploit
Replacing Instructions
• This instruction contains nulls


– mov ebx,0


• This one doesn't


– xor ebx,ebx


• This instruction contains nulls, because it
moves 32 bits


– mov eax,1


• This one doesn't, moving only 8 bits


– mov al, 1
OLD
	
	
	
	
	
	
	
NEW
objdump of New Exit Shellcode
Spawning a Shell
Beyond exit()
• The exit() shellcode stops the program, so
it's just a DoS attack


• Any illegal instruction can make the
program crash, so that's of little use


• We want shellcode that offers the
attacker a shell, so the attacker can type
in arbitrary commands
Five Steps to Shellcode
1. Write high-level code


2. Compile and disassemble


3. Analyze the assembly


4. Clean up assembly, remove nulls


5. Extract commands and create shellcode
fork() and execve()
• Two ways to create a new process in Linux


• Replace a running process


– Uses execve()


• Copy a running process to create a new
one


– Uses fork() and execve() together
man execve
C Program to Use execve()
• Static linking preserves our execve syscall
In gdb, disassemble main
• Pushes 3 Arguments


• Calls __execve
disassemble execve
• Puts four parameters into edx, ecx, ebx, and eax
Versions of syscall
• Link Ch 3n
Final Shellcode
CNIT 127 Ch 3: Shellcode

CNIT 127 Ch 3: Shellcode

  • 1.
    CNIT 127: ExploitDevelopment 
 
 Ch 3: Shellcode Updated 2-22-21
  • 2.
    Topics • Protection rings •Syscalls • Shellcode • nasm Assembler • ld GNU Linker • objdump to see contents of object files • strace System Call Tracer • Removing Nulls • Spawning a Shell
  • 3.
  • 4.
    Shellcode • Written inassembler • Translated into hexadecimal opcodes • Intended to inject into a system by exploiting a vulnerability • Typically spawns a root shell, but may do something else
  • 5.
    System Calls (orSyscalls) • Syscalls directly access the kernel, to: – Get input – Produce output – Exit a process – Execute a binary file – And more • They are the interface between protected kernel mode and user mode
  • 6.
    Protection Rings • Althoughthe x86 provides four rings, only rings 0 and 3 are used by Windows or Unix • Ring 3 is user- land • Ring 0 is kernel- land • Links Ch 3a-3c
  • 7.
    Protecting the Kernel •Protected kernel mode – Prevents user applications from compromising the OS • If a user mode program attempts to access kernel memory, this generates an access exception • Syscalls are the interface between user mode and kernel mode
  • 8.
    Libc • C librarywrapper • C functions that perform syscalls • Advantages of libc – Allows programs to continue to function normally even if a syscall is changed – Provides useful functions, like malloc – (malloc allocates space on the heap) • See link Ch 3d
  • 9.
    Syscalls use INT0x80 1. Load syscall number into EAX 2. Put arguments in other registers 3. Execute INT 0x80 4. CPU switches to kernel mode 5. Syscall function executes
  • 10.
    Syscall Number andArguments • Syscall number is an integer in EAX • Up to six arguments are loaded into – EBX, ECX, EDX, ESI, EDI, and EBP • For more than six arguments, the first argument holds a pointer to a data structure
  • 11.
  • 12.
    exit() • The libcexit function does a lot of preparation, carefully covering many possible situations, and then calls SYSCALL to exit
  • 13.
    Disassembling exit • gdb-q e – disassemble main – main calls exit – exit calls __run_exit_handlers – __run_exit_handlers calls _exit – disassemble _exit • int 0x80 – call *$gs:10 – int 0x80
  • 14.
    Four Ways toDo Syscall • Link Ch 3o
  • 15.
    Disassembling _exit • syscall252 (0xfc), exit_group() (kill all threads) • syscall 1, exit() (kill calling thread) – Link Ch 3e
  • 16.
    Writing Shellcode forthe exit() Syscall
  • 17.
    Shellcode Size • Shellcodeshould be as simple and compact as possible • Because vulnerabilities often only allow a small number of injected bytes – It therefore lacks error-handling, and will crash easily
  • 18.
    sys_exit Syscall • Twoarguments: eax=1, ebx is return value (0 in our case) • Link Ch 3m
  • 19.
  • 20.
    nasm and ld •sudo apt install nasm • nasm creates object file • gcc links it, creating an executable ELF file
  • 21.
    objdump • Shows thecontents of object files
  • 22.
    C Code toTest Shellcode • From link Ch 3k • Textbook version explained at link Ch 3i
  • 23.
    Compile and Run •Textbook omits the "-z execstack" option • It's required now or you get a segfault • Next, we'll use "strace" to see all system calls when this program runs • That shows a lot of complex calls, and "exit(0)" at the end
  • 24.
    Using strace • sudoapt install strace
  • 25.
  • 26.
    Getting Rid ofNulls • We have null bytes, which will terminate a string and break the exploit
  • 27.
    Replacing Instructions • Thisinstruction contains nulls – mov ebx,0 • This one doesn't – xor ebx,ebx • This instruction contains nulls, because it moves 32 bits – mov eax,1 • This one doesn't, moving only 8 bits – mov al, 1
  • 28.
  • 29.
    objdump of NewExit Shellcode
  • 30.
  • 31.
    Beyond exit() • Theexit() shellcode stops the program, so it's just a DoS attack • Any illegal instruction can make the program crash, so that's of little use • We want shellcode that offers the attacker a shell, so the attacker can type in arbitrary commands
  • 32.
    Five Steps toShellcode 1. Write high-level code 2. Compile and disassemble 3. Analyze the assembly 4. Clean up assembly, remove nulls 5. Extract commands and create shellcode
  • 33.
    fork() and execve() •Two ways to create a new process in Linux • Replace a running process – Uses execve() • Copy a running process to create a new one – Uses fork() and execve() together
  • 34.
  • 35.
    C Program toUse execve() • Static linking preserves our execve syscall
  • 36.
    In gdb, disassemblemain • Pushes 3 Arguments • Calls __execve
  • 37.
    disassemble execve • Putsfour parameters into edx, ecx, ebx, and eax
  • 38.
  • 40.