sqli-labs(一)
第一关:第一关会讲的比较详细,后面的关卡中只有特殊的地方我会单独拿出来说。
第一关是一个很简单的string类型的sql注入,并且会报错,输入参数id=',页面会报错
值得注意的是:
1.报错信息中 near "1" limit 0,1' at line 1,但是我们输入的是1',所以说这半句中的单双引号和后台sql语句中的单双引号不是对应的关系,我们做测试的时候不能根据报错信息来判断后台sql语句是用的单引号还是双引号进行的拼接。(这里说错了,补充一下啊:实际上这里页面的报错信息不是双引符号,是两个单引符号最前面和最后面的代表这是一句话,也就是说sql中的字符串片段实际上是'1'' limit 0,1这里的''是两个单引符号,这样就解释得清楚了我们输入1’和sql中的'组成了1''所以报错了,写这段话得原因是我们可以根据这段报错信息推出后台是'还是")
2.如果输入的是中文的单引符号、中文的双引符号以及英文的双引符号都不会报错,只是查询不出数据来,因为后台将这些符号作为变量进行查询,比如输入id=1",那么后台会在数据库中寻找id为1"的用户信息,显然不存在嘛。
3.使用order by时一般需要在sql语句的后面,如下图中sql语句进行拼凑的后面还有 limit 0,1,需要进行注释掉,一般使用#或--
4.在get请求中的特殊字符如空格、#以及单双引号都需要用url编码,否则sql语句的执行可能报错、甚至时http请求出错(空格没编码时)。空格(%20)、单引号(%27)、双引号(%22)、#(%23).....
ok,现在正式开始sql注入。(post中最好也使用url编码)
一般单引符号报错后可以初步判断存在sql注入,接下来的
第一步:判断当前表有多少列,使用order by 来判断,一般使用夹逼法,先使用一个较大的列号,输入id=1'%20order%20by%209%23
可以看到当order by 后面的列号大于数据表的列数就会报错,如order by后面的列号时小于数据表的列数,页面则能正常显示。
这关中order by 4会报错,order by 3正常显示,可以看出该表中是三个字段。
第二步:判断该表中的三个字段分别是什么数据类型,且哪些字段会在页面中显示
注意:1.很多时候执行玩查询操作后,后台程序只取第一行显示出来,所以id后面的参数应该是-1或者为空,只有前面查询出的数据为空,这样才会将后面的联合查询的数据显示出来
2.实际场景中还需要判断哪显示在页面中的字段哪些是字符型,比如说我们用user()查询当前用户名,却放在一个int类似的字段上会报错。但第一关中users表中的字段都是string类型,所以不存在此类问题。实际场景中最好是先使用union select null,null,null# 然后再一个个试出数据类型。
3.但后面我们却是直接使用的union select 1,2,3# 然后查看页面中哪个数字在显示页面上,来判断是哪个字段被显示在页面。这是因为sqli-labs使用得是php搭建得,而php是弱语言类型,int类型传入后台拼凑在sql中时,如果表中该字段是string类型会自动转换数据类型。
这里需要使用union 联合查询,输入id=-1'%20union%20select%201,2,3%23
可以看到,是第二个和第三个字段被显示在页面上
第三步:
所以后面我们只需将第二三这两个字段中换成我们想要进行得查询操作即可,mysql中自带一些函数可以供我们使用
user() 当前用户名
database() 当前数据库名
version() 当前数据库名
这里有一处小技巧:比如说我们想一处查询出上面三个信息,当表单只显示两个字段中的数据,怎么办?
可以使用使用mysql中的连接函数concat_ws,concat_ws的第一个参数是分割符,后面的是需要拼接的字符串
例如输入id='%20union%20select%201,concat_ws(':',user(),database(),version()),3%23
不过,为了保险起见还是不要直接使用特殊字符,concat_ws(char(32,58,32),user(),database(),version())
。空格的十进制ASCII是32,:的十进制ASCII是58
也可以使用group_concat将查询出来的多行连接起来
第四步:查询知道当前数据库名是security后,如何才能知道该数据库中有哪些表,表中又有哪些字段呢?
这里需要利用到mysql的系统数据库information_schema,需要利用到一下三个表
SCHEMATA表:储存mysql所有数据库的基本信息,包括数据库名,编码类型路径等,show databases的结果取之此表。
TABLES表:储存mysql中的表信息,(当然也有数据库名这一列,这样才能找到哪个数据库有哪些表嘛)包括这个表是基本表还是系统表,数据库的引擎是什么,表有多少行,创建时间,最后更新时间等。show tables from schemaname的结果取之此表
COLUMNS表:提供了表中的列信息,(当然也有数据库名和表名称这两列)详细表述了某张表的所有列以及每个列的信息,包括该列是那个表中的第几列,列的数据类型,列的编码类型,列的权限,猎德注释等。是show columns from schemaname.tablename的结果取之此表。
1.shemata表中有一个字段是需要记住的:schema_name,里面是所有的数据库名
输入id='%20union%20select%201,group_concat(schema_name),3%20from%20information_schema.schemata%23
这里使用的group_concat将多行连接起来,如下图
2.tables表中有两个字段需要记住:table_schema,table_name分别代表,数据库名和表面
现在已经知道所有数据库名后,这里查询security数据库中有哪些表
id='%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schema='security'%23
3.columns表中有两个字段是需要记住的:table_name和column_name分别代表表名和字段名
现在想查询出users这个表有哪些字段
id='%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_name='users'%23
第五步:查询users表中用户的账号密码