Post

Canvas - HTB Easy Challenge | JavaScript Obfuscation Reversing

Complete walkthrough of Canvas from Hack The Box. An easy misc challenge featuring a heavily obfuscated JavaScript login script serving a static website. Analyzing the login.js source reveals an array of hexadecimal byte values matching the HTB{...} flag format. Converting the hex bytes to their ASCII characters with a short Python script directly recovers the flag.

Canvas - HTB Easy Challenge | JavaScript Obfuscation Reversing

Challenge Overview

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

Source Code

Here’s the source code structure using the tree . command:

1
2
3
4
5
6
7
8
9
.
├── css
│   └── style.css
├── dashboard.html
├── index.html
└── js
    └── login.js

3 directories, 7 files

File Analysis

The HTML and CSS files don’t matter to us. What matters is the login.js file. Here’s its content (originally a single line, but reformatted with JavaScript’s prettier for readability):

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
var _0x4e0b = [
  "\x74\x6f\x53\x74\x72\x69\x6e\x67",
  "\x75\x73\x65\x72\x6e\x61\x6d\x65",
  "\x63\x6f\x6e\x73\x6f\x6c\x65",
  "\x67\x65\x74\x45\x6c\x65\x6d\x65\x6e\x74\x42\x79\x49\x64",
  "\x6c\x6f\x67",
  "\x62\x69\x6e\x64",
  "\x64\x69\x73\x61\x62\x6c\x65\x64",
  "\x61\x70\x70\x6c\x79",
  "\x61\x64\x6d\x69\x6e",
  "\x70\x72\x6f\x74\x6f\x74\x79\x70\x65",
  "\x7b\x7d\x2e\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72\x28\x22\x72\x65\x74\x75\x72\x6e\x20\x74\x68\x69\x73\x22\x29\x28\x20\x29",
  "\x20\x61\x74\x74\x65\x6d\x70\x74\x3b",
  "\x76\x61\x6c\x75\x65",
  "\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72",
  "\x59\x6f\x75\x20\x68\x61\x76\x65\x20\x6c\x65\x66\x74\x20",
  "\x74\x72\x61\x63\x65",
  "\x72\x65\x74\x75\x72\x6e\x20\x2f\x22\x20\x2b\x20\x74\x68\x69\x73\x20\x2b\x20\x22\x2f",
  "\x74\x61\x62\x6c\x65",
  "\x6c\x65\x6e\x67\x74\x68",
  "\x5f\x5f\x70\x72\x6f\x74\x6f\x5f\x5f",
  "\x65\x72\x72\x6f\x72",
  "\x4c\x6f\x67\x69\x6e\x20\x73\x75\x63\x63\x65\x73\x73\x66\x75\x6c\x6c\x79",
];
(function (_0x173c04, _0x4e0b6e) {
  var _0x20fedb = function (_0x2548ec) {
      while (--_0x2548ec) {
        _0x173c04["\x70\x75\x73\x68"](_0x173c04["\x73\x68\x69\x66\x74"]());
      }
    },
    _0x544f36 = function () {
      var _0x4c641a = {
          "\x64\x61\x74\x61": {
            "\x6b\x65\x79": "\x63\x6f\x6f\x6b\x69\x65",
            
<SNIP>

var res = String["\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65"](
  0x48,
  0x54,
  0x42,
  0x7b,
  0x57,
  0x33,
  0x4c,
  0x63,
  0x30,
  0x6d,
  0x33,
  0x5f,
  0x37,
  0x30,
  0x5f,
  0x4a,
  0x34,
  0x56,
  0x34,
  0x35,
  0x43,
  0x52,
  0x31,
  0x70,
  0x37,
  0x5f,
  0x64,
  0x33,
  0x30,
  0x62,
  0x46,
  0x75,
  0x35,
  0x43,
  0x34,
  0x37,
  0x31,
  0x30,
  0x4e,
  0x7d,
  0xa,
);

The JavaScript code has clearly been obfuscated, replacing plaintext strings with hex-encoded text. Most of this code doesn’t matter, since knowing the HTB{flag} format we can search for the byte 0x48, representing the uppercase H, to locate the flag.

Exploit

We can find the uppercase H and T bytes at the bottom of the code (last part of the snippet above). Here’s a short Python exploit to quickly do the conversion:

1
2
3
4
5
6
7
hex_encoded_flag = [0x48,0x54,0x42,0x7B,0x57,0x33,0x4C,0x63,0x30,0x6D,0x33,0x5F,0x37,0x30,0x5F,0x4A,0x34,0x56,0x34,0x35,0x43,0x52,0x31,0x70,0x37,0x5F,0x64,0x33,0x30,0x62,0x46,0x75,0x35,0x43,0x34,0x37,0x31,0x30,0x4E,0x7D,0xA]
flag = ''

for i in hex_encoded_flag:
    flag += chr(i)

print(flag)

Flag obtained.

This post is licensed under CC BY 4.0 by the author.