1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

picoCTF 2021 Some Assembly Required 1 Writeup

Last updated at Posted at 2021-03-30

何度,心が折れても,あきらめずに粘り強く頑張った結果解けた問題なので,うれしさのあまり Writeup を残す。

image.png

外見
image.png

ソース

<html>
<head>
	<meta charset="UTF-8">
	<script type="text/javascript" src="http://gc.kis.v2.scr.kaspersky-labs.com/FD126C42-EBFA-4E12-B309-BB3FDD723AC1/main.js?attr=zfDykIDMiQvcx9foL-veRUG-WvILWzA6D1-Oe8lKtGgKHIAIGJ5pQGpISvCBVnEvZLIsS9ByPXs0qLQMYgQ9jw" charset="UTF-8"></script><script src="G82XCw5CX3.js"></script>
</head>
<body>
	<h4>Enter flag:</h4>
	<input type="text" id="input"/>
	<button onclick="onButtonPress()">Submit</button>
	<p id="result"></p>
</body>
</html>

JavaScript で getElementById('input')とか出てきそうですね。

JavaScriptのソース

G82XCw5CX3.js
const _0x402c=['value','2wfTpTR','instantiate','275341bEPcme','innerHTML','1195047NznhZg','1qfevql','input','1699808QuoWhA','Correct!','check_flag','Incorrect!','./JIFxzHyW8W','23SMpAuA','802698XOMSrr','charCodeAt','474547vVoGDO','getElementById','instance','copy_char','43591XxcWUl','504454llVtzW','arrayBuffer','2NIQmVj','result'];const _0x4e0e=function(_0x553839,_0x53c021){_0x553839=_0x553839-0x1d6;let _0x402c6f=_0x402c[_0x553839];return _0x402c6f;};(function(_0x76dd13,_0x3dfcae){const _0x371ac6=_0x4e0e;while(!![]){try{const _0x478583=-parseInt(_0x371ac6(0x1eb))+parseInt(_0x371ac6(0x1ed))+-parseInt(_0x371ac6(0x1db))*-parseInt(_0x371ac6(0x1d9))+-parseInt(_0x371ac6(0x1e2))*-parseInt(_0x371ac6(0x1e3))+-parseInt(_0x371ac6(0x1de))*parseInt(_0x371ac6(0x1e0))+parseInt(_0x371ac6(0x1d8))*parseInt(_0x371ac6(0x1ea))+-parseInt(_0x371ac6(0x1e5));if(_0x478583===_0x3dfcae)break;else _0x76dd13['push'](_0x76dd13['shift']());}catch(_0x41d31a){_0x76dd13['push'](_0x76dd13['shift']());}}}(_0x402c,0x994c3));let exports;(async()=>{const _0x48c3be=_0x4e0e;let _0x5f0229=await fetch(_0x48c3be(0x1e9)),_0x1d99e9=await WebAssembly[_0x48c3be(0x1df)](await _0x5f0229[_0x48c3be(0x1da)]()),_0x1f8628=_0x1d99e9[_0x48c3be(0x1d6)];exports=_0x1f8628['exports'];})();function onButtonPress(){const _0xa80748=_0x4e0e;let _0x3761f8=document['getElementById'](_0xa80748(0x1e4))[_0xa80748(0x1dd)];for(let _0x16c626=0x0;_0x16c626<_0x3761f8['length'];_0x16c626++){exports[_0xa80748(0x1d7)](_0x3761f8[_0xa80748(0x1ec)](_0x16c626),_0x16c626);}exports['copy_char'](0x0,_0x3761f8['length']),exports[_0xa80748(0x1e7)]()==0x1?document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e6):document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e8);}

Syncerで整形してみる

