# Square CTF 2018 - C8: CAPTCHA
## DescriptionCharvises (the native species which lived on Charvis 8HD before the first settlers arrived) were very good at math. In a surprising symbiosis relationship between humans and Charvises, it was agreed that the Charvises would be responsible for C8.
Can you pass their CAPTCHA (Completely Automated Public Turing Test to tell Charvises and Humans Apart)?
### DetailsYou get the url to a website showing some lenghty equation that needs to be solved (in time(!)) and the result needs to be submitted.
Looks like this:![captcha.jpg](captcha.jpg?raw=true "captcha.jpg")
The problem here is that you cannot just copy and past the quation string from screen/source since the page provides a custom font the text to render.So the real text would more look like this:```FFx G FFFi P BDz G BDz G FFBD P FY G Yzz G FFi G pz G fzzzz n FFFx P FM G Mzz P FFFx n FO n FB P pzzz P Ff G Fr n rzzz G FFFY n Mz n Mz G fzzz G FFFY P iz G Mz G FFFFf n Fr n izz P Mz P FM P FFB G Yz P Mzzz n FFFi n FFx P BDz P fzz G rz G FFB G FBD G pzz P FFFx n rz G Mz G FFBD G fz G FY G izzzzzzzzz```
From here one would think you could just (note: you still would need those symbols) map the letters to the equation symbols. For example map letter **'F'** to symbol **'('**. But unfortunately the equation itself obviously has to change every time but so does the mapping itself.And of course you do not have plenty of time to do so, so its necessary to script this whole process.
## Solution(s)
1. Be Charvises or a really fast at typing2. Grab the screen and try extracting the equation via OCR, produce a string, calc & submit result3. Grab the source and analyze the font mapping, grab the equation as letters, transform to equation string via the found mapping, calc & submit result
### 1. Be CharvisesNot for me
### 3. OCRI came up with this [script](get-page-as-image.py) and did also manual tweaking but the results were rather dissapointing and not very reliable. For example looked like this:```«(1 x (10 + (9 + 4)))x<<<<<1o + e) + a) + (<3 x <6 — a» + (2 + (e x 4))» x (a + 3)) + (5 x ((4 x 7) x <2 x 4)))» x «(((e — ((6 +10)x($16533) + 1) 7 (10 7 9)) x (a 7 (((«2 + 9) 7 «e 7 4) + (v 7 (s 7 10))» 7 9)71)+([\w\s]+).*name="token" value="(\d+).*"', r.text)if match:    ttfb64 = match.group(1)    eqstr = match.group(2)    token = match.group(3)

