480 likes | 736 Views
Killing the myth of Cisco IOS rootkits: DIK (Da Ios rootKit) . Sebastian 'topo' Muñiz EuSecWest London, March 2008. Speaker info Name: Sebastian 'topo' Muñiz Work: Sr. Exploit Writer at CORE Likes: Reverse Engineering & Vuln Research Contact: topo@coresecurity.com. Agenda Introduction
E N D
Killing the myth of Cisco IOS rootkits: DIK(Da Ios rootKit) Sebastian 'topo' Muñiz EuSecWest London, March 2008
Speaker info Name: Sebastian 'topo' Muñiz Work: Sr. Exploit Writer at CORE Likes: Reverse Engineering & Vuln Research Contact: topo@coresecurity.com
Agenda • Introduction • IOS characteristics and internal structure • IOS file format structure • IOS analysis phase • Binary patching technique • Rootkit source code advantages and limitations • Setting image ready • Countermeasures
What is a rootkits? • A program that seizes control of the entire OS by hiding files, processes, network connections and everything else. • Allows unauthorized users to act as with super user privileges (in IOS this means level 15, like root in Linux). • Stealth: hides attacker's presence indefinitely. • This is achieved by intercepting OS low level functions and manipulating internal structures.
Rootkits along history • Existed on other OS's like Windows, Unix and Linux distros for several years. • Natural evolution of backdoors. • Present in AV & virii race to avoid one to locate each other. • More common now a days, specially in malware.
Rootkits on IOS • Are IOS rootkits new? No • Did it begin years ago? Yes, before stolen IOS source code. • Any publicly known IOS rootkit? No, until today. • Can a generic rootkit be created for multiple IOS version? Yes • Does it matter if they have different arch (MIPS or PowerPC)? No • Do I need to know a specific assembly code? No, just plain C :)
Consequences • Image your company network (ISP, bank, .gov or whoever you are) compromised on strategic points. • Network traffic concentrators owned by the attacker. • Attackers able to see and manipulate all network traffic. • Consequences in one word: Disastrous.
Introduction to IOS architecture • Monolithic architecture which runs as a single image. • All processes have access to each others memory. • No memory protection between processes. • Uses 'run to completion' priority scheduling. • FIFO (First In First Out) processes queue. • This model reduces local security and system stability. • Completely different to modern OS's.
IOS image file format • Modern Cisco devices use ELF (Extensible File Format). • It's a standard file format on Linux. • File contains CODE segments (instructions) and DATA segments (strings). • Lot's of information available about it on the net. • Why ELF as IOS format? Implementations available, relocatable, etc. • Values on IOS ELF headers are not equal to the standards. • ELF infection methods (binary modification) were well known by virus writers for years.
Initial setup on memory • Bootloader performs POST and invokes IOS image. • Downloaded image is not really the image that runs IOS. • Image contains a self decompressing (SFX) header code that unpacks the fully functional IOS. • A simple ZIP utility can decompress it. • It's compressed because it contains lots of strings that occupy precious memory. • c2600-i-mz.123-24 occupies 7.4MB ->18.6 MB Decomp (2.51%)
ELF structure as IOS image +------------------------------+ | ELF header | +------------------------------+ | SFX code | Self decompressing code +------------------------------+ --+ | Magic (0xFEEDFACE) | | +------------------------------+ | | Compressed image length | | +------------------------------+ | Magic | Compressed image checksum | | Structure +------------------------------+ | | Uncompressed image checksum | | +------------------------------+ | | Uncompressed image length | | +------------------------------+ --+ | Compressed image | Compressed IOS image +------------------------------+
ELF structure as IOS image (cont.) • SFX code uses Magic structure along the entire decompression process. • Magic values are employed to validate decompression result. • Magic structure length are expressed in words (4 bytes) Ex. Length of 1024 words = 4096 (1024 * 4) bytes • Magic length values help to verify available memory and size of buffer to checksum. • Image is checksummed before and after decompression.
ELF structure as IOS image (cont.) • Simple (unsecure) checksum algorithm: int nwords = compressed_size / sizeof(ulong); unsigned long sum = 0; // contains the checksum result unsigned long val = 0; // temporary value unsigned char* bufp = (uchar*) ptrData; // pointer to // data to verify while (nwords--) { // Read every 4 bytes val = *bufp++; sum += val; if (sum < val) // There was a carry sum++; }
Obtain IOS image file • If decompression was successful, resulting (uncompressed) will be running on device memory. • This image will contain our rootkit. • It's needed for analysis, so download using the known CLI's copy command (from flash to ftp or any another destination) • Unzip the compressed (downloaded) image with ZIP. • With the decompressed image in our hands, move to analysis phase.
Analysis phase • Why? • What tool should we use? • Why IDA (Interactive Disassembler Debugger) ?
Analysis phase (cont.) • IOS image contains lots of debug strings with information about the internal OS working. • Take advantage of debug strings info to locate interesting functions for an attacker. • Feed IDA with the uncompressed IOS image (will throw warnings) • Come back several minutes (sometimes hours) later :)
Analysis phase (cont.) • IDA will do a good job, but not enough. • Several functions and string won't be recognized • Part of the IOS image was not correctly analyzed. • On a c2600-i-mz.123-24 IDA detected: 28121 Functions 126379 Strings • An enhanced analysis is needed.
Enhanced image analysis • Let's use IDA-Python (python support for IDA scripting). • Create a script to detect remaining functions and strings. • Remember that MIPS and PowerPC instructions are aligned to a 4 byte boundary. • Fixed instruction size of 4 bytes.
Enhanced image analysis for functions • Iterate on every CODE section (like .text) • Compiler writes one function after another. • Strings are not inlined in CODE sections. • Move on a 4 byte boundary and tell IDA to create functions. • Rely on IDA magic.
Enhanced image analysis for strings • Iterate on every DATA section (like .data) • Strings length not 4 byte modulo are padded with zeros. • DATA segments may include references to other sections. • Move on a 4 byte boundary and analyse the memory content. • Try to resolve if current value is the begin of a string or a pointer to another location (instruction or string).
Enhanced image analysis for strings (cont.) • TIPS: Printable chars (between 0x20 and 0x7f) are probably strings. Also check for Tab (0xD), CR (0xA) and LF ('0xD'). Bytes with values between CODE sections range may be pointers. • What if both happens? Like in a CODE section from 0x61000000 to 0x61700000? • Is 0x61616120 (“AAA ”) a pointer or just the begin of a string from the AAA subsystem?
Enhanced image analysis results • After enhanced analysis: 46296 Functions (18175 new functions) 143603 Strings (17224 new strings) • IOS image is now successfully analysed and ready to give us info.
Locating low-level IOS functions • Locate functions of interest for the attacker like: Password checking. File manipulation. Logging information. Packet handling functions. Access lists manipulation function.
Locating low-level IOS functions (cont.) • Strings are used to diagnose key functions result. • Some of them are usually displayed as output. • Locating their references, we locate those functions. • Iterate through every string to locate the ones of attacker interest. • For each one, use string XREF property from IDA to know it's callers (IDA-Python magic again :)
Locating low-level IOS functions (cont.) • What if function does not use strings? • Functions are compiled in the same order as source file. • Other functions (neighbors) next to it will surely do (whether other IOS function call them or not). • Apply this procedure to every function that we want to fin using simple IDA-Python functions.
Rootkit code home • IOS contains lot's of debug strings. • Sacrifice one large (probably never used) string to put code. • Also another CODE section could be added (known ELF infection technique). • String overwrite is the easier to implement. • Remember to change section's permissions on ELF section header.
Analyze low-level functions • Rootkit contains IOS functions counterpart that do attacker's will. • Recompile rootkit code every time is not an option. • Cross-compile it once (for MIPS and PowerPC). • How to locate compiled counterpart functions offsets? • Use 'objdump' to obtains symbolic info and offsets. • Name of a counterpart functions resolves to it's offset in compiled code.
Redirect IOS execution flow • Knowing counterpart function offsets means that they are callable now. • Intercept IOS functions and redirect it's execution flow. • Hook every interesting IOS function with a 'trampoline' code. • Trampoline code is located at function first instruction. • Jump to rootkit code location in memory (sacrificed string). • Trampoline code (like jmp on x86) for: PowerPC -> unconditional branch instruction (1 inst.) MIPS -> unconditional jump instruction (2 inst.)
Redirect IOS execution flow (cont.) • Can I just jump to compiled C code? No, bad boy, you can't. • A 'glue' code is needed to create a bridge between IOS assembly code and plain C code. • The glue code should work either on MIPS or PowerPC. • Redirection must occur without crashing current process state.
Gluing all together • Save the return address • Store the function parameters currently allocated • Allocate stack space for extra parameter needed by rootkit code. • Call the rootkit plain C code. • Decide whether to continue or not to hooked function. • If it continues, restore original parameters, execute instruction at trampoline address and jump after trampoline • If it goes back to caller, set extra parameter value as hooked function return value and go the saved return address.
Glueing all together (cont.) IOS caller chk_pass_IOS(p) +-----------------+ +-----------------+ | | | | | r=chk_pass(p) |--->| trampoline |--> | | | | | if r == true: | | rest of code | | login() | | ... | | else: | | return legal_res| | deny_login() | | | | ... | +-----------------+ +-----------------+
Glueing all together (cont.) Glue code chk_pass_DIK(p,i) +----------------------+ +-----------------+ | store parent RA | +-->| if p == 'l337': | | store params p | | | i = true | | create param i | | +-| return RET | | add stack | | | | else: | | o = chk_pass_DIK(p,i)|-+ |-| return CONT | | fix stack | | | | | if o == CONT: |<--+ | | | exec orig instruct | +-----------------+ | return params p | | cont chk_pass_IOS | | else: | | r = i | | jump to RA | +----------------------+
Glueing all together (cont.) IOS caller chk_pass_IOS(p) +-----------------+ +-----------------+ | | | | | r=chk_pass(p) | | trampoline | | | | | | if r == true: |<-+ | rest of code | | login() | | | ... | | else: | +-| return legal_res| | deny_login() | | | | | ... | | +-----------------+ +-----------------+ | +----<-------<-----------<--
Advantages of this method • A few lines of shellcode called 'trampoline' and 'glue' code filled the gap between a C function compiled and existing IOS code. • Only one C code is maintained instead of two assembly codes that perform the same actions on different architectures (a MIPS code and a PowerPC code).
Limitation of C code • Strings are put in another a DATA section. • All code together is needed. • Code must be PIC (Position independent Code). • Only relevant code to rootkit is needed.
Workaround the Limitations • Strings are declared with a MACRO like this: char* pszPassword(void) // String pointer name { jump_to_next_inst var = ret_addr // prev inst address var += after function's end // string begins there return var } asm(".ascii \"my backdoor password\"); asm(".byte 0"); // NULL terminator
Workaround the Limitations • Set 'flags' in C code to mark rootkit code region #define BOF_DIK_CODE asm(".ascii \"BOF_\"") #define EOF_DIK_CODE asm(".ascii \"EOF_\"") • Find those markers on generated code: BOF_ = 0x424f465f EOF_ = 0x454f465f
IOS functions for rootkit usage • Not only intercept low-level functions. • Obtain other IOS functions addresses. • Use them as functions pointers. • Enhance rootkit functionality using them inside our code. • Raise rootkit stealth level of the rootkit.
IOS functions for rootkit usage (cont.) • Implement functions/structures pointer table. • Call functions as tables indexes. • Pointers to internal structures, too.
Putting it all together • Dump modified IDA sections. • Merge changed bytes with original decompressed IOS image on disk. • Compress using Zlib / ZIP. • Calculate new checksums. • Merge with compressed IOS image. • Ready to rock n' roll :)
Simple runtime patching • GDB inside every image. • GDB can read/writer memory and processor registers. • Debugging one process can write entire memory. • Entire system compromised by simple process debug. • Use TCL to automate local GDB usage and self-patching after every boot. • This TCL file will be hidden by the rootkit once it's running.
Resulting IOS image • Binary patched IOS image. • No new processes created (“show proc” won't help). • Rootkit code execution is triggered by events. • Cannot trust router info if it's compromised. • Only external clean up methods will work.
Countermeasures • Follow Cisco guidelines. • Periodically cheksum images using MD5, SHA1, etc. to see binary changes!!! • Try CIR (Cisco Incident Response) from Recurity-Labs • Harden network infrastructure.