codezen.fr code hacking, zen coding

30Apr/12Off

PlaidCTF 2012 – Potpourri 100 – The Game Writeup

Posted by aXs

Robots enjoy some strange games and we just can't quite figure this one out. Maybe you will have better luck than us.
23.22.16.34:6969

We have a game running on that port:

You have gotten 0 of 75
Choice 1 = 98d00c65d341be04600f915b32c01c81ab
Choice 2 = 7a859a01731c050797ac952d82b895882a
Which one is bigger? (1 or 2)
1
1
Correct!
--------------------
You have gotten 1 of 75
Choice 1 = d6e4fbe0e4cd99e8fac2b40fbaa80ea8b0
Choice 2 = 9535d4c5a1a007f302c3f2cc6d1733989f
Which one is bigger? (1 or 2)
1
1
Wrong 🙁

As you can see, "bigger" is not related to the number expressed in hexadecimal has being really greater than the other. We tried many different things to try to find a relation (modulo, adding the digits, ...) ... until I starred for a few minutes at our script that was playing the game in a loop and noticed the hashes were coming back.. it wasn't random numbers!

My first approach was to "learn" all the possible round. If a similar round comes back, we know the answer. I noticed that if we know only one of the number, if this number has won before, there is a slightly (slightly!) chance that it will won this match again. This approach kinds of worked but was very slow.. after 6 hours of learning, we weren't going higher than ~30-40 winning round in a row.

The next approach was to consider this challenge as a bubble sort: we will maintain an ordered list of the numbers and swap them around depend of which is considered bigger, basically using the service as an oracle.

This version worked much better and can solve The Game in around ~30 minutes.

I'm still learning Python so this isn't anything Im proud of on the point of view of the Python style of whatever 🙂

#!/usr/bin/env python
# -*- coding: latin-1 -*-

import socket
import sys
import re

if len(sys.argv) != 3:
  print '\nUsage:\t./bigger.py [host] [port]'
  sys.exit(1)

host = sys.argv[1]
port = int(sys.argv[2])

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

fs=s.makefile()

regex = re.compile(".*= (.*)")

matchs = {}
winner = []
numbers = []

while 1:
  welcome = fs.readline()
  print welcome

  if welcome == 'Yay you have won!\n':
    while 1:
      line = fs.readline()
      if not line:
        break
      print 'Received', repr(line)
    s.close()
    exit(1)

  choice1 = fs.readline()
  choice2 = fs.readline()
  question = fs.readline()

  r = regex.search(choice1)
  choice1 = r.groups()[0]
  num1 = int(choice1,16)
 
  r = regex.search(choice2)
  choice2 = r.groups()[0]
  num2 = int(choice2, 16)

  print 'Choice 1', choice1, 'Choice 2', choice2

  key1 = choice1 + choice2
  key2 = choice2 + choice1

  if key1 in matchs:
    choice = matchs[key1]
    print 'Send', choice, 'because previous match result'
    s.send('%d\n' %choice)
    predicted = 'previous'
  elif key2 in matchs:
    choice = matchs[key2]
    print 'Send', choice, 'because previous match result'
    s.send('%d\n' %choice)
    predicted = 'previous'
  else:
    if choice1 in numbers and choice2 in numbers:
        if numbers.index(choice1) < numbers.index(choice2):
          print 'Send 1 because lower index'
          s.send('1\n')
          predicted = 1
          unpredicted = 2
          candidate = choice1
          notcandidate = choice2
        else:
          print 'Send 2 because lower index'
          s.send('2\n')
          predicted = 2
          unpredicted = 1
          candidate = choice2
          notcandidate = choice1
    elif choice1 in winner:
      print 'Send 1 because previous winner'
      s.send('1\n')
      predicted = 1
      unpredicted = 2
      candidate = choice1
      notcandidate = choice2
    elif choice2 in winner:
      print 'Send 2 because previous winner'
      s.send('2\n')
      predicted = 2
      unpredicted = 1
      candidate = choice2
      notcandidate = choice1
    else:
      print 'Send 1 because arbitrary'
      s.send('1\n')
      predicted = 1
      unpredicted = 2
      candidate = choice1
      notcandidate = choice2

  result = fs.readline()
  result = fs.readline()

  print 'Result', result

  if result == 'Correct!\n':
    if predicted != 'previous':
      matchs[key1] = predicted
      matchs[key2] = unpredicted
      winner.append(candidate)
  else:
    matchs[key1] = unpredicted
    matchs[key2] = predicted
    winner.append(notcandidate)
    if candidate in numbers:
      if notcandidate in numbers:
        i = numbers.index(candidate)
        j = numbers.index(notcandidate)
        numbers[i], numbers[j] = numbers[j], numbers[i]
      else:
        numbers.append(notcandidate)
    else:
      numbers.append(candidate)

  result = fs.readline()

