
這題明明就 Crypto,哪裡是 reverse
網站連進去後長這樣

檢查一下能發現一個 encode.js

打開會發現是混淆過後的

yeah…..yeah…….
reverse……
總之就 format 一下,然後稍微 Revese 一下
程式的最上面有一個 const 的 array,裡面存著一堆的 keyword 等的
而後面由兩個 function 組成,第一個 function 將 array 的值處理了一下,反正也是混淆的一部份
而且到這裡我才知道 javascript 中 const array 是能動的,wut ???

what ever…. javascript 嘛,當我知道他的 class 是從 function 來的時候就已經見怪不怪了
作為人體 javascript beautifier,看到快起笑
decompiled(?) 的 code 就放在文章最後了
因為第一個大 function 是 const function ,所以就拿處理的結果代掉原 global_arr,然後刪掉了
在第二個大 function 的後面能看到會建一個 eventListener 並監聽使用者的輸入
且會在特定的狀況下增加 counter 的值
反正就是要求一連串特殊的輸入啦
順序是 ↑↑↓↓←→←→ba
ok…I see…..
還好我老到還知道這個(?
輸入後會給加密後的 flag

好評 OvOb

隨便玩一下能發現是以 5 個字元為單位,轉換成 4 個字
有一個小坑就是網站上顯示的都是大寫,但有些其實是小寫,會影響答案…..吧?(未經驗證
而 encode.js 中有一段 function 是將輸入的字轉換成 一連串的 binary
長度以 10 為倍數,未滿的補0
再以 10 為一個單位,轉換成 key 的 index
key = “AlS3{BasE64_i5+b0rNIng~\Qwo/-xH8WzCj7vFD2eyVktqOL1GhKYufmZdJpX9}”
那個字串為 global_arr 中某個值 b64 decode 的結果可惡當時我還以為這就是 flag ,興高采烈的丟上去
所以能以拿到的字轉換回 index
但問題來了,轉換回來的只有原字元的後 6 bit
前面還有 4 個bit,但像 “1” 跟 “A” 都是顯示出 “{“
那我要怎麼知道答案是哪個?
這個真的卡了我好一段時間,我原本還想著要爆開
但 POC 要麻有 bug,要麻跑到死
直到在亂玩網站的時候發現 “1” 跟 “A” 的顏色不一樣


突然想起來 encode 的那個 function 好像有拿前 4 bit 的值拿去做 class 的參數
r 是 >> 9 ,所以是第 10 bit
cl 是 >> 6 後 & 7 ,所以是第 6 bit 開始往後數 3 個,也就是 6 ~ 9 bit
而 index 則是 & 63 ,也就是 1 ~ 5 bit
抽取出來剛好是分成 | 10 | 9 – 6 | 5 – 1 | bit 的方式
所以就能直接將原本的 10 bit 還原
先簡單的做了個 extractor 將個別的值取出來
from bs4 import *
doc = '''<span><div class="c4 r0">{</div></span><span><div class="c3 r0">=</div></span><span><div class="c2 r0">=</div></span><span><div class="c1 r0">=</div></span>'''
soup = BeautifulSoup(doc,'html.parser')
print(soup.prettify())
div_info = []
divs = soup.find_all('div')
for div in divs:
div_cls = div.get('class')
div_text = div.text
div_cls.append(div_text)
div_info.append(div_cls)
print(div_info)Code language: HTML, XML (xml)
再將值轉回 bytes array 後轉回字串
flag_enc_info = [['c4', 'r0', 'B'], ['c2', 'r0', 'g'], ['c3', 'r0', 'i'], ['c5', 'r1', 'J'], ['c6', 'r0', '6'], ['c0', 'r1', '\\'], ['c3', 'r0', 'w'], ['c4', 'r0', '1'], ['c3', 'r0', 'A'], ['c4', 'r1', 'j'], ['c4', 'r0', '\\'], ['c4', 'r1', '1'], ['c3', 'r0', 'g'], ['c7', 'r0', 'u'], ['c3', 'r0', 'i'], ['c1', 'r0', 'k'], ['c3', 'r0', 'l'], ['c4', 'r0', '7'], ['c6', 'r0', 'x'], ['c5', 'r0', 'i'], ['c5', 'r0', 'X'], ['c1', 'r0', 'K'], ['c1', 'r0', 'I'], ['c4', 'r0', 'h'], ['c5', 'r0', 'X'], ['c0', 'r0', 'K'], ['c4', 'r1', 'i'], ['c5', 'r1', 'l'], ['c7', 'r0', '6'], ['c7', 'r0', 'f'], ['c4', 'r0', 'o'], ['c1', 'r0', '6'], ['c5', 'r0', '5'], ['c7', 'r0', 'K'], ['c1', 'r1', 'n'], ['c5', 'r1', '8'], ['c7', 'r0', '7'], ['c4', 'r1', 'B'], ['c5', 'r0', '-'], ['c1', 'r1', '8'], ['c4', 'r0', 'w'], ['c3', 'r1', 'a'], ['c1', 'r0', 'r'], ['c4', 'r1', 'z'], ['c7', 'r0', 'K'], ['c3', 'r0', '='], ['c2', 'r0', '='], ['c1', 'r0', '=']]
# flag_enc_info = [['c4', 'r0', '{'], ['c3', 'r0', '='], ['c2', 'r0', '='], ['c1', 'r0', '=']]
binary = ""
for chr_info in flag_enc_info:
c = bin(int(chr_info[0][1:]))[2:]
c = '0' * (3 - len(c)) + c
r = bin(int(chr_info[1][1:]))[2:]
ch = ""
if chr_info[2] != '=':
ch = bin(key.find(chr_info[2]))[2:]
ch = '0' * (6 - len(ch)) + ch
# chr = chr[::-1]
else:
ch = "000000"
binary += r + c + ch
print(binary)
for i in range(len(binary)//8):
print(chr(int(binary[i*8:(i+1)*8],2)),end="")Code language: PHP (php)
最後能拿到 flag : AIS3{base1024_15_c0l0RFuL_GAM3_CL3Ar_thIS_IS_y0Ur_FlaG!}
這題真的是莫名的花了我不少時間阿…..
const global_arr = ['padStart', 'Backspace', 'repeat', '1YqKovX', 'NDBCMjBnMzBpNTFKNjA2MDFcMzB3NDAxMzBBNDFqNDBcNDExMzBnNzB1MzBpMTBrMzBsNDA3NjB4NTBpNTBYMTBLMTBJNDBoNTBYMDBLNDFpNTFsNzA2NzBmNDBvMTA2NTA1NzBLMTFuNTE4NzA3NDFCNTAtMTE4NDB3MzFhMTByNDF6NzBLMzA9MjA9MTA9', 'substr', 'output', 'getElementsByTagName', '65022JgPEZp', 'keydown', 'length', 'innerHTML', '677PRUQAU', 'ArrowLeft', 'QWxTM3tCYXNFNjRfaTUrYjByTkluZ35cUXdvLy14SDhXekNqN3ZGRDJleVZrdHFPTDFHaEtZdWZtWmRKcFg5fQ==', '133781JKLWBV', 'ArrowUp', '90407czXCgh', 'PGRpdiBzdHlsZT0id2lkdGg6IDM1MHB4OyBwb3NpdGlvbjogYWJzb2x1dGU7IGJvdHRvbTogMHB4OyBsZWZ0OiAwcHg7Ij48ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7IGFuaW1hdGlvbjogcmFpbmJvdyAycyBsaW5lYXIgMHMgaW5maW5pdGUgbm9ybWFsOyBwb3NpdGlvbjogYWJzb2x1dGU7IHRvcDogLTEwcHg7IGxlZnQ6IDUwJTsgZm9udC1zaXplOiAyMHB4OyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7IHdpZHRoOiAzNTBweDsiPkhlcmUgaXMgeW91cjxicj4iZW5jb2RlZCIgZmxhZyw8YnI+PC9lbGxpcHNlPjwvc3ZnPjwvZGl2Pg==', '131837PcDnWL', '19pQimXL', '623605MIswVM', 'charCodeAt', 'join', '4WsUYDr', '686oWrfyq', 'body', 'map', 'getElementById', 'textContent', 'match', 'key', '302349wKdZHP', '4OYJFlQ', 'input'];
function ret_arr(a, unused) {
a = a - 0x1c6;
let ret = global_arr[a];
return ret;
}
(
(() => {
const _0x54579e = ret_arr(0x1d8)
const _0x78ed5a = ret_arr(0x1ca)
const _0x24fcac = ret_arr(0x1d4)
let _0x1e21d9, counter = 0x0;
function _0xce93(arg1) {
if (!arg1["length"]) return '';
let str1 = '';
let str2 = '';
let var1 = 0x0;
for (let i = 0x0; i < arg1.length();i++){
// convert arg1 to 8 bit binary
str1 += arg1.charCodeAt(i).toString(0x2).padStart(0x8, '0');
}
var1 = (str1.length() % 10) / 2 - 0x1;
if (var1 != -0x1)
str1 += '0'.repeat(10 - str1.length() % 10);
str1 = str1.match(/(.{1,10})/g);
for (let c of str1) {
let key = parseInt(c, 0x2);
let cl = parseInt(key >>6 ) & 7
let r = parseInt(key >> 9)
let chr = "AlS3{BasE64_i5+b0rNIng~\\Qwo/-xH8WzCj7vFD2eyVktqOL1GhKYufmZdJpX9}"[key & 63];
str2 += str_to_div( cl,r,chr);
}
for (; var1 > 0x0; var1--) {
str2 += _0x9f530c(var1 % 8, 0x0, '=');
}
return str2;
}
let _0x9f530c = (str1, str2, str3) => '<span><div class= c' + str1 + ' r' + str2 +'">' + str3 + '</div></span>';
let _0x1fdafa = _0x29e3ab => document.getElementById('output')['innerHTML'] = _0xce93(_0x29e3ab);
document['addEventListener']('keydown', event => {
if (event['key'] === "Backspace" && counter == 0xa)
_0x1e21d9['textContent'] = _0x1e21d9['textContent'].substr(
0x0, _0x1e21d9['textContent'][ret_arr(0x1d0)] - 0x1);
else {
if (event['key'] === 'ArrowUp' && counter < 2)
return counter += 0x1;
else {
if (event['key'] === 'ArrowDown' && counter < 4)
return counter += 0x1;
else {
if (event['key'] === 'ArrowLeft' && (counter == 4 || counter == 6))
return counter += 0x1;
else {
if (event['key'] === 'ArrowRight' && (counter == 0x5 || counter == 0x7))
return counter += 0x1;
else {
if (event['key'] === 'b' && counter == 0x8)
return counter += 0x1;
else {
if (event['key'] === 'a' && counter == 9)
return document[ret_arr(0x1cd)](ret_arr(
0x1e0))[0x0]['innerHTML'] += atob(_0x54579e),
_0x1e21d9 = document[ret_arr(0x1e2)](ret_arr(0x1e8)),
_0x1e21d9[ret_arr(0x1d1)] = '',
document[ret_arr(0x1e2)]('output')[ret_arr(0x1d1)] =
atob(_0x78ed5a)[ret_arr(0x1e4)](
/(.{1,3})/g)[ret_arr(0x1e1)](
_0x5efa9e => _0x9f530c(
_0x5efa9e[0x0], _0x5efa9e[0x1],
_0x5efa9e[0x2]))[ret_arr(0x1dd)](''),
counter += 0x1;
else {
if (event['key'][ret_arr(0x1d0)] == 0x1 && counter == 0xa)
_0x1e21d9[ret_arr(0x1e3)] += String['fromCharCode']( event['key'][ret_arr(0x1dc)]());
else
return;
}
}
}
}
}
}
}
_0x1fdafa(_0x1e21d9[ret_arr(0x1e3)]);
});
}) ());
console.log("wtf");Code language: JavaScript (javascript)