VolgaCTF 2015 captcha
@mrexcessive WHA
& @DeathsPirate WHA
The problem
We've got a rather strange png file. Very strange png. Something isn't right about it...
The solution
So foremost reveals tehre are 1892 PNG files in here
Pull them all out... they each have a single character.
DeathsPirate mentions in teamchat that he's found that if you take the images one by one in sequence number order, you get characters for base64 which decodes to a PNG file header...
(decimal) 137 80 78 71 13 10 26 10 (hexadecimal) 89 50 4e 47 0d 0a 1a 0a (ASCII C notation) \211 P N G \r \n \032 \n
We're all working on something else then...
But at about 3am.. sigh...
I think, so maybe... are the same characters represented by identical files - so I could hash the files.. store the hashes and then only have to show a human the things to recognise once per character..
Yes !
Phew...
OK ... I can code this before bedtime... (author's note, during CTFs bedtime is approximately equal to point of maximum coffee dosage, when the production of melatonin has caught up with the absorption of caffeine and any further coffee will not help.
So... some python later.
#!/usr/bin/python # try.py for VolgaCTF / captcha # categorise lots of png files, only ask for new hashes # @mrexcessive @WHA - solving algos and python import os, sys, code import readline, rlcompleter import socket,time import random import re import itertools import subprocess import operator import hashlib from PIL import Image pngfname = "output/png/0000%04i.png" outputfile = "myoutput.png" progressfile = "hashes.txt" filehashes = {} debug = True flagGoInteractive = True # go interactive after running stuff alphanums = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" printables = alphanums + ".,<>?/!$%^&*()_-+=@'#][{}`#" #useful def GetLoadsOfRandomForSeed(seed): p = subprocess.Popen(['./random', '%i' % seed, '%i' % count], stdout=subprocess.PIPE, stderr = subprocess.PIPE) out,err = p.communicate() randomstrings = out.split() def Log(s,alwaysLog = False): if logfname <> None: f=open(logfname,"a") f.write("%s\n" % s) f.close if debug: print s def SerialiseProgress(): global filehashes ser = "" for k in filehashes.keys(): ser += "%s=%02x\n" % (k,ord(filehashes[k])) WriteOutput(progressfile,ser) def RestartProgress(): global filehashes filehashes = {} if os.path.isfile(progressfile): ser = "" f=open(progressfile,"rb") data = f.read() f.close() h = data.split("\n") for d in h: if "=" in d: (key,hexvalue) = d.split("=") filehashes[key] = hexvalue.decode("hex") def WriteOutput(fname,data): f = open(fname,"wb") f.write(data) f.close() if __name__ == "__main__": vars = globals() vars.update(locals()) readline.set_completer(rlcompleter.Completer(vars).complete) readline.parse_and_bind("tab: complete") shell = code.InteractiveConsole(vars) RestartProgress() output = "" for i in xrange(0,3169): # file numbers fname = pngfname % i if os.path.isfile(fname): f = open(fname,"rb") data = f.read() f.close() m = hashlib.md5() m.update(data) dig = m.hexdigest() if filehashes.has_key(dig): output += filehashes[dig] else: im = Image.open(fname) im.show() sys.stdout.write("\nImage Char :") sys.stdout.flush() d = raw_input() ch = d[0] filehashes[dig] = ch SerialiseProgress() output += ch print output WriteOutput(outputfile,output) # go interactive if flagGoInteractive: shell.interact()
Run the program... look at about 60 images... type in a single letter.
Make no massive mistakes. Good job I made the program restartable!
Get Capital I and lowercase l mixed up... Fix that by deleting rows from the hashfile and running again - get re-asked just those two.
Now we have a base64 string:
iVBORw0KGgoAAAANSUhEUgAAARAAAACDCAIAAADK7dMbAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAUfSURBVHhe7dhtYtowEEVR1sWCWA+rYTNdTOqRhTSjD6NHEmjSe37Z8kgaGV6T9PQBYBmBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEQmD+XM+n0+l8/ZPvB6zkcss3/53b5TQ4/fSdjMvf7zd9iOk7mw9j7/vzb3w9MOU9piZ6lqRvetf+2JKnJz6lJsDvO30nBOb7NV+ALzjaemAGn283JDe09qVpjr3u6YlPITDvNvxCut+JvuBoPyIwP8T4MATmdYZfyDcGpv37Zdjf5WbD5be0O3t0t8/xIw++OmGjsvym7ajlJq71lou3svP1tg/vlX3/SR0+X691s5V9Xc1msv6ITXTt28x8O1xkbyDfNLuOTBsert8049YfNjOzFW+rrG5qSu3Gyn1ZLdyq3FpW87CVY8uBGe1VX062N507tKf5Mkz2s7oVxmqZreTf5gNu/aPefD/p0p67zkKNa8GPhymzfdsJviZf+/UnbGapKOVhkdTNfmPj9+Gw60Ra576+2yqsU5dZaKaMzoVN3WS7HGw6WbE/3Dbi6/oC1Vpgmm3vuu3D8Wbd+cMuHsCV2eWolzE3cdLb+NXHvtqa7Wm6bcbdpOm+7km9mq0/5SaUS7dlUu5jA21Zb6l+1IG7dGPJ0oncNuNd3apW0K/YTxts/LCXQ8s/YUZH6Mbisf1je+LcOx6tOhDL7C6sMucmTnobdxBHm+YTe9rMdbfuMu7rntSr2fpzNiOdvly0zdT72EBb1pvXN33eX/+gmaYyOdw1bup3nWy61wyG4jbbSH3sO3zWd/wNk2/q43TmMu6b7k84NC6z0QendxMPeusXiRuOa7pxN2m6r93l21ozW//IPtstHlt297GBtqw3qXed57vScr5xE8PjFW7upky3i8mmhXWYRx8ebiuQ2upJgWmb6YbiscvjcGwbLV3bzcIJBntvxu8vcBMnvXXNpctmw1DjWFnuIJWUombfWDWpGax/xKa7HfPA/c515jfaJx3vZM3UijI59JjWce9+uz9fLm6eeqJU37+lw00zq8mjVhEKmjbsVmhq5CWByY3v0v8mlVOVB4fnqCvZVXU4yTQt1PrQuls0j4XHiTuBuT+sw7N/7rfR8h9um/p5xj0m6x/Yuw6F7iDhe1PGQ5MTsSKeJC/TfIibQTPSifZNS5916fGm7qCbunSp9i3Hx8d9PPSpwOCd7NMPsfjJvuCrvOClgXnNkbDqV+XlNwYm7db8qP9K8ads9fCAT0/8xx2f65N5ectLO9j0BYFJu3/66ysEBgCBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBhAQGEBAYAABgQEEBAYQEBhAQGAAAYEBBAQGEBAYQEBgAAGBAQQEBlj28fEX4wPz1G62YicAAAAASUVORK5CYII=
OK... so decode that,
Python 2.7.3 (default, Mar 13 2014, 11:03:55) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import base64 >>> f=open("op.txt","rb") >>> d=f.read() >>> f.close() >>> pic=base64.b64decode(d) >>> f=open("flag.png","wb") >>> f.write(pic) >>> f.close() >>> # to the gimp-mobile... ... # it's a thing... ...
look at the image.. and ... FLAGG !!!