Skip to content

Instantly share code, notes, and snippets.

@Kwpolska
Created September 21, 2017 10:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kwpolska/51d8350b73b03a9dc913c0715502c574 to your computer and use it in GitHub Desktop.
Save Kwpolska/51d8350b73b03a9dc913c0715502c574 to your computer and use it in GitHub Desktop.
Gynvael’s Mission 15 (en): a writeup by Chris Warrick

Gynvael’s Mission 15 (en): A writeup by Chris Warrick

(Spoilers ahead!)

the chart

I started solving the mission by opening the chart with GIMP and measuring the first few lines. I found out that the first red bars are:

 60 63 112 104 112 10 10

Then, I used Python’s chr() and converted them to letters. I got:

'<?php\n\n'

It became obvious that the height of every red bar is equal to an ASCII code. I wrote a short, hacky Python script using Pillow (02_read_chart.py) to count red pixels in each vertical line and convert it to text.

The result is 03_pass.php — a simple PHP script that checks a 25-character password using MD5. The password is checked twice: once as a whole, and then in 5-character sums. Brute-forcing 5-character strings is much easier than 25-character strings, so that can help us.

How do we proceed from now? A good way to start is to ask Google about each of the 6 sums. I actually found someone else’s solution (with passwords blanked out; I didn’t look any further at that). I also found the last sum — it’s ious!.

We can start brute-forcing now. I wrote yet another hacky Python script — 04_brute_md5.py, which uses Python 2 to avoid .encode() roundtrips. I started by running it with string.ascii_lowercase on all of the 5 fields, and I ended up with

*****harts*****delicious!

So, we can start guessing. Those are bar charts, so perhaps the first part is bar?c? Well, not quite. I started a brute-everything (all printable ASCII) process in the background, but also tried other guesses. Eventually I found that the middle fragment is are (with spaces around). Then another idea came to me: perhaps “bar” misled me there? I tried pie?c — and sure enough, Pie c matched the first fragment.

Final password: Pie charts are delicious!

#!/usr/bin/env python3
from PIL import Image
img = Image.open("01_chart.png")
for byte in range(693):
bvalue = 0
for i in range(300):
px = img.getpixel((byte, i))
if px == (255, 0, 0): # count red pixels
bvalue += 1
print(chr(bvalue), end='')
<?php
if (!isset($_GET['password']) || !is_string($_GET['password'])) {
die("bad password");
}
$p = $_GET['password'];
if (strlen($p) !== 25) {
die("bad password");
}
if (md5($p) !== 'e66c97b8837d0328f3e5522ebb058f85') {
die("bad password");
}
// Split the password in five and check the pieces.
// We need to be sure!
$values = array(
0 => 'e6d9fe6df8fd2a07ca6636729d4a615a',
5 => '273e97dc41693b152c71715d099a1049',
10 => 'bd014fafb6f235929c73a6e9d5f1e458',
15 => 'ab892a96d92d434432d23429483c0a39',
20 => 'b56a807858d5948a4e4604c117a62c2d'
);
for ($i = 0; $i < 25; $i += 5) {
if (md5(substr($p, $i, 5)) !== $values[$i]) {
die("bad password");
}
}
die("GW!");
#!/usr/bin/env python2
from __future__ import print_function
import hashlib
import itertools
import string
md5_fragments = [b'e6d9fe6df8fd2a07ca6636729d4a615a', b'273e97dc41693b152c71715d099a1049', b'bd014fafb6f235929c73a6e9d5f1e458',
b'ab892a96d92d434432d23429483c0a39', b'b56a807858d5948a4e4604c117a62c2d']
# SPOILERS AHEAD!
md5_recovered = {
# 'e6d9fe6df8fd2a07ca6636729d4a615a': 'Pie c', # guess
# '273e97dc41693b152c71715d099a1049': 'harts', # ascii_lowercase
# 'bd014fafb6f235929c73a6e9d5f1e458': ' are ', # guess
# 'ab892a96d92d434432d23429483c0a39': 'delic', # ascii_lowercase
'b56a807858d5948a4e4604c117a62c2d': 'ious!', # google
}
L = string.ascii_letters
C = string.punctuation + string.digits + ' '
def do(src):
for chars in src:
fragment = ''.join(chars).encode('ascii')
#print(fragment)
md5sum = hashlib.md5(fragment).hexdigest()
if md5sum in md5_fragments:
print("FOUND: ", md5sum, "=", fragment)
do(itertools.product(*((string.ascii_lowercase,) * 5)))
do(itertools.product(C, 'Aa', 'Rr', 'Ee', C))
do(itertools.product('Pp', 'Ii', 'Ee', C, 'Cc'))
password = ''
for f in md5_fragments:
password += md5_recovered[f]
print("PASSWORD:", password)
md5sum = hashlib.md5(password).hexdigest()
if md5sum == b'e66c97b8837d0328f3e5522ebb058f85':
print("SUM MATCHES!")
else:
print("SUM DOES NOT MATCH")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment