HackTheBox Canvas CTF Writeup

Surya Dev Singh
InfoSec Write-ups
Published in
6 min readOct 4, 2022

--

DESCRIPTIONS :

We want to update our website but we are unable to because the developer who coded this left today. Can you take a look?

SOLUTION :

After unzipping the content of the file we got from the task we can see we got some files, which seems like the file of websites, including javascript, CSS and dashborad.html, and index.html.

at first, I thought of let’s open the index.html in the browser, to see what’s there actually !!

as you can see we got some login page, since everything is static means the javascript code would have been use for authentication purposes, so out of curiosity I entered some random creds and I got this pop-up:

so, means the javascript code is being used to count the wrong attempts. after failing for three attempts, the username and password field becomes unclickable. (we can make it normal; just refresh the page)

after trying to figure out the creds, I have randomly use the universal attempts creds admin: admin, and I got this pop-up!!

and we are redirected to dahsboard.html, which contains the flag template, not the actual flag.

I tried to look around the source code and other cookies, but nothing interesting comes up. till now I have not analyzed the javascript file. so let’s analyze it.

after opening the javascript file everything is gibberish. the javascript obfuscation is done to make it harder to understand. so let’s deobfuscate it, I will use an online tool: https://lelinhtinh.github.io/de4js/

and you can now see the deobfuscated javascript source code :

'use strict';

var _0x4e0b = ["toString", "username", "console", "getElementById", "log", "bind", "disabled", "apply", "admin", "prototype", '{}.constructor("return this")( )', " attempt;", "value", "constructor", "You have left ", "trace", 'return /" + this + "/', "table", "length", "__proto__", "error", "Login successfully"];
(function (params, content) {

var fn = function (selected_image) {
for (; --selected_image;) {
params["push"](params["shift"]());
}
};

var build = function () {
var target = {
"data": {
"key": "cookie",
"value": "timeout"
},
"setCookie": function (value, name, path, headers) {
headers = headers || {};

var cookie = name + "=" + path;

var _0x3f3096 = 0;

var url = 0;
var key = value["length"];
for (; url < key; url++) {
var i = value[url];

cookie = cookie + ("; " + i);
var char = value[i];
value["push"](char);
key = value["length"];
if (char !== !![]) {

cookie = cookie + ("=" + char);
}
}

headers["cookie"] = cookie;
},
"removeCookie": function () {
return "dev";
},
"getCookie": function (match, href) {
match = match || function (canCreateDiscussions) {
return canCreateDiscussions;
};
var v = match(new RegExp("(?:^|; )" + href["replace"](/([.$?*|{}()[]\/+^])/g, "$1") + "=([^;]*)"));

var test = function (callback, i) {
callback(++i);
};
return test(fn, content), v ? decodeURIComponent(v[1]) : undefined;
}
};

var init = function () {

var test = new RegExp("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}");
return test["test"](target["removeCookie"]["toString"]());
};

target["updateCookie"] = init;

var array = "";
var _0x4ac08e = target["updateCookie"]();
if (!_0x4ac08e) {
target["setCookie"](["*"], "counter", 1);
} else {
if (_0x4ac08e) {
array = target["getCookie"](null, "counter");
} else {
target["removeCookie"]();
}
}
};
build();
})(_0x4e0b, 386);

var _0x20fe = function (level, ai_test) {

level = level - 0;
var rowsOfColumns = _0x4e0b[level];
return rowsOfColumns;
};
var _0x35c856 = function () {

var y$$ = !![];
return function (ch, myPreferences) {

var voronoi = y$$ ? function () {

var getPreferenceKey = _0x20fe;
if (myPreferences) {
var bytes = myPreferences[getPreferenceKey("0x11")](ch, arguments);
return myPreferences = null, bytes;
}
} : function () {};
return y$$ = ![], voronoi;
};
}();
var _0x4ac08e = _0x35c856(this, function () {

var checkApplyFunction = function () {

var check = _0x20fe;
var B713 = checkApplyFunction[check("0x1")](check("0x4"))()[check("0x1")]("^([^ ]+( +[^ ]+)+)+[^ ]}");
return !B713["test"](_0x4ac08e);
};
return checkApplyFunction();
});
_0x4ac08e();
var _0x4c641a = function () {

var y$$ = !![];
return function (ch, myPreferences) {

var voronoi = y$$ ? function () {

var getPreferenceKey = _0x20fe;
if (myPreferences) {
var bytes = myPreferences[getPreferenceKey("0x11")](ch, arguments);
return myPreferences = null, bytes;
}
} : function () {};
return y$$ = ![], voronoi;
};
}();
var _0x2548ec = _0x4c641a(this, function () {

var rel2Mstr = _0x20fe;
var el;
try {
var render = Function("return (function() " + rel2Mstr("0x14") + ");");
el = render();
} catch (_0x57823f) {

el = window;
}
var uids = el[rel2Mstr("0xc")] = el[rel2Mstr("0xc")] || {};

var levels = [rel2Mstr("0xe"), "warn", "info", rel2Mstr("0x8"), "exception", rel2Mstr("0x5"), rel2Mstr("0x3")];

var j = 0;
for (; j < levels[rel2Mstr("0x6")]; j++) {
var intval = _0x4c641a[rel2Mstr("0x1")][rel2Mstr("0x13")]["bind"](_0x4c641a);
var i = levels[j];
var same = uids[i] || intval;
intval[rel2Mstr("0x7")] = _0x4c641a[rel2Mstr("0xf")](_0x4c641a);
intval["toString"] = same[rel2Mstr("0xa")][rel2Mstr("0xf")](same);
uids[i] = intval;
}
});
_0x2548ec();

var attempt = 3;

function validate() {

var _ = _0x20fe;
var oldValue = document["getElementById"]("username")["value"];
var newValue = document[_("0xd")]("password")[_("0x0")];
if (oldValue == _("0x12") && newValue == _("0x12")) {
return alert(_("0x9")), window["location"] = "dashboard.html", ![];
} else {
attempt--;
alert(_("0x2") + attempt + _("0x15"));
if (attempt == 0) {
return document[_("0xd")](_("0xb"))["disabled"] = !![], document[_("0xd")]("password")[_("0x10")] = !![], document[_("0xd")]("submit")[_("0x10")] = !![], ![];
}
}
}
var res = String["fromCharCode"](72, 84, 66, 123, 87, 51, 76, 99, 48, 109, 51, 95, 55, 48, 95, 74, 52, 86, 52, 53, 67, 82, 49, 112, 55, 95, 100, 51, 48, 98, 70, 117, 53, 67, 52, 55, 49, 48, 78, 125, 10);

I have tried to understand the code but wasn’t properly understanding everything

but the last variable res which is not used anywhere, and seems interesting. which uses the code String.fromCharCode . we simply decode it to understand what’s the value of that variable

72, 84, 66, 123, 87, 51, 76, 99, 48, 109, 51, 95, 55, 48, 95, 74, 52, 86, 52, 53, 67, 82, 49, 112, 55, 95, 100, 51, 48, 98, 70, 117, 53, 67, 52, 55, 49, 48, 78, 125, 10

I will use cyberchef for this, first, let’s replace the space in between, and then we can either use magic or from decimal as recipes

and as you can see we got our flag !!!!

THANK YOU FOR READING MY ARTICLE !! 👊👊

please support me by following me on medium and other social platforms:

https://surya-dev.medium.com/

https://twitter.com/kryolite_secure/

https://www.instagram.com/kryolite_security/

https://github.com/surya-dev-singh/

you guys can subscribe to me 🙌on YouTube: I post walkthroughs and other ethical hacking-related videos there.

From Infosec Writeups: A lot is coming up in the Infosec every day that it’s hard to keep up with. Join our weekly newsletter to get all the latest Infosec trends in the form of 5 articles, 4 Threads, 3 videos, 2 GitHub Repos and tools, and 1 job alert for FREE!

--

--

enthusiast cyber security learner and penetration tester / ethical hacker , python programmer and in my free time you will find me solving CTFs