keep doing this until you get bored.
http://ctf.b01lers.com:5125
Author: Dx
Navigate on website, you will have a value to copy and paste in the form.
<html>
<head>
<style>
@font-face {font-family:b;src:url("index.ttf")}
p, input { font-size:3vw; }
span { font-family:b;font-size:2vw; }
input { border: solid 0.4vw;width:60vw; }
</style>
</head>
<body>
<table width="100%" height="100%"><tbody><tr><td><center>
<p>Enter "<span>EIEjtvPAY0fxF4sviaIR90pgg9ob6gFGdBEUihkc</span>" to continue</p><input>
</center></td></tr></tbody></table>
<script>
var input = document.querySelector("input");
input.addEventListener("keypress", function(e) {
if (e.keyCode == 13) {
window.location.href = input.value + ".html";
}
});
</script>
</body>
</html>
We need to navigate in http://ctf.b01lers.com:5125/EIEjtvPAY0fxF4sviaIR90pgg9ob6gFGdBEUihkc.html
to get next page, and we have a new value to copy and paste in the form, until we get flag.
Let’s create a script to do this for us.
import bs4
import requests
import sys
base = "http://ctf.b01lers.com:5125/"
path = "index"
while True:
r = requests.get(base + path + ".html")
soup = bs4.BeautifulSoup(r.text, "html.parser")
path = soup.find("span").text
print(path)
if "bctf" in path:
print("Found flag: {}".format(path))
sys.exit(0)
Code looks running until http://ctf.b01lers.com:5125/x70OK5gxhlPEbhmRRmqhimTOSkTz3oAJUTo2VoC8.html
page, something goes wrong…
Let’s check the source code of the page:
<html>
<head>
<style>
@font-face {font-family:b;src:url("x70OK5gxhlPEbhmRRmqhimTOSkTz3oAJUTo2VoC8.ttf")}
p, input { font-size:3vw; }
span { font-family:b;font-size:2vw; }
input { border: solid 0.4vw;width:60vw; }
</style>
</head>
<body>
<table width="100%" height="100%"><tbody><tr><td><center>
<p>Enter "<span>vBBEO.CpefN.TBsgS.HfjLG.wcZee.qZrhY.TDFdp.mBbei.IbHlG.tmXTZ.XqBtD.LYzBt.upRSj.EOzlj.izClL.oRdKf.CpefN.XceXS.mBbei.XqBtD.qPcfO.IbHlG.qZrhY.TDFdp.DMmXT.adNyQ.JkxgL.hhGEG.hhGEG.kcXxq.tmXTZ.yWzOK.EtLOl.adNyQ.NliRt.hMtRY.jNjpP.rAufC.EOzlj.yRfgC.</span>" to continue</p><input>
</center></td></tr></tbody></table>
<script>
var input = document.querySelector("input");
input.addEventListener("keypress", function(e) {
if (e.keyCode == 13) {
window.location.href = input.value + ".html";
}
});
</script>
</body>
</html>
Span element contains a long string, instead of next page path. Why?
Analyzing the source code, we can see that the font used is a custom font, with a custom name. Let’s check the font file using FontDrop tool, and we can see that the font contains a lot of ligatures:
Span element use a custom font, with ligatures.
Ligatures are a way to combine two or more characters into a single glyph. For example, the “fi” ligature combines the letters “f” and “i” into a single glyph. This is useful for reducing the number of glyphs in a font, and for making text more readable.
Define some usefull function for resolve ligatures:
import bs4
import requests
import sys
from fontTools.ttLib import TTFont
# This is a list of all particular glyphs in the font
replace_map = {
'zero': '0',
'one': '1',
'two': '2',
'three': '3',
'four': '4',
'five': '5',
'six': '6',
'seven': '7',
'eight': '8',
'nine': '9',
'underscore': '_',
'braceleft': '{',
'braceright': '}',
'space': ' ',
'comma': ',',
'period': '.',
'exclam': '!',
'question': '?',
'hyphen': '-',
}
# This function resolves the glyphs to their real text
def resolve_text(text):
for x in replace_map:
text = text.replace(x, replace_map[x])
return text
# This function gets all the ligatures from the font in a dictionary
def get_ligatures(font_path):
font = TTFont(font_path)
ligatures = {}
for table in font['GSUB'].table.LookupList.Lookup:
if table.LookupType == 4:
for subtable in table.SubTable:
for key, value in subtable.ligatures.items():
for glyph in value:
glyph_text = resolve_text(key)
for x in glyph.Component:
glyph_text += resolve_text(x)
ligatures[glyph_text] = resolve_text(glyph.LigGlyph)
return ligatures
# This function resolves the path to the real path using font ligatures
def resolvePath(path, font="font.ttf"):
ligature_table = get_ligatures(font)
for key in ligature_table:
path = path.replace(key, ligature_table[key])
return path
Starting from last point, resolve next steps until we get the flag.
base = "http://ctf.b01lers.com:5125/"
path = "x70OK5gxhlPEbhmRRmqhimTOSkTz3oAJUTo2VoC8"
while True:
# Download the font
r = requests.get((base + path + ".ttf"), allow_redirects=True)
open('font.ttf', 'wb').write(r.content)
# Get the next path
r = requests.get(base + path + ".html")
soup = bs4.BeautifulSoup(r.text, "html.parser")
path = resolvePath(soup.find("span").text)
print(path)
if "bctf" in path:
print("Found flag: {}".format(path))
sys.exit(0)
Script runs until http://ctf.b01lers.com:5125/wDcIyytPUCxMxQB2YGrlQPDuASUp3ueyjeOnDswA.html
is reached.
Something is wrong, we have to check the url. Flag is in <p>
instead <span>
base = "http://ctf.b01lers.com:5125/"
path = "wDcIyytPUCxMxQB2YGrlQPDuASUp3ueyjeOnDswA"
# Download the font
r = requests.get((base + path + ".ttf"), allow_redirects=True)
open('font.ttf', 'wb').write(r.content)
# Get the flag path
r = requests.get(base + path + ".html")
soup = bs4.BeautifulSoup(r.text, "html.parser")
path = resolvePath(soup.find("p").text)
print(path)
bctf{l1gatur3_4bus3_15_fun_X0UOBDvfRkKa99fEVloY0iYuaxzS9hj4rIFXlA3B}