HACK.LU 2014 : Dalton's Corporate Security Safe for Business

The Dalton Brothers are tricking people into buying their “safe” locks. So they can rob them afterwards. The lock has some safety features, as it resets itself after a few seconds. It also requires a lot of valid inputs before it's letting you open it. Please find out what their weakness is and report back.


On arrive sur une page où il faut entrer un captcha.
En le faisant manuellement la même page reste affiché, le capctha change et un message s'ajoute :
Good . Let's continue !

Manuellement ce n'est pas possible de tenir la cadence et de rentrer à la suite et rapidement les captcha.
Regardons le code source de la page pour chercher comment est gérer le captcha.

Voici la partie javascript nous interressant :

var j=c.getContext('2d');
var p=j.createLinearGradient(0,0,c.width,0);
p.addColorStop('0','#b870cb');
p.addColorStop('1.0','#c4815b');
j.fillStyle=p;
j.font='bold 13px verdana';
var k=String.fromCharCode(51);
j.fillText(k,5,19);
var m=j.createLinearGradient(0,0,c.width,0);
var u=String.fromCharCode(53);
m.addColorStop('0','#d6070f');
m.addColorStop('1.0','#8ca117');
j.fillStyle=m;
j.font='bold 13px verdana';
j.fillText(u,71,15);
var h=j.createLinearGradient(0,0,c.width,0);
h.addColorStop('0','#a08abd');
h.addColorStop('1.0','#e0957a');
var m=(8).toString(36);
j.fillStyle=h;
j.font='italic 15px serif';
j.fillText(m,33,15);
var r=j.createLinearGradient(0,0,c.width,0);
r.addColorStop('0','#54dd67');
var u=atob('Yg==');
r.addColorStop('1.0','#f560da');
j.fillStyle=r;
j.font='bold 12px helvetica';
j.fillText(u,44,18);
var x=j.createLinearGradient(0,0,c.width,0);
x.addColorStop('0','#66de78');
x.addColorStop('1.0','#3c300a');
j.fillStyle=x;
j.font='italic 15px serif';
var w=([]+{})[5];
j.fillText(w,54,15);
var z=j.createLinearGradient(0,0,c.width,0);
z.addColorStop('0','#d8033a');
var l=([][+[]]+"")[4];
z.addColorStop('1.0','#1e62a1');
j.fillStyle=z;
j.font=' 16px verdana';
j.fillText(l,22,18);
var o=/0/.source;
var y=j.createLinearGradient(0,0,c.width,0);
y.addColorStop('0','#5264ab');
y.addColorStop('1.0','#3562d3');
j.fillStyle=y;
j.font='bold 11px courier';
j.fillText(o,65,19);
var l=j.createLinearGradient(0,0,c.width,0);
l.addColorStop('0','#653711');
l.addColorStop('1.0','#e6a5ed');
j.fillStyle=l;
j.font='bold 13px helvetica';
var e=String.fromCharCode(50);
j.fillText(e,11,15);

On a donc un captcha généré uniquement via du javascript, cool on va pouvoir surveiller tout ça et résoudre les captcha avec un 100% de réussite ;)

On remarque les fillText qui permette d'afficher du texte à des coordonnées x et y.
Il va donc falloir récupérer tous les caractères ainsi que leur position afin d'en déterminer l'ordre.

C'est avec Python et les librairies BeautifulSoup et selenium que je vais bosser.
BeautifulSoup : pour parser le HTML
selenium : pour jouer avec le javascript

Voici comment je vais procéder :

Mon script pour résoudre ce challenge :

# -*- coding: utf-8 -*-
 
'''
	HACK.LU CTF 2014
	Dalton's Corporate Security Safe for Business (Web 200)
 
	Python resolver by Krach
	contact{at}krach.me
'''
 
import re
import time
from BeautifulSoup import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from operator import itemgetter
 
 
if __name__ == "__main__":
	f = webdriver.Firefox()
	f.get("https://wildwildweb.fluxfingers.net:1422")
 
	counter = 0
	while True:
		counter += 1
		content = f.page_source
		#open("page_%d.html" % counter, "w").write(content)
		try:
			secZone = f.find_element_by_link_text("Security Zone")
			if secZone:
				secZone.click()
				content = f.page_source
				open("page_SecurityZone.html", "w").write(content)
				print content
				break
		except:
			print "Security Zone not found"
 
		content = re.sub(r"(\<script\>)", "\g<1>var ret='';", content)
		content = re.sub(r"([a-z]\.fillText\(([a-z])\,[0-9]{1,2}\,[0-9]{1,2}\);)", "\g<1>ret+=\g<2>;", content)
		content = re.sub(r"(\<\/script\>)", "document.title=ret;\g<1>", content)
 
		soup = BeautifulSoup(content)
 
		scripts = soup.findAll("script")
		for script in scripts:
			print "execute script"
			f.execute_script(script.string)
 
		content = f.page_source
		soup = BeautifulSoup(content)
 
		chars = soup.title.string
		if not chars: exit(1)
		if len(chars) != 8: exit(1)
		print "chars : %s" % (chars)
 
		listing = re.findall(r"[a-z]\.fillText\(([a-z])\,([0-9]{1,2})\,([0-9]{1,2})\)", content)
		l2 = []
		for i in range(0, len(listing)):
			bufList = list(listing[i])
			bufList[0] = listing[i][0]
			bufList[1] = int(listing[i][1])
			bufList[2] = int(listing[i][2])
			bufList.append(chars[i])
			l2.append(tuple(bufList))
		listing = sorted(l2, key=itemgetter(1))
 
		captcha = ""
		for i in listing:
			print i
			captcha += i[3]
 
		f.execute_script("var sol=document.getElementsByName('solution');sol[0].value='%s';" % (captcha));
 
		inputTxt = f.find_element_by_name("solution")
		inputTxt.send_keys(Keys.ENTER)
 
		time.sleep(1)
 
#  Result : 
#    https://wildwildweb.fluxfingers.net:1422/?login=rRrtTE0WYFh5bVHToYQwKyvP
#    FLAG :D :D fef9565c97c3a62fe10d2a0084a9e8179d72f4a05084997cb80e900d1a77a42e3

Par Krach (contact{at}krach{dot}me)