May 10, 2016 - sCTF 2016 Q1 : The Ducks

Author: dade

Publish Date: 2016-05-10

Category: Web Points: 30 Description:

The ducks and I have an unfinished score to settle.


The ducks is a seemingly boring site, only prompting us for a password. But they are kind enough to provide us the source.php document, which shows us the entire source code for the page.

        <title>The Ducks</title>
        <link href="" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
        <script src="" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
        <div class="container">
            <div class="jumbotron">
                    <h1>The Ducks</h1>
                    <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
                        if ($pass == $thepassword_123) { ?>
                            <div class="alert alert-success">
                                <code><?php echo $theflag; ?></code>
                        <?php } ?>
                    <?php } ?>
                    <form action="." method="POST">
                        <div class="row">
                            <div class="col-md-6 col-md-offset-3">
                                <div class="row">
                                    <div class="col-md-9">
                                        <input type="password" class="form-control" name="pass" placeholder="Password" />
                                    <div class="col-md-3">
                                        <input type="submit" class="btn btn-primary" value="Submit" />
                    source at <a href="source.php" target="_blank">/source.php</a>

In source.php we see an if statement that runs if our HTTP verb was POST. Then it extracts the variables from $_POST. Then it compares our $pass variable with the value of $thepassword_123, and if they are equal it will echo us out the flag! We just need to make those two values equal. Luckily, it appears to indiscriminately extract variables from $_POST, so we whip out a tool (Fiddler) to manually send a POST request.


Instead of just submitting the $pass variable in the body of our POST, let’s also submit $thepassword_123. So our POST looks something like

	Content-Type: application/x-www-form-urlencoded;


Now we can see what we got back from the server, and under the The Ducks header, we have an alert with the flag in it!



May 10, 2016 - ASIS CTF Quals 2016: firtog

Author: aagallag

Publish Date: 2016-05-10

Category: Forensic Points: 109 Solves: 113 Description:

Obscurity is definitely not security.


As with the other challenges in this CTF, I start by renaming the file to *.tar.xz and extract the contents. Once extracted, I find a TCP packet capture file called firtog.pcap. I loaded up the capture file into Wireshark and started by checking for HTTP objects with…

File -> Export Objects -> HTTP...

Unfortunately, there aren’t any HTTP objects found.

After checking for HTTP objects, my next step when working with packet captures is usually to inspect the individual TCP streams.

Right Click Packet -> Follow -> TCP Stream

Wireshark lets you quickly switch between the different streams by increasing the Stream counter at the bottom right of the pop-up window. Scrolling through the first couple TCP streams reveals that this is Git traffic.

Now that we know we’re looking at Git traffic, how do we extract the data? There may be cleaner ways of doing it, but I decide to manually dump the raw bytes from each TCP stream. Wireshark makes this really easy. With the ‘Follow TCP Stream’ window open, select only the direction of traffic you would like to capture. In the case of Git, we’re interested in the server’s traffic. By default, Wireshark encodes the data as ASCII, change this to ‘Raw’ and click the ‘Save as…’ button. I did this for each TCP stream.

Then I ran the following command to extract the data from all TCP streams at once.

$ binwalk -e *

This ended up revealing multiple revisions of the Python script used to generate and encode the flag. Using the commit messages (and a little bit of intuition) I realized that this was the final revision of the script.

# Simple but secure flag generator for ASIS CTF

from os import urandom
from hashlib import md5

l = 128
rd = urandom(l)
h = md5(rd).hexdigest()
flag = 'ASIS{' + h + '}'
f = open('flag.txt', 'r').read()
flag = ''
for c in f:
	code = hex(pow(ord(c), 65537, 143))[2:]
	print('%s => %s' % (c,code))
	flag += code
print flag

And additionally, the encoded flag was also checked into the Git repo.


Now my mission is clear! I have to reverse the encoded flag back to the original flag text.


It looks like this is the code we want to crack…

code = hex(pow(ord(c), 65537, 143))[2:]

Since this isn’t a real encryption algorithm, there isn’t any chaining involved. That means that each character of the original message is encoded independently of each other. This makes it very easy to crack!

My approach was to simply pre-calculate the value of all printable ASCII characters and store these in a dictionary. Then to decode a given message, we just lookup the encoded value (key) in the dictionary and it should return the non-encoded value. No different than a decoder ring on the back of a cereal box.

Be sure to drink your ovaltine

