Google CTF 2018
Floppy
Well it’s definitely the 90s. Using what was found in the mysterious .ico file, you extract the driver for the Aluminum-Key Hardware password storage device. Let’s see what it has in store.
You can find my all CTF solution in here
First I downloaded the attachment.This include HTMl file when I open this html file I saw the above page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<script> async function x(password) { // TODO: check if they can just use Google to get the password once they understand how this works. var code = 'icffjcifkciilckfmckincmfockkpcofqcoircqfscoktcsfucsivcufwcooxcwfycwiAcyfBcwkCcBfDcBiEcDfFcwoGcFfHcFiIcHfJcFkKcJfLcJiMcLfNcwwOcNNPcOOQcPORcQNScRkTcSiUcONVcUoWcOwXcWkYcVkЀcYiЁcЀfЂcQoЃcЂkЄcЃfЅcPNІcЅwЇcІoЈcЇiЉcЈfЊcPkЋcЊiЌcІiЍcЌfЎcWoЏcЎkАcЏiБcІkВcБfГcNkДcГfЕcЇkЖcЕiЗcЖfИcRwЙcИoКcЙkЛcUkМcЛiНcМfОcИkПcОiРcПfСcUwТcСiУcQkФcУiХcЃiЦcQwЧcЦoШcЧkЩcШiЪcЩfЫcRiЬcЫfЭcКiЮcЭfЯcСoаcЯiбcГiвcЙiгcRoдcгkеcдiжdТaзcЛfиdзaжcжийcСkкdйaжcжклcйfмdлaжcжмнdТaжcжноdЀaжcжопdNaжcжпрcUiсcрfтdсaуdЁaтcтутcтофcТfхdфaтcтхтcтктcтнтcтмцdсaтcтцтcтктcтутcтнчaaтшdЯaщcйiъcщfыdъaьcжыэcVfюdэaьcьюьcьояdЛaьcьяьcьуьcьыѐчшьёѐшшђcOfѓdђaѓcѓнѓcѓнєcUfѕdєaѓcѓѕіcЯfїdіaѓcѓїјaёѓљaaтњcжшћcЎiќcћfѝdќaњcњѝњcњeўcЏfџdўaњcњџѠdАaњcњѠњcњшњcњѝњcњfњcњџѡљшњѢaaтѣcжшѣcѣѝѣcѣeѣcѣџѤcЯkѥdѤaѣcѣѥѣcѣшѣcѣѝѣcѣfѣcѣџѦѢшѣѧcцнѧcѧїѨdСaѧcѧѨѧcѧкѧcѧуѩaёѧѪcхмѫdрaѪcѪѫѪcѪкѬdYaѪcѪѬѪcѪиѭaѩѪѮcяюѯdНaѮcѮѯѮcѮиѮcѮхѮcѮкѰaѭѮѱdVaѲcхѱѲcѲѕѳcNoѴcѳkѵcѴfѶdѵaѲcѲѶѲcѲiѲcѲlѲcѲmѷјѲgѸјѭѷѹbѰѸѺcXfѻdѺaѻcѻюѻcѻоѻcѻкѻcѻoѼdђaѻcѻѼѻcѻнѻcѻнѻcѻѕѻcѻїѽaёѻѾѽѹшѿceeҀceeҁcee҂ceeѿaѾeҀјѿT҂ѡҀшҁјh҂hѦҁшѿaѾfҀјѿV҂ѡҀшҁјh҂hѦҁшѿaѾiҀјѿU҂ѡҀшҁјh҂hѦҁшѿaѾjҀјѿX҂ѡҀшҁјh҂hѦҁшѿaѾkҀјѿЁ҂ѡҀшҁјh҂hѦҁшѿaѾlҀјѿF҂ѡҀшҁјh҂hѦҁшѿaѾmҀјѿЄ҂ѡҀшҁјh҂hѦҁшѿaѾnҀјѿЉ҂ѡҀшҁјh҂hѦҁшѿaѾoҀјѿЄ҂ѡҀшҁјh҂hѦҁшѿaѾpҀјѿЋ҂ѡҀшҁјh҂hѦҁшѿaѾqҀјѿЍ҂ѡҀшҁјh҂hѦҁшѿaѾrҀјѿА҂ѡҀшҁјh҂hѦҁшѿaѾsҀјѿF҂ѡҀшҁјh҂hѦҁшѿaѾtҀјѿВ҂ѡҀшҁјh҂hѦҁшѿaѾuҀјѿД҂ѡҀшҁјh҂hѦҁшѿaѾvҀјѿЗ҂ѡҀшҁјh҂hѦҁшѿaѾwҀјѿК҂ѡҀшҁјh҂hѦҁшѿaѾxҀјѿН҂ѡҀшҁјh҂hѦҁшѿaѾyҀјѿР҂ѡҀшҁјh҂hѦҁшѿaѾAҀјѿТ҂ѡҀшҁјh҂hѦҁшѿaѾBҀјѿФ҂ѡҀшҁјh҂hѦҁшѿaѾCҀјѿW҂ѡҀшҁјh҂hѦҁшѿaѾDҀјѿХ҂ѡҀшҁјh҂hѦҁшѿaѾEҀјѿЪ҂ѡҀшҁјh҂hѦҁшѿaѾFҀјѿЬ҂ѡҀшҁјh҂hѦҁшѿaѾGҀјѿЮ҂ѡҀшҁјh҂hѦҁшѿaѾHҀјѿа҂ѡҀшҁјh҂hѦҁшѿaѾIҀјѿe҂ѡҀшҁјh҂hѦҁшѿaѾJҀјѿб҂ѡҀшҁјh҂hѦҁшѿaѾKҀјѿв҂ѡҀшҁјh҂hѦҁшѿaѾLҀјѿK҂ѡҀшҁјh҂hѦҁшѿaѾMҀјѿе҂ѡҀшҁјh҂hѦҁшѐceeёceeѓceeјceeљceeњceeѡceeѢceeѣceeѦceeѧceeѩceeѪceeѭceeѮceeѰceeѲceeѷceeѸceeѹceeѻceeѽceeѾceeҀceeҁceeжceeтceeчceeьcee' var env = { a: (x,y) => x[y], b: (x,y) => Function.constructor.apply.apply(x, y), c: (x,y) => x+y, d: (x) => String.fromCharCode(x), e: 0, f: 1, g: new TextEncoder().encode(password), h: 0, }; for (var i = 0; i < code.length; i += 4) { var [lhs, fn, arg1, arg2] = code.substr(i, 4); try { env[lhs] = env[fn](env[arg1], env[arg2]); } catch(e) { env[lhs] = new env[fn](env[arg1], env[arg2]); } if (env[lhs] instanceof Promise) env[lhs] = await env[lhs]; } return !env.h; } </script> <script> const alg = { name: 'AES-CBC', iv: Uint8Array.from([211,42,178,197,55,212,108,85,255,21,132,210,209,137,37,24])}; const secret = Uint8Array.from([26,151,171,117,143,168,228,24,197,212,192,15,242,175,113,59,102,57,120,172,50,64,201,73,39,92,100,64,172,223,46,189,65,120,223,15,34,96,132,7,53,63,227,157,15,37,126,106]); async function open_safe() { keyhole.disabled = true; password = /^CTF{([0-9a-zA-Z_@!?-]+)}$/.exec(keyhole.value); if (!password || !(await x(password[1]))) return document.body.className = 'denied'; document.body.className = 'granted'; const pwHash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(password[1])); const key = await crypto.subtle.importKey('raw', pwHash, alg, false, ['decrypt']); content.value = new TextDecoder("utf-8").decode(await crypto.subtle.decrypt(alg, key, secret)) } </script> |
When I dive in the html code. I figure out somethings;
- Secret is hardcoded in source code as a Uint8Array
- Code used for encryption is AES-CBC which is quite hard to decryption.
- Password check first following regex: /^CTF{([0-9a-zA-Z_@!?-]+)}$/
- opensafe() function check the CTF{value} with !password and await x(password[1]) return if both are false start to encoding.
When I printed password[1] for the CTF{value} password, password[1] contains “value” So that, x() function decode inside “CTF{…} ” parameter.
Bellow env dict show when env “g” input given in arguments
1 2 3 4 5 6 7 8 9 10 |
var env = { a: (x,y) => x[y], b: (x,y) => Function.constructor.apply.apply(x, y), c: (x,y) => x+y, d: (x) => String.fromCharCode(x), e: 0, f: 1, g: new TextEncoder().encode(password), h: 0, }; |
lets the follow “g” arguments.
Add some lines to code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
for (var i = 0; i < code.length; i += 4) { var [lhs, fn, arg1, arg2] = code.substr(i, 4); if (arg1 == "g" || arg2 == "g"){ console.log(i); console.log(lhs, fn, arg1, arg2); console.log(env[lhs], env[fn], env[arg1], env[arg2]); console.log(env[fn](env[arg1], env[arg2])); } try { env[lhs] = env[fn](env[arg1], env[arg2]); } catch(e) { env[lhs] = new env[fn](env[arg1], env[arg2]); } if (env[lhs] instanceof Promise) env[lhs] = await env[lhs]; } |
Output of console is
1 2 3 4 |
876 ѷ ј Ѳ g ƒ Array() { [native code] } "sha-256" Uint8Array(4) [65, 65, 65, 65] ["sha-256", Uint8Array(4)] |
When we track “ѷ” output is
1 2 3 4 |
880 Ѹ ј ѭ ѷ ƒ Array() { [native code] } SubtleCrypto {} (2) ["sha-256", Uint8Array(4)] [SubtleCrypto, Array(2)] |
When we track “Ѹ” output is
1 2 3 4 |
884 ѹ b Ѱ Ѹ (x,y) => Function.constructor.apply.apply(x, y) ƒ digest() { [native code] } (2) [SubtleCrypto, Array(2)] Promise {<pending>} |
When we track “ѹ” output is
1 2 3 4 |
940 Ѿ ѽ ѹ ш ƒ Uint8Array() { [native code] } ArrayBuffer(32) {} "x" <span class="object-description">Uint8Array(32) </span><span class="object-properties-preview">[<span class="object-value-number">237</span>, <span class="object-value-number">2</span>, <span class="object-value-number">69</span>, <span class="object-value-number">123</span>, <span class="object-value-number">92</span>, <span class="object-value-number">65</span>, <span class="object-value-number">217</span>, <span class="object-value-number">100</span>, <span class="object-value-number">219</span>, <span class="object-value-number">210</span>, <span class="object-value-number">242</span>, <span class="object-value-number">166</span>, <span class="object-value-number">9</span>, <span class="object-value-number">214</span>, <span class="object-value-number">63</span>, <span class="object-value-number">225</span>, <span class="object-value-number">187</span>, <span class="object-value-number">117</span>, <span class="object-value-number">40</span>, <span class="object-value-number">219</span>, <span class="object-value-number">229</span>, <span class="object-value-number">94</span>, <span class="object-value-number">26</span>, <span class="object-value-number">191</span>, <span class="object-value-number">91</span>, <span class="object-value-number">82</span>, <span class="object-value-number">194</span>, <span class="object-value-number">73</span>, <span class="object-value-number">205</span>, <span class="object-value-number">115</span>, <span class="object-value-number">87</span>, <span class="object-value-number">151</span></span> |
Until “ѿ” you must repeated. After that I realize the SHA256 converted with 32 bit array code .
I add the code for the find this 32 bit array
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var a = []; for (var i = 0; i < code.length; i += 4) { var [lhs, fn, arg1, arg2] = code.substr(i, 4); if (arg1 == "ѿ"){ a.push(env[fn](env[arg1], env[arg2])[1]); //console.log(i); console.log(lhs, fn, arg1, arg2); console.log(env[lhs], env[fn], env[arg1], env[arg2]); console.log(env[fn](env[arg1], env[arg2])); } try { env[lhs] = env[fn](env[arg1], env[arg2]); } catch(e) { env[lhs] = new env[fn](env[arg1], env[arg2]); } if (env[lhs] instanceof Promise) env[lhs] = await env[lhs]; } console.log(a); |
array of is ;
[230, 104, 96, 84, 111, 24, 205, 187, 205, 134, 179, 94, 24, 181, 37, 191, 252, 103, 247, 114, 198, 80, 206, 223, 227, 255, 122, 0, 38, 250, 29, 238]
We receive Unit8Array(32) this is the secret.
We must to find hash with this array. We can use hashlib in python. I write to code for that
1 2 3 4 5 |
import hashlib print str(bytearray([230, 104, 96, 84, 111, 24, 205, 187, 205, 134, 179, 94, 24, 181, 37, 191, 252, 103, 247, 114, 198, 80, 206, 223, 227, 255, 122, 0, 38, 250, 29, 238])).encode('hex') |
Output of this code is;
e66860546f18cdbbcd86b35e18b525bffc67f772c650cedfe3ff7a0026fa1dee
For the Sha256 this hash code is
1 |
<span id="decodedValue">Passw0rd!</span> |
We can try to CTF{Passw0rd!}
Also 🙂