Rooting Routers Using Symbolic Execution
Mathy Vanhoef β @vanhoefm HITB DXB 2018, Dubai, 27 November 2018
Symbolic Execution Mathy Vanhoef @vanhoefm HITB DXB 2018, Dubai, 27 - - PowerPoint PPT Presentation
Rooting Routers Using Symbolic Execution Mathy Vanhoef @vanhoefm HITB DXB 2018, Dubai, 27 November 2018 Overview Symbolic Execution 4-way handshake Handling Crypto Results 2 Overview Symbolic Execution 4-way handshake Handling Crypto
Rooting Routers Using Symbolic Execution
Mathy Vanhoef β @vanhoefm HITB DXB 2018, Dubai, 27 November 2018
Overview
2
Symbolic Execution Handling Crypto 4-way handshake Results
Overview
3
Symbolic Execution Handling Crypto 4-way handshake Results
Symbolic Execution
4
void recv(data, len) { if (data[0] != 1) return if (data[1] != len) return int num = len/data[2] ... }
Mark data as symbolic Symbolic branch
Symbolic Execution
5
data[0] != 1 void recv(data, len) { if (data[0] != 1) return if (data[1] != len) return int num = len/data[2] ... } data[0] == 1 void recv(data, len) { if (data[0] != 1) return if (data[1] != len) return int num = len/data[2] ... }
Symbolic Execution
6
data[0] == 1 data[0] != 1
Continue execution: if (data[1] != len)
PC = Path Constraint
Symbolic Execution
7
data[0] != 1 Continue execution
data[0] == 1 && data[1] != len data[0] == 1 && data[1] == len
Symbolic Execution
8
Can data[2] equal zero under the current PC? Yes! Bug detected!
data[0] == 1 && data[1] == len void recv(data, len) { if (data[0] != 1) return if (data[1] != len) return int num = len/data[2] ...
Implementations
Practical limitations: βΊ πππ’βπ‘ = 2|ππβπ‘π’ππ’πππππ’π‘| βΊ Infinite-length paths βΊ SMT query complexity
9
We build upon KLEE βΊ Works on LLVM bytecode βΊ Actively maintained
Overview
10
Symbolic Execution Handling Crypto 4-way handshake Results
Motivating Example
11
void recv(data, len) { plain = decrypt(data, len) if (plain == NULL) return if (plain[0] == COMMAND) process_command(plain) else ... }
Mark data as symbolic Summarize crypto algo. (time consuming) Analyze crypto algo. (time consuming)
Wonβt reach this function!
Efficiently handling decryption?
12
Example
13
void recv(data, len) { plain = decrypt(data, len) if (plain == NULL) return if (plain[0] == COMMAND) process_command(plain) else ... }
Create fresh symbolic variable Normal analysis Mark data as symbolic
ο Can now analyze code that parses decrypted data
Other than handling decryption
Handling hash functions βΊ Output = fresh symbolic variable βΊ Also works for HMACs (Message Authentication Codes)
14
Tracking use of crypto primitives? βΊ Record relationship between input & output βΊ = Treat fresh variable as information flow taint
Detecting Crypto Misuse
Timing side-channels βΊ β(πππ’βπ‘): all bytes of MAC in path constraint? βΊ If not: comparison exits on first byte difference
15
Decryption oracles βΊ Behavior depends on unauth. decrypted data βΊ Decrypt data is in path constraint, but not in MAC
Overview
16
Symbolic Execution Handling Crypto 4-way handshake Results
The 4-way handshake
Used to connect to any protected Wi-Fi network
17
Negotiates fresh PTK: pairwise transient key Mutual authentication
4-way handshake (simplified)
18
4-way handshake (simplified)
19
4-way handshake (simplified)
20
PTK = Combine(shared secret, ANonce, SNonce)
4-way handshake (simplified)
21
4-way handshake (simplified)
22
4-way handshake (simplified)
23
Encrypted with PTK
4-way handshake (simplified)
24
4-way handshake (simplified)
25
4-way handshake (simplified)
26
Authenticated with a MAC
We focus on the client
Symbolic execution of
27
How to get these working under KLEE? Intelβs iwd deamon wpa_supplicant kernel driver
Intelβs iwd
Avoid running full program under KLEE βΊ Would need to model Wi-Fi stack symbolically Our approach βΊ iwd contains unit test for the 4-way handshake βΊ Reuse initialization code of unit test! βΊ Symbolically execute only receive function
28
wpa_supplicant
Unit test uses virtual Wi-Fi interface ⺠Would again need to simulate Wi-Fi stack⦠Alternative approach: ⺠Write unit test that isolates 4-way handshake like iwd ⺠Then symbolically execute receive function! ⺠Need to modify code of wpa_supplicant (non-trivial)
29
MediaTekβs Driver
No unit tests & itβs a Linux driver βΊ Symbolically executing the Linux kernel?! Inspired by previous cases βΊ Write unit test & simulate used kernel functions in userspace βΊ Verify that code is correctly simulated in userspace βΊ Again symbolically execute receive function!
30
Not all our unit tests have clean code
31
https://github.com/vanhoefm/woot2018
Overview
32
Symbolic Execution Handling Crypto 4-way handshake Results
Discovered Bugs I
33
Timing side-channels βΊ Authenticity tag not checked in constant time βΊ MediaTek and iwd are vulnerable Denial-of-service in iwd βΊ Caused by integer underflow βΊ Leads to huge malloc that fails
Discovered Bugs II
Flawed AES unwrap crypto primitive βΊ Also in MediaTekβs kernel driver βΊ Manually discovered
34
Buffer overflow in MediaTek kernel module βΊ Occurs when copying the group key βΊ Remote code execution (details follow)
Decryption oracle in wpa_supplicant
ο Decrypt group key in Msg3 (details follow)
35
Decryption oracle: βΊ Authenticity of Msg3 not checked βΊ But decrypts and processes data
Buffer overflow in MediaTek kernel module
36
MediaTek buffer overflow preconditions I
Triggered when the client processes Msg3 βΊ Adversary needs password of network βΊ Examples: Wi-Fi at conferences, hotels, etc.
37
MediaTek buffer overflow preconditions II
Which clients use the MediaTek driver? βΊ Not part of Linux kernel source tree βΊ Used in repeater modes of routers
38
Our target: βΊ RT-AC51U running Padavan firmware βΊ Original firmware has no WPA2 repeater
Popularity of Padavan firmware
39
Popularity of Padavan firmware
40
We exploit this version
The vulnerable code (simplified)
41
void RMTPParseEapolKeyData(pKeyData, KeyDataLen, MsgType) { UCHAR GTK[MAX_LEN_GTK]; if (MsgType == PAIR_MSG3 || MsgType == GROUP_MSG_1) { PKDE_HDR *pKDE = find_tlv(pKeyData, KeyDataLen, WPA2GTK); GTK_KDE *pKdeGtk = (GTK_KDE*)pKDE->octet; UCHAR GTKLEN = pKDE->Len β 6; NdisMoveMemory(GTK, pKdeGtk->GTK, GTKLEN); } APCliInstallSharedKey(GTK, GTKLEN); }
The vulnerable code (simplified)
42
void RMTPParseEapolKeyData(pKeyData, KeyDataLen, MsgType) { UCHAR GTK[MAX_LEN_GTK]; if (MsgType == PAIR_MSG3 || MsgType == GROUP_MSG_1) { PKDE_HDR *pKDE = find_tlv(pKeyData, KeyDataLen, WPA2GTK); GTK_KDE *pKdeGtk = (GTK_KDE*)pKDE->octet; UCHAR GTKLEN = pKDE->Len β 6; NdisMoveMemory(GTK, pKdeGtk->GTK, GTKLEN); } APCliInstallSharedKey(GTK, GTKLEN); }
The vulnerable code (simplified)
43
void RMTPParseEapolKeyData(pKeyData, KeyDataLen, MsgType) { UCHAR GTK[MAX_LEN_GTK]; if (MsgType == PAIR_MSG3 || MsgType == GROUP_MSG_1) { PKDE_HDR *pKDE = find_tlv(pKeyData, KeyDataLen, WPA2GTK); GTK_KDE *pKdeGtk = (GTK_KDE*)pKDE->octet; UCHAR GTKLEN = pKDE->Len β 6; NdisMoveMemory(GTK, pKdeGtk->GTK, GTKLEN); } APCliInstallSharedKey(GTK, GTKLEN); }
Len controlled by attacker Destination buffer 32 bytes
dMain exploitation steps
44
Main exploitation steps
45
Gaining kernel code execution
How to control return address & where to return? βΊ Kernel doesnβt use stack canaries βΊ Kernel stack has no address randomization βΊ And the kernel stack is executable
46
Return to shellcode on stack & done?
Gaining kernel code execution
How to control return address & where to return? βΊ Kernel doesnβt use stack canaries βΊ Kernel stack has no address randomization βΊ And the kernel stack is executable
47
Return to shellcode on stack & done? Nope⦠our shellcode crashes
Problem: cache incoherency on MIPS
Data cache
β¦
β¦
48
Memory
β¦
β¦
Problem: cache incoherency on MIPS
Data cache
β¦
shellcode
β¦
49
Instruction cache
β¦
<no cached entry>
β¦
Memory
β¦
β¦
Fetch
Problem: cache incoherency on MIPS
Data cache
β¦
shellcode
β¦
50
Instruction cache
β¦
β¦
Memory
β¦
β¦
Fetch
Solution: flush cache after write
Data cache
β¦
shellcode
β¦
51
Instruction cache
β¦
<no cached entry>
β¦
Memory
β¦
β¦
Flush
Solution: flush cache after write
Data cache
β¦
shellcode
β¦
52
Instruction cache
β¦
<no cached entry>
β¦
Memory
β¦
shellcode
β¦
Flush Fetch
Solution: flush cache after write
Data cache
β¦
shellcode
β¦
53
Instruction cache
β¦
shellcode
β¦
Memory
β¦
shellcode
β¦
Flush Fetch
How to flush the cache?
Execute kernel function to flush cache βΊ Rely on Return Oriented Programming (ROP) βΊ Use mipsrop tool of Craig Heffner
54
ο Building ROP chain is tedious but doable
Main exploitation steps
55
Obtaining a process context
Code execution in kernel, letβs spawn a shell? βΊ Tricky when in interrupt context βΊ Easier in process context: access to address space
56
How to obtain a process context? βΊ System calls run in process context β¦ βΊ β¦ so intercept a close() system call
Intercepting system calls
57
System call table:
sys_open sys_read sys_close β¦
sys_close normal code
Intercepting system calls
58
System call table:
sys_open sys_read sys_close β¦
sys_close normal code Interceptor attackers code Jump to sys_close
Main exploitation steps
59
Hijacking a process
Kernel now executes in process context βΊ Hijack unimportant detect_link process βΊ Recognize by its predictable PID Now easy to inject shellcode in process:
60
Main exploitation steps
61
User space shellcode
When close() returns, shellcode is triggered βΊ It runs βtelnetd βp 1337 βl /bin/shβ using execve βΊ Adversary can now connect to router Important remaks: βΊ Original process is killed, but causes no problems βΊ Used telnetd to keep shellcode small
62
Running the full exploit
Multi-chain exploit. Space for shellcode? βΊ For initial stage we have 250 bytes βΊ Handshake frame can transport ~2048 bytes βΊ We can even use null bytes!
63
Exploit recap & lessons learned
64
io.netgarage.org
___ / /\ /__/\ / /::\ \__\:\ / /:/\:\ / /::\ / /:/ \:\ __/ /:/\/ /__/:/ \__\:\ /__/\/:/~~ \ \:\ / /:/ \ \::/ \ \:\ /:/ \ \:\ \ \:\/:/ \__\/ \ \::/ \__\/
Debug with infinite loops
First test ideas in C Cache incoherence
65
Recall: decryption oracle in wpa_supplicant
66
Decryption oracle: βΊ Authenticity of Msg3 not checked βΊ Does decrypt and process data
How can this be abused to leak data?
Background: process ordinary Msg3
On reception of Msg3 the receiver:
67
header Key Data
Encrypted and authenticated
Background: process ordinary Msg3
On reception of Msg3 the receiver:
68
header
Encrypted and authenticated
Background: process ordinary Msg3
On reception of Msg3 the receiver:
69
header 48 18 Type Len
Encrypted and authenticated
Background: process ordinary Msg3
On reception of Msg3 the receiver:
70
header 48 18 ππ β¦ πππ Type Len RSNE
Encrypted and authenticated
Background: process ordinary Msg3
On reception of Msg3 the receiver:
71
header 48 18 ππ β¦ πππ 221 38 Type Len RSNE Type Len
Encrypted and authenticated
Background: process ordinary Msg3
On reception of Msg3 the receiver:
72
header 48 18 ππ β¦ πππ 221 38 ππ β¦ πππ Type Len RSNE Type Len GTK
Encrypted and authenticated
Background: process ordinary Msg3
On reception of Msg3 the receiver:
73
header 48 18 ππ β¦ πππ 221 38 ππ β¦ πππ Type Len RSNE Type Len GTK
Encrypted and authenticated
74
Constructing an oracle
75
header 221 38 ππ β¦ πππ Type Len GTK
Encrypted Adversary knows type and length, but not GTK
Constructing an oracle
76
header 221 36 ππ β¦ πππ Type Len
Encrypted Adversary knows type and length, but not GTK.
Constructing an oracle
77
header 221 36 ππ β¦ πππ Type Len
Encrypted Adversary knows type and length, but not GTK.
Constructing an oracle
78
header 221 36 ππ β¦ πππ Type Len
Encrypted Adversary knows type and length, but not GTK.
Constructing an oracle
79
header 221 36 ππ β¦ πππ πππ πππ Type Len GTKβ
Encrypted Adversary knows type and length, but not GTK.
Constructing an oracle
80
header 221 36 ππ β¦ πππ πππ πππ Type Len GTKβ Type Len
Encrypted Adversary knows type and length, but not GTK.
Constructing an oracle
81
header 221 36 ππ β¦ πππ πππ πππ Type Len GTKβ Type Len
Encrypted Adversary knows type and length, but not GTK.
Abusing the oracle in practice
Parsing succeeds & we get a reply
Parsing fails, no reply
ο Keep guessing last byte until parsing succeeds
82
Practical aspects
Test against Debian 8 client: βΊ Adversary can guess a value every 14 seconds βΊ Decrypting 16-byte group key takes ~8 hours
83
Attack can be made faster by: βΊ Attacking several clients simultaneously βΊ Can brute-force the last 4 bytes
The big picture
84
The big picture
85
Although limitations remain, symbolic execution tools are now more usable & efficient.
Future symbolic execution work
Short-term βΊ Efficiently simulate reception of multiple packets βΊ If 1st packet doesnβt affect state, stop exploring this path Long-term βΊ Extract packet formats and state machine βΊ Verify basic properties of protocol
86
Conclusion
βΊ Symbolic execution of protocols βΊ Simple simulation of crypto βΊ Root exploit & decryption oracle βΊ Interesting future work
87