SELECT * FROM user WHERE username=''$username'' AND password=''$password''SELECT * FROM user WHERE username=''$username'' |
相同的就是当条件为真时,就会给出正确的提示信息,如果我们构造出后面的AND条件部分,并使这部分为真,那我们的目的也就达到了,还是利用刚才建立的user数据库,用户名为angel,密码为mypass,
看了上面的例子,应该知道构造了吧,如果我们提交:
http://127.0.0.1/injection/user.php?username=angel'' and password=''mypass |
这个是绝对为真的,因为我们这样提交上面的SQL语句变成了下面的样子:
SELECT * FROM user WHERE username=''angel'' AND password=''mypass'' |
但在实际的攻击中,我们是肯定不知道密码的,假设我们知道数据库的各个字段,下面我们就开始探测密码了,首先获取密码长度:
http://127.0.0.1/injection/user.php?username=angel'' and LENGTH(password)=''6 |
在ACCESS中,用LEN()函数来获取字符串长度,在MYSQL中,要使用LENGTH(),只要没有构造错误,也就是说SQL语句能正常执行,那返回结果无外乎两种,不是返回用户ID,就是返回“该记录不存在”。当用户名为angel并且密码长度为6的时候返回真,就会返回相关记录,是不是和ASP里一样?再用LEFT()、RIGHT()、MID()函数猜密码:
http://127.0.0.1/injection/user.php?username=angel'' and LEFT(password,1)=''m |
看,密码不是出来了吗?简单吧?当然实际情况会有不少条件限制,下面还会讲到这个例子的深入应用。
② 跨表查询
这部分就和ASP有点出入了,除了一定要用UNION连接两条SQL语句,最难掌握的就是字段的数量,如果看过MYSQL参考手册,就知道了在 SELECT 中的 select_expression (select_expression 表示你希望检索的列[字段]) 部分列出的列必须具有同样的类型。第一个 SELECT 查询中使用的列名将作为结果集的列名返回。简单的说,也就是UNION后面查选的字段数量、字段类型都应该与前面的SELECT一样,而且,如果前面的SELECT为真,就同时返回两个SELECT的结果,当前面的SELECT为假,就会返回第二个SELECT所得的结果,某些情况会替换掉在第一个SELECT原来应该显示的字段,如下图:
看了这个图直观多了吧?所以应该先知道前面查询表的数据表的结构。如果我们查询两个数据表的字段相同,类型也相同,我们就可以这样提交:
SELECT * FROM article WHERE articleid=''$id'' UNION SELECT * FROM…… |
如果字段数量、字段类型任意一个不相同,就只能搞清除数据类型和字段数量,这样提交:
SELECT * FROM article WHERE articleid=''$id'' UNION SELECT 1,1,1,1,1,1,1 FROM…… |
否则就会报错:
The used SELECT statements have a different number of columns |
如果不知道数据类型和字段数量,可以用1来慢慢试,因为1属于int\str\var类型,所以我们只要慢慢改变数量,一定可以猜到的。如果不能马上理解上面的理论,后面有很详细的例子。
我们看看下面的数据结构,是一个简单的