Showing posts with label CANVAS. Show all posts
Showing posts with label CANVAS. Show all posts

Friday, March 6, 2015

CANVAS - Psexec & Kerberos credentials

With the recent release of MS14-068 it became quite clear that a PSEXEC (sysinternals) module would be a fine addition in CANVAS. We wrote and released in CANVAS 6.99 a quite simple yet rather effective one with a couple of fine features.

1. PSEXEC and its basics

First of all let us remember how the original SysInternals tool works. A remote command (be it interactive or not) is executed following this procedure:

  • The PSEXEC client extracts out of its own binary a Windows service (PSEXESVC.exe) and uses the current user token (or alternate credentials) to store it in one of the writable SMB shares of the target, usually ADMIN$.
  • The client then uses the DCE/RPC API associated with the SVCCTL named pipe to create a Windows service associated with PSEXESVC.exe. This obviously requires ADMIN privileges on the remote host.
    • The client remotely starts the service.
    • Once started this service creates a control pipe (\PSEXESVC) on the target.
  • The client remotely opens this pipe using the SMB API. It reads and writes on it following an internal protocol.
    • An internal cookie is used to ensure that both the client and the server are using a same version of the protocol (this is mandatory in case the Windows service would be left running on the target). 
    • The service gets the knowledge of various options requested by the client such as the command to execute, if the command should be run with lower privileges, etc.
  • The service creates 3 named pipes and starts a new process whose STDIN, STDOUT and STDERR file descriptors may be redirected to the 3 aforementioned pipes.
  • The client connects to the 3 pipes using the SMB API and initiates a read polling on STDOUT/STDERR pipes. If necessary (CMD.exe), it will also write to the STDIN pipe.
  • When the new process' life is over, the service may be stopped and destroyed.
  • The service binary may be removed from the share.
That said, people usually either use PSEXEC to:
  • Execute a command (RCE)
  • Start CMD.exe (interactive shell)
For obvious reasons, in a security context such as a penetration test they rarely use the Desktop interaction feature.

2. Our PSEXEC module

2.1. Implementation of the RCE/interactive shell features

We chose to keep the original PSEXEC named pipes polling model to implement the RCE functionality in our module. This was not strictly mandatory as other ways to do this exist. MSF for example relies on the redirection of the standard output in a file which is later downloaded using SMB. We decided to use named pipes in order to anticipate future needs (and avoid leaving files on disk in the event of a disconnection, which is slightly better OSPEC). On the other hand, we decided to use a traditional MOSDEF connect back to mimic the interactive shell. This is exactly what was implemented in our MS14-068 exploit.

Both methods have their pros and cons:
  • The RCE only requires a client connection to the 445 TCP port. However the pipe management is not 100% perfect and side effects may sometimes be observed with the current version. 
  • The MOSDEF shell is quite powerful (it includes the RCE and interactive shell abilities) but may not be possible if egress filtering is used. While you might eventually be able to disable the Windows firewall of your target using the RCE, there is nothing you could do against an external equipment.
Note: The choice between both of them is done by filling the "cmd" parameter. If "mosdef" is specified, then the MOSDEF connect back is used otherwise what ever command is specified will be executed (if possible).

2.2. The authentication in SMB


This module provides two ways to authenticate the user:
  • Using NTLMSSP (login + password)
  • Using Kerberos (login + password + domain OR login + domain + credential file)

The NTLMSSP authentication may use the plaintext password or the NTLM hash of the password. This is the so called pass-the-hash technique as shown below:

Computing the NTLM hash

Using the NTLM hash in the CLI

The Kerberos authentication is used in two cases:

  • Implicitly as a fallback method if the NTLMSSP fails (this can happen with domain policies enforced) but only if the user had also specified the domain FQDN (which is not mandatory with NTLMSSP).
  • Explicitly if we have Kerberos credentials (potentially retrieved using post-intrusion tools) and we intend to use them. We decided that these credentials would always be stored in a UNIX ccache file because we had done the effort to write an API for MS14-068. 
To illustrate the situation, let's generate artificial ADMIN credentials (basically the TGT of the domain administrator) using kinit in the IMMU4.COM domain:

Artificially generating a Kerberos TGT
We can then fill the appropriate field in CANVAS to specify these credentials:

Using a Kerberos credential file to compromise the target
And we finally get our node popping:

Target is owned!

2.3. Upload and execution of a specific binary

In a few cases, you may want to run your own binary on the target. Our module will take care of both the upload and the execution of this specific binary. It will basically be seen as a specific RCE.

Several options may be specified either on the command line or using the GUI:
  • The command and argument to execute (cmd)
  • The local directory in which is stored the binary to upload (local_upl)
  • The directory in which should be stored the binary once uploaded (remote_path_upl)
For example, suppose the user is running this command:

$ python exploits/psexec/psexec.py -t 192.168.0.1 -p 445 -Ocmd:"mybinary mybinaryargument" -Ouser:administrator -Odomain:IMMU2.COM -Okrb5_ccache:/tmp/krb5cc_1000 -Olocal_upl:/tmp/BABAR -Oremote_path_upl:"C:\\"

Then /tmp/BABAR will be uploaded in C:\\ as mybinary.exe (the .exe suffix being automatically added) and executed from this directory.

3. Stealing credentials using "kerberos_ticket_export"

We wrote a command module that allows us to detect the presence of kerberos credentials on both Windows and Unix targets. This module is used to list the credentials that are associated with a compromised account under which is running the MOSDEF callback:
  • If the node is a Linux/BSD system, all the Kerberos tools will be using standard MIT libraries which store credentials in specific directories (for example /tmp/krb5cc_%{uid} on Ubuntu/FreeBSD).
  • If the node is Windows we use LsaCallAuthenticationPackage() in a MOSDEF-C payload.
