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

1 comment: