2

Good morning,

I had some problems yesterday and got help, unfortunately, my app still not does 100% does what I want it to do, although only a small detail is missing.

Given a scenario where I want to do an SQL injection to drop a database, and when it happens, render a PHP page. Everything works fine until I want the render to happen - even though the injection executes and the DB is dropped when I check it MySQL, still no rendering. The problem is probably due to the incorrect usage of multi_query. More details in comments in the code.

<?php
include("/../../connection.php");

if(isset($_POST["button_one"])){
    $username = $_POST['username'];
    $password = $_POST['password'];

    if($conn->multi_query("SELECT id FROM users WHERE username = '$username' OR password = '$password'")) // IF THE USER HAS A VALID USERNAME OR PASSWORD,
    {
        do {
            if ($result = $conn->store_result()) {
                while ($row = $result->fetch_row()) { // THEN ENABLE BUTTON TWO, WHICH HAS TO BE CLICKED TO DROP THE DATABASE
                    echo "
                    <script type=\"text/javascript\">
                        document.getElementById('button_two').disabled=false;
                    </script>
                    ";
                }
                $result->free();
            }
        } while ($conn->next_result());
    }
}

if(isset($_POST["button_two"])){
    $username = $_POST['username']; // SQL INJECTION TO DROP THE DB HAPPENS HERE
    $password = $_POST['password'];

    if($conn->multi_query("SELECT id FROM users WHERE username = '$username' OR password = '$password'")) // SQL INJECTION SUCCEEDED
    {
        do {
            if ($result = $conn->store_result()) {
                while ($row = $result->fetch_row()) {
                    if ($result = $conn->query("SHOW DATABASES LIKE 'mydatabase'")) { // NO MORE DATABASE LIKE THAT, IT HAS BEEN DROPPED DUE TO THE INJECTION
                        if($result->num_rows == 0) {
                            include("another.php"); // THE PROBLEM IS HERE. EVEN THOUGH THE DB IS DROPPED, THIS PAGE IS NOT RENDERING
                        }
                    }
                }
                $result->free();
            }
        } while ($conn->next_result());
    }
}
?>

Any helpful idea would be appreciated!

HamzaNig
  • 1,019
  • 1
  • 10
  • 33
Riwi
  • 81
  • 11
  • really no one? wonder if the problem itself is too easy for all to bother to answer or no one has any clue – Riwi Jun 30 '18 at 18:19

1 Answers1

1

The code block to include another.php never runs, because the SHOW DATABASES query fails.

I tested your code and added some error reporting:

if ($result = $conn->query("SHOW DATABASES LIKE 'mydatabase'")) {
    if($result->num_rows == 0) {
        include("another.php");
    }
} else {
    echo "Error: {$conn->error}\n";
}

I got this:

Error: Commands out of sync; you can't run this command now

You can't run another SQL query while the one you already have executed still has results to fetch. Even though you have used store_result() to fetch the result set, that only fetches the current result set. You used mulit_query() which produces multiple result sets. You have to process all result sets until the end of the next_result() loop before you can start a new query.

Another lesson here is that you should always check for and report errors after you try to query() or multi_query() or prepare() or execute().


Here's an example: You have to wait until after the last result has been processed before you can run another query. This means after the loop on $conn->next_result() is done.

if(isset($_POST["button_two"])){
    $username = $_POST['username'];
    $password = $_POST['password'];

    if($conn->multi_query("SELECT id FROM users WHERE username = '$username' OR password = '$password'"))
    {
        do {
            if ($result = $conn->store_result()) {
                while ($row = $result->fetch_row()) {
                    // DISPLAY RESULTS FROM QUERY
                }
            }
            $result->free();
        } while ($conn->next_result());

        // CAN'T START ANOTHER QUERY UNTIL AFTER THE NEXT_RESULT LOOP IS DONE
        if ($result = $conn->query("SHOW DATABASES LIKE 'mydatabase'")) {
            if($result->num_rows == 0) {
            include("another.php");
        }
    }
}
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • hi Bill, thanks for your answer. I do run multiple queries to demonstrate SQL injection, it's on purpose. Furthermore, the DROP DATABASE actually is running, it happens. What's missing, is the "include("another.php");" part. – Riwi Jul 02 '18 at 05:52
  • Yeah, I got that. I have added a bold sentence at the start of my answer to make it clear why the include doesn't happen. – Bill Karwin Jul 02 '18 at 05:59
  • ah okay, sorry, it's too early morning for me yet. not sure if I followed your logic along though (which is probably more like my fault than yours). you recommend to put this part "while ($row = $result->fetch_row()) { if ($result = $conn->query("SHOW DATABASES LIKE 'mydatabase'")) {" after $result->free(); ? not sure if we are on the same page... – Riwi Jul 02 '18 at 06:05
  • You should get some sleep, eat a healthy breakfast, and then think about my answer for a while. – Bill Karwin Jul 02 '18 at 06:11
  • well, tried to play around with "$result->free();" as I concluded that has something to do with "freeing" the result set so it can proceed to the next one, but I had no luck :( – Riwi Jul 02 '18 at 07:00
  • @Riwi, see my example above of how to move the second query out of the next_result loop. – Bill Karwin Jul 02 '18 at 17:45
  • Thanks Bill, as soon as I have a moment (likely tomorrow) I'll get back to you! – Riwi Jul 03 '18 at 07:58
  • sorry for the late answer Bill, just got to test your code - and it's working:) thank you for the help, appreciate it! – Riwi Jul 04 '18 at 16:25