Points: 110
Tags: picoCTF 2021, Web Exploitation
Author: SEARS SCHULZ
Description:
http://mercury.picoctf.net:53929/index.html
Hints:
(None)
Challenge link: https://play.picoctf.org/practice/challenge/131
Browse to the web site and then right-click and select 'View page source' (or press CTRL + U
).
We get a very short HTML page
<html>
<head>
<meta charset="UTF-8">
<script src="Y8splx37qY.js"></script>
</head>
<body>
<h4>Enter flag:</h4>
<input type="text" id="input"/>
<button onclick="onButtonPress()">Submit</button>
<p id="result"></p>
</body>
</html>
Click on the link to Y8splx37qY.js
to investigate the javascript source
const _0x6d8f=['copy_char','value','207aLjBod','1301420SaUSqf','233ZRpipt','2224QffgXU','check_flag','408533hsoVYx','instance','278338GVFUrH','Correct!','549933ZVjkwI','innerHTML','charCodeAt','./aD8SvhyVkb','result','977AzKzwq','Incorrect!','exports','length','getElementById','1jIrMBu','input','615361geljRK'];const _0x5c00=function(_0x58505a,_0x4d6e6c){_0x58505a=_0x58505a-0xc3;let _0x6d8fc4=_0x6d8f[_0x58505a];return _0x6d8fc4;};(function(_0x12fd07,_0x4e9d05){const _0x4f7b75=_0x5c00;while(!![]){try{const _0x1bb902=-parseInt(_0x4f7b75(0xc8))*-parseInt(_0x4f7b75(0xc9))+-parseInt(_0x4f7b75(0xcd))+parseInt(_0x4f7b75(0xcf))+parseInt(_0x4f7b75(0xc3))+-parseInt(_0x4f7b75(0xc6))*parseInt(_0x4f7b75(0xd4))+parseInt(_0x4f7b75(0xcb))+-parseInt(_0x4f7b75(0xd9))*parseInt(_0x4f7b75(0xc7));if(_0x1bb902===_0x4e9d05)break;else _0x12fd07['push'](_0x12fd07['shift']());}catch(_0x4f8a){_0x12fd07['push'](_0x12fd07['shift']());}}}(_0x6d8f,0x4bb06));let exports;(async()=>{const _0x835967=_0x5c00;let _0x1adb5f=await fetch(_0x835967(0xd2)),_0x355961=await WebAssembly['instantiate'](await _0x1adb5f['arrayBuffer']()),_0x5c0ffa=_0x355961[_0x835967(0xcc)];exports=_0x5c0ffa[_0x835967(0xd6)];})();function onButtonPress(){const _0x50ea62=_0x5c00;let _0x5f4170=document[_0x50ea62(0xd8)](_0x50ea62(0xda))[_0x50ea62(0xc5)];for(let _0x19d3ca=0x0;_0x19d3ca<_0x5f4170['length'];_0x19d3ca++){exports[_0x50ea62(0xc4)](_0x5f4170[_0x50ea62(0xd1)](_0x19d3ca),_0x19d3ca);}exports['copy_char'](0x0,_0x5f4170[_0x50ea62(0xd7)]),exports[_0x50ea62(0xca)]()==0x1?document['getElementById'](_0x50ea62(0xd3))[_0x50ea62(0xd0)]=_0x50ea62(0xce):document[_0x50ea62(0xd8)](_0x50ea62(0xd3))['innerHTML']=_0x50ea62(0xd5);}
Hhm, a bit obfuscated but we see a number of interesting strings in the _0x6d8f
array
- value
- check_flag
- Correct!
- charCodeAt
- ./aD8SvhyVkb (looks like a relative path)
- result
- Incorrect!
Let's retreive and analyse the file called aD8SvhyVkb
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2021/Web_Exploitation/Some_Assembly_Required_2]
└─$ wget http://mercury.picoctf.net:53929/aD8SvhyVkb
--2023-09-13 09:58:32-- http://mercury.picoctf.net:53929/aD8SvhyVkb
Resolving mercury.picoctf.net (mercury.picoctf.net)... 18.189.209.142
Connecting to mercury.picoctf.net (mercury.picoctf.net)|18.189.209.142|:53929... connected.
HTTP request sent, awaiting response... 200 OK
Length: 864
Saving to: ‘aD8SvhyVkb’
aD8SvhyVkb 100%[===============================================================================================================================>] 864 --.-KB/s in 0s
2023-09-13 09:58:32 (95.7 MB/s) - ‘aD8SvhyVkb’ saved [864/864]
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2021/Web_Exploitation/Some_Assembly_Required_2]
└─$ file aD8SvhyVkb
aD8SvhyVkb: WebAssembly (wasm) binary module version 0x1 (MVP)
As stated by file
it is in the binary format but we can always check for strings
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2021/Web_Exploitation/Some_Assembly_Required_2]
└─$ strings -n 8 aD8SvhyVkb
__wasm_call_ctors
check_flag
copy_char
__dso_handle
__data_end
__global_base
__heap_base
__memory_base
__table_base
!" ! "q!# #
!% $ %q!&
!( ' (q!) & )k!*
+xakgK\Ns>n;jl90;9:mjn9m<0n9::0::881<00?>u
Nope, not that easy this time! No cleartext flag.
Next, we decompile the webassembly file with wasm-decompile
from The WebAssembly Binary Toolkit - WABT
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2021/Web_Exploitation/Some_Assembly_Required_2]
└─$ ~/Tools/wabt/bin/wasm-decompile aD8SvhyVkb
export memory memory(initial: 2, max: 0);
global g_a:int = 66864;
export global input:int = 1072;
export global dso_handle:int = 1024;
export global data_end:int = 1328;
export global global_base:int = 1024;
export global heap_base:int = 66864;
export global memory_base:int = 0;
export global table_base:int = 1;
table T_a:funcref(min: 1, max: 1);
data d_xakgKNsnjl909mjn9m0n9088100u(offset: 1024) =
"xakgK\Ns>n;jl90;9:mjn9m<0n9::0::881<00?>u\00\00";
export function wasm_call_ctors() {
}
export function strcmp(a:int, b:int):int {
var c:int = g_a;
var d:int = 32;
var e:int = c - d;
e[6]:int = a;
e[5]:int = b;
var f:int = e[6]:int;
e[4]:int = f;
var g:int = e[5]:int;
e[3]:int = g;
loop L_b {
var h:ubyte_ptr = e[4]:int;
var i:int = 1;
var j:int = h + i;
e[4]:int = j;
var k:int = h[0];
e[11]:byte = k;
var l:ubyte_ptr = e[3]:int;
var m:int = 1;
var n:int = l + m;
e[3]:int = n;
var o:int = l[0];
e[10]:byte = o;
var p:int = e[11]:ubyte;
var q:int = 255;
var r:int = p & q;
if (r) goto B_c;
var s:int = e[11]:ubyte;
var t:int = 255;
var u:int = s & t;
var v:int = e[10]:ubyte;
var w:int = 255;
var x:int = v & w;
var y:int = u - x;
e[7]:int = y;
goto B_a;
label B_c:
var z:int = e[11]:ubyte;
var aa:int = 255;
var ba:int = z & aa;
var ca:int = e[10]:ubyte;
var da:int = 255;
var ea:int = ca & da;
var fa:int = ba;
var ga:int = ea;
var ha:int = fa == ga;
var ia:int = 1;
var ja:int = ha & ia;
if (ja) continue L_b;
}
var ka:int = e[11]:ubyte;
var la:int = 255;
var ma:int = ka & la;
var na:int = e[10]:ubyte;
var oa:int = 255;
var pa:int = na & oa;
var qa:int = ma - pa;
e[7]:int = qa;
label B_a:
var ra:int = e[7]:int;
return ra;
}
export function check_flag():int {
var a:int = 0;
var b:int = 1072;
var c:int = 1024;
var d:int = strcmp(c, b);
var e:int = d;
var f:int = a;
var g:int = e != f;
var h:int = -1;
var i:int = g ^ h;
var j:int = 1;
var k:int = i & j;
return k;
}
function copy(a:int, b:int) {
var c:int = g_a;
var d:int = 16;
var e:int_ptr = c - d;
e[3] = a;
e[2] = b;
var f:int = e[3];
if (eqz(f)) goto B_a;
var g:int = e[3];
var h:int = 8;
var i:int = g ^ h;
e[3] = i;
label B_a:
var j:int = e[3];
var k:byte_ptr = e[2];
k[1072] = j;
}
In the beginning of the decompiled data we can see what looks like an encrypted flag xakgK\Ns>n;jl90;9:mjn9m<0n9::0::881<00?>u\00\00
.
Also, we see an XOR-operation (^
) in the check_flag
function with the value 8
var h:int = 8;
var i:int = g ^ h;
Finally, let's check if this could be the encryption
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2021/Web_Exploitation/Some_Assembly_Required_2]
└─$ ~/python_venvs/pwntools/bin/python
Python 3.11.4 (main, Jun 7 2023, 10:13:09) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import xor
>>> enc_flag = b"xakgK\Ns>n;jl90;9:mjn9m<0n9::0::881<00?>u\00\00"
>>> xor(enc_flag, 8)
b'picoCTF{<REDACTED>}\x08\x08'
>>>
And it was!
For additional information, please see the references below.