Here is a little demo:



We also wrote a similar module to actually extract the tickets and convert them (if necessary) to ccache files. This is where PSEXEC comes to play. Both modules are quite similar:
  • Exporting credentials on Unix systems basically means copying a file that we can immediately reuse. The ccache file may include a TGT but also one of several TGS.
  • On Windows systems, we are (currently) limited to TGT extraction. Basically we keep using LsaCallAuthenticationPackage but with different parameters. This may allow you to extract the TGT and the associated session key. In a couple of circumstances and for security reasons that we may explain in another blogpost, the session key cannot always be retrieved in which case the TGT is useless. Once the TGT, the session key, and other parameters are extracted, we use our ccache API to build and store the tickets locally (in a session directory).
The following screenshot illustrates the ticket extraction:

Ticket is extracted and saved (oops small typo in the module code :P)

And the subsequent use of PSEXEC to own a new node:

The previous relative path is specified (although cut by the GUI here)

4. Last words

The Kerberos ticket modules are currently in an early stage of development. There is lots of room for improvement including full 64 bits support, corner case situations and privileged account related tricks. As for the PSEXEC module itself, we may add a couple of features such as a "runas" option.

Monday, November 4, 2013

Exploiting CVE-2013-3881: A Win32k NULL Page Vulnerability

Microsoft Security Bulletin MS13-081 announced an elevation of privilege vulnerability [http://technet.microsoft.com/en-us/security/bulletin/ms13-081]. Several days later Endgame published [http://endgame.com/news/microsoft-win32k-null-page-vulnerability-technical-analysis.html] some further details on the vulnerability in question but did not provide full exploitation details. In this post we will discuss how to successfully exploit CVE-2013-3881.

The Vulnerability


The vulnerability resides in xxxTrackPopupMenuEx, this function is responsible for displaying shortcut menus and tracking user selections. During this process it will try to get a reference to the GlobalMenuState object via a call to xxxMNAllocMenuState, if the object is in use, for example: when another pop-up menu is already active, this function will try to create a new instance.

If xxxMNAllocMenuState fails it will return False but it will also set the pGlobalMenuState thread global variable to NULL. The caller verifies the return value, and in case of failure it will try to do some cleanup in order to fail gracefully.

During this cleanup the xxxEndMenuState procedure is called. This function's main responsibility is to free and unlock all the resources acquired and saved for the MenuState object, but it does not check that the pGlobalMenuState variable is not NULL before using it. As a result a bunch of kernel operations are performed on a kernel object whose address is zero and thus potentially controlled from userland memory on platforms that allow it.

Triggering the vulnerability is relatively easy by just creating and displaying two popup instances and exhausting GDI objects for the current session, as explained by Endgame. However, actually getting code execution is not trivial.

Exploitation


Usually a NULL dereference vulnerability in the kernel can be exploited by mapping memory at address zero in userland memory (when allowed by the OS), creating a fake object inside of this null page and then triggering the vulnerability in the kernel from the current process context of your exploit which has the null page mapped with attacker controlled data. With some luck we get a function pointer of some sort called from our controlled object data and we achieve code execution with Kernel privileges (e.g. this was the case of MS11-054). As such, NULL dereference vulnerabilities have for many years provided a simple and straightforward route to kernel exploitation and privilege escalation in scenarios where you are allowed to map at zero.

Unfortunately  in the case of CVE-2013-3881 life is not that simple, even on platforms that allow the null page to be allocated.

When xxxTrackPopupMenuEx calls xxxMNAllocMenuState and fails, it will directly jump to destroy the (non-existant) MenuState object, and after some function calls, it will inevitably try to free the memory. This means that it does not matter if we create a perfectly valid object at region zero. At some point before xxxEndMenuState returns, a call to ExFreePoolWithTag(0x0, tag) will be made. This call will produce a system crash as it tries to access the pool headers which are normally located just before the poolAddress which in this case is at address 0. Thus the kernel tries to fetch at 0-minus something which is unallocated and/or uncontrolled memory and we trigger a BSOD.



This means the only viable exploitation option is to try and get code execution before this Free occurs.


Situational Awareness


At this point we try to understand the entire behavior of xxxEndMenuState, and all of the structures and objects being manipulated before we trigger any fatal crash. The main structure we have to deal with is the one that is being read from address zero, which is referenced from the pGlobalMenuState variable:

win32k!tagMENUSTATE
+0x000 pGlobalPopupMenu : Ptr32 tagPOPUPMENU
+0x004 fMenuStarted : Pos 0, 1 Bit
+0x004 fIsSysMenu : Pos 1, 1 Bit
+0x004 fInsideMenuLoop : Pos 2, 1 Bit
+0x004 fButtonDown : Pos 3, 1 Bit
+0x004 fInEndMenu : Pos 4, 1 Bit
+0x004 fUnderline : Pos 5, 1 Bit
+0x004 fButtonAlwaysDown : Pos 6, 1 Bit
+0x004 fDragging : Pos 7, 1 Bit
+0x004 fModelessMenu : Pos 8, 1 Bit
+0x004 fInCallHandleMenuMessages : Pos 9, 1 Bit
+0x004 fDragAndDrop : Pos 10, 1 Bit
+0x004 fAutoDismiss : Pos 11, 1 Bit
+0x004 fAboutToAutoDismiss : Pos 12, 1 Bit
+0x004 fIgnoreButtonUp : Pos 13, 1 Bit
+0x004 fMouseOffMenu : Pos 14, 1 Bit
+0x004 fInDoDragDrop : Pos 15, 1 Bit
+0x004 fActiveNoForeground : Pos 16, 1 Bit
+0x004 fNotifyByPos : Pos 17, 1 Bit
+0x004 fSetCapture : Pos 18, 1 Bit
+0x004 iAniDropDir : Pos 19, 5 Bits
+0x008 ptMouseLast : tagPOINT
+0x010 mnFocus : Int4B
+0x014 cmdLast : Int4B
+0x018 ptiMenuStateOwner : Ptr32 tagTHREADINFO
+0x01c dwLockCount : Uint4B
+0x020 pmnsPrev : Ptr32 tagMENUSTATE
+0x024 ptButtonDown : tagPOINT
+0x02c uButtonDownHitArea : Uint4B
+0x030 uButtonDownIndex : Uint4B
+0x034 vkButtonDown : Int4B
+0x038 uDraggingHitArea : Uint4B
+0x03c uDraggingIndex : Uint4B
+0x040 uDraggingFlags : Uint4B
+0x044 hdcWndAni : Ptr32 HDC__
+0x048 dwAniStartTime : Uint4B
+0x04c ixAni : Int4B
+0x050 iyAni : Int4B
+0x054 cxAni : Int4B
+0x058 cyAni : Int4B
+0x05c hbmAni : Ptr32 HBITMAP__
+0x060 hdcAni : Ptr32 HDC__

This is the main object which xxxEndMenuState will deal with, it will perform a couple of actions using the object and finally attempts to free it with the call to ExFreePoolWithTag. The interaction with the object that occurs prior to the free are the ones we have to analyze deeply as they are our only hope in getting code execution before the imminent crash.

xxxEndMenuState is a destructor, and as such it will first call the destructor of all the objects contained inside the main object before actually freeing their associated allocated memory, for example:

_MNFreePopup(pGlobalMenuState->pGlobalPopupMenu)
_UnlockMFMWFPWindow(pGlobalMenuState->uButtonDownHitArea)
_UnlockMFMWFPWindow(pGlobalMenuState->uDraggingHitArea)
_MNDestroyAnimationBitmap(pGlobalMenuState->hbmAni)

The _MNFreePopup call is very interesting, as PopupMenu objects contain several WND objects and these have Handle references. This is relevant because if this WND object has its lock count equal to one when MNFreePopup is called, at some point it will try to destroy the object that the Handle is referencing. These objects are global to a user session. This means that we can force the deletion of any object within the current windows session, or at the very least decrement its reference count.

win32k!tagPOPUPMENU
+0x000 fIsMenuBar : Pos 0, 1 Bit
+0x000 fHasMenuBar : Pos 1, 1 Bit
+0x000 fIsSysMenu : Pos 2, 1 Bit
+0x000 fIsTrackPopup : Pos 3, 1 Bit
+0x000 fDroppedLeft : Pos 4, 1 Bit
+0x000 fHierarchyDropped : Pos 5, 1 Bit
+0x000 fRightButton : Pos 6, 1 Bit
+0x000 fToggle : Pos 7, 1 Bit
+0x000 fSynchronous : Pos 8, 1 Bit
+0x000 fFirstClick : Pos 9, 1 Bit
+0x000 fDropNextPopup : Pos 10, 1 Bit
+0x000 fNoNotify : Pos 11, 1 Bit
+0x000 fAboutToHide : Pos 12, 1 Bit
+0x000 fShowTimer : Pos 13, 1 Bit
+0x000 fHideTimer : Pos 14, 1 Bit
+0x000 fDestroyed : Pos 15, 1 Bit
+0x000 fDelayedFree : Pos 16, 1 Bit
+0x000 fFlushDelayedFree : Pos 17, 1 Bit
+0x000 fFreed : Pos 18, 1 Bit
+0x000 fInCancel : Pos 19, 1 Bit
+0x000 fTrackMouseEvent : Pos 20, 1 Bit
+0x000 fSendUninit : Pos 21, 1 Bit
+0x000 fRtoL : Pos 22, 1 Bit
+0x000 iDropDir : Pos 23, 5 Bits
+0x000 fUseMonitorRect : Pos 28, 1 Bit
+0x004 spwndNotify : Ptr32 tagWND
+0x008 spwndPopupMenu : Ptr32 tagWND
+0x00c spwndNextPopup : Ptr32 tagWND
+0x010 spwndPrevPopup : Ptr32 tagWND
+0x014 spmenu : Ptr32 tagMENU
+0x018 spmenuAlternate : Ptr32 tagMENU
+0x01c spwndActivePopup : Ptr32 tagWND
+0x020 ppopupmenuRoot : Ptr32 tagPOPUPMENU
+0x024 ppmDelayedFree : Ptr32 tagPOPUPMENU
+0x028 posSelectedItem : Uint4B
+0x02c posDropped : Uint4B
…...


In order to understand why this is so useful, let's analyze what happens when a WND object is destroyed:


pWND __stdcall HMUnlockObject(pWND pWndObject)
{
pWND result = pWndObject;

pWndObject->cLockObj--;

if (!pWndObject->cLockObj)
result = HMUnlockObjectInternal(pWndObject);
return result;
}

The first thing done is a decrement of the cLockObj counter, and if the counter is then zero the function HMUnlockObjectInternal is called.


pWND __stdcall HMUnlockObjectInternal( pWND pWndObject)
{
pWND result;
char v2;

result = pWndObject;

unsigned int entryIndex;
pHandleEntry entry;

entryIndex = pWndObject->handle & 0xFFFF;
entry = gSharedInfo.aheList + gSharedInfo.HeEntrySize * entryIndex



if ( entry->bFlags & HANDLEF_DESTROY )
{
if ( !(entry->bFlags & HANDLEF_INDESTROY) )
{
HMDestroyUnlockedObject(entry);
result = 0;
}
}
return result;
}

Once it knows that the reference count has reached zero, it has to actually destroy the object. For this task it gets the handle value and applies a mask in order to get the index of the HandleEntry into the handle table.
Then it validates some state flags, and calls HMDestroyUnlockedObject.
The HandleEntry contains information about the object type and state. This information will be used to select between the different destructor functions.

int __stdcall HMDestroyUnlockedObject(pHandleEntry handleEntry)
{
int index;
index = 0xC * handleEntry->bType
handleEntry->bFlags |= HANDLEF_INDESTROY;

return (gahti[v2])(handleEntry->phead);

}

The handle type information table (gahti) holds properties specific to each object type, as well as their Destroy functions. So this function will use the bType value from the handleEntry in order to determine which Destroy function to call.

At this point it is important to remember that we have full control over the MenuState object, and that means we can create and fully control its inner PopupMenu object, and in turn the WND objects inside this PopupMenu. This implies that we have control over the handle value in the WND object.

Another important fact is that entry zero on the gahti table is always zero, and it represents the FREE object type.

So our strategy in order to get code execution here is to, by some means, create an object whose HandleEntry in the HandleEntry table has a bType = 0x0, and bFlags = 0x1. If we can manage to do so we can then create a fake WND object with a handle that makes reference to this object of bType=0x0. When the HMDestroyUnlockedObject is called it will end up in a call gahti[0x0]. As the first element in gahti table is zero, this ends up as a "call 0". In other words we can force a path that will execute our controlled data at address zero.


What we need



We need to create a user object of bType=FREE (0x0) and bFlags= HANDLEF_DESTROY (0x1).
This is not possible directly, so we first focus on getting an object with the bFlag value equal to 0x1. For this purpose we create a Menu object, set it to a window, and then Destroy it. The internal reference count for the object did not reach zero because it is still being accessed by the window object, so it is not actually deleted but instead flagged as HANDLEF_DESTROY on the HandleEntry. This means the bFlag will equal to 0x1.

The bType value is directly associated to the Object Type. In the case of a menu object the value is 0x2 and there is no way of creating an object of type 0x0. So we focus on what ways we have to alter this value using some of the functions being called before destroying the WND object.

As you can probably remember from the PopupMenu structure shown before, it contains several WND objects, and one of the first actions performed when HMUnlockObject(pWnd) is called is to decrement the lockCount. So we simply set-up two fake WND objects in such a way that the lockCount field will be pointing to the HandleEntry->bType field. When each of those fake WND objects is destroyed it will actually perform a “dec” operation over the bType of our menu object, thus decrementing it from 0x2 to 0x0. We now have a bFlag of 0x1 and a bType of 0x0.





Using this little trick we are able to create a User object with the needed values on the HandleEntry.


Summary


First we will create a MenuObject and force it to be flagged as HANDLEF_DESTROY.

Then we will trigger the vulnerability, where xxxEndMenuState will get a reference to the menuState structure from a global thread pointer, and its value will be zero. So we map this address and create a fake MenuState structure at zero.

XxxEndMenuState will call FreePopup(..) on a popup object instance we created, and will in turn try to destroy its internal objects. Three of these objects will be fake WND objects which we also create. The first two will serve the purpose of decrementing the bType value of our menu object, and the third one will trigger a HMDestroyUnlockedObject on this same object. This will result on code execution being redirected to address 0x0 as previously discussed.

We have to remember that when we redirect execution to address 0, this memory also servers as a MenuState object. In particular the first field is a pointer to the PopupMenu object that we need to use. So what we do is to choose the address of this popup menu object in such a way that the least significant bytes of the address also represent a valid X86 jump opcode (e.g. 0x04eb translates to eb 04 in little endian memory ordering which represents a jump 4).


Finish him!


Once we achieve execution at ring 0 we patch the Enabled field on the _SEP_TOKEN_PRIVILEGES structure from the MOSDEF callback process in order to enable all the privileges for the process. We fix up the HandleEntry we modified before, and restore the stack in order to return after the PoolFree thus skipping the BSOD.

Once all of this is done we return to user-land, but now our MOSDEF process has all the privileges, this allows us to for example migrate to LSASS and get System privileges.



-- Matias Soler


Monday, June 24, 2013

Adobe XFA exploits for all! First Part: The Info-leak

Some notes on exploit development

There are two types of frustration as an exploit developer when you are facing a malware with a zero day or a public proof of concept that generally kick in on the first day or two.

The first one is a classic: spending hours navigating the darkest corners of the Internet, looking for a the right trial version of the vulnerable application. The more obscure the software is, the harder of a time you will have, I know dumb stack overflows that took more time to find the server than to exploit.

Luckily, this was not our case since we are exploiting Adobe Reader and you can easily find all the versions.

The second problem and the most common while reversing Chinese malware is the low percentage of success they often have. You are able to crash the vulnerable software, of course, and this is generally enough in our line of business to demonstrate the weakness. But you also want to understand what techniques they use to gain control and compare them against yours, and this requires their exploit to actually work.

In the case of the Acroform XFA bug, no matter how much we try with different environment and versions, the heap layout was never massaged correctly to allow the exploit to work.

This leaves an open question we generally have (and we have so many theories... yes, some of them involve aliens!). Why are the Chinese offensive teams not investing a couple more weeks on the heap layout, like we did, and to dramatically improve the reliability of their exploits?

In malware design, reliability == more computer owned == more money.

At the same time, from an OPSEC perspective: reliability == stealthiness. And stealthiness means you don't loose your zero day and your investment is worth more over a long term.

Technical description

The vulnerability lies in the AcroForm.api module when handling Adobe XFA Forms in a particular way. The exploit uses an XFA form with 1024 fields like this:



We first need to get UI (user interface) objects from the XFA form, and from within the UI objects the choiceList objects. We need to create 2 arrays with these objects:

These arrays will be used during the whole exploitation process. The code in charge of triggering the vulnerability is:

    var node = xfa.resolveNode
("xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field0[0].#ui");

    node.oneOfChild = choiceListNodes.pop();

Everytime the oneOfChild attribute of a node is set with one of the choiceListNodes node, the vulnerability is triggered. When creating a new "XFAObject" of size 0x40, there is an access outside the bounds of the object on "XFAObject"+44, using uninitialized data. At "XFAObject"+44 there is a pointer to some structure we will describe later.  If the pointer is null nothing happens but if we are able to control that uninitialized data after the "XFAObject", we will trigger an info-leak or trigger code execution.

When the pointer is not null, an structure like the following one is accessed:
  ----  0x0 Vtable pointer
  |     0x4 RefCount
  --->  0x8 Destructor's address

This structure is accessed twice during the vulnerability trigger. Since we are in control of the RefCount and the "Vtable", if our RefCount is bigger than two, then we can use the bug as a decrement primitive, otherwise when the RefCount gets to zero, the object's destructor will be called.

We are in control of this memory so we can pretty much control what is going to be executed.
With the right heap layout set, we will a get a string followed by an object object, so with our decrement magic we decrement the null terminator and obtain the vtable address right from our object.
Infoleak running on a Windows 7

Sounds simple right? Wrong.

We can read the vtable, but we can only read it correctly if all bytes of the vtable are below 0x7f. So if any of the bytes is greater than 0x7f, we use the pointer decrement primitive to get that byte below 0x7f.

Pseudo-Code:


This gave us the ability to be version agnostic, and follow our mantra "an harcoded-less exploit is a happy exploit".

At this point, it was time to get into the second stage of our exploit which is sandbox bypassing. The Chinese exploit was dropping a DLL with the code. We decided that invading the hard-drive was a bad practice and so with a little help with our Python-based assembler (MOSDEF) embedded in CANVAS we decide it to embed the code into the exploit itself.

And so, we decided it was time to bypass the sandbox. But that my friends, will be for our next blogpost entry.

Keep in touch!
David and Enrique

Thursday, May 23, 2013

Jinx Part 2: nginx CVE-2013-2028

Who doesn't love vulnerabilities in web servers? We've written nginx bugs before and it was a lot of fun. Now Immunity is pleased to release to its CEU customers the 64 bit version of CVE-2013-2028 written up by a new member of the Linux exploit team. Since this is exploit is in recent versions of nginx only and in our experience most modern web servers tend to be 64 bit, we decided to develop against that architecture. This particular exploit is a good example of a modern remote exploit against hard to exploit software. There has been some good analysis of this vulnerability thus far but as Immunity has a working exploit we thought it worthwhile to chime in.

One of the first hurdles to overcome is not knowing a function's location in memory, ASLR has made information leak vulnerabilities very valuable as a result of its widespread implementation. In the absence of an information leak an attacker is left with brute force or another alternative that we'll discuss later. From there it's on to a ROP chain which may be very dependent on the version of libraries available on the system. Complicating all this is the fact that compiling software from scratch on Linux systems is very common, system administrators may pass any number of configuration or compiler options that change things just enough to break exploits that make too many assumptions.

A problem with basing targeting for exploits on pre-compiled binaries that you might get through apt-get or yum is that maintaining a list of targets and offset combinations becomes very cumbersome. And you've got to test against a large cross section of distribution and server version combinations which can be time intensive. When developing the exploit for this vulnerability we decided to make it as universal as possible and find all the memory locations we would need manually. This has the consequence of taking more time to run (5-20 minutes) but the benefit of working out of the box against more environment combinations. You may remember a similar situation with our exploit for Samba's CVE-2012-1182.

With this vulnerability the exploit takes over an nginx worker process (defined in conf/nginx.conf, default 4) and that process will not respond to other normal nginx work while your shell is active so launching a trojan and getting out of the worker if there aren't many will help avoid detection. In talking with the developer who wrote up this exploit another interesting issue presented itself. There is a condition whereby the target is vulnerable but not exploitable. If the stack canary or function addresses we use from libc contain bad bytes then that can cause exploitation to fail. The worker processes inherit their canaries from the parent and therefore killing them won't grant you a new canary and if by some cosmic roll of the dice libc is in a bad location then you're just out of luck. The upshot is that failed exploitation attempts will only kill the worker process and you can try again.

This exploit reuses the socket that established the connection to the web server in the first place. This is very helpful when dealing with hosts that have strict egress filtering, for instance where web servers are not able to initiate outbound connections. So before you upload and execute your trojan to get out of the worker process you'll want to determine what egress filtering (if any) may be in place. If you anticipate strict egress filtering is present then compromising the server during off hours and automating finding an egress part should be part of your game plan. The likelihood of crashing the server or the parent nginx process with this exploit is very low, nor did we observe the case of a worker process getting hung and no longer being available. In our testing we found the exploit to reliably get a shell over 90% of the time. The exploit presents a low risk high reliability method for getting a shell on an nginx webserver.

Wednesday, May 22, 2013

An Unusual MDaemon Exploit (a.k.a it's not always about shells)

In penetration testing there is an enormous focus on obtaining shells; and rightly so. Having that level of access to a host, regardless of privilege level, is incredibly useful for an attacker and is usually just the start of a full compromise of a host. Getting a shell can be difficult with all the modern memory corruption protections. Maintaining a shell isn't easy either as you have to contend with all manner of IDS, egress filtering, host monitoring and so forth.

Luckily having a shell isn't the only path to victory. MDaemon is a Windows based mail server (owned by BlackBerry) that is an alternative to Microsoft Exchange, it provides much of the same basic functionality but in a simpler to manage package. Using SWARM we were able to determine that while certainly not as popular as Exchange, MDaemon does have a pretty significant presence. It's not just in the commercial space either - there are government servers in various countries using this software as well.

The new CANVAS exploit takes advantage of a patched vulnerability in several versions of MDaemon that allows account takeover. Since there's not a lot of information on this vulnerability publicly available that's where I'll leave it - the curious have a low cost method for satisfying their curiosity. Many of the versions for 12.X and below are vulnerable though we have not been able to confirm how far back it goes. Account takeover allows for a lot of different interesting risks, such as getting passwords to cloud services such as Twitter reset, or social engineering other people in your organization.

We used SWARM to examine the version distribution of MDaemon for over a million IP addresses and I've summarized the results in a table below.

 
Version Percentage
13.X 12.6%
12.X 21.5%
11.X 20.4%
10.X 21.1%
9.X 17.4%
8.X 2.8%
7.X 2.7%
6.X 1.4%


The results are pretty interesting in a number of respects. Firstly there is a big legacy presence of MDaemon and given some of the disclosures, especially in the web portion, there are many paths to victory. Second - there are some users who just seem unable to ever upgrade their MDaemon. The rough right leaning bell curve shape of the versions is common to almost any server that does not auto update.

Wednesday, April 24, 2013

Yet Another Java Security Warning Bypass

Not so long ago we posted about a JavaSecurity Warning bypass that used a serialized applet instance.
That bypass was fixed in Java 7 update 13 so we had to keep looking at new ways of defeating the warning pop-up that requires user interaction in order to run applets.

We continued auditing the code that performed the checks when starting an applet and ended up arriving at the method “sun.plugin2.main.client.PluginMain.performSSVValidation(Plugin2Manager)

This method will end up calling some other methods in the com.sun.javaws.ui.SecureStaticVersioning class that will show us that annoying security warning pop up.



But just take a quick look at the performSSVValidation method implementation:

What is that __applet_ssv_validated parameter??

Obviously this is an internal undocumented parameter and, as you can see, it turns out that if it is set to true, no checks are performed.

The first thing we tried was to simply set that parameter to true in our evil applet, but it didn't work.
While debugging we noticed that the parameter was not set on the applet despite our setting it to true.

Basically sun.plugin2.main.server.MozillaPlugin.addParameter(String, String) is filtering the parameters:


But as you may know, Java provides another way of launching applets in a browser besides using the applet, object or embed tags.
Java Web Start technology is what we can use.
Now the applet description is provided by using a JNLP file and parameters can be set to the applet by using the <param> tag.

We can see that when using Java Web Start, the performSSVValidation method is also called



So lets try to launch an applet with Java Web Start and set the __applet_ssv_validated parameter to true with a JNLP file like this one:


And by know you have already realized that this just works and parameters are not filtered.
The Security Warning pop-up message is not displayed and our applet happily runs!

Ironically on Tuesday 16th April, exactly while I was at the Infiltrate MasterClass  teaching how to audit and exploit Java, Oracle released update 21 which fixed this bypass and a ton of others.

The time investment for stealthily exploiting Java is increasing but finding bypasses like this makes it worth the time!

Esteban Guillardoy

Friday, March 15, 2013

Immunity Releases an Exploit for the Linux Kernel PTRACE vulnerability


Linux PTRACE CVE_2013_0871

Solar Designer calls this one of the more dangerous Linux local exploits since  CVE-2010-3081. (c.f. http://seclists.org/oss-sec/2013/q1/342 )

There's some contention over how easy it is to exploit, and like many race conditions, it's not simple. Our current version works on 64 bit kernels in VM's (which have not been patched). To be perfectly honest, we largely tested this on VMWare VMs, so on other hypervisors YMMV.

2.6.29 changed the creds structure, so currently our released exploit is only 2.6.29 or greater. We do have a 32 bit version and a 2.x version which we'll finish testing and release at some point in the near future. And we'll try to fix the 64 bit version to work on non-VM's. It's going to be a while until this hits normal CANVAS as we need to finish 64-bit Linux MOSDEF in order to integrate it properly.

That said, VM's are in fairly common use at the moment so we thought people would get value out of it as-is.

Enjoy!


Exploit discussed in this blog post is here: https://ceu.immunityinc.com/immpartners/linux_ptrace_setregs.tar

Of course, you'll need a CANVAS Early Updates subscription to download this. You can email sales@immunityinc.com if you don't have one.

Monday, February 25, 2013

VisualSploit 2.0

Immunity is well known for its product base that is designed to help the lives and duties as network professionals, security auditors and penetration testers much easier.  However one of the lesser known features of CANVAS is VisualSploit.

VisualSploit is a learning utility that we created specifically for our popular Unethical Hacking training course that we conduct at INFILTRATE.

I have been an instructor of this course for a few years now so I have been in a position to see how a lot of people consume, assimilate and digest topics such as buffer overflows, memory corruption, debugging and assembly and the conclusion of this analysis is that these topics are best illustrated with simple, visual tools.  This way the students can walk away with a solid understanding of what happens before, during and after a buffer overflow.

VisualSploit is that simple, visual tool.  I decided to create VisualSploit v2.0 for a few reasons but topping the list is because I was paying close attention to how the tool could be improved to make sure the students got the most out of training and learning about these topics.

The new VisualSploit v2.0 web interface




During the Unethical Hacking course we teach you everything you need to know about assembly in order to write an exploit for buffer overflows.  With the help of VisualSploit you can literally go from analyzing the crash in Immunity Debugger to a working exploit/proof of concept in a matter of minutes because no programming is required.  VisualSploit behind the scenes just builds a CANVAS exploit for you which means that everything you build will be available to you as a regular exploit module the next time you start up CANVAS.  You're welcome.

This visual and hands-on method of teaching and learning about buffer overflows is very effective.  I have yet to encounter a student who didn't have that "ah-ha!" moment where it all clicked and they were able to finish writing the more challenging (and fun) exploits for real-world applications by the end of the course.

So come join me in April during the INFILTRATE edition of the Unethical Hacking class.  It will be fun and educational but more importantly you get to break stuff.

- @MarkWuergler


Friday, February 15, 2013

MOSDEF-C for you and me

One of the super neat things about CANVAS and MOSDEF is that it provides a vehicle to write code that executes in memory of an exploited host, meaning it doesn't have to touch disk if you don't want it to. This is a boon for covertness as it requires any defensive measures to do in memory forensics. So today we'll take a look at a quick post exploitation command that I wrote up for CANVAS based on a Windows kernel quirk discovered by Walied Assar.

Walied discovered a signedness error in NtSetInformationThread, I'll let his blog cover the specifics but what it means for us is that we can set a thread's I/O and memory priority to max. While this isn't terribly relevant in a security context (you could leverage a more efficient DoS on the box you have code exec on, but that's silly), writing up a quick module is demonstrative so let's go ahead and dive in!

When you start out on this path I would strongly encourage you to have working C/C++ code to base the module on because debugging in this scenario can be a frustrating process. So you will need:

1) Working C/C++ code
2) A Windows 7 VM with Immunity Debugger installed
3) A standard callback trojan deployed on the Win7 VM