ttf = open(ttffile, "wb")ttf.write(base64.b64decode(ttfb64))ttf.close()```
#### Analyze fontYou can then use fonttools ttLib to parse the file and access the tables. However I had trouble to get to the contours information via the lib so the (faster) workaround here was to use the **ttx** tool that comes with fonttools.
```$ ttx -t glyf -g -d glyphs_ref/ captchattf```This generates one file for each glyph, we have basically 15 named like glyphs_ref/glyph000[01..15].ttxThere's a number zero as well, you can see in the image below how thos glyphs might really look like and that we have the same at position (aka ID) zero and one. Zero is kind of an default ID, for now we just need 1-15.![glyphs](read_font_online_download_4_glyphs_Screenshot.png?raw=true)
Looking at this, and I mentioned it earlier, what changes in the file here is which glyph gets assigned to which ID. But the relation between the glyph symbol itself and its contour is exactly the same all the time. Therefore if you generate the files from the glyph table with ttx command shown above you will get (almost) the exact same files.For the same glyph the will only differ in the name attribute.Show below are lines from those files were I added a **sym** attribute that will map the glyph sym to this file. Then we can do a lookup glyph contour to symbol.
```    <TTGlyph sym="9" name="glyph00001" xMin="0" yMin="0" xMax="561" yMax="689">    <TTGlyph sym="7" name="glyph00002" xMin="0" yMin="0" xMax="510" yMax="696">    <TTGlyph sym="4" name="glyph00003" xMin="0" yMin="-3" xMax="576" yMax="690">    <TTGlyph sym="5" name="glyph00004" xMin="0" yMin="0" xMax="531" yMax="690">    <TTGlyph sym="*" name="glyph00005" xMin="0" yMin="0" xMax="444" yMax="481">    <TTGlyph sym="6" name="glyph00006" xMin="0" yMin="0" xMax="544" yMax="679">    <TTGlyph sym="2" name="glyph00007" xMin="0" yMin="0" xMax="497" yMax="704">    <TTGlyph sym=")" name="glyph00008" xMin="0" yMin="-128" xMax="290" yMax="747">    <TTGlyph sym="3" name="glyph00009" xMin="0" yMin="0" xMax="548" yMax="684">    <TTGlyph sym="-" name="glyph00010" xMin="0" yMin="0" xMax="465" yMax="347">    <TTGlyph sym="8" name="glyph00011" xMin="0" yMin="0" xMax="569" yMax="689">    <TTGlyph sym="+" name="glyph00012" xMin="0" yMin="0" xMax="495" yMax="519">    <TTGlyph sym="(" name="glyph00013" xMin="0" yMin="-128" xMax="290" yMax="747">    <TTGlyph sym="1" name="glyph00014" xMin="0" yMin="0" xMax="311" yMax="673">    <TTGlyph sym="0" name="glyph00015" xMin="0" yMin="0" xMax="585" yMax="660">```
So we still need another mapping of the actual ascii letter shown in the html source and the glyph symbol. The ttf file provides the cmap table which does a mapping between ascii letter and glyph name (aka the glyphID). Table looks like this for example, note this mapping changes as well in each new  ttf file:```  <cmap>    <tableVersion version="0"/>    <cmap_format_4 platformID="0" platEncID="3" language="0">      <map code="0x42" name="glyph00005"/>      <map code="0x4b" name="glyph00006"/>      <map code="0x50" name="glyph00003"/>      <map code="0x52" name="glyph00002"/>      <map code="0x53" name="glyph00012"/>      <map code="0x54" name="glyph00001"/>      <map code="0x56" name="glyph00013"/>      <map code="0x58" name="glyph00009"/>      <map code="0x63" name="glyph00008"/>      <map code="0x65" name="glyph00007"/>      <map code="0x6a" name="glyph00015"/>      <map code="0x6d" name="glyph00014"/>      <map code="0x70" name="glyph00004"/>      <map code="0x73" name="glyph00010"/>      <map code="0x74" name="glyph00011"/>    </cmap_format_4>```
With that in place we are almost done.As mentioned above however I had problems using python to extract the contour from glyf table, therefore ttx is executed via os.system().This time the files are placed  in ttx_out directory.
```pythoncmd = 'rm -rf ttx_out && mkdir ttx_out && ttx -t glyf -g -d ttx_out ' + ttffileprint("running system command: " + cmd)os.system(cmd)```
Now loop through each of the 15 glyphs (skipping glyph zero) from this file and figure out which sym matches its contours```pythonfor glyph in font['glyf'].glyphs:    #glyphObj = font['glyf'].glyphs[glyph]    #print(glyph)    ttxglyphfile = "ttx_out/" + ttffile + "._g_l_y_f." + glyph + ".ttx"    if "glyph00000" != glyph:        sym = glyphId2symbol(ttxglyphfile)        code2sym[glyph2code[glyph]] = sym```
this is the sym lookup function called as sym = glyphId2symbol(ttxglyphfile).once again I was lazy and used just diff system command to figure out if only the name differs for a matching contour (reminder learn more python)
```pythondef glyphId2symbol(search):    for glyphfile in os.listdir('glyphs_ref'):        #print("reference file: " + glyphfile)        cmd = "diff -q -I '<TTGlyph' -u " + search + " glyphs_ref/" + glyphfile + " > /dev/null"        rc = os.system(cmd)        #print("diff rc=" + str(rc))        if 0 == rc:            # get sym from ref file ...            #print("the glyph " + search + " matches ref file: " + glyphfile)            with open("glyphs_ref/" + glyphfile) as f:                for line in f:                    match = re.search('.* sym="(.)" .*', line)                    if match:                        #print(match.group(1))                        return match.group(1)
            break
    return ""```
