2

So here's the deal. I've been working on an SQL injection challenge and here's what comes up.

There's a registration page where you input your Username, password and confirm password. It's vulnerable to INSERT SQL injection, I'm basically trying to insert my own data and make myself and admin (admin=1). However, there is a SELECT statement before the INSERT statement that checks if the username exists in the database. The problem is, if I try inserting data with SQL injection, the SELECT statement will fail and will generate an error, and the INSERT statement will never be executed.

I've made an in-a-nutshell PHP code to show you how it works.

<?php
    $username = $_POST['username'];
    $password = md5($_POST['password']);

    $sql = mysqli_query("SELECT * FROM users WHERE username = '$username';");
    if(mysqli_num_rows($sql) > 0 || !$sql) {
        // this code will be run if the username already exists OR an SQL error in the query above.
    }
    else {
        $sql = mysqli_query("INSERT INTO users (`id`,`username`,`password`,`admin`) VALUES (NULL,'$username','$password',0);");
    }
?>

So the thing is, if I tried signing up with the username "admintest','password',1);-- " which should in theory INSERT myself into the database as an admin, here comes the problems.

The problem, is the SELECT query. Watch what happens.

SELECT * FROM users WHERE username = 'admintest','password',1);-- ';

This of course is a syntax-error, and as we saw by the code I provided above, an IF statement will confirm that the SQL query was a syntax error, and the INSERT statement will NEVER run.

In an ideal world, this should happen in the INSERT statement, which will insert me as an ADMIN.

INSERT INTO users (`id`,`username`,`password`,`admin`) VALUES (NULL,'admintest','password',1);-- ','password',0);

I've tried to work out something that doesn't generate a syntax error on the SELECT, and also INSERTs the data I want to insert. Would be appreciated if anyone could help out :)

5
  • I think this is where the whole OR 1==1 pattern comes into play.
    – schroeder
    Sep 6, 2020 at 13:20
  • I was thinking something of the same, but had no idea how to execute it. Do you have any suggestions? Sep 6, 2020 at 13:23
  • While I am looking into this, I have another suggestion for you: since this site is obviously vulnerable I would try to dump the table of users, for this SQLmap should do the job. Then, if you have the md5 for the admin user there is a good chance you will be able to retrieve the password unless it is quite difficult/unique. Then you will be able to login as admin.
    – Kate
    Sep 6, 2020 at 14:04
  • I've already tried doing this with manual injection, sadly, the MD5 seems to be quite difficult/unique as no site or hashcat could decrypt it. Thanks though! :) Sep 6, 2020 at 14:14
  • Does mysqli_query allow you to run multiple SQL queries? Could you insert the admin user in the select query by using a username like foo'; INSERT INTO users ... --?
    – Anders
    Sep 7, 2020 at 13:02

2 Answers 2

1

You don't need to enter into the else branch. What do you think will happen for someone whose name is

doesntexist' UNION SELECT 1, 'Charlie','a744e1091c25babd36b50e40fb8d311a','1"

?

2
  • Hi, I'd need to include a ")" at the end for it to be valid in the INSERT. Nice idea though! Thanks. Sep 6, 2020 at 21:57
  • @CharlieWells you don't go at the insertion, this simply makes the select return a user Charlie with password stackoverflow which is an admin
    – Ángel
    Sep 7, 2020 at 1:33
0

Here is my proposal.

You have two options here: tamper with the username or the password. The trick is to devise a query that will work in both the SELECT and the INSERT. We have to trick the password value.

First of all, choose a password and compute the MD5 yourself. For example, if the password is "thepassword", then the MD5 is: b25bc8c9efabdd0837bb7d9deace1308.

Choose some username that does not already exist on the target system. This code:

$username = "some_user";
$password = "3c41ff681c1e3dcb68b4d8573bf1c74c', 1); -- ";

will produce the following queries:

SELECT * FROM users WHERE username = 'some_user';

=> This will work since it's syntactically correct

INSERT INTO users (`id`,`username`,`password`,`admin`) VALUES (NULL,'some_user','3c41ff681c1e3dcb68b4d8573bf1c74c', 1); -- ',0);

If the first query will not find a matching user, then the INSERT query will be run. This should add a record with the chosen username and password, and admin flag = 1.

1
  • 1
    I love the idea, but the only problem, is that the Password is MD5 hashed right at the start of the script, meaning any SQL injection payload will just be turned into a MD5 hash. $password = md5($_POST['password']); Sep 6, 2020 at 19:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .