Killing the Myth of IOS rootkits: DIK, Da IOS rookit

Download Report

Transcript Killing the Myth of IOS rootkits: DIK, Da IOS rookit

Killing the myth of Cisco IOS
rootkits: DIK
(Da Ios rootKit)
Sebastian 'topo' Muñiz
EuSecWest
London, May 2008
Speaker info
Name: Sebastian 'topo' Muñiz
Work: Sr. Exploit Writer at CORE
Likes: Reverse Engineering & Vuln Research
Contact: [email protected]
[email protected]
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 rootkit?

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 low-level OS functions and
manipulating internal structures.
Rootkits along history
• Existed on other OSes 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 versions? Yes

Does it matter if they have different arch (MIPS or PowerPC)? No

Do I need to know assembly code for a specific arch? No, just
plain C :)
Consequences
• Imagine your company’s 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 other’s memory.

No memory protection between processes.

Uses 'run to completion' priority scheduling.

FIFO (First In First Out) process queue.

This model reduces local security and system stability.

Completely different to modern OSes.
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).

Lots 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.5x)
ELF structure as IOS image
ELF header
SFX code
Self
code de-compressing
MAGIC (0xFEEDFACE)
Compressed image length
Compressed image checksum
Magic
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.

Values in Magic Structure are employed to validate
decompression result.

Length values in Magic Structure are expressed in words (4 bytes)
Ex. Length of 1024 words = 4096 (1024 * 4) bytes

Length values help to verify available memory and size of buffer
to checksum.

Image’s checksum is calculated before and after decompression.
ELF structure as IOS image (cont.)

Simple (insecure) 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, the resulting (uncompressed)
image will end up running on the device’s memory.

This image will contain our rootkit.

It's needed for analysis, so download using the 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 workings of the OS.

Take advantage of debug strings info to locate functions of
interest to 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

Parts of the IOS image were not analyzed correctly.

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 over 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 over every DATA section (like .data)

Strings where (0 != length mod 4) are padded with null bytes.

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 beginning 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 (0x09), CR (0x0a) and LF (0x0d).

Bytes with values within CODE section ranges may be pointers.
What if both happens? Like in a CODE section from 0x61000000 to
0x61700000?
Is 0x61616120 (“AAA ”) a pointer or just the beginning 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 results of key functions.

Some of them are usually displayed as output.

By locating their references, we locate those functions.

Iterate over every string to locate those of interest to an attacker.

For each one, use IDA’s string XREF property to identify it's
callers (IDA-Python magic again :)
Locating low-level IOS functions (cont.)

What if a function does not use any string?

Functions are compiled in the same order as source file.

Other functions (neighbours) next to it will surely do (whether
other IOS function call them or not).

Apply this procedure to every function that we want to find using
simple IDA-Python functions.
A home for the rootkit’s code

IOS contains lots 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 counterparts to IOS functions that do attacker's
will.

Recompiling the rootkit code every time is not an option.

Cross-compile it once (for MIPS and PowerPC).

How to locate offsets of compiled counterpart functions?

Use 'objdump' to obtain symbolic info and offsets.

Name of a counterpart function resolves to it's offset in compiled
code.
Redirect IOS execution flow

Knowing offsets of counterpart functions means that they are
callable now.

Intercept IOS functions and redirect their execution flow.

Hook every interesting IOS function with a trampoline code.

Trampoline code is placed at function’s first instruction.

Jumps to the location of rootkit code 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.
Glueing 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’s plain C code.

Decide whether flow should continue or not to the hooked
function.

If it should restore original parameters, execute instruction at
trampoline address and jump after trampoline

If it should go back to caller, set extra parameter value as the
hooked function’s return value and go to the saved return
address.
Glueing all together
IOS caller
…
r = chk_pass(p)
if (r == true):
login()
else:
deny_login()
chk_pass()
trampoline
…
chk_pass code
…
return (value)
Glue code
add stack
store parent’s RA
store params p
create param i
o = chk_pass_DIK(p)
fix stack
if (o == CONT):
execute orig inst
return params p
cont chk_pass_IOS
else:
r = i
jump to RA
chk_pass_DIK()
if (p == ‘1337’):
i = true
return RET
else:
return CONT
Advantages of this method

A few lines of shellcode called trampoline and glue
code bridge the gap between a compiled C function 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).
Limitations of C code

Strings are put in another 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
#define EOF_DIK_CODE

asm(".ascii \"BOF_\"")
asm(".ascii \"EOF_\"")
Find those markers on generated code:
BOF_ = 0x424f465f
EOF_ = 0x454f465f
IOS functions for rootkit usage

Not only able to intercept low-level functions.

Obtain addresses of other IOS functions.

Use them as function pointers.

Enhance rootkit functionality using them inside our
code.

Increase rootkit’s stealthness level.
IOS functions for rootkit usage (cont.)

Implement tables of function/structure pointers.

Call functions as table’s 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/write 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 checksum images using MD5, SHA1, etc.
to see binary changes!!!

Try CIR (Cisco Incident Response) from Recurity-Lab
to detect anomalies.

Harden network infrastructure.
DEMO