Exzendtential-crisis  
\--------  
We are given a [site](http://d4a386ad.quals2018.oooverflow.io/) with two forms
in the homepage: one to register an account, and one to login to an account.
There is also a "debug me" link that shows the source code of the page.

Once we register an account, we can write an essay on the page `essays.php`.
This page lists all the essays that the user wrote, and provides a preview.
Appending `?source` to the url shows the page source (as in index.php). There
is an obvious file disclosure:

```php  
if (isset($_GET['preview']))  
{  
$dirname = "upload/${_SESSION['userid']}/";  
$fname = $_GET['name'];

if (check_fname($fname) === False)  
{  
header("Location: /essays.php");  
exit();  
}  
$content = file_get_contents($dirname . $fname, False, NULL, 0, 524288);  
echo "<h1>Your essay submission</h1>";  
echo "

    
    
    ";  
       echo $content;  
       echo "

";  
echo "  
";  
echo "back";  
exit();  
}  
```

There is also a `flag.php` file, that only says:  
```  
Only sarte knows the flag. You are not him. Enjoy a quote though:  
One love, a career, a revolution, as many companies as we begin ignoring their
outcome  
```

Retrieving `php.ini` with the file disclousure shows that there is a custom
module in the PHP installation, called `mydb.so`. With the file disclousure we
downloaded the module, and then we started reversing it.

After reversing the module, we find that it exports 3 functions to PHP:
`create_user`, `get_result` (both used in `register.php`), and
`check_credentials` (used in `login.php`).  
Internally, the module uses SQLite for storing user credentials, without
validating the input (this is done on the PHP-side).  
After looking a bit, we found an out-of-bounds write vulnerability that we can
use to inject arbitrary SQL into a query.  
In `check_credentials`, the module first retrieves the function arguments, and
then calls `get_user_id` in order to verify the username/password. It passes
to it a callback function, `check_hacking_attempt`, that takes two buffers,
one containing the username, and one to copy the username to. It does some
security checks before sending a query to SQLite. `check_hacking_attempt`
copies the username string to the destination buffer, as long as its length is
less than 150 characters. However, the destination buffer resides in the stack
frame of `get_user_id`, which only allocated 112 bytes for it. Therefore,
there is a 38 byte overflow.

In `get_user_id`, the destination buffer is located just before a table name
buffer, which contains the name of the table used in the user selection query.
By overwriting the table name, we can inject arbitrary SQL into the query. The
injection that we choose is pretty trivial: `users where username="sarte" --
`.

The final payload is generated by the Python snippet `print('a' * 112 + 'users
where username="sarte" -- ')`, that once inserted as username in the login,
authenticates us as `sarte`. We can now retrieve the flag.  

Original writeup
(https://mhackeroni.it/archive/2018/05/20/defconctfquals-2018-all-
writeups.html#exzendtential-crisis).