The elf in ELF use 0-day to cheat all disassemblers david942j @ - - PowerPoint PPT Presentation

the elf in elf
SMART_READER_LITE
LIVE PREVIEW

The elf in ELF use 0-day to cheat all disassemblers david942j @ - - PowerPoint PPT Presentation

The elf in ELF use 0-day to cheat all disassemblers david942j @ CyberSEC 2019 1 . 1 This talk Tricks to cheat disassemblers objdump, readelf, IDA Pro, etc. 2 . 1 IDA Pro The best tool for reverse-engineering Take it as examples in this


slide-1
SLIDE 1

The elf in ELF

use 0-day to cheat all disassemblers

@ CyberSEC 2019 david942j

1 . 1

slide-2
SLIDE 2

This talk

Tricks to cheat disassemblers

  • bjdump, readelf, IDA Pro, etc.

2 . 1

slide-3
SLIDE 3

IDA Pro

The best tool for reverse-engineering Take it as examples in this talk

2 . 2

slide-4
SLIDE 4

anti-reverse-engineering

  • What you see is NOT what it really is

IDA Pro

2 . 3

slide-5
SLIDE 5

Introduction to ELF

3 . 1

slide-6
SLIDE 6

ELF

Executable and Linkable Format Linux

3 . 2

slide-7
SLIDE 7

Header

ELF header Section header (not important here) Program header

3 . 3

slide-8
SLIDE 8

3 . 4

slide-9
SLIDE 9

ELF header

ELF class: 32 / 64-bit arch: x86 / ARM / MIPS .. section / program header

3 . 5

slide-10
SLIDE 10

Section header

(static linker) ELF .text, .rodata, etc.

3 . 6

slide-11
SLIDE 11

Program header

Needed Libraries, Segment Permissions, etc. _DYNAMIC table

3 . 7

slide-12
SLIDE 12

_DYNAMIC

3 . 8

slide-13
SLIDE 13

Example

#include <stdio.h> #include <iostream> using std::cout; int main() { char s[100] = {}; scanf("%99s", s); // libc.so.6#scanf cout << "Hello, " << s << "!\n"; // libstdc++.so.6#std::cout return 0; }

3 . 9

slide-14
SLIDE 14

_DYNAMIC

Need libraries: libc.so.6, libstdc++.so.6 Need functions: scanf & std::cout ld.so _DYNAMIC function

3 . 10

slide-15
SLIDE 15

In this talk

IDA Pro _DYNAMIC table e.g. IDA Pro printf system 0-day bug in Linux kernel Bug(?) in ld.so

3 . 11

slide-16
SLIDE 16

The Linux 0-day bug

4 . 1

slide-17
SLIDE 17

PT_LOAD

4 . 2

slide-18
SLIDE 18

PT_LOAD

Program header PT_LOAD entry ELF memory

4 . 3

slide-19
SLIDE 19

PT_LOAD

4 . 4

slide-20
SLIDE 20

Memory mapping

ELF header program header many tables.. executable code .eh_frame .init_array/.fini_array .data/.bss ... .rodata executable data

0x400000 0x600000 0xe08 0x600e08

.dynamic

0x400e08 0x0

ELF file In memory

4 . 5

slide-21
SLIDE 21

Linux#execve

4 . 6

slide-22
SLIDE 22

linux/fs/binfmt_elf.c#load_elf_binary Read and check ELF header Parse program header PT_INTERP PT_LOAD PT_GNU_STACK Setup AUXV

4 . 7

slide-23
SLIDE 23

AUXV

AUXiliary Vector interpreter(ld.so) AT_PHDR AT_ENTRY AT_UID ...

4 . 8

slide-24
SLIDE 24

Flow of execve

execve("a.out", ...)

load_libraries elf_dynamic_do_rela (relocation)

kernel space load_elf_binary

load_elf_interp (ld.so) mmap(PT_LOADs) create_elf_tables (AUXV) *phdr, phnum, *entry, *auxv

ld.so#dl_main

4 . 9

slide-25
SLIDE 25

Bug

Kernel AT_PHDR

4 . 10

slide-26
SLIDE 26

binfmt_elf.c#create_elf_tables

4 . 11

slide-27
SLIDE 27

Normally

load_addr exec->e_phoff 0x400000 0x40 0x400040

4 . 12

slide-28
SLIDE 28

load_addr is

The rst LOADed address

4 . 13

slide-29
SLIDE 29

ELF header program header many tables.. executable code .eh_frame .init_array/.fini_array .data/.bss ... .rodata executable data

0x400000 0x600000 0xe08 0x600e08

.dynamic