G82XCw5CX3.js
const _0x402c = ['value', '2wfTpTR', 'instantiate', '275341bEPcme', 'innerHTML', '1195047NznhZg', '1qfevql', 'input', '1699808QuoWhA', 'Correct!', 'check_flag', 'Incorrect!', './JIFxzHyW8W', '23SMpAuA', '802698XOMSrr', 'charCodeAt', '474547vVoGDO', 'getElementById', 'instance', 'copy_char', '43591XxcWUl', '504454llVtzW', 'arrayBuffer', '2NIQmVj', 'result'];
const _0x4e0e = function (_0x553839, _0x53c021) {
  _0x553839 = _0x553839 - 0x1d6;
  let _0x402c6f = _0x402c[_0x553839];
  return _0x402c6f;
};
(function (_0x76dd13, _0x3dfcae) {
  const _0x371ac6 = _0x4e0e;
  while (!![]) {
    try {
      const _0x478583 = -parseInt(_0x371ac6(0x1eb)) + parseInt(_0x371ac6(0x1ed)) + -parseInt(_0x371ac6(0x1db)) * -parseInt(_0x371ac6(0x1d9)) + -parseInt(_0x371ac6(0x1e2)) * -parseInt(_0x371ac6(0x1e3)) + -parseInt(_0x371ac6(0x1de)) * parseInt(_0x371ac6(0x1e0)) + parseInt(_0x371ac6(0x1d8)) * parseInt(_0x371ac6(0x1ea)) + -parseInt(_0x371ac6(0x1e5));
      if (_0x478583 === _0x3dfcae) break;
      else _0x76dd13['push'](_0x76dd13['shift']());
    } catch (_0x41d31a) {
      _0x76dd13['push'](_0x76dd13['shift']());
    }
  }
}(_0x402c, 0x994c3));
let exports;
(async() => {
  const _0x48c3be = _0x4e0e;
  let _0x5f0229 = await fetch(_0x48c3be(0x1e9)),
    _0x1d99e9 = await WebAssembly[_0x48c3be(0x1df)](await _0x5f0229[_0x48c3be(0x1da)]()),
    _0x1f8628 = _0x1d99e9[_0x48c3be(0x1d6)];
  exports = _0x1f8628['exports'];
})();

function onButtonPress() {
  const _0xa80748 = _0x4e0e;
  let _0x3761f8 = document['getElementById'](_0xa80748(0x1e4))[_0xa80748(0x1dd)];
  for (let _0x16c626 = 0x0; _0x16c626 < _0x3761f8['length']; _0x16c626++) {
    exports[_0xa80748(0x1d7)](_0x3761f8[_0xa80748(0x1ec)](_0x16c626), _0x16c626);
  }
  exports['copy_char'](0x0, _0x3761f8['length']), exports[_0xa80748(0x1e7)]() == 0x1 ? document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)] = _0xa80748(0x1e6) : document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)] = _0xa80748(0x1e8);
}

混乱を恐れず,自分の失敗を書いておく

Consoleで_0x402c をたたき変換表を確認
image.png

変換表(シャッフル前)
0: "instance"
1: "copy_char"
2: "43591XxcWUl"
3: "504454llVtzW"
4: "arrayBuffer"
5: "2NIQmVj"
6: "result"
7: "value"
8: "2wfTpTR"
9: "instantiate"
10: "275341bEPcme"
11: "innerHTML"
12: "1195047NznhZg"
13: "1qfevql"
14: "input"
15: "1699808QuoWhA"
16: "Correct!"
17: "check_flag"
18: "Incorrect!"
19: "./JIFxzHyW8W"
20: "23SMpAuA"
21: "802698XOMSrr"
22: "charCodeAt"
23: "474547vVoGDO"
24: "getElementById"

変換表(シャッフル前)に基づいた難読化の解除

onButtonPress()
function onButtonPress() {
  const _0xa80748 = _0x4e0e;
  let _0x3761f8 = document['getElementById']('802698XOMSrr')['input'];
  for (let _0x16c626 = 0x0; _0x16c626 < _0x3761f8['length']; _0x16c626++) {
    exports['2wfTpTR'](_0x3761f8['arrayBuffer'](_0x16c626), _0x16c626);
  }
  exports['copy_char'](0x0, _0x3761f8['length']), exports['getElementById']() == 0x1 ? document['result']('1qfevql')['Incorrect!'] = '474547vVoGDO' : document['result']('1qfevql')['Incorrect!'] = 'instance';
}

あれ?意味判らん???

