==== 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 : * ouverture de la page * check si le lien pour la récupération du flag est là * si oui : on ouvre le lien et on récupère le contenu de la page avec le flag * récupération de la source de la page * modification du javascript * ajout d'une variable ''ret'' au début * ajout de ''ret+={ici la variable du caractère};'' * ajout de ''document.title=ret;'' en fin * parse du code de la page modifié dans ''BeautifulSoup'' * exécution des javascript via ''selenium'' * parse à nouveau du code de la page dans ''BeautifulSoup'' pour récupérer son titre (qui contiendra les caractères) * parse via regex des ''filltext'' pour récupérer leurs variables et positions (c'est là qu'intervient ce que j'ai récupérer dans le titre afin d'avoir le caractère correspondant) * on sort le tableau par la position sur ''x'' (du coup on récupère les caractères du captcha dans le bon ordre) * via ''selenium'' j'exécute du javascript pour renseigner l'input du captcha * via ''selenium'' j'envoi la touche ''ENTER'' pour valider le captcha 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"(\)", "\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)// ----