When writing a new CANVAS module you'll need to create a new directory under CANVAS_ROOT/exploits with the module's name (note '-' is not allowed in module names so use '_' instead), and then within that directory you'll need a dialog.glade2 file as well as a .py with the module name. So my directory structure looks like:

CANVAS_ROOT/exploits/threadio
    dialog.glade2
    threadio.py

Normally we recommend that customers take an existing module and adapt it to their needs, I used windows_sniffer for this purpose but it required a lot of work since windows_sniffer is fairly complex and threadio is very simple. If you plan on writing your own commands using MOSDEF-C I'd recommend using threadio as your example, so just copy it into your exploit module's directory and give it the proper name and start modifying. Let's take a look at some souce:

#! /usr/bin/env python

# Proprietary CANVAS source code - use only under the license agreement
# specified in LICENSE.txt in your CANVAS distribution
# Copyright Immunity, Inc, 2002-2013
# http://www.immunityinc.com/CANVAS/ for more information

import sys
if "." not in sys.path: sys.path.append(".")


from localNode          import localNode
from timeoutsocket      import Timeout
from MOSDEF.mosdefutils import intel_order
from ExploitTypes.localcommand import LocalCommand

NAME                        = "threadio"
DESCRIPTION                 = "Set thread I/O and memory priority to max"
VERSION                     = "0.1"
GTK2_DIALOG                 = "dialog.glade2"
DOCUMENTATION               = {}
DOCUMENTATION["References"] = "http://waleedassar.blogspot.com/2013/02/kernel-bug-0-threadiopriority.html"
DOCUMENTATION["Notes"]      = """

Tested on Win7 x86

A module to demonstrate MOSDEF-C, if you're looking to pass simple values (int) 
back from the host this is a good demonstration

It will attempt to set a thread's I/O and memory priority to the maximum assignable values

"""

