CTF/gits2012teaser/1-TelAviv

From Fixme.ch
Revision as of 16:52, 8 January 2012 by Francois (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

#1 TelAviv

Question

What is the password? (File)
Hint: TeLaViv+ is a packet forensics challenge.

Solution

The file 7139a4ea239dcac655f7c38ca6a77b61.bin is a regular pcap file which contains a single TCP session.

Gist-telaviv-tcp-session.png

The client sends 245 bytes to the server as an authentification mechanism (red data in the screenshot). The actual data is composed of multiple parts:

  • "GitS", probably some dummy data
  • a NULL byte
  • "Plague", potential username
  • 233 remaining bytes, this is the actual password we're looking for

The hint (TeLaViv+) tells us that this password is probably encoded with Type-Length-Value (TLV) encoding. However, there was actually no type fields and the length of each field was one byte long.

Gist-telaviv-password-data.png

The following Python script (tlv.py) decodes the password:

#!/usr/bin/env python
#
# http://ghostintheshellcode.com/
# Ghost in the Shellcode 2012 Teaser
#
# Challenge #1 TelAviv
#
# By Francois Deppierraz <francois@ctrlaltdel.ch>
 
import sys
from pprint import pprint
from binascii import hexlify
 
f = open("7139a4ea239dcac655f7c38ca6a77b61.bin")
f.seek(0x244) # seek to the data of interest, offset found with wireshark
data = f.read(233) # data size
 
total_len = 0
packets = []
index=0
while index < len(data):
    length = ord(data[index])
    packets.append(data[index+1:index+1+length])
    index += length+1
    total_len += length+1
 
# Ensure that all data was actually parsed
assert total_len == len(data)
 
print "Found %d packets: " % len(packets)
for p in packets:
  print "  ",
  for c in p:
    print hex(ord(c)),
  print
print
 
numbers = [[ord(c) for c in p] for p in packets]
#print "Values: ",
#pprint(numbers)
#print
 
# Sum all byte values for each packet (idea comes from the + sign in the hint TeLaViv+)
sums = [sum(row) for row in numbers]
print "Sums: " + repr(sums)
print
 
s = "".join([chr(c/2) for c in sums])
print "Divide by 2 and then convert to ASCII: "
print s
print
 
print "Simple subsitution: "
# "Dro Zkccgybn sc" to "The Password is"
from_txt = "\":dro zkccgybn sc"
to_txt   = "\":the password is"
assert len(from_txt) == len(to_txt)
 
for c in s.lower():
  idx = from_txt.find(c)
  if idx != -1:
    sys.stdout.write(to_txt[idx])
  else:
    sys.stdout.write(".")
print
$ ./tlv.py
Found 37 packets: 
   0x2b 0x2e 0x1 0x17 0x10 0x1 0x5 0x1
   0x57 0x21 0x57 0x1 0x1 0x12 0x1
   0x4d 0x5d 0x1d 0x8 0xd 0x2
   0x1b 0xa 0x18 0x2 0x1
   0x5a 0x4 0x46 0x10
   0x84 0x27 0x16 0x12 0x3
   0x9d 0x22 0x5 0x1 0x1
   0xb8 0x9 0x4 0x1
   0x33 0x5d 0x38 0x5 0x1
   0x5e 0xd 0x68 0x1f
   0x50 0x2d 0x1a 0x20 0x2 0x9 0x2
   0x90 0xc 0x20 0x10 0xf 0x1
   0x3a 0x4 0x1 0x1
   0x17 0x3b 0x34 0x18 0x37 0xf 0x1 0x1
   0x21 0x78 0x25 0x8
   0x1d 0x4b 0x8 0x3 0x1
   0x1a 0x21 0x2 0x3
   0x19 0x25 0x4 0x1 0x1
   0x5c 0x17 0x12 0x2 0x1
   0x5d 0x49 0x33 0x4 0x3 0x2 0x1 0x1
   0x96 0x1a 0x29 0x5
   0x3a 0x5 0x1
   0x39 0x4 0x53 0xa 0x1 0x1
   0x79 0x2 0x7 0x1b 0x1 0x37 0x1
   0x3 0xe 0x18 0x17
   0x6e 0x11 0x9 0x3 0x1
   0xb4 0x6 0x1 0x3 0x4 0x3 0x1e 0x2 0x1
   0x2 0xa7 0x10 0x10 0x12 0x13 0x2
   0x4c 0x9 0x43 0x7 0xd 0x4 0x2a
   0xd 0x78 0x5f 0x2
   0x2b 0x7 0xd 0x1
   0x74 0xd 0xe 0x9 0x2
   0x2d 0xa6 0xd 0xb 0x1 0x6
   0x9d 0x39 0x5 0x1
   0xd5 0x9
   0x38 0x6 0x2 0x2 0x1 0x1
   0x2f 0x5 0xb 0x1

Sums: [136, 228, 222, 64, 180, 214, 198, 198,
       206, 242, 196, 220, 64, 230, 198, 116,
       64, 68, 136, 228, 222, 64, 156, 214,
       64, 140, 230, 240, 218, 230, 64, 154,
       242, 220, 222, 68, 64]

Divide by 2 and then convert to ASCII: 
Dro Zkccgybn sc: "Dro Nk Fsxms Myno" 

Simple subsitution: 
the password is: "the da .i..i .ode"

Update: we have missed the fact that result was ROT-16 encoded instead of being arbitrarily substitued. Thanks to Leet More's writeup for the info.