software security
TRANSCRIPT
Software Security December 2014
Roman Oliynykov
Professor atInformation Technologies Security Department
Kharkov National University of Radioelectronics
Head of Scientific Research Department JSC “Institute of Information Technologies”
Ukraine
Visiting professor at Samsung Advanced Technology Training Institute
Lectures outline
A few words about myself Importance of secure solutions Buffer overflow vulnerability and
countermeasures Heap overruns and integer overflows,
recommendations for avoiding Format string vulnerabilities and security
recommendations
For these lecturesI suppose you are familiar
for general understanding of discussing problems: C and C++ programming languages (basic level)
it will be discussed, but would be an advantage if you already familiar with operation system architecture (process, address
space, stack, heap, etc.) x86 assembler language source code (preferably
AT&T notation) basics of Linux (command line) and computer
networking
About myself (I)
I’m from Ukraine (Eastern part of Europe), host country of Euro2012 football championship
I live in Kharkov (the second biggest city in the country, population is 1.5 million people), Eastern Ukraine (near Russia),former capital of the Soviet Ukraine (1918-1934)three Nobel prize winners worked at Kharkov University
About myself (II)
Professor of Information Technologies Security Department at Kharkov National University of Radioelectronics courses on computer networks and
operation system security, special mathematics for cryptographic applications
Head of Scientific Research Department at JSC “Institute of Information Technologies” Scientific interests: symmetric
cryptographic primitives synthesis and cryptanalysis
Modern malware
functions of different categories: viruses, worms and Trojan horses
belongs to network of bot programs (botnet) executes commands received from the
botnet control center has stealth/polymorphysm/armoring
functions against antivirus software
What happens if strcpy() argument is longer than the destination buffer
strcpy( &dst, &src ) in contrast to
strncpy( &dst, &src, sizeof (dst) ) takes into account only destination string length (buffer size) and copies data until finds termination zero in src
netcalcd – vulnerable daemon (service) for Linux (x86)
intentionally written for this lecture and contains intentionally man-made vulnerabilities
processes simple network text requests for basic calculations
prints debug information about its stack on the server console
Vulnerability in get_result() function
strcpy( &dst, &src ) in contrast to
strncpy( &dst, &src, sizeof (dst) ) takes into account only destination string length (buffer size) and copies data until finds termination zero in src
Shellcode in the example: relocatable binary code can be run at any user address
Protect the running code in the stack, find absolute address it is run at and decode the rest part of the shellcode
After encoding the rest part of the shellcode runs web server at port 8801
or does everything intruder wants to do with the vulnerable process privileges
NB: cross-platform exploits working well different processors and OS
Possible countermeasures against buffer overflow
write secure code based on secure functions calls and all necessary user input verification (the most important recommendation)
make your operation system to use Address Space Layout Randomization (ASLR)
make your operation system use processor NX bit (on x86 platform)
keep on canary words in your compiler run the code with the least necessary privileges
Write secure code based on secure functions calls
strcpy( &dst, &src ) fills destination buffer without taking into account its size;
strncpy( &dst, &src, sizeof( dst ) ) won’t write outside the destination buffer (but it’s possible the lost of terminating zero)
Write secure code based on secure functions calls
And many other recommendations for writing secure code…
Security check of existing projects: automated tools
But no guarantee that all vulnerabilities are discovered
Address Space Layout Randomization
computer security method which involves randomly arranging the positions of key data areas, usually including the base of the executable and position of libraries, heap, and stack, in a process's address space
Each running time stack, heap, etc. are put at random addresses in the process address space
Address Space Layout Randomization (example)
It’s difficult to guess correct return address to be written on the stack smashing. But it is possible: only16 less bits of address are changed
Running code addresses are NOT changed
ASLR appeared:
Linux kernel support: 2.6.12 (released June 2005)
Microsoft's Windows Vista (released January 2007), Windows Server 2008, Windows 7, and later have ASLR enabled by default
Android 4.0 Ice Cream Sandwich provides ASLR
…
ASLR evasion techniques
brute force address search attempt return into code on non-randomized memory jmp *esp (ret address points to such bytes in code) etc.
x86 calling conventions
cdecl (C declaration) arguments are pushed to the stack in the reverse
order (the last one has the higher address) calling function cleans stack (allows arbitrary
number of arguments after program compilation)
stdcall (standard call) arguments are pushed to the stack in the reverse
order (like in cdecl) called function cleans stack
x86 calling conventions (cont.)
pascal arguments are pushed to the stack in the direct order (the
last one has the lower address) called function cleans stack
fastcall first two arguments are passed via registers, the rest (if
any) are pushed to the stack in the reverse order (like in cdecl)
called function cleans stack thiscall (for OOP non-static member functions)
this pointer (to object *this) is an additional parameter for gcc: calling function cleans stack; for MS Visual C++: it
depends on fixed (called) or variable (calling) number of arguments
x86_64 calling conventions
the single calling conversion: first 4 arguments are passed via registers rcx, rdx,
r8, r9, the rest (if any) are pushed to the stack in the reverse order (like in cdecl)
calling function cleans stack (like in cdecl)
Make your operation system use processor NX bit (on x86 platform)
NX bit, which stands for Never eXecute, is a technology used in CPUs to segregate areas of memory for use by either storage of processor instructions (or code) or for storage of data
NX bit protection evasion:return-to-libc attack
no code in the stack (no processor exception)
return address is overwritten and points to the existing code
intruder calls standard function and passes arbitrary arguments to it
in Windows it is possible to call a sequence of functions due to _stdcall_ convention
Never switch off canary words in your compiler
Canary words are known values that are placed between a buffer and control data on the stack to monitor buffer overflows
Canary words
Implementation: GCC Stack-Smashing Protector (ProPolice) Microsoft Visual Studio 2003 and higher ( /GS ) etc.
What cannot be handled: buffer overflows in the heap
(intruder uses pointers to functions in virtual method tables of dynamic objects)
Beyond stack overflow: heap overruns
heap memory allocation: dynamic allocation (no fixed addresses) considered as data only (no execution)
Threats for heap overflow beyond OOP
function pointers indexes for arrays (will be discussed with
integer overflows) other data structures located at heap may
have influence to program execution
cf: Heap Spraying methods used by intruders
Possible string length
size_t strlen( const char *s );
size_t: long unsigned int (64 bit for 64-bit platform)
Integer conversion rules
1) signed (n bits) to unsigned of the same size positive and zero: the same value negative: value + 2n
2) signed to signed of the bigger size positive and zero: the same value negative: most significant bit extends
3) signed to unsigned of the bigger size signed converts to signed of the bigger size, and then
converts to unsigned positive and zero: the same value negative: see item 2) then item 1)
Integer conversion rules (cont.)
4) unsigned to unsigned of the bigger size the same value (extended by zero bits)
5) signed to signed of the bigger size the same value
6) unsigned (n bits) to signed of the same size 0.. 2n-1: the same value bigger than 2n-1: negative value
7) unsigned to signed of the bigger size unsigned converts to signed of the same size, see 6) and
then converts to signed of the necessary size
Integer conversion rules (cont.)
signed or unsigned to integer with smaller size: rather complex behavior depending on system
architecture (little endian, big endian) should be avoided unless predictable special
function appropriate for program logic is implemented.
Rules for integer types conversion for different operations
if operands size are less than 32 bit (char, short), they conversed to int (32 bit)
bitwise logical operators follow this rule, e.g.: result of (unsigned short) | (unsigned short) belongs to int
Rules for integer types conversion for different operations (cont.)
unary ~ (compliment) also extends result type
++ and – do not change result type
% should be carefully analyzed during index check:
Rules for integer types conversion for different operations (cont.)
/ is also should be carefully analyzed
Recommendations for avoiding integer overflows
keep in mind, that there is NO universal solution, speed and effectiveness of C/C++ should be paid by developer’s attention
don’t compare signed and unsigned types carefully check array indexes, pointer operations use unsigned variables for array indexes and sizes
for memory allocation always pay attention to compiler’s warnings during software testing always check boundary
values (0, max, -1, -2, max-1, max+1, etc.) given to input of your code
Format string vulnerabilities
untrusted input (user, network, etc.) is sent directly to *prinf() function from the standard library
Vulnerable functions
and all functions directly passing arguments to these (error(), syslog(), etc.)
Principles of vulnerability exploitation (32-bit systems)
printf() allows variable number of arguments passed through the stack
Results of exploiting vulnerability
program/service/daemon crash (DoS attack) viewing local function variables viewing any block of memory available to the
process (thread) write access to memory available to the
process (thread)
Program crash
“%s%s%s%s%s%s%s%s%s%s%s%s” is taken from untrusted input
printf() expects to find 12 pointers to the zero-ended string at stack among it’s parameters
if there is at least one “pointer” found on stack is invalid, program crashes
Viewing local function variables
“%08x. %08x. %08x. %08x. %08x\n” is taken from untrusted input
printf() expects to find 5 integer variables at stack as it’s parameters
values are taken from the stack (variables of the calling function, its returning address, etc.) and printed
Viewing any block of memory
“\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|” is taken from untrusted input
it’s very likely that buffer for untrusted input is also located in the stack
printf() is made to take necessary number of bytes from the stack by %08x parameters given by hacker
address of interesting memory is given in little-endian format by \x10\x01\x48\x08 and printed out with %s parameter
Write-access and code execution (I)
it seems (but seems only) that attack like buffer overflow is protected by %400 string limit
"%497d\x3c\xd3\xff\xbf<nops><shellcode>“is taken from untrusted input
Write-access and code execution (I)
buffer for untrusted input is located in the stack and can be used for smashing returning address
\x3c\xd3\xff\xbf address points to nops or to the beginning of shellcode
example works in case of canary absence and disabled NX bit (but there are evasion methods)
Write-access and code execution(I): is it enough to use such solution for protection?
snprintf() is used instead of insecure sprintf()
end of string array is marked by \0 in any case
secure functions are used for further processing of this string
is it enough for securing a program?
printf() and other similar functions can write variables:
%n is used to get the number of already written bytes to the variable which address is given as a parameter to printf()
number written by printf() can be adjusted with %100n, %150n, etc. format string value
Write-access to process memory (II): tasks for exploiters
find format-string vulnerability find a block of code putting parameter to the
stack write a basic sequence for format string find an offset in stack for taking parameters
and addresses in case of code execution (not only memory
read/write): ASLR, canary and NX bit evasion [beyond this attack]
Write-access to process memory (II)
format string contains: address of memory to be modified (0xbfffc8c0) %08x parameters for setting enough stack offset %n parameter to make printf() writing to process
memory
Write-access to process memory (II)
additional features: %hn may be used to write 2 bytes instead of 4 global offset table (GOT) in Linux process or
Windows stubs may be modified instead of stack returning address (preserving canaries and evading NX bit), including “return-to-libc method”
addresses of virtual functions, destructors, etc. in heap can be also overwritten
NB: Sequential calls with untrusted input are also vulnerable!
any nested sequence of snprintf() can be used
for attacker it’s enough to find one call with snprintf( outbuf, buf ) without %s specifier
all similar functions are also affected
Recommendations for functions taking format string: use snprintf( outbuf, “%s”, buf ) in all cases; remember
that snprintf( outbuf, buf ) vulnerable in any nested call if some part of buf is taken from untrusted input
use only secure functions (snprintf() instead of sprintf(), etc., as pointed out in man pages and msdn)
mark the end of string array by \0 end in any case keep in mind, that there is NO universal solution, speed
and effectiveness of C/C++ should be paid by developer’s attention
don’t believe that this is only C/C++ problem: Java virtual machines (JVM), Perl, etc. are written in C/C++ and may cause this vulnerability even to script languages
Recommended books: further reading 24 Deadly Sins of Software Security: Programming
Flaws and How to Fix Them (Michael Howard, David LeBlanc, John Viega)
Writing Secure Code (Michael Howard) Software Security: Building Security In (Gary McGraw) The Security Development Lifecycle (Michael Howard,
Steve Lipner) Secure Coding: Principles and Practices (Mark G. Graff,
Kenneth R. van Wyk) Scott Meyers. Effective C++: 55 Specific Ways to
Improve Your Programs and Designs (3rd Edition)