... almost done.We do have the equation string already in *eqstr* so just need to replace the letters. Note that **'x'** was already mapped to **'*'** and we have a mapping fpr spaces (*code2sym[32] = ' '*).
```pythonfor x in eqstr:    eqstr2 += code2sym[ord(x)]```
#### calc and submitand simply calculate using evil eval```pythonresult = eval(eqstr2)```
post it```pythonr = s.post(c8_url, data = {'answer': str(result), 'token' : token})```
et voila```$ ./anal-ttf.pytoken:     1542154265Eq string: aaaaaY d aI B VNN B amc d GNN v aaV B mcN d aI v aG d am d YNNNNN d aaaao d GN d mcN d aao B oN v INN d amc v aaD d DN d aY v aaaG v YN d mcN d aX B GNNNNNNN B aamc d aaaI d DN B am d mNN d aaaX d mN d IN d INNN B aaaD B XN d amc d mNN v aaao v XN B aaX v bN d aD d oNNN d aamc d aaI d oN B YNN v mNNNNNanalyzing ttf file: captchattfrunning system command: rm -rf ttx_out && mkdir ttx_out && ttx -t glyf -g -d ttx_out captchattfDumping "captchattf" to "ttx_out/captchattf.ttx"...Dumping 'glyf' table...<fontTools.ttLib.tables._c_m_a_p.cmap_format_0 object at 0x7f6f0b39d668>code: 0x61 (a) - glyph00008code: 0x42 (B) - glyph00013code: 0x63 (c) - glyph00005code: 0x44 (D) - glyph00002code: 0x76 (v) - glyph00009code: 0x64 (d) - glyph00001code: 0x47 (G) - glyph00004code: 0x49 (I) - glyph00006code: 0x62 (b) - glyph00014code: 0x4e (N) - glyph00010code: 0x6d (m) - glyph00003code: 0x56 (V) - glyph00012code: 0x58 (X) - glyph00011code: 0x59 (Y) - glyph00015code: 0x6f (o) - glyph00007glyph00003 <--> 1 <--> 109glyph00010 <--> ) <--> 78glyph00004 <--> 4 <--> 71glyph00015 <--> 5 <--> 89glyph00008 <--> ( <--> 97glyph00005 <--> 0 <--> 99glyph00011 <--> 7 <--> 88glyph00006 <--> 2 <--> 73glyph00007 <--> 3 <--> 111glyph00013 <--> - <--> 66glyph00002 <--> 6 <--> 68glyph00014 <--> 9 <--> 98glyph00012 <--> 8 <--> 86glyph00009 <--> + <--> 118glyph00001 <--> * <--> 100(((((5 * (2 - 8)) - (10 * 4)) + ((8 - 10) * (2 + (4 * (1 * 5))))) * ((((3 * 4) * 10) * ((3 - 3) + 2)) * (10 + ((6 * 6) * (5 + (((4 + 5) * 10) * (7 - 4))))))) - ((10 * (((2 * 6) - (1 * 1)) * (((7 * 1) * 2) * 2))) - (((6 - 7) * (10 * 1)) + (((3 + 7) - ((7 + 9) * (6 * 3))) * ((10 * ((2 * 3) - 5)) + 1)))))-271143748```
```<html><body>If you can see this then you have solved the CAPTCHA.If you have solved the CAPTCHA then you are a Charvise.If you are a Charvise then you are welcome on Charvis.If you are welcome on Charvis then:You can disable this system using flag-a76013167fd4c04e3134You should be given useful information.If you should be given useful information then this informs you that there are two layers of defense left, and the last one is trivial.</body></html>```
If you can see this then you have solved the CAPTCHA.
If you have solved the CAPTCHA then you are a Charvise.
If you are a Charvise then you are welcome on Charvis.
If you are welcome on Charvis then:
You should be given useful information.
If you should be given useful information then this informs you that there are two layers of defense left, and the last one is trivial.
nice challange, thx.