There is an HTML injection in the
write.html endpoint. However, it is not exploitable because of a strict CSP
script-src "self" "unsafe-eval".
program.ts has a call to
eval that allows us to bypass the CSP if we can control the HTPL compiler output.
It is possible to forge HTML-like comments using the HTPL language to invalidate the
; at the end of each line.
We can now forge code to access an object (array) property and get references to
function.constructor to create code from a string and, with that in mind, we can obtain a reference to the
After this, exploitation is trivial to retrieve the value of
(Implementation details in the attachments)
Analyzing the Service
This challenge implements a simple compiler for an XML-based language called Hyper Text Programming Language.
src/ast/program.ts line 41).
While exploring the service, we noticed that there was a plain HTML injection in the
We also noticed that the bot clicked on all the buttons on the page that had the
run-btn class assigned.
However, this is not easily exploitable due to the page having a strict CSP (
script-src "self" "unsafe-eval").
After noticing this, we concluded that we needed to somehow exploit the compiler itself.
The compiler has a very reduced set of functionalities.
We also cannot access already defined variables like the
window object because the
ASTIdentifier node prepends and appends a
$ to the variable name.
There is, however, a way to create arrays and call some built-in functions.
We will use this later in the exploit.
Following this cue, we stumbled upon a rather famous programming language called JSFuck.
Taking inspiration from this we started toying around with array creation, since if we can access the property
filter of an array, we get a reference to a function.
It was around this time that we noticed that the main issue with the compiler is that it appends a
This meant we couldn’t easily produce the following output:
 ["filter"] ["constructor"]
Instead, we would get the following:
; ["filter"]; ["constructor"];
Note that the two payloads are effectively different since the first evals to
function Function() and the second evals to the creation of 3 arrays.
The next thought we had is that if we can somehow inject comments before the
;, we could have a working exploit rather easily.
//; ["filter"]//; ["constructor"];
We started exploring the division functionality of the language without success, since we always needed to provide a left-hand and a right-hand operator for the
ASTDiv node to compile successfully.
<!--; ["filter"]<!--; ["constructor"];
We were amazed that this not only worked but was also spec-compliant (see this).
We could generate the above output using the following HTPL code using the less than operator, the not operator and an array node.
So the following code:
<x-let> <x-identifier>filter_constructor</x-identifier> <x-lt> <x-array>a</x-array> <x-not> <x-dec> <x-identifier>a</x-identifier> </x-dec> </x-not> </x-lt> </x-let> <x-lt> <x-array><x-str>filter</x-str></x-array> <x-not> <x-dec> <x-identifier>a</x-identifier> </x-dec> </x-not> </x-lt> <x-array><x-str>constructor</x-str></x-array>
let $filter_constructor$ = <!--$a$; ["filter"]<!--$a$; ["constructor"];
As the language supports function calls, we could easily run arbitrary code with a reference to a function constructor using the following code:
<x-let> <x-identifier>window_fn</x-identifier> <x-call> <x-identifier>filter_constructor</x-identifier> <x-str>return this</x-str> </x-call> </x-let> <x-let> <x-identifier>window</x-identifier> <x-call> <x-identifier>window_fn</x-identifier> </x-call> </x-let>
let $window_fn$ = filter_constructor("return this"); let $window$ = $window_fn$();
And after this, we got a reference to the
window object :D
The rest of the exploit uses the above functionalities to access the
window.document.cookie and return the cookies using the