PROPERTY               = {}
PROPERTY['SITE']       = "Local"
PROPERTY['TYPE']       = "Commands"
PROPERTY['ARCH']       = [ ["Windows"] ]

I generally call this the preamble to the module, where we take care of imports, the documentation dictionary and the properties dictionary. All of this should be easy to understand if you've done any Python so I'll just touch on a few points. 1) All the variables are required (NAME, DOCUMENTATION, etc), 2) it is worth your while to fill these out completely when you begin writing the module especially the references section. Finding that blog post you want to remember two months from now is not very fun.


class theexploit(LocalCommand):
    def __init__(self):
        LocalCommand.__init__(self)
        self.result         = ""
        self.name           = NAME       

    def run(self):
        self.setInfo("%s (in progress)" % (NAME))

        node     = self.argsDict['passednodes'][0]
        type     = node.nodetype.lower()
        nodename = node.getname()

        if isinstance(node, localNode):
            self.log('Node of type %s not supported.' % type)
            return 0
            
        if type not in ['win32node']:
            self.log('Node of type %s not supported yet.' % type)
            return 0

"thexploit" class is the standard class from which all modules are run, by passing LocalCommand (in lieu of say tcpexploit) we tell CANVAS what type of module this is. Next we get into the run function which is another required function and where in this case all of our heavy lifting occurs.

