hxp


hxp CTF 2017: misc100 "drucker" writeup

extract the flag! Download:

83ff3b21362b514c20861c94fb3f68aed3e11ebf81c80f5e1f6ecfcc4ca8ed64.tar.xz

Introduction

The challenge consisted of extracting a flag from a .pcapng-stream, captured while scanning a sheet of paper via USB.

What is observable?

There are quite some USB-packets to and from the scanner. Some of them obviously contain raw data.

Extract the data

As we’re not keen on klicking on each packet with raw data in wireshark and extract the data manually, automating the task is desirable. Fortunately there are some libraries for handling .pcapng. I found pypcappy to be the most usable (or usable at all for that matter).

from pypcappy import PcapNgFile

p = PcapNgFile('ctf.pcapng')
# make packets subscriptable
ps = [p for p in p.packets]

As we only want to extract the raw data, we try to find an easy criterium. Let’s take the packet size. Packets containing data are mostly larger than 1024, others smaller. So let’s filter those out:

# filter out packets containing data, skipping some
dt = [p for p in ps[700:] if len(p.data) >= 1024]

(I also filtered out a protocol-packet that was larger than 1024 byte.)

Write it to a file

I used this little helper funktion:

def w(fn, ps):
    with open(fn, 'bw') as o:
        for p in ps:
            # discard usb header
            o.write (p.data[64:])

w('out_s0_sol.raw', dt)

Recover the Image

I used GIMP as follows:

  • open GIMP (Do not open the image with gimp. Simply open gimp.)
  • select the file with the raw data for opening
  • now you can select the type: Raw Image Data
  • in the dialog we can play with the parameters it should become obvious that two pages have been transmitted
  • as they seem to have different orientation, I cut the raw data in half and had a look at both separately

    # get first page
    dt_s0 = dt[:int(len(dt)/2)]
    # get second page
    dt_s1 = dt[int(len(dt)/2):]
    # write second page
    w('out_s0_sol.raw', dt_s1)
    

The flag turns out to be at the second page with the following parameters:

  • Image Type: RGB
  • Offset: something around 6000
  • Width: 3504
  • Heigh: more than double than width to be sure

The whole script:

from pypcappy import PcapNgFile

def w(fn, ps):
    with open(fn, 'bw') as o:
        for p in ps:
            # discard usb header
            o.write (p.data[64:])

p = PcapNgFile('ctf.pcapng')
# make packets subscriptable
ps = [p for p in p.packets]
# filter out packets containing data, skipping some
dt = [p for p in ps[700:] if len(p.data) >= 1024]
# get first page
dt_s0 = dt[:int(len(dt)/2)]
# get second page
dt_s1 = dt[int(len(dt)/2):]
# write second page (containing flag) to raw data
w('out_s0_sol.raw', dt_s1)

## Then
## - open GIMP
## - select the raw data
## - select type: Raw Image Data
## - in the dialog select
##   - Image Type: RGB
##   - Offset: something about 6000
##   - Width: 3504
##   - Height: more than double than width to be sure