失敗の原因

      else _0x76dd13['push'](_0x76dd13['shift']());
    } catch (_0x41d31a) {
      _0x76dd13['push'](_0x76dd13['shift']());

push や shift で配列をシャッフルしてる。
静的解析はまだ私には無理だ。
動的解析するしかない。

Submit前の _0x402c (再掲)

変換表(シャッフル前)
0: "instance"
1: "copy_char"
2: "43591XxcWUl"
3: "504454llVtzW"
4: "arrayBuffer"
5: "2NIQmVj"
6: "result"
7: "value"
8: "2wfTpTR"
9: "instantiate"
10: "275341bEPcme"
11: "innerHTML"
12: "1195047NznhZg"
13: "1qfevql"
14: "input"
15: "1699808QuoWhA"
16: "Correct!"
17: "check_flag"
18: "Incorrect!"
19: "./JIFxzHyW8W"
20: "23SMpAuA"
21: "802698XOMSrr"
22: "charCodeAt"
23: "474547vVoGDO"
24: "getElementById"

Submit後
image.png
image.png

変換表(シャッフル後)
0: "instance"
1: "copy_char"
2: "43591XxcWUl"
3: "504454llVtzW"
4: "arrayBuffer"
5: "2NIQmVj"
6: "result"
7: "value"
8: "2wfTpTR"
9: "instantiate"
10: "275341bEPcme"
11: "innerHTML"
12: "1195047NznhZg"
13: "1qfevql"
14: "input"
15: "1699808QuoWhA"
16: "Correct!"
17: "check_flag"
18: "Incorrect!"
19: "./JIFxzHyW8W"
20: "23SMpAuA"
21: "802698XOMSrr"
22: "charCodeAt"
23: "474547vVoGDO"
24: "getElementById"

変換表(シャッフル後)に基づいた難読化の解除

onButtonPress()
function onButtonPress() {
  const _0xa80748 = _0x4e0e;
  let _0x3761f8 = document['getElementById']("input")["value"];
  for (let _0x16c626 = 0x0; _0x16c626 < _0x3761f8['length']; _0x16c626++) {
    exports["copy_char"](_0x3761f8["charCodeAt"](_0x16c626), _0x16c626);
  }
  exports['copy_char'](0x0, _0x3761f8['length']), exports["check_flag"]() == 0x1 ? document["getElementById"]("result")["innerHTML"] = "Correct!" : document["getElementById"]("result")["innerHTML"] = "Incorrect!";
}

意味判るようになった。
check_flagという関数とcopy_charという関数をexportしてる。

なるほど, JavaScript モジュールを動的に作成するのね
が,中身はようわからん。
たぶん,シャッフル兼,フラグを復号しているところ

(function (_0x76dd13, _0x3dfcae) {
  const _0x371ac6 = _0x4e0e;
  while (!![]) {
    try {
      const _0x478583 = -parseInt(_0x371ac6(0x1eb)) + parseInt(_0x371ac6(0x1ed)) + -parseInt(_0x371ac6(0x1db)) * -parseInt(_0x371ac6(0x1d9)) + -parseInt(_0x371ac6(0x1e2)) * -parseInt(_0x371ac6(0x1e3)) + -parseInt(_0x371ac6(0x1de)) * parseInt(_0x371ac6(0x1e0)) + parseInt(_0x371ac6(0x1d8)) * parseInt(_0x371ac6(0x1ea)) + -parseInt(_0x371ac6(0x1e5));
      if (_0x478583 === _0x3dfcae) break;
      else _0x76dd13['push'](_0x76dd13['shift']());
    } catch (_0x41d31a) {
      _0x76dd13['push'](_0x76dd13['shift']());
    }
  }
}(_0x402c, 0x994c3));
let exports;
(async() => {
  const _0x48c3be = _0x4e0e;
  let _0x5f0229 = await fetch(_0x48c3be(0x1e9)),
    _0x1d99e9 = await WebAssembly[_0x48c3be(0x1df)](await _0x5f0229[_0x48c3be(0x1da)]()),
    _0x1f8628 = _0x1d99e9[_0x48c3be(0x1d6)];
  exports = _0x1f8628['exports'];
})();

この中では WebAssembly が気になる

WebAssembly は JavaScript と並行して動作するらしい

image.png

exportしてたcheck_flag()があった。
image.png
copy_charも
image.png
その下には。。。
image.png
ビンゴ!
あの変なJavascriptちゃんと動くのね
image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?