while 1:
    line = s.recv(4096)
    if not line:
        break
    print 'Received', repr(line)

s.close()

After around 30 minutes...

You have gotten 73 of 75

Choice 1 0872b5c42221f31ffadb08e634ab8e5ab6 Choice 2 41b9ffcabc545e4b71b5d9ce1399a145e0
Send 1 because lower index
Result Correct!

You have gotten 74 of 75

Choice 1 dee427827d0b8b54f9545f6e0073c7195f Choice 2 0285648f245ad5c9074defa6800f2b229b
Send 1 because lower index
Result Correct!

Yay you have won!

The key is: d03snt_3v3ry0n3_md5'

Share
30Apr/12Off

PlaidCTF 2012 – Practical Packets 200 – Torrents Writeup

Posted by aXs

"It turns out that robots, like humans, are cheap and do not like paying for their movies and music. We were able to intercept some torrent downloads but are unsure what the file being downloaded was. Can you figure it out?"

We get a pcap file with the P2P part of a BitTorrent exchange between 2 peers.

Hopefully Wireshark has a fairly complete BitTorrent dissector which we will use to get the "pieces" of data.

According to the protocol specification, data is transferred in pieces that have an index and an offset. We need to extract each pieces with its index and offset and a Python script will reorder them.

tshark -r torrent.pcap -R 'bittorrent.piece.data' -T fields -e bittorrent.piece.index -e bittorrent.piece.begin -e bittorrent.piece.data -E separator=\| > torrents.dump
#!/usr/bin/python

import sys
import struct

if len(sys.argv) ==2:
  print "Parsing "+str(sys.argv[1])
else:
  print "Usage: python "+sys.argv[0]+" file.pcap"
  exit(10)

pcap=file(sys.argv[1],"r")
out=file(sys.argv[1]+".hex","w")

data = {}
for p in pcap:
  a = p.split("|")

  index = int(a[0], 16)
  offset = int(a[1], 16)

  print 'Index', index, 'Offset', offset

  order = "%08x" % index + "_" + "%08x" % offset
  data[order] = a[2].split(":")

for key in sorted(data.iterkeys()):
  print key + "\n"
  for b in data[key]:
    out.write(chr(int(b,16)))

pcap.close()
out.close()

$ file torrents.dump.hex
torrents.dump.hex: bzip2 compressed data, block size = 900k
$ mkdir key ; cd key ; tar xvfj ../torrents.dump.hex
key.mp3
key.txt
$ cat key.txt
t0renz0_v0n_m4tt3rh0rn

The key is: t0renz0_v0n_m4tt3rh0rn

PS: notice the useless MP3 file just to make the archive and so the bittorrent transfer bigger 😉

Share
30Apr/12Off

PlaidCTF 2012 – Practical Packets 250 – 80s Thinking Writeup

Posted by aXs

In this challenge we get a sound wave file named 80s.

Listening to it will immediately bring back some memories if you are in your thirties: DTMF dialing, short modem handshake, data.

The handshake is very short so I guestimated the speed to be 9600 bauds also the overall sound of it was screaming in my brain: "OMG it's a fax!!!1!!"

So it's very simple, it's a recorded fax transfer and you need to decode it to get the fax pages.

This challenge depends very much of your Google-fu. There is many commercial softwares that can decode fax recordings, most for lawful interception purposes. But hopefully, there is a known opensource alternative which is popular in the Asterisk community as the core fax library: SpanDSP

It's a huge library that does many things beside fax decoding so you will need some time to find what you need: a unit test-case for fax decoding!

From there, it's trival, you massage the sound file a bit to 8000Hz and the test-case output a nice TIF file:

The key is: BlastFromThePast^_^

PS: output from fax_decode: fax_decode

Share