So first we must build the decoder ring. Notice, I only chose to pre-calculate values 32-126, as this is the range for printable ASCII characters. If I included too many numbers to pre-calculate, we run the risk of experiencing collisions (2 different plain-text characters could get encoded to the same value).

def build_decoder_ring():
	decoder_ring = {}
	for c in range(32,126):
		code = hex(pow(c, 65537, 143))[2:]
		decoder_ring[code] = chr(c)
	return decoder_ring

My first attempt at decoding the flag had a bug though. The code looked like this…

def crack_encoded_msg(encmsg):
	decoder_ring = build_decoder_ring()

	flag = ''
	i = 0
	while (i < len(encmsg)):
		flag += find_possible_matches(decoder_ring, encmsg[i] + encmsg[i+1])
		i += 2
	return flag

The problem was that not all characters got encoded as 2 hex characters. Some get encoded as just a single hex character. So I tweaked the code to perform a try/catch. If it fails to find a match on 2 characters, it looks for a match on just the first character.

My final solution:

#!/usr/bin/env python

def build_decoder_ring():
	decoder_ring = {}
	for c in range(32,126):
		code = hex(pow(c, 65537, 143))[2:]
		decoder_ring[code] = chr(c)
	return decoder_ring

def find_possible_matches(decoder_ring, two_char):
	return decoder_ring[two_char]

def crack_encoded_msg(encmsg):
	decoder_ring = build_decoder_ring()

	flag = ''
	i = 0
	while (i < len(encmsg)):
			flag += find_possible_matches(decoder_ring, encmsg[i] + encmsg[i+1])
			i += 2
			flag += find_possible_matches(decoder_ring, encmsg[i])
			i += 1
	return flag

def main():
	encflag = open('flag.txt', 'rb').read()
	flag = crack_encoded_msg(encflag)

if __name__ == "__main__":



May 1, 2016 - Google CTF 2016 : For2

Author: aagallag

Publish Date: 2016-05-01

Category: Forensics Points: 200 Solves: 203 Description:

Find the flag.

Attached: capture.pcapng


Upon opening the capture file with Wireshark, it’s immediatly obvious that it contains USB traffic. However, it wasn’t obvious to me what device(s) the traffic is for. I sorted the logs by ‘Protocol’ hoping for a protocol at a layer above USB. Sure enough, there is one USBHID message.

My initial assumption was that this was keyboard traffic. But intuitively, the data didn’t appear to contain keypresses. So after a few moments of looking at the logs, I remembered reading a writeup a few months ago for a CTF in which they were given a capture file containing USB traffic.

Sure enough, I found the writeup! The folks at wiremask have written a great writeup that helped me a tremendous amount in solving this challenge.

Using this filter:


I was able to find the USB vendor and product ID:

idVendor: Logitech, Inc. (0x046d)
idProduct: M90/M100 Optical Mouse (0xc05a)

Yup, looks like a mouse to me!! So I continue following right along with the other writeup.


I extracted the mouse data from the pcap-ng file using tshark.

$ tshark -r ./capture.pcapng -T fields -e usb.capdata > mouse_traffic.txt

Next, I wrote some code to read the mouse data from text into memory.

def parse_traffic_file(traffic_file):
  f = open(traffic_file, 'r')
  lines = f.readlines()
  good_lines = lines[97:]

  mouse_data = []

  for lin in good_lines:
    hex_bytes = lin.strip().split(':')
    b_bytes = ''
    for hx in hex_bytes:
      b = hx.decode('hex')
      b_bytes += b

  data = struct.unpack("bbbb", b_bytes)

  return mouse_data

And finally, plot the mouse traffic onto an image.

#cursor movement in red, mouse clicks are black squares
def plot_mouse_traffic(mouse_data):
  picture ="RGB", (1600, 800), "white")
  pixels = picture.load()

  click_size = 4
  x, y = INIT_X, INIT_Y

  for data_point in mouse_data:
    status = data_point[0]
    x = x + data_point[1]
    y = y + data_point[2]

    if (status == 1):
      for i in range(-1*click_size, click_size):
        for j in range(-1*click_size, click_size):
          pixels[x + i , y + j] = (0, 0, 0, 0)
      pixels[x, y] = (255, 0, 0, 0)

  print('Saving picture...')"mouse_traffic.png", "PNG")



After a little bruteforce to get the capitalization right, I finally get the scoreboard to accept the flag.

Flag: CTF{tHE_cAT_iS_the_cULpRiT}

Complete Python script