With all command type modules it's always a good plan to put in some helpful error checking which you see with our first two if statements. node = self.argsDict['passednodes'][0] provides us a node object which we can compare against another object type, localNode. If you've ever used the CANVAS GUI localNode is the red circle that represents your CANVAS host, so here we check to ensure that isn't selected, because commands are meant to be run on compromised hosts rather than your CANVAS host. Next we get our node type with type = node.nodetype.lower() and check it against a list of node types this will work against. Since this is a Windows kernel issue it makes sense that we only allow the module to be run on Windows nodes.

code = """
        #import "remote", "ntdll.dll|ZwSetInformationThread" as "ZwSetInformationThread"
        #import "remote", "ntdll.dll|ZwQueryInformationThread" as "ZwQueryInformationThread"
        #import "remote", "kernel32.dll|GetCurrentThread" as "GetCurrentThread"
        #import "remote", "kernel32.dll|GetCurrentThreadId" as "GetCurrentThreadId"
        #import "local", "sendint" as "sendint"
        void main() {
            int success;
            int threadId;
            int setResult;
            int queryResult;
            unsigned long p1;
            unsigned long p2;
            
            success = 42;
            p1 = 0xFF3FFF3C;
            p2 = 0;
            
            threadId = GetCurrentThreadId();
            sendint(threadId);
            setResult = ZwSetInformationThread(GetCurrentThread(), 0x16, &p1, 4);
            sendint(setResult);
            queryResult = ZwQueryInformationThread(GetCurrentThread(),0x16, &p2,4,0);
            sendint(queryResult);
            sendint(success);
        }
        """
        
        # Compile the code and ship it over
        vars = {}
        node.shell.clearfunctioncache()
        request = node.shell.compile(code, vars)
        node.shell.sendrequest(request)

