# Google CTF 2017 Quals: Introspective CRC

Posted 2017/06/21. Last updated 2017/06/21.

## Introduction

This past weekend, I participated in Google's 2017 CTF Qualifiers as the captain of the Oxford team, Ox002147. This was quite likely the hardest CTF we've done, but we still did well, placing 59/1977. I wanted to share the solutions to some of the problems I solved, starting with a crypto one, called "Introspective CRC". The description merely says:

We saw https://shells.aachen.ccc.de/~spq/md5.gif and were inspired. Challenge running at selfhash.ctfcompetition.com:1337

The link is to an animated GIF that shows its own MD5 hash, but the challenge does not have any source code. Time to explore!

## Understanding the Task

I connected to the server using `nc selfhash.ctfcompetition.com 1337`

, and gave it some data (seen in red):

```
Give me some data: AAA
Check failed.
Expected:
len(data) == 82
Was:
3
```

Clearly, the server expects 82 characters. Sending the output of `python -c 'print "A"*82'`

to the server gives us a different response:

```
Expected:
set(data) <= set("01")
Was:
set(['A'])
```

OK, so let's send 82 zeros instead:

```
Expected:
crc_82_darc(data) == int(data, 2)
Was:
1021102219365466010738322L
0
```

Right, so the CRC-82/DARC of what we send (interpreted as ASCII) needs to match what we send interpreted as a binary integer.

## Exporing the CRC

A Cyclic Redundancy Check (CRC) is, broadly speaking, the remainder of a polynomial division, typically over the polynomial ring **F**_{2}[X], so that coefficients are interpreted mod 2. In other words, the data to be checked is expressed as a binary number, whose bits are then interpreted as the coefficients of the polynomial to be divided. For example, the binary number `0b1011`

would be interpreted as the polynomial `X`

. The divisor used is typically expressed as a number ^{3} + X^{1} + 1`d`

, and a width `W`

, with the actual polynomial being `D=(1 << W) | d`

. Note: there are some intricacies with whether inputs and outputs need to be modified by XORing or swapping bits and bytes, but they are tangential to this high level discussion, and are only reflected in the code linked below.

For CRC-82/DARC, `W=82`

and `d=0x308c0111011401440411`

. Moreover, character "`0`

" is expressed as `00110000`

in binary, while "`1`

" as `00110001`

. Let the desired value be

, where **a**=a_{W-1}a_{W-2}...a_{0}`a`

. Let _{i}∈{0,1}`b`

denote the exponent to which the LSB of _{i}`a`

corresponds, which is the only difference in the two characters. With _{i}`P`

, the polynomial corresponding to the desired value _{i}=X^{bi}`P`

is related to the polynomial corresponding to the all _{a}`0`

s string by the following equation: `P`

, where the equation holds in _{a}=P_{0} + ∑a_{i}P_{i}

.**F**_{2}[X]

Let `R`

denote the (polynomial) remainder in the division of _{x}=∑r_{x,j}X^{j}`P`

by _{x}`D`

. Then the same equation as above holds: `R`

. This is a _{a}=R_{0} + ∑a_{i}R_{i}**polynomial** equality, and `R`

by assumption, so for _{a}=∑a_{i}X^{i}`0 ≤ i ≤ W`

, the following holds:

`a`

, where the sum is over _{i}=r_{0,i} + ∑a_{j}r_{j,i}`j=0,...,W-1`

. This equation on the coefficients is now an equation that holds in

, i.e., modulo 2. We just now simply need to solve this system of equations!**F**_{2}

## Putting It All Together

In CTFs, solving a problem quickly is more important than the quality of code. For that reason, I decided to take a mixed approach in my coding. At first, I calculated the remainders in Python, using the pwntools library that the problem was likely also using, and which contains an implementation of `crc_82_darc`

that I could dig into and understand. As I didn't readily find a Python library that can solve systems of linear equations in a field other than the real numbers, I decided to solve the equations in Mathematica, and then verify the solution in Python. My code is on my Github, and is sufficiently well-commented. The polynomials are setup by replicating the `pwntools`

code, and the code ensures that the bit ordering is respected.

Solving the problem in Mathematica reveals that the equations are under-specified, so there are, in fact, two possible solutions: `1010010010111000110111101011101001101011011000010000100001011100101001001100000000`

and `1111110111111011001110001110101000001010101001100111010000100000010011101011100010`

. Connecting to the server and sending either of these two solutions finally reveals the flag: `CTF{i-hope-you-like-linear-algebra}`

!