0x400e08 0x0

ELF file In memory

4 . 14

slide-30
SLIDE 30

Nobody promises PHDR is located in the rst PT_LOAD

4 . 15

slide-31
SLIDE 31

Put PHDR in the second PT_LOAD

4 . 16

slide-32
SLIDE 32

ELF header program header many tables.. executable code .eh_frame .init_array/.fini_array .data ...

0x400000 0x604000 0x0

ELF file In memory fake program header

0x204000 0x4000 0x804000 program header

.data

fake prog. hdr e_phoff

load_addr 4 . 17

slide-33
SLIDE 33

Effect

Kernel loads binary correctly But kernel cheats ld.so the address of PHDR

4 . 18

slide-34
SLIDE 34

ld.so

4 . 19

slide-35
SLIDE 35

ld.so ?

Load shared libraries Process dynamic relocation

4 . 20

slide-36
SLIDE 36

_DYNAMIC

4 . 21

slide-37
SLIDE 37

function

e.g. printf -> system

4 . 22

slide-38
SLIDE 38

4 . 23

slide-39
SLIDE 39

Relocation

type 1: scanf scanf@got type 2: put backdoor on scanf@got

4 . 24

slide-40
SLIDE 40

relocation table

IDA scanf relocate

4 . 25

slide-41
SLIDE 41

lea rdi,[rip+0xba] mov eax,0x0

call 5f0 <scanf@plt> lea rdx,[rbp­0xe0] lea rax,[rbp­0x70]

int ret = scanf(args);

if(trigger(args)) backdoor(); return ret;

4 . 26

slide-42
SLIDE 42

Demo

4 . 27

slide-43
SLIDE 43

Let's play ld.so

5 . 1

slide-44
SLIDE 44

PT_PHDR in Program header

5 . 2

slide-45
SLIDE 45

PT_PHDR points to itself

ELF header program header ELF file PT_PHDR ... PT_LOAD PT_LOAD

5 . 3

slide-46
SLIDE 46

glibc/elf/rtld.c#1147

for (ph = phdr; ph < &phdr[phnum]; ++ph) switch (ph->p_type) { case PT_PHDR: /* Find out the load address. */ main_map->l_addr = phdr - ph->p_vaddr; break; case PT_DYNAMIC: /* This tells us where to find the dynamic section, which tells us everything we need to do. */ main_map->l_ld = main_map->l_addr + ph->p_vaddr; break;

5 . 4

slide-47
SLIDE 47

PT_PHDR

ld.so binary !

5 . 5

slide-48
SLIDE 48

the Linux kernel bug

Program header for kernel for ld.so

5 . 6

slide-49
SLIDE 49

?

ld.so binary

5 . 7

slide-50
SLIDE 50

program header

PT_PHDR

main_map->l_addr = phdr - ph->p_vaddr

PT_LOAD PT_LOAD PT_DYNAMIC

main_map->l_ld = main_map->l_addr + ph->p_vaddr

...

5 . 8

slide-51
SLIDE 51

Use two PT_PHDRs

5 . 9

slide-52
SLIDE 52

glibc/elf/rtld.c#1147

for (ph = phdr; ph < &phdr[phnum]; ++ph) switch (ph->p_type) { case PT_PHDR: /* Find out the load address. */ main_map->l_addr = phdr - ph->p_vaddr; break; case PT_DYNAMIC: /* This tells us where to find the dynamic section, which tells us everything we need to do. */ main_map->l_ld = main_map->l_addr + ph->p_vaddr; break;

5 . 10

slide-53
SLIDE 53

Two PT_PHDRs

PT_PHDR

main_map->l_addr = phdr - ph->p_vaddr

PT_DYNAMIC

main_map->l_ld = main_map->l_addr + ph->p_vaddr

PT_PHDR

main_map->l_addr = phdr - ph->p_vaddr

PT_LOAD PT_LOAD ...

5 . 11

slide-54
SLIDE 54

_DYNAMIC

relocation

5 . 12

slide-55
SLIDE 55

Demo

Given two ELFs Looks like A in IDA Pro but actually B

5 . 13

slide-56
SLIDE 56

Conclusion

6 . 1

slide-57
SLIDE 57

The Linux kernel 0-day bug

Kernel calculates PHDR incorrectly ld.so gets wrong address of program header

6 . 2

slide-58
SLIDE 58

ld.so

ld.so using PT_PHDR for calculating base address Nobody checks correctness of PT_PHDR

6 . 3

slide-59
SLIDE 59

_DYNAMIC table

6 . 4

slide-60
SLIDE 60

david942j @

7 . 1