Porting_cve 2016 6366
layout: post title: “Porting an Exploit for CVE-2016-6366” date: 2022-01-21 00:00:00 -0400 categories: posts cve — A few years ago I wrote a blog post for a class I was taking in school exploring the Cisco Adaptive Security Appliance and trying to port the exploit to a known vulnerable version of the firmware that did not yet have an exploit written for it. As you can see from how the post ends, I ran out of time that semester and was unable to finish the exploit. In 2018 I picked the project back up and successfully ported the exploit. In continuing my habit of picking up old projects years later, this post serves as an update to the original post explaining the problem and how I solved it.
Picking Up Where We Left Off
The vulnerability in question is a buffer overflow in the Simple Network Management Protocol (SNMP) within the ASA, specifically the code implementing the getBulkRequest method. The overflow exists in the part of the code that reads in the Management Information Base number sent as part of the request.

The exploit patches the password verification function used by the ASA to check passwords. When throwing the RiskSense improved exploit at the ASA, instead of patching the function, the ASA crashes. The crashdump generated by the ASA looks like this:

Debugging Shellcode with gdbserver
The shellcode used by the RiskSense exploit code is helpfully included in nasm
format in the repo for the exploit.
The shellcode is fairly straightforward: it stores the original values of the
various registers on the stack, calls the sys_mprotect system call to allow
the password check function to be modified, copies the patch code, then
returns. The small amount of code means there were not that many areas where
something could’ve went wrong. To investigate further, I used the gdbserver
included with the ASA for debugging purposes to troubleshoot the shellcode. The
asatools scripts discussed in the first blog post automates the process for
patching the firmware to enable the gdbserver on startup.
Let’s take another look at the crashdump. The instruction pointer is pointing
at 0xcb980943, which is in the area of memory the stack is stored in. The
shellcode makes changes to eax, esi, edi, ebx, and ebp. ebx, ebp,
and edi are all set to the values that the shellcode changes them to before
returning execution, which suggests that the code crashed towards the end of
execution.
Using the gdbserver and a gdb client on a workstation connected to the ASA over a serial connection, we can set a breakpoint at the SNMP function right before it jumps to the shellcode and look at the values of the registers at that point as well as when the code crashes to investigate further.
Troubleshooting the Shellcode
In a quirk of the shellcode that was either to make it more difficult for script kiddies to run the exploit on unpatched ASAs or an artifact from development that was accidentally left in, the shellcode includes a breakpoint just before returning execution, which made it much easier to troubleshoot further but was the actual cause for the crash - the hardware interrupt is not caught by a debugger, so the lina binary and thus the ASA crashes. The breakpoint being hit in gdb is shown below.
Thread 2 hit Breakpoint 2, 0x0907e34e in ?? ()
(gdb) info register
eax 0x2 2
ecx 0xcc45b988 -867845752
edx 0xcc0dc600 -871512576
ebx 0xcc0dc600 -871512576
esp 0xcc0dc5c8 0xcc0dc5c8
ebp 0xcc0dc610 0xcc0dc610
esi 0x4 4
edi 0x10 16
eip 0x907e34e
[snip]
However, even if you remove the breakpoint, the exploit would still break. Updated gdb output is below.
Thread 2 received signal SIGTRAP, trace/breakpoint trap.
[Switching to Thread 491]
0xcc471113 in ?? ()
(gdb) info register
eax 0x0 0
ecx 0x0 0
edx 0x0 0
ebx 0x10 16
esp 0xcc0dc51c 0xcc0dc51c
ebp 0xcc0dc564 0xcc0dc564
esi 0x0 0
edi 0xf0f0f0b 252645131
eip 0xcc471113 0xcc471113
[snip]
As you can see from the register values, the stack pointers ebp and esp are
off by four when reset by the shellcode. Because the stack is not being
properly returned to its original structure prior to the exploit, whenever the
ASA references something on the stack after exploitation, the value of whatever
variable is going to be wrong, causing more problems.
Solution
To fix the shellcode, I removed the hardware interrupt and added one more
instruction that adds 4 bytes to ebp before the ebp offset is added back to
ebp. You can see these changes in my fork of the RiskSense repo.