HeroCTF v5 — Open your eyes #1 [Sponsors]

Muhammad Ichwan
4 min readMay 16, 2023

--

Deskripsi:

Sometimes there is more than meets the eye. Be clever and collect the 5 flags. Some are easy, some are hard.

Access the challenge here : https://heroctf.joinopencyber.tech/
Format : Hero{J…}
Author : OPENCYBER

Challenge ini adalah Web to Reversing dengan kategori Sponsors karena dibuat oleh Sponsors HeroCTF.

Proses awal nya berada dari aplikasi Web. Namun service web nya sudah dimatikan. Untuk gambarannya:

Pada web aplikasi, terdapat service untuk mengirim pesan, namun membutuhkan nama penerima dan secret yang tidak diketahui. Oleh karena itu, dilakukan analisis source file dan didapatkan sesuatu yang menarik pada file App.js

Source App.js

var _0x2fd66f = _0x48f2;

function _0x48f2(_0x4bf838, _0x32e0d4) {
var _0x490f40 = _0x490f();
return _0x48f2 = function(_0x48f26a, _0x7afb4f) {
_0x48f26a = _0x48f26a - 0xd2;
var _0x3a1bf3 = _0x490f40[_0x48f26a];
return _0x3a1bf3;
}, _0x48f2(_0x4bf838, _0x32e0d4);
}(function(_0x5ed8d7, _0x32731c) {
var _0x53ac89 = _0x48f2,
_0xd2e4dc = _0x5ed8d7();
while (!![]) {
try {
var _0x53e8dd = -parseInt(_0x53ac89(0xd8)) / 0x1 + parseInt(_0x53ac89(0xda)) / 0x2 * (parseInt(_0x53ac89(0xe3)) / 0x3) + -parseInt(_0x53ac89(0xea)) / 0x4 * (-parseInt(_0x53ac89(0xd7)) / 0x5) + -parseInt(_0x53ac89(0xdf)) / 0x6 + parseInt(_0x53ac89(0xdb)) / 0x7 * (parseInt(_0x53ac89(0xe0)) / 0x8) + parseInt(_0x53ac89(0xde)) / 0x9 * (-parseInt(_0x53ac89(0xe9)) / 0xa) + parseInt(_0x53ac89(0xe8)) / 0xb;
if (_0x53e8dd === _0x32731c) break;
else _0xd2e4dc['push'](_0xd2e4dc['shift']());
} catch (_0xc4b30e) {
_0xd2e4dc['push'](_0xd2e4dc['shift']());
}
}
}(_0x490f, 0xd3277), document[_0x2fd66f(0xd3)]('DOMContentLoaded', function() {
var _0x4cbad0 = _0x2fd66f,
_0x205285 = '',
_0x2e08e0 = 'H';
_0x2e08e0 += _0x4cbad0(0xeb), _0x2e08e0 += 'o', _0x2e08e0 += '{', _0x2e08e0 += 'J@v', _0x2e08e0 += '@', _0x2e08e0 += 'Scr', _0x2e08e0 += _0x4cbad0(0xdc), _0x2e08e0 += _0x4cbad0(0xe2), _0x2e08e0 += 'l3s', _0x2e08e0 += _0x4cbad0(0xdd);
let _0x3c22af = _0x4cbad0(0xe1);
document[_0x4cbad0(0xd4)] = function(_0x1f806d) {
var _0x45a81e = _0x4cbad0;
_0x205285 += _0x1f806d[_0x45a81e(0xe7)];
if (_0x205285[_0x45a81e(0xd9)](_0x3c22af)) {
_0x2e08e0 += 'lw', _0x2e08e0 += 'ay', _0x2e08e0 += _0x45a81e(0xd5), _0x2e08e0 += _0x45a81e(0xd6), _0x2e08e0 += _0x45a81e(0xe5), _0x2e08e0 += _0x45a81e(0xe4), _0x2e08e0 += '}';
let _0x204ff7 = prompt(_0x45a81e(0xd2));
_0x204ff7 === _0x2e08e0 && alert(_0x45a81e(0xe6)), _0x205285 = '';
}
};
}));