This is the meat of our module. I'll leave the specifics of the C code to the blog post referenced in the first paragraph. But I do want to point out a few things. First, this example is tied to MOSDEF-C for win32, if you're interested in MOSDEF-C for win64 I'll refer you to the windows_sniffer module, the changes are important but not difficult. In MOSDEF-C you have to import all your functions, you do this with a line like: #import "remote", "ntdll.dll|ZwSetInformationThread" as "ZwSetInformationThread". So a few things to note here, MSDN is your friend for determining which DLLs should contain which functions but save yourself the aggravation and check that this is the case by using Immunity Debugger. Open a program that has your DLL loaded, alt+e to get the imports list, right click your DLL and choose View Names, find your function name. Additionally, it is wise (though not required) to import the function into MOSDEF-C with the same name as it exists in the Windows API.

Having a line like: #import "remote" "ntdll.dll|ZwSetInformationThread" as "ZwSetInformationThreat"; is very annoying to debug if you use ZwSetInformationThread() later. Which brings me to my next point: yacc will give you some help when compiling on the CANVAS side before shipping it over to the target host but if it passes compilation any host side errors you will have to use your cunning, savvy and a debugger to find.

Variables do take a bit to get used to. Declaring a variable via: int ret = 4; gave me headaches. So I declared all my variables at the top then assigned them values after they'd all been declared. It may not be your style but I stopped getting wonky yacc errors after I followed this method.

