Pikachu靶场通关笔记(19) — SQL Inject (字符型注入)

32次阅读
没有评论

摘要 / 前言:
上一关我们完成了数字型注入,这一关是 字符型注入(String/Character Injection)。这是 SQL 注入中最常见的情形。与数字型不同,字符型注入的参数在 SQL 语句中是被单引号(或双引号)包裹的。如果我们的 Payload 不闭合这个引号,数据库会将我们的攻击代码视为普通的字符串处理,从而导致攻击失败。


一、漏洞分析与判断

打开页面,提示 “what’s your username?”,这是一个根据用户名查询信息的输入框。

1. 尝试数字型 Payload(失败)

首先尝试像上一关那样直接输入逻辑判断:

  • Payload: kobe or 1=1
  • 结果: 提示 “ 您输入的 username 不存在,请重新输入!”。
  • 原因: 后端 SQL 语句大概率写成了 WHERE username = 'kobe or 1=1'。整个字符串被当作用户名去查找,当然找不到。

2. 尝试字符型 Payload(成功)

为了让数据库执行我们的逻辑,必须先把原本的单引号闭合掉,然后再把后面的引号注释掉。

  • Payload:
    sql 123'or 1=1--+
    (注:123是随意输入的用户名,' 用于闭合前面的引号,--+ 用于注释掉后面多余的引号,+在 URL 中代表空格)
  • 结果: 页面显示了所有用户的信息(如 vince, allen, kobe 等)。这证明了 or 1=1 逻辑生效,存在字符型 SQL 注入。
Pikachu 靶场通关笔记(19) — SQL Inject (字符型注入)

二、注入利用过程

后续步骤与数字型注入类似,唯一的区别是每次构造 Payload 时,都需要以 ' 开头闭合前面的字符串,并以 --+ 结尾注释掉尾部。

1. 获取数据库版本信息 (Union Select)

首先通过 order by 确认字段数为 2(步骤略,同上一关)。然后使用联合查询获取数据库名和版本。

  • Payload:
    name=123'+union+select+database(),version()--+&submit=%E6%9F%A5%E8%AF%A2
  • 结果回显:
    > your uid: pikachu
    > your email is: 5.7.26-0ubuntu0.18.04.1-log

2. 获取表结构 (Table Schema)

获取 member 表的列名。

  • Payload:
    123'+union+select+database(),group_concat(column_name)+from+information_schema.columns+where+table_schema='pikachu'+and+table_name='member'--+
  • 结果: 成功获取列名,接下来即可根据列名 dump 出所有账号密码数据。
Pikachu 靶场通关笔记(19) — SQL Inject (字符型注入)

三、源码深度分析

通过查看后端源码,我们可以清楚地看到字符型注入的成因。

核心代码段:

if(isset($_GET['submit']) && $_GET['name']!=null){
    // 1. 接收参数,未做任何过滤
    $name=$_GET['name'];

    // 2. 拼接 SQL 语句
    // 注意这里:变量 $name 被单引号 '' 包裹住了
    $query="select id,email from member where username='$name'";

    $result=execute($link, $query);
    // ... 后续输出逻辑...
}

解析:
当输入 $name = 123 时,SQL 语句变为:
select ... where username='123' (正常)

当输入 $name = 123' or 1=1--+ 时,SQL 语句变为:

select ... where username='123' or 1=1--+'
  • 红色部分的 ' 和代码中的第一个 ' 组成了一对,构成了完整的字符串 '123'
  • 中间的 or 1=1 变成了可执行的逻辑代码。
  • 最后的 --+ 把代码中原本用于闭合的末尾单引号注释掉了,从而避免语法错误。

四、总结与防御

数字型 vs 字符型:

  • 数字型: id = $id -> 不需要闭合引号,利用简单。
  • 字符型: username = '$name' -> 需要构造 ' 闭合前方,并使用 --+# 注释后方。

防御措施:
依然是强调使用 预编译语句(Prepared Statements)。在预编译模式下,数据库会将用户输入严格视为“参数”或“纯文本”,无论输入中包含多少单引号或 SQL 关键字,都不会改变 SQL 语句原本的逻辑结构。


下一篇预告:SQL Inject (搜索型注入)

正文完
 0
评论(没有评论)