2. Jordan Gruskovnjak
● Currently Working at Crowdstrike, Inc.
○ Reverse Engineering & Malware Analysis
○ Exploitation & Mitigation Research
● Previously worked as an Exploit Developer at:
○ Exodus Intelligence
○ VUPEN Security (with the infamous @cbekrar and @n_joly)
● @jgrusko on Twitter
3. Alex Wheeler
● Currently at Exodus Intelligence
○ VP of Research
● Previously worked at
○ Accuvant
○ HP TippingPoint
○ IMB ISS X-Force (hi @mdowd @neelmehta)
● @vonbloke on Twitter
4. Target Background: CVE-2016-1287
Cisco ASA 5500 Series Adaptive Security Appliances
Cisco ASA 5500-X Series Next-Generation Firewalls
Cisco ASA Services Module for Cisco Catalyst 6500 Series Switches and
Cisco 7600 Series Routers
Cisco ASA 1000V Cloud Firewall
Cisco Adaptive Security Virtual Appliance (ASAv)
Cisco Firepower 9300 ASA Security Module
Cisco ISA 3000 Industrial Security Appliance
5. Target Background: Why?
- Perimeter security devices == High ROI
- Exploit mitigation on Cisco ASA < current browser exploit mitigation
- Relatively under-researched area, especially considering:
- criticality
- market share
- see affected products in next slide
6. Target Background: Prior Cisco ASA Work
Breaking Bricks @ Ruxcon 2014
by Alec Stuart
- CVE-2014-3393: Auth bypass
in WebVPN to gain
authenticated user rights
- CVE-2014-3389: Command
injection in Failover Protocol
to gain privilege escalation
and lateral compromise
10. Getting Started: Dump Firmware
Copy asa924-k8.bin from the CF card
It’s just a FAT filesystem, nothing special
OR
Download it
(check MD5 against Cisco’s website)
11. Getting Started: Analyze Firmware
$ binwalk -e asa924-k8.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
75000 0x124F8 SHA256 hash constants, little endian
144510 0x2347E gzip compressed data… (Linux kernel)
1501296 0x16E870 gzip compressed data, has original file name: "rootfs.img"…
27168620 0x19E8F6C MySQL ISAM index file Version 4
28192154 0x1AE2D9A Zip archive data, at least v2.0 to extract…
28773362 0x1B70BF2 Zip archive data, at least v2.0 to extract…
13. Getting Started: Debug Target Device
JTAG: Failed
Traced signals + Brute force combinations with
Bus Pirate
Enable gdb in ROMmon: It does nothing
Desoldered flash + Poked around in IDA
Get root: Achievement Unlocked
Run lina under gdb-server + Disable the
watchdog
15. Getting Started: Debug Target Device — gdbserver
The developers left helpful comments in boot script /asa/scripts/rcS:
# Use -g to have system await gdb connect during boot.
#echo "/asa/bin/lina_monitor -l -g -d" >> /tmp/run_cmd
# Use -s to specify a serial device other than the default /dev/ttyS1
#echo "/asa/bin/lina_monitor -l -g -s /dev/ttyUSB0 -d" >> /tmp/run_cmd
Boot the target, at the root prompt use sed to uncomment that last line and
change ttyUSB0 to ttyS0 for the console port, then continue booting normally.
# sed -i 's/#(.*)ttyUSB0(.*)/1ttyS02/' /asa/scripts/rcS
# exec /sbin/init
…
SMFW PID: 514, Starting /asa/bin/lina under gdbserver /dev/ttyS0
Process /asa/bin/lina created; pid = 517
Remote debugging using /dev/ttyS0
16. Getting Started: Disable Watchdog for Debugging
Patch that watchdog
lina uses setitimer() to schedule a SIGALARM
signal to be delivered periodically to the
process.
Use a gdb init script to attach to the target and
overwrite watchdog_timeout with zero,
disabling it.
target remote /dev/ttyXXX
set *0x0a53f168 = 0 (version
specific)
19. Audit: Summary
Goal: Identify + Exploit at least 1 vulnerability to yield anonymous system level
RCE without user interaction
Approach:
• Static using only IDA Pro (between 40 and 60 hours spent on this phase)
• Confirm findings using gdb (between 4 and 8 hours)
21. Audit: Following Memory
Resolving indirection and meaning can be done w/ a debugger (SLOW) or by
inference (FAST).
Allocators are useful cross references for identifying memory corruption.
Questions to infer allocators should be this:
- Is a size field passed to this call?
- Is a return value checked for not zero and used as a destination buffer
subsequent to this call?
22. Audit: Following Memory Example Plus 8 (could be size
or offset)
Test for Not Zero
Return Value
Some Offset +
Return Value
Passed as an
Argument, What’s
this Function
23. Audit: Following Memory Resolved Example
Where is this Size from?
Now We Know
Direction == Input
Minus 8 is Interesting (Underflow?)
Length for Our Copy
MALLOC() – 573 XREFS FIXED J
MEMCPY() – 4,109 XREFS FIXED J
24. Audit: Cheap Trick – Byte Reordering
Specifically on the ASA project, but also generally useful:
- Network data is big-endian and requires reordering on little-endian CPU’s:
- shl bits + (add/or), ror bits, bswap, mul 0x100
- Inferring the direction of the data:
- INPUT == byte reorder then operate
- OUTPUT == operate then reorder
Useful Even on Big Endian CPU:
lbu $v0, 0($a0)
lbu $v1, 1($a0)
sll $t0, $v0, 8
…
addu $t0, $v1
25. Audit: Cheap Trick – Byte Reordering
Direction == ?
We Need to Follow This
Direction == Input
Reassembly
Allocation Length
NOT GOOD
26. Audit: Cheap Trick - Logging
Specific to Cisco ASA Firewall firmware, but useful in general.
Symbols were stripped from the binary. However, manufacturer left in valuable
engineering and error reporting information.
It is useful to create an IDA Pro script to follow the cross references and name the
function it is being cross referenced from according to one of its arguments.
27. Audit: Cheap Trick – Logging
Logging functions state context:
3rd Argument is Function Name
1222 XREFS FIXED
THANK YOU CISCO ENGINEERING J
28. Audit: Triggering the Bug
Ikev2_get_assembled_pkt()
Allocate Too Small Reassembly Buffer
ikev2_add_rcv_frag()
Underflow Cisco Fragment with Length < 8
ikev2_check_neg_and_sa()
Establish IKEv2 Phase 1 SA
Underflow the Payload
Length AND Pass
Signed Reassembly
Length Check
Small because of
Underflowed Payload
Length(s)
Forces Attacker to Use
Legit IP Address
OR be MITM
30. Audit: Concluded
For every allocation examine size allocated vs size copied.
Followup only on differences.
Point Auditing allows quick identification of potential issues without much
application specific knowledge.
Now we can trigger the vulnerability to bounce the box, which is not good enough:
We want RCE.
32. Exploitation: Taming the wild copy 1 / 3
Need to craft a correct fragment sequence to:
● Still have an undersized allocation
● Avoid the negative memcpy()
Fragment can’t have a sequence # > last fragment sequence #
Fragment copy will stop when next sequence # is not found
33. Exploitation: Taming the wild copy 2 / 3
All fragments must have the same size
Only the last fragment is allowed a different size
packet_size = 1 - 8 + 1 - 8 + 10 + 8 = 4 bytes allocation. So far so good :)
But will crash and burn when processing the first fragment due to the negative
memcpy() :’(
34. Exploitation: Taming the wild copy 3 / 3
Fragment processing function has some quirks regarding the fragments
● Insertion of fragment with sequence number 0
● Insertion of fragment having a mismatching size
Using this 2 quirks eventually leads to the following working fragment sequence
This fragment sequence leads to
● undersized allocation
● Only the fragment #1 will be processed avoiding the wild memcpy()
Leads to a 1 byte corruption of the next heap chunk’s size field:
35. Exploitation: Heap Overflow 101
We need to have the heap in a predictable state
Heap Feng Shui FTW
Basic alloc & free primitive:
○ IKEv2 Configuration Attributes
○ Took advantage of 0x100 bytes buffer being freed after each request
36. Exploitation: Cisco ASA Heap Primer
Old dlmalloc compiled with debug options + a few new fields in metadata
Allocated chunk Free chunk
No Safe Unlinking :)
2 write4 on unlink due to the 2 different linked lists :))
37. Exploitation: From 1 byte to n-bytes overflow
1 byte overflow allows overwriting the adjacent chunk’s size field
Create an overlapping chunk by freeing the corrupted chunk to a bigger linked list
Reallocate the overlapping chunk with controlled data & corrupt the allocator
linked list pointers
We now have a classic write4 on unlink() (actually 2)
38. Exploitation: Getting EIP
Cisco doesn’t have ASLR / DEP enabled
Decided to target the list_add function pointer location into .data
Called when a new fragment is sent and inserted in the fragment list
Cool, but where’s my shellcode ?
39. Exploitation: Landing in the shellcode
ECX points to the newly created fragment, and its first dword points to the
fragment’s actual data
Can’t use the write4 to jump on a jmp [ecx] / call [ecx] gadget in .text section,
since write4 requires both pointers to point to writable memory
Write address 0xc821ff90 at address 0xc8002000 using 2nd write 4
This address translates to the jmp [ecx] byte code sequence
gdb) x/2i 0xc8002000
0xc8002000: nop
0xc8002001: jmp DWORD PTR [ecx]
Execution flow finally landed into shellcode o/
40. Exploitation: Cleanup
Sames problems as when exploiting a kernel RCE
You can’t afford to crash after successful exploitation
Otherwise, the device reboots and exploitation was useless
To avoid rebooting, use object on the stack to find and fix stuffs we broke:
● fix list_add function pointer
● find the corrupted chunk and fix heap metadata
We can move on to the “real” payload execution
41. Exploitation: Can I haz a shell ?
We don’t want a classic /bin/sh, but Cisco CLI
Cisco doesn’t use POSIX sockets :( but channels
Use the alloc_ch() with the following string as parameter to create a connect-
back:
42. Exploitation: Can I haz a shell ?
Cisco doesn’t dup() since it doesn’t use socket
Each running thread has a default channel in which it redirect in/out data
Just overwrite it with the newly created channel:
Allocate and set the privileges structure to highest privileges (enable_15)
43. Exploitation: Can I haz a shell ?
The shellcode then jumps on the ci_cons_shell() function responsible for
displaying the Cisco CLI prompt
We are finally greeted by a “root” Cisco CLI o/
45. Exploitation: Timeline
● Bug discovered (day 0)
● Figuring out how to bypass the wild memcpy(): 1 week
● Figuring heap primitives & Crafting the heap correctly: 1 other week
● Creating overlapping chunk + achieving write4: 2 or 3 days
● Getting to EIP from that point on: 1 week
● Cleaning up the heap: 2 or 3 days
● Figuring out how to get an actual connect-back: 2 weeks :(
46. Exploitation: Conclusion
Even bugs looking unexploitable can be turned into something better
Still good to know the old heap exploitation tricks as well as the new ones
Really interesting RE work to figure out the shellcode
Cisco virtual appliances are 64-bits and might have ASLR / DEP which
significantly raises the bar
47. Open Problems
Reliability:
● Didn’t try to achieve gov grade exploit (Pareto’s law is a good metric for exploit dev).
Just look at the timeline to see it’ll take forever
● Concurrent connections will mess with the heap
Targeting:
● Shellcode is not version independant (hardcoded values)
● Need to have a binary version of firmware to add a new target
Non-Factors:
● ASLR / DEP mitigation
● Up to date dlmalloc implementation (safe unlinking)
● 64-bit binaries will probably need different exploit technique (bigger heap metadata
size)