sendint is a mosdef built in that allows you to, as you expected, send an integer back to your CANVAS host. This is incredibly useful for localizing where your MOSDEF-C might be failing. I make use of it in multiple locations, you'll note that the success variable isn't strictly required as no additional instructions are executed after the ZwQueryInformationThread call. This is a remnant of development but having a final send after all substantive instructions have been executed allows you to know that all of your code ran.

# Handle the responses
        threadId = 0
        success = 0
        threadId = node.shell.readint(signed=True)     # recv threadId
        setResult = node.shell.readint(signed=False)   # recv ZwQueryInformationThread result 
        queryResult = node.shell.readint(signed=False) # recv new thread priority
        success = node.shell.readint(signed=True)      # recv success, not strictly needed
        node.shell.leave()

As you may expect the CANVAS has a corresponding readint() for receiving these values. I found it helpful to have my CANVAS python variable names and my MOSDEF-C variable names be consistent and to label my readint()'s with enough information that I could easily figure out which one wasn't firing. When you get into more complex code, like a readint() within a conditional statement, keeping things labeled will help immensely with debugging.

# Lets have some verbose error handling
        try:
            if threadId == 0:
                self.log("Unable to get current thread ID, this will likely fail")
            
            setResult = hex(setResult)
            if setResult != "0x0":
                self.log("Received an error when attempting to call ZwSetInformationThread")
                self.log("Error no: %s"%(setResult))
                self.log("Check here for error details: http://msdn.microsoft.com/en-us/library/cc704588.aspx")
                raise ValueError
            
            if queryResult != 0:
                self.log("Error when attemping to call ZwQueryInformationThread, the module may have worked but unable to confirm")
                raise ValueError
            
            if success != 42:
                self.log("Encountered an error before the module exited")
                raise ValueError
            
        except ValueError:
            self.setInfo("%s - Done (failed)"%(NAME))
            return 0
        
        except Exception as e:
            self.log("Encountered an unhandled exception")
            self.setInfo("%s - Done (failed)"%(NAME))
            print e.message
            return 0

This may not be the most elegant or Pythonic way to do error handling but I found it made sense to me. The more effort you put into having good error handling now means debugging this module in six months when Microsoft has adjusted something is much easier. A few functions here that are useful: self.log() will generate CANVAS log events, I recommend using this over print for debugging. self.setInfo() will set the module's status in the Current Status GUI tab and is helpful to set if others will be using your code.

        self.log("Thead Id: %d"%threadId)
        self.log("ZwSetinformationThread: %s"%setResult)
        self.log("ZwQueryInformationThread: %s"%queryResult)
        self.log("Success: %d"%success)
        
        self.setInfo("%s - Done (success)"%(NAME))
        return 1

Finally we dump some information to the user and tell CANVAS the module has completed by returning. As you can probably guess return 0 will tell CANVAS the module failed, return 1 the module succeeded.

I think the benefit to MOSDEF-C is that it quickly allows you to interface with the Windows API without touching the remote file system. There's no DLL to load, if you have a Windows CANVAS Node this code is inserted and run into the running process. A defender may be able to determine that a machine was compromised but determining what specifically was done to that machine if you make use of techniques like this can be substantially more difficult. After all, hooking the entire Windows API isn't practical.

MOSDEF-C is a bit of a labor of love. If you're interested in starting to use it I would seriously suggest starting to read through the ./MOSDEF/ directory in CANVAS and then proceeding to ./MOSDEF/MOSDEFlibc. It is a powerful tool but it's important to note some of the current implementation limitations and some of the language quirks before you start doing anything too complicated.

The link to the complete module source can be found at: http://partners.immunityinc.com/threadio.tar