function _0x490f() {
var _0x175788 = ['Gr@b', '_t0_', 'Good\x20job\x20!', 'key', '20613340MllZmz', '13300kJNTLe', '1116ZMLZms', 'er', 'Guess\x20my\x20secret', 'addEventListener', 'onkeydown', '$_N', 'ic3', '18665cgRZrY', '766515GFdEek', 'includes', '110694aVtJvA', '14lZjadv', '!pt', '_R_a', '9972JuzoNl', '8811684tckuuf', '212584bxTpGA', 'opencyber-hero', '_f!', '87rsflun'];
_0x490f = function() {
return _0x175788;
};
return _0x490f();
}

Diketahui bahwa code javascript tersebut dilakukan obfuscate, Coba lakukan deobfuscate code tersebut entah kenapa tidak berhasil. Karena tidak bisa dilakukan deobfuscate, maka lakukan analisa sendiri. Analisa dilakukan dari baris code paling bawah sampai ke atas karena lebih mudah dipahami.

Analisa file App.js:

....SNIP....
function _0x490f() {
var _0x175788 = ['Gr@b', '_t0_', 'Good\x20job\x20!', 'key', '20613340MllZmz', '13300kJNTLe', '1116ZMLZms', 'er', 'Guess\x20my\x20secret', 'addEventListener', 'onkeydown', '$_N', 'ic3', '18665cgRZrY', '766515GFdEek', 'includes', '110694aVtJvA', '14lZjadv', '!pt', '_R_a', '9972JuzoNl', '8811684tckuuf', '212584bxTpGA', 'opencyber-hero', '_f!', '87rsflun'];
_0x490f = function() {
return _0x175788;
};
return _0x490f();
}
....SNIP....

Pertama, mulai dari fungsi _0x490f(). Fungsi _0x490f berisi sebuah variable _0x175788 yang menampung list string. Setelah itu, akan dilakukan return ke variable tersebut apabila fungsi dijalankan.

....SNIP....
var _0x4cbad0 = _0x2fd66f,
_0x205285 = '',
_0x2e08e0 = 'H';
_0x2e08e0 += _0x4cbad0(0xeb), _0x2e08e0 += 'o', _0x2e08e0 += '{', _0x2e08e0 += 'J@v', _0x2e08e0 += '@', _0x2e08e0 += 'Scr', _0x2e08e0 += _0x4cbad0(0xdc), _0x2e08e0 += _0x4cbad0(0xe2), _0x2e08e0 += 'l3s', _0x2e08e0 += _0x4cbad0(0xdd);
let _0x3c22af = _0x4cbad0(0xe1);
document[_0x4cbad0(0xd4)] = function(_0x1f806d) {
var _0x45a81e = _0x4cbad0;
_0x205285 += _0x1f806d[_0x45a81e(0xe7)];
if (_0x205285[_0x45a81e(0xd9)](_0x3c22af)) {
_0x2e08e0 += 'lw', _0x2e08e0 += 'ay', _0x2e08e0 += _0x45a81e(0xd5), _0x2e08e0 += _0x45a81e(0xd6), _0x2e08e0 += _0x45a81e(0xe5), _0x2e08e0 += _0x45a81e(0xe4), _0x2e08e0 += '}';
....SNIP....

Kedua, mari berfokus ke fungsi tengah, karena terdapat proses yang berisi pattern dari flag seperti karakter “H, o, {, J@v, @, Scr, l3s”.

Variable _0x4cbad0 menampung fungsi _0x2fd66f(). Apabila memanggil variable _0x4cbad0 sama dengan memanggil fungsi _0x2fd66f.

Pada variable _0x2e08e0 awalnya menampung huruf “H”, namun pada proses selanjutnya, variable tersebut dilakukan operator penugasan / join (+=) dengan karakter dan fungsi _0x4cbad0(). Asumsinya, variable ini menampung string flag.

....SNIP....
var _0x45a81e = _0x4cbad0;
...
_0x2e08e0 += 'lw', _0x2e08e0 += 'ay', _0x2e08e0 += _0x45a81e(0xd5), _0x2e08e0 += _0x45a81e(0xd6), _0x2e08e0 += _0x45a81e(0xe5), _0x2e08e0 += _0x45a81e(0xe4), _0x2e08e0 += '}';
....SNIP....

Ketiga, Diketahui bahwa variable _0x45181e menampung fungsi _0x4cbad0. Apabila memanggil variable _0x45181e sama dengan memanggil _0x4cbad0.

Selain itu, terdapat join variable yang sama seperti sebelumnya, yaitu _0x2e08e0. Diketahui bahwa main proses code tersebut yaitu fungsi _0x4cbad0, sehingga perlu dilakukan analisa ke fungsi tersebut.

var _0x2fd66f = _0x48f2;

function _0x48f2(_0x4bf838, _0x32e0d4) {
var _0x490f40 = _0x490f();
return _0x48f2 = function(_0x48f26a, _0x7afb4f) {
_0x48f26a = _0x48f26a - 0xd2;
var _0x3a1bf3 = _0x490f40[_0x48f26a];
return _0x3a1bf3;
....SNIP....

Keempat, sebelumnya diketahui bahwa _0x4cbad0() memanggil _0x2fd66f. Pada code bagian atas, diketahui bahwa variable _0x2fd66f akan memanggil ke fungsi _0x48f2(). Hingga kita ketahui bahwa fungsi akhir yang benar adalah _0x48f2().

Pada fungsi _0x48f2() tersebut berisi 2 parameter, serta terdapat variable _0x490f40 yang menampung fungsi _0x490f() atau fungsi yang berisi list pada code bagian bawah.

Didalam fungsi tersebut, parameter _0x48f26a akan dikurangi dengan 0xd2. Selanjutnya, variable _0x3a1bf3 akan memanggil fungsi _0x490f() dengan index variable _0x48f26a yang telah melakukan proses pengurangan.

Solusi:

Pada intinya, app.js ini akan melakukan proses join variable dengan karakter serta fungsi yang telah dilakukan pemanggilan dengan index tertentu. Tetapi flow code nya dibuat terlihat rumit.

Solver:

def _0x490f():
_0x175788 = ['Gr@b', '_t0_', 'Good\x20job\x20!', 'key', '20613340MllZmz', '13300kJNTLe', '1116ZMLZms', 'er', 'Guess\x20my\x20secret', 'addEventListener', 'onkeydown', '$_N', 'ic3', '18665cgRZrY', '766515GFdEek', 'includes', '110694aVtJvA', '14lZjadv', '!pt', '_R_a', '9972JuzoNl', '8811684tckuuf', '212584bxTpGA', 'opencyber-hero', '_f!', '87rsflun']

return _0x175788

def _0x48f2(_0x48f26a):
_0x48f26a -= 0xe4 # Sebelumnya 0xd2, dilakukan bruteforce manual untuk mendapatkan output yang membentuk kata
_0x3a1bf3 = _0x490f()[_0x48f26a]
return _0x3a1bf3

_0x2e08e0 = 'H'
_0x2e08e0 += _0x48f2(0xeb) + 'o' + '{' + 'J@v' + '@' + 'Scr' + _0x48f2(0xdc) + _0x48f2(0xe2) + 'l3s' + _0x48f2(0xdd)

_0x205285 = ''
_0x205285 += _0x48f2(0xe7)

_0x2e08e0 += 'lw' + 'ay' + _0x48f2(0xd5) + _0x48f2(0xd6) + _0x48f2(0xe5) + _0x48f2(0xe4) + '}'
print(_0x2e08e0)

Tinggal jalankan solver nya:

Mohon maaf apabila writeup ini susah dipahami, karena penulis juga bingung merangkai kata-katanya :)

Terima kasih sudah membaca, semoga bermanfaat untuk kita semua.

--

--

Muhammad Ichwan

IT Security Enthusiast | CTF Player with warlock_rootx and [MEPhI] Kernel Escape