In one of our recent pentests, we discovered an 0day for a custom C application server running on the AIX Operating System. After debugging the crash, we discovered that the bug could lead to remote code execution and since we don’t deal very often with AIX exploitation, we decided to write an exploit for it. The first steps were accomplished pretty quickly and we successfully diverted the execution flow by jumping to a controlled buffer. At this point, we thought we could easily generate some shellcode from MSF and enjoy our remote shell.
Unfortunately for us, none of the MSF PowerPC payloads was working correctly. As you can see in the following pictures, the shellcode embedded in a simple C program, is executing “/bin/csh” but it’s not binding it to a tcp port as it should.
At this point, we were forced to dig around a bit more into the AIX shellcode internals in order to understand what was wrong.
As usual, the Metasploit framework is a huge source of information and by looking at the code of an AIX bind shell present in the external subdirectory (/opt/metasploit/msf3/external/source/unixasm/aix-power-bndsockcode.c in Backtrack), we realized what was going on:
The bindshell code in the above picture supports different versions of the AIX operating system but even minor version changes in the OS have an impact on the payload implementation. By looking at the actual msf bindshell payload module (/opt/metasploit/msf3/modules/payloads/singles/aix/ppc/shell_bind_tcp.rb in Backtrack) , it became evident that the differences are related to the system call numbers used in order to invoke the operating system services.
A quick Google search on the topic confirmed all of the above:
All of the AIX metasploit payload modules import the aix.rb library, which can be found at /opt/metasploit/msf3/lib/msf/core/payload/aix.rb in BackTrack. Looking through the code in this library helps provide us with a direction to follow in getting our shellcode to work.
The easiest way to port the existing MSF AIX shellcodes to other operating system versions is by adding a ruby hash with the relative sys call set to the aix.rb library:
At this point, we identified the target OS version of our exploit:
This above output tells us that we are running AIX Version 6 Technology Level (TL) 7 with no service packs (00-0000). The term Maintainance Level in the above tweet is now reserved for legacy AIX systems. The new IBM methodology dictates two TL releases per year.
To identify the right system call numbers for our AIX specific version, we compiled a C program that uses the same function set used by our shellcode. A bind shell C program found on the Internet, for example, can do the trick:
By setting a few breakpoints on the involved functions (socket, bind, listen, accept, close, kfcntl, and execve), we can step through the system call invocation in gdb and check the argument values:
In the PowerPC architecture, the sc instruction is used whenever the operating system services are to be called. The r2 CPU register denotes the system call number and registers r3-r10 are appropriately filled with the given system call arguments (
AIX 6.1 Information, “AIX PowerPC buffer overflow step by step”). In our case, r2, before branching the ctr register to execute the system call, is holding the value 254; we now know the socket sys call number for AIX 6.1.7.
We then identified the remaining sys call numbers and filled up an aix_617_syscalls hash in the aix.rb library:
and added a line to the version hash:
Our final step was to generate and test our newly edited payload:
Success! Our AIX shellcode works as expected. We have updated the MSF AIX payloads to include these newer versions of AIX Patch Levels – these should be committed to Metasploit soon.