February 20, 2013

GiTS 2013 - Writeup for Crypto250, Rabinsbitch

Last weekend I participated in the GitS 2013 CTF for team Clevcode. Here is my writeup for the crypto 250 challenge, called Rabinsbitch.

The challenge consisted of a python script running on a remote server. The goal was to extract the cryptographic keys from the script.

#
#for the answer take the hash of p,q concatenated together as decimal strings
#such as if p=7,q=11 p being by definition smaller you'd hash the string "711"
#please hash with sha512, thank you and g'luck

import math
import operator
import random,struct
import os,SocketServer
import base64 as b64

def encrypt(m,n):
    c=pow(m,2,n)
    return c
def extended_gcd(a, b):
    if b == 0:
       return (1, 0)
    else:
        (q, r) = (a/b, a%b)
        (s, t) = extended_gcd(b, r)
        return (t, s - q * t)
def invmod(a, p, maxiter=1000000):
    if a == 0:
        raise ValueError('0 has no inverse mod %d' % p)
    r = a
    d = 1
    for i in xrange(min(p, maxiter)):
        d = ((p // r + 1) * d) % p
        r = (d * a) % p
        if r == 1:
            break
    else:
        raise ValueError('%d has no inverse mod %d' % (a, p))
    return d

def reste_chinois(la,lm):
    """
    Return the solution of the Chinese theorem.
    """
    M = reduce(operator.mul, lm)
    lM = [M/mi for mi in lm]
    ly = map(invmod, lM, lm)
    laMy = map((lambda ai, Mi, yi : ai*Mi*yi), la, lM, ly)
    return sum(laMy) % M

def decrypt(c,p,q):
    mp=pow(c,(p+1)/4,p)
    mq=pow(c,(q+1)/4,q)
    r1 = pow(c, (p+1)/4, p)
    r2 = pow(c, (q+1)/4, q)

    return (reste_chinois([r1, r2], [p, q]), \
                reste_chinois([-r1, r2], [p, q]), \
                reste_chinois([r1, -r2], [p, q]), \
                reste_chinois([-r1, -r2], [p, q]))    
p=7
q=11
n=p*q
TEST=True
if TEST:
    m=[]
    for x in xrange(200):
        m.append(random.getrandbits(1200))
    print m[0]
    print len(set(m))
    assert(len(set(m))>2)
    i=0
    print decrypt(3,p,q)
    for x in m:
        enc=encrypt(x,n)
        if i%20==0:
            print "ENCRYPTED IS %r" %enc
        i+=1
        assert(x in decrypt(enc,p,q) )

class  SignHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        req=self.request
  req.sendall("You must first solve a puzzle, a sha1 sum ending in 26 bit's set to 1, it must be of length %s bytes, starting with %s"%(len(proof)+5,proof))
  test=req.recv(21)
  ha=hashlib.sha1()
  ha.update(test)
  if (test[0:16]!=proof or ord(ha.digest()[-1])!=0xff or 
            ord(ha.digest()[-2])!=0xff or
   ord(ha.digest()[-3])!=0xff or
   ord(ha.digest()[-4])&3!=3 
   ):
   req.sendall("NOPE")
   req.close()
   return

        leng=struct.unpack("H",req.recv(2))[0]
        s=""
        while len(s) leng:
            req.sendall("Okaly Doakaly")
            req.close()
            return
        i=0
        s=s[::-1]
        for el in xrange(len(s)):
            i+=(ord(s[el])<<(8*el))
        rets=decrypt(i,p,q)
        for el in rets[:-1]:
            req.sendall(str(el)+",")
        req.sendall(str(rets[-1]))


        req.close()


class ThreadedServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
   pass
if __name__ == "__main__" and not TEST:
   HOST, PORT = "", 9955
   server = ThreadedServer((HOST, PORT), SignHandler)
   server.allow_reuse_address = True
   server.serve_forever()

The challenge server first requires the client to compute a proof-of-work to prevent brute-forcing. The client should find a string so that, when concatenated to a seed provided by the server, the last 26 bits of its SHA1 hash are ones. This took approximately one minute with a naive python implementation on the slow machine I had at hand.

The server then accepted an integer c encoded as a byte stream, computed some values using c and returned them. The computations were:

p,q = secret

r1 = c ** (p+1)/4 (mod p)
r2 = c ** (q+1)/4 (mod q)

a, so that  a*r1 = 1 (mod p) and  a*r2 = 1 (mod q)
b, so that b*-r1 = 1 (mod p) and  b*r2 = 1 (mod q)
c, so that  c*r1 = 1 (mod p) and c*-r2 = 1 (mod q)
d, so that d*-r1 = 1 (mod p) and d*-r2 = 1 (mod q)

The hack here is to choose c = 1, then both r1 and r2 becomes 1. d will be congruent to -1 in both modulo p and q, so d = p*q - 1 = M - 1 and M can trivially be computed. We also have that b = p*k - 1 for some integer k. We can now compute p as GCD(M,b-1) and then q=M/p.

The flag were to be computed as the SHA256 hash of the concatenated p and q. This was actually the most problematic part of the problem, due a copy-paste error from the proof-of-work code that used SHA1. The final solution is listed below.

import hashlib, struct
import socket

HOST = 'rabinsbitch.2013.ghostintheshellcode.com'
PORT = 9955

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(132)
proof = data.split()[-1]
print proof


test = ''

x = 0
while True:
   ha = hashlib.sha1()
   ha.update(proof + struct.pack("I",x))
   d = ha.digest()
   if d[-3:] == '\xff\xff\xff' and ord(d[-4])&3 == 3:
      test = proof + struct.pack("I",x)
      break
   if d[-2:] == '\xff\xff':
      print "Close..."

   x += 1
   #assert x & (2**32 - 1) != 0, "Could not find matching proof!"

print "Found proof %r" % test

s.send(test)


i = 0x1

toSend =''
while i > 0:
   toSend += chr(i%256)
   i = int(i/256)

datagram = struct.pack('H', len(toSend)) + toSend
s.send(datagram)
result = ''
tmp = 'asdf'
while tmp != '':
   tmp = s.recv(999)
   result += tmp

#result = "1,16941066001474695845719308384813140784186795259157054765289986998445863711720505625812362392697741205506049415906549237302653271360565551697039440068630125139408726686167733805604385582596700326652668377493932061724923381450000827786706063473133681438897765791275734911181038668585952430992240545833488889467911361773431544879600184386683684500892680154414816031266754352400273467267938247266548887205133112948093607346676644817468289304022898908247554057630196442472940983356348803549279910983869343866117264685687034360294868608260912165854176452135379353057412438116196758723769316960521491688495464097529269456197,5634409376365928014416246503986138236992108737039947072941477791958438637877531730514281925969449690964163598045979764319142248921381193502060187717633426958368050694066134300481039643146320871981320853532778576589804902495007704046087597562459337727373717481169459494040528451601731742862806515204023196360495905604537025264792329270035269210755345238017503967990869306160108267542185442376337836021860709096121093532913732125456749131910969411738108129561943901454827954858124025207923012141584943546695856004655276250645522524369645338890458467726951800793914414373991692269936254513675131200905511369778088032944,22575475377840623860135554888799279021178903996197001838231464790404302349598037356326644318667190896470213013952529001621795520281946745199099627786263552097776777380233868106085425225743021198633989231026710638314728283945008531832793661035593019166271483272445194405221567120187684173855047061037512085828407267377968570144392513656718953711648025392432319999257623658560381734810123689642886723226993822044214700879590376942925038435933868319985662187192140343927768938214472828757202923125454287412813120690342310610940391132630557504744634919862331153851326852490188450993705571474196622889400975467307357489140"

[a,b,c,d] = map(int, result.split(','))

M = d+1
pk = b+1

from fractions import gcd

p = gcd(M,pk)
q = M/p

toHash = 'p=0x%x,q=0x%x'%(p,q)
print toHash

ha = hashlib.sha256()
ha.update(toHash)
print 'Solution:', ha.digest().encode('hex')

I liked the proof-of-work mechanism, there were no problems with overloaded servers. See you all at the Codegate quals in early March!

November 29, 2012

MSP430 LaunchPi - expansion board for the Raspberry Pi


So I got my Raspberry Pi a few days ago. (Time from order to delivery was one business day from http://lawicel-shop.se/ .) As I have been playing a bit with the MSP430 Launchpad lately, I thought it would be nice to interface MSP430 microcontrollers with the Raspi. Why not make an expansion board? Inspired by the MSP430 Launchpad, this is what I ended up with:


The expansion board, which I would like to call the MSP430 LaunchPi, is fully pin-compatible with the normal Launchpad (except for the touchbutton, wich I never used anyway). The TX/RX pins are easy to connect with the Raspi UART (GPIO pins 8 and 10) and all GPIO pins from the Raspi are accessable.

Just as on the original Launchpad, the leds and uart connections are configurable using jumpers or double female connectors.

I plan to create a hardware driver for mspdebug to be able to program the board using the GPIO pins 11 and 13 on the Raspi.


Building process

The time from idea to finished board was approximately four hours, the priority was to make something that worked. The design was done using pen and paper.
 In hindsight, it would have been easier to use wirewrap female headers (Arduino stackable) but I used normal female headers with bent legs and soldered these on the solder side of the board.
 I accidentally cut one copper strip, the one leading 3.3 V from the header. Fixed it with some wire.
 I wanted more space on the top of the board to be able to easily change the microcontrollers, so I chose to mount a 47k SMD resistor on the soldering side to pull-up the reset pin.
 After soldering headers, leds, jumpers and resistors, I connected it to the Launchpad. It worked! =)

Plugged in the Raspi. The Test and Reset pins of the MSP430 does not like the default state of the Raspi GPIO pins 11 and 13, so these are disconnected for now.

I had problems connecting to the serial port at first, this was because a getty was connected to the serial port. I disabled this in the file /etc/inittab and rebooted the Raspi.

pi@raspberrypi ~ $ tail -3 /etc/inittab
#Spawn a getty on Raspberry Pi serial line
#Commented out for use with the MSP430 LaunchPi
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
pi@raspberrypi ~ $


I had previously loaded the MSP430 with a UART test program (source code available at https://github.com/LarsH/msp430-uart).

pi@raspberrypi ~ $ screen /dev/ttyAMA0 9600

...

Unknown command.
>>>?
Uart test program
Commands:
r: blink red led
g: blink green led
t: read temperature sensor
?: print this help
>>>r
Blinking red led...
>>>g
Blinking green led...
>>>t
Temperature: d6b4
>>>


Success!

Finally I noticed that I forgot to make the green led optional, I resoldered the board a bit to make it possible to disconnect. I also moved the resistor so that I can use the led with another pin and a double female connector. Here are pictures of the final board. Wire colors are red/black for 3V/Gnd, green/yellow for UART Rx/Tx and blue/white for reset pull-up/green led.



July 23, 2012

The inner workings of a keycard terminal

I recently got my hands on an old key-card terminal. I decided to take it apart and figure out how it worked.

It is quite heavy for its size, the case is made out of 2mm thick stainless steel. It weighs about 0.7 kg.

The front is attached to the main pcb with 7-wire connector. It turned out to be an ordinary 4*3 button array. The connected wires were:
Rows, top-down: brown, blue, green, white
Columns, left-right: black, red, purple
The pcb is all through-hole technology. There is no microcontroller, no epoxy blobs and all the IC's are from the 74HC and 4000 series, so the circuit should be fairly easy to reverse engineer.

The card reader was easily removed.

Swedish quality.

I guess this board was manufactured in march 1999. I could not find any information on ASI konsult, but Teletron was a Swedish security systems company that merged with ISEC in 2002 and was declared bankrupt in 2003.

I thought the card reader could be a good part to start analyse. The first hit on google revealed the datasheet! =) It is a single track reader for track 2 of a magnetic card. I hooked it up to my BusPirate:

I used the raw-bitbang-mode of the BusPirate to read out data from the data and clock lines. With a few lines of python code I ended up with this plot after swiping an old discount card:

The blue line is the clock and the red is the data line. (The units on the horizontal axis are the sample numbers.) This looks very much like figure 2-2 in the datasheet.

Sampling the data for every falling edge on the clock resulted in this binary data:

...0000000011010100111110010101010000100011001000100100010011110010110101000111001001100001001001011010000010000000101000111110111000000000...

The Wikipedia article on magnetic cards describes the format of track 2. With this information, the bits were decoded to:

;9752238293627904=1109?6
Wich is the card number and expiration date. The '6' in the end is the checksum; all values xor:ed together should equal 0.

This started out well, I'll have a closer look at the PCB later on.