利用CodeQL分析并挖掘Log4j漏洞

VSole2021-12-24 15:11:14

前言

分析漏洞的本质是为了能让我们从中学习漏洞挖掘者的思路以及挖掘到新的漏洞,而CodeQL就是一款可以将我们对漏洞的理解快速转化为可实现的规则并挖掘漏洞的利器。根据网上的传言Log4j2的RCE漏洞就是作者通过CodeQL挖掘出的。虽然如何挖掘的我们不得而知,但我们现在站在事后的角度再去想想,可以推测一下作者如何通过CodeQL挖掘到漏洞的,并尝试基于作者的思路挖掘新漏洞。

分析过程

首先我们要构建Log4j的数据库,由于lgtm.com中构建的是新版本的Log4j数据库,所以只能手动构建数据库了。首先从github获取源码并切换到2.14.1版本。

git clone https://github.com/apache/logging-log4j2.git
git checkout be881e5

由于我们这次分析的主要是log4j-corelog4j-api中的内容,所以打开根目录的Pom.xml注释下面的内容。

    log4j-api-java9
    log4j-api
    log4j-core-java9
    log4j-core
    
  

由于log4j-api-java9log4j-core- java9需要依赖JDK9,所以要先下载JDK9并且在C:\Users\用户名\.m2\toolchains.xml中加上下面的内容。

  
  jdk  
    
    9  
    sun  
    
    
    C:\Program Files\Java\jdk-9.0.4  
    
  

通过下面的命令完成数据库构建

CodeQL database create Log4jDB --language=java --overwrite --command="mvn clean install -Dmaven.test.skip=true"

构建好数据库后,我们要找JNDI注入的漏洞,首先要确定在这套系统中调用了InitialContext#lookup方法。在LookupInterface项目中已经集成了常见的发起JNDI请求的类,只要稍微改一下即可。

首先定义Context类型,这个类中综合了可能发起JNDI请求的类。

class Context extends  RefType{
    Context(){
        this.hasQualifiedName("javax.naming", "Context")
        or
        this.hasQualifiedName("javax.naming", "InitialContext")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiCallback")
        or 
        this.hasQualifiedName("org.springframework.jndi", "JndiTemplate")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiLocatorDelegate")
        or
        this.hasQualifiedName("org.apache.shiro.jndi", "JndiCallback")
        or
        this.getQualifiedName().matches("%JndiCallback")
        or
        this.getQualifiedName().matches("%JndiLocatorDelegate")
        or
        this.getQualifiedName().matches("%JndiTemplate")
    }
}

下面寻找那里调用了Context的lookup方法。

from Call call,Callable parseExpression
where
    call.getCallee() = parseExpression and 
    parseExpression.getDeclaringType() instanceof Context and
    parseExpression.hasName("lookup")
select call

  • DataSourceConnectionSource#createConnectionSource
@PluginFactory
    public static DataSourceConnectionSource createConnectionSource(@PluginAttribute("jndiName") final String jndiName) {
        if (Strings.isEmpty(jndiName)) {
            LOGGER.error("No JNDI name provided.");
            return null;
        }
        try {
            final InitialContext context = new InitialContext();
            final DataSource dataSource = (DataSource) context.lookup(jndiName);
            if (dataSource == null) {
                LOGGER.error("No data source found with JNDI name [" + jndiName + "].");
                return null;
            }
            return new DataSourceConnectionSource(jndiName, dataSource);
        } catch (final NamingException e) {
            LOGGER.error(e.getMessage(), e);
            return null;
        }
    }
  • JndiManager#lookup
@SuppressWarnings("unchecked")
    public <T> T lookup(final String name) throws NamingException {
        return (T) this.context.lookup(name);
    }

找到sink后我们还需要找到source,虽然Codeql定义了RemoteFlowSource支持多种source,但是我们还是要根据实际的代码业务来分析可能作为source的点。

在Log4j作为日志记录的工具,除了从HTTP请求中获取输入点外,还可以在记录日志请求或者解析配置文件中来获取source。先不看解析配置文件获取source的点了,因为这需要分析Log4j解析配置文件的流程比较复杂。所以目前我们只考虑通过日志记录作为source的情况。稍微了解Log4j的同学都知道,Log4j会通过error/fatal/info/debug/trace等方法对不同级别的日志进行记录。通过分析我们可以看到我们输入的message都调用了logIfEnabled方法并作为第四个参数输入,所以可以将这里定义为source。

下面使用全局污点追踪分析JNDI漏洞,还是套用LookupInterface项目中的代码,修改source部分即可。

/**
 *@name Tainttrack Context lookup
 *@kind path-problem
 */
import java
import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
class Context extends  RefType{
    Context(){
        this.hasQualifiedName("javax.naming", "Context")
        or
        this.hasQualifiedName("javax.naming", "InitialContext")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiCallback")
        or 
        this.hasQualifiedName("org.springframework.jndi", "JndiTemplate")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiLocatorDelegate")
        or
        this.hasQualifiedName("org.apache.shiro.jndi", "JndiCallback")
        or
        this.getQualifiedName().matches("%JndiCallback")
        or
        this.getQualifiedName().matches("%JndiLocatorDelegate")
        or
        this.getQualifiedName().matches("%JndiTemplate")
    }
}
class Logger extends  RefType{
    Logger(){
        this.hasQualifiedName("org.apache.logging.log4j.spi", "AbstractLogger")
    }
}
predicate isLookup(Expr arg) {
    exists(MethodAccess ma |
        ma.getMethod().getName() = "lookup"
        and
        ma.getMethod().getDeclaringType() instanceof Context
        and
        arg = ma.getArgument(0)
    )
}
predicate isLogging(Expr arg) {
    exists(MethodAccess ma |
        ma.getMethod().getName() = "logIfEnabled"
        and
        ma.getMethod().getDeclaringType() instanceof Logger
        and
        arg = ma.getArgument(3)
    )
}
class TainttrackLookup  extends TaintTracking::Configuration {
    TainttrackLookup() { 
        this = "TainttrackLookup" 
    }

    override predicate isSource(DataFlow::Node source) {
        exists(Expr exp |
            isLogging(exp)
            and
            source.asExpr() = exp
        )
    }

    override predicate isSink(DataFlow::Node sink) {
        exists(Expr arg |
            isLookup(arg)
            and
            sink.asExpr() = arg
        )
    }
} 
from TainttrackLookup config , DataFlow::PathNode source, DataFlow::PathNode sink
where
    config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "unsafe lookup", source.getNode(), "this is user input"

虽然这些也得到了很多查询结果,但是在实际使用Log4j打印日志时可能不会带上Marker参数而是直接写入messge的内容。

所以我们现在要追踪的source应该是带有一个参数的error/fatal/info/debug/trace等方法。我这里以error方法为例对source部分进行修改。

class LoggerInput extends  Method {
    LoggerInput(){
        //限定调用的类名、方法名、以及方法只有一个参数
        this.getDeclaringType() instanceof Logger and
        this.hasName("error") and this.getNumberOfParameters() = 1
    }
    //将第一个参数作为source
    Parameter getAnUntrustedParameter() { result = this.getParameter(0) }
}
override predicate isSource(DataFlow::Node source) {
        exists(LoggerInput LoggerMethod |
            source.asParameter() = LoggerMethod.getAnUntrustedParameter())
    }

这样我们就得到了多条链,现在我们要写个Demo验证这个链是否可行,比如最简单的logger.error("xxxxx");

1    message : Message     AbstractLogger.java:709:23
2    message : Message     AbstractLogger.java:710:47
3    message : Message     AbstractLogger.java:1833:89
4    message : Message     AbstractLogger.java:1835:38
5    message : Message     Logger.java:262:70
6    message : Message     Logger.java:263:52
7    msg : Message     Logger.java:617:64
8    msg : Message     Logger.java:620:78
9    msg : Message     RegexFilter.java:73:87
10    msg : Message     RegexFilter.java:78:63
...
64    convertJndiName(...) : String     JndiLookup.java:54:33
65    jndiName : String     JndiLookup.java:56:56
66    name : String     JndiManager.java:171:25
67    name     JndiManager.java:172:40
Path

但是这条链只有配置了Filter为RegexFilter才会继续执行,而默认没有配置则为空。

所以这种方式就稍微有些限制,所以我们再去看看其他链。这条链似乎不用配置Filter。

1    message : Message     AbstractLogger.java:709:23
2    message : Message     AbstractLogger.java:710:47
3    message : Message     AbstractLogger.java:1833:89
4    message : Message     AbstractLogger.java:1836:51
5    message : Message     AbstractLogger.java:2139:94
6    message : Message     AbstractLogger.java:2142:59
7    message : Message     AbstractLogger.java:2155:43
8    message : Message     AbstractLogger.java:2159:67
9    message : Message     AbstractLogger.java:2202:32
10    message : Message     AbstractLogger.java:2205:48
11    message : Message     AbstractLogger.java:2116:9
12    message : Message     AbstractLogger.java:2117:41
...
78    var : String     Interpolator.java:230:92
79    key : String     JndiLookup.java:50:48
80    key : String     JndiLookup.java:54:49
81    jndiName : String     JndiLookup.java:70:36
82    jndiName : String     JndiLookup.java:74:16
83    convertJndiName(...) : String     JndiLookup.java:54:33
84    jndiName : String     JndiLookup.java:56:56
85    name : String     JndiManager.java:171:25
86    name     JndiManager.java:172:40

但是在AbstractLogger#tryLogMessage中Codeql会直接分析到AbstractLogger#log而实际请求时会解析到Logger#log方法。这是因为LoggerAbstractLogger的子类并且也实现了log方法,而且我们实例化的也是Logger对象,所以这里会调用到Logger#log

实际请求

CodeQL分析

再看看下面这条链

1    message : Message     AbstractLogger.java:709:23
2    message : Message     AbstractLogger.java:710:47
3    message : Message     AbstractLogger.java:1833:89
4    message : Message     AbstractLogger.java:1836:51
5    message : Message     AbstractLogger.java:2139:94
6    message : Message     AbstractLogger.java:2142:59
7    message : Message     AbstractLogger.java:2155:43
8    message : Message     AbstractLogger.java:2159:67
9    message : Message     AbstractLogger.java:2202:32
10    message : Message     AbstractLogger.java:2205:48
11    message : Message     Logger.java:158:9
12    message : Message     Logger.java:162:17
13    data : Message     AwaitCompletionReliabilityStrategy.java:78:83
14    data : Message     AwaitCompletionReliabilityStrategy.java:82:67
15    data : Message     LoggerConfig.java:430:28
16    data : Message     LoggerConfig.java:454:17
17    message : Message     ReusableLogEventFactory.java:78:86
18    message : Message     ReusableLogEventFactory.java:100:27
19    msg : Message     MutableLogEvent.java:209:28
20    (...)... : Message     MutableLogEvent.java:211:46
21    reusable : Message     MutableLogEvent.java:212:13
22    parameter this : Message     ReusableObjectMessage.java:47:17
23    obj : Object     ReusableObjectMessage.java:48:44
...
88    convertJndiName(...) : String     JndiLookup.java:54:33
89    jndiName : String     JndiLookup.java:56:56
90    name : String     JndiManager.java:171:25
91    name     JndiManager.java:172:40

这条链在执行到MutableLogEvent#setMessage时和CodeQL的分析结果略有不同。

在CodeQL中resusable.formatTo会调用到ReusableObjectMessage中。

但是实际运行过程中由于MessgeFactorty创建Message对象时默认创建的是ResableSimpleMessage对象,所以会执行到ResableSimpleMessage#formatTo方法。

所以似乎目前使用使用CodeQL的规则是发现不了Log4jShell那个漏洞的,既然我们已经知道了这个漏洞的触发链,可以分析下CodeQL为什么没有分析出来。

通过之前对CodeQL检测出的调用链分析,CodeQL已经分析到了createEvent方法。

查看createEvent方法的调用,在Log4jShell的触发链中实际上是在对返回LogEvent的处理过程中触发的,所以这里CodeQL可能没有将返回的LogEvent对象再当作污点进行分析,所以导致没有分析成功。

我们可以创建一个isAdditionalTaintStep函数,将ReusableLogEventFactory#createEvent的第六个参数Message和LoggerConfig#log第一个参数logEvent连接起来。

override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
        exists(MethodAccess ma,MethodAccess ma2 |
            ma.getMethod().getDeclaringType().hasQualifiedName("org.apache.logging.log4j.core.impl", "ReusableLogEventFactory") 
            and ma.getMethod().hasName("createEvent") and fromNode.asExpr()=ma.getArgument(5) and ma2.getMethod().getDeclaringType().hasQualifiedName("org.apache.logging.log4j.core.config", "LoggerConfig")  
            and ma2.getMethod().hasName("log") and ma2.getMethod().getNumberOfParameters() = 2 and toNode.asExpr()=ma2.getArgument(0)
                    )
      }

最后我们就可以通过CodeQL分析到Log4j shell漏洞的调用链。

1    message : Message     AbstractLogger.java:709:23
2    message : Message     AbstractLogger.java:710:47
3    message : Message     AbstractLogger.java:1833:89
4    message : Message     AbstractLogger.java:1836:51
5    message : Message     AbstractLogger.java:2139:94
6    message : Message     AbstractLogger.java:2142:59
7    message : Message     AbstractLogger.java:2155:43
8    message : Message     AbstractLogger.java:2159:67
9    message : Message     AbstractLogger.java:2202:32
10    message : Message     AbstractLogger.java:2205:48
11    message : Message     Logger.java:158:9
12    message : Message     Logger.java:162:17
13    data : Message     DefaultReliabilityStrategy.java:61:83
14    data : Message     DefaultReliabilityStrategy.java:63:69
15    data : Message     LoggerConfig.java:430:28
16    data : Message     LoggerConfig.java:454:96
17    message : Message     ReusableLogEventFactory.java:58:47
18    message : Message     ReusableLogEventFactory.java:60:67
19    event : LogEvent     LoggerConfig.java:469:13
20    event : LogEvent     LoggerConfig.java:479:24
21    event : LogEvent     LoggerConfig.java:481:29
22    event : LogEvent     LoggerConfig.java:495:34
23    event : LogEvent     LoggerConfig.java:498:27
24    event : LogEvent     LoggerConfig.java:536:34
25    event : LogEvent     LoggerConfig.java:540:38
26    event : LogEvent     AppenderControl.java:80:30
27    event : LogEvent     AppenderControl.java:84:38
28    event : LogEvent     AppenderControl.java:117:47
29    event : LogEvent     AppenderControl.java:120:27
30    event : LogEvent     AppenderControl.java:126:32
31    event : LogEvent     AppenderControl.java:129:29
32    event : LogEvent     AppenderControl.java:154:34
33    event : LogEvent     AppenderControl.java:156:29
34    event : LogEvent     AbstractDatabaseAppender.java:107:30
35    event : LogEvent     AbstractDatabaseAppender.java:110:37
36    event : LogEvent     AbstractDatabaseManager.java:260:42
37    event : LogEvent     AbstractDatabaseManager.java:262:20
38    event : LogEvent     AbstractDatabaseManager.java:122:27
39    event : LogEvent     AbstractDatabaseManager.java:123:25
40    parameter this : LogEvent     Log4jLogEvent.java:530:26
41    this : LogEvent     Log4jLogEvent.java:534:16
42    toImmutable(...) : LogEvent     AbstractDatabaseManager.java:123:25
43    this.buffer [post update] [<element>] : LogEvent     AbstractDatabaseManager.java:123:9
44    this [post update] [buffer, ] : LogEvent     AbstractDatabaseManager.java:123:9
45    this <.method> [post update] [buffer, ] : LogEvent     AbstractDatabaseManager.java:262:13
46    getManager(...) [post update] [buffer, ] : LogEvent     AbstractDatabaseAppender.java:110:13
47    this [post update] [manager, buffer, ] : LogEvent     AbstractDatabaseAppender.java:110:13
48    appender [post update] [manager, buffer, ] : LogEvent     AppenderControl.java:156:13
49    this <.field> [post update] [appender, manager, buffer, ] : LogEvent     AppenderControl.java:156:13
50    this <.method> [post update] [appender, manager, buffer, ] : LogEvent     AppenderControl.java:129:13
51    this <.method> [post update] [appender, manager, buffer, ] : LogEvent     AppenderControl.java:120:13
52    this <.method> [post update] [appender, manager, buffer, ] : LogEvent     AppenderControl.java:84:9
53    event : LogEvent     AppenderControl.java:80:30
54    event : LogEvent     AppenderControl.java:84:38
55    event : LogEvent     AppenderControl.java:117:47
56    event : LogEvent     AppenderControl.java:120:27
57    event : LogEvent     AppenderControl.java:126:32
58    event : LogEvent     AppenderControl.java:129:29
59    event : LogEvent     AppenderControl.java:154:34
60    event : LogEvent     AppenderControl.java:156:29
61    event : LogEvent     AbstractOutputStreamAppender.java:179:24
62    event : LogEvent     AbstractOutputStreamAppender.java:181:23
63    event : LogEvent     AbstractOutputStreamAppender.java:188:28
64    event : LogEvent     AbstractOutputStreamAppender.java:190:31
65    event : LogEvent     AbstractOutputStreamAppender.java:196:38
66    event : LogEvent     AbstractOutputStreamAppender.java:197:28
67    event : LogEvent     GelfLayout.java:433:24
68    event : LogEvent     GelfLayout.java:438:43
69    event : LogEvent     GelfLayout.java:471:34
70    event : LogEvent     GelfLayout.java:496:46
71    event : LogEvent     StrSubstitutor.java:462:27
72    event : LogEvent     StrSubstitutor.java:467:25
73    event : LogEvent     StrSubstitutor.java:911:34
74    event : LogEvent     StrSubstitutor.java:912:27
75    event : LogEvent     StrSubstitutor.java:928:28
76    event : LogEvent     StrSubstitutor.java:978:44
77    event : LogEvent     StrSubstitutor.java:911:34
78    event : LogEvent     StrSubstitutor.java:912:27
79    event : LogEvent     StrSubstitutor.java:928:28
80    event : LogEvent     StrSubstitutor.java:1033:63
81    event : LogEvent     StrSubstitutor.java:1104:38
82    event : LogEvent     StrSubstitutor.java:1110:32
83    event : LogEvent     StructuredDataLookup.java:46:26
84    event : LogEvent     StructuredDataLookup.java:50:67
85    parameter this : LogEvent     RingBufferLogEvent.java:206:20
86    message : Message     RingBufferLogEvent.java:210:16
87    getMessage(...) : Message     StructuredDataLookup.java:50:67
88    (...)... : Message     StructuredDataLookup.java:50:43
89    msg : Message     StructuredDataLookup.java:54:20
90    parameter this : Message     StructuredDataMessage.java:239:19
91    type : String     StructuredDataMessage.java:240:16
92    getType(...) : String     StructuredDataLookup.java:54:20
93    lookup(...) : String     StrSubstitutor.java:1110:16
94    resolveVariable(...) : String     StrSubstitutor.java:1033:47
95    varValue : String     StrSubstitutor.java:1040:63
96    buf [post update] : StringBuilder     StrSubstitutor.java:1040:33
97    buf [post update] : StringBuilder     StrSubstitutor.java:912:34
98    bufName [post update] : StringBuilder     StrSubstitutor.java:978:51
99    bufName : StringBuilder     StrSubstitutor.java:979:47
100    toString(...) : String     StrSubstitutor.java:979:47
101    varNameExpr : String     StrSubstitutor.java:1010:55
102    substring(...) : String     StrSubstitutor.java:1010:55
103    varName : String     StrSubstitutor.java:1033:70
104    variableName : String     StrSubstitutor.java:1104:60
105    variableName : String     StrSubstitutor.java:1110:39
106    key : String     JndiLookup.java:50:48
107    key : String     JndiLookup.java:54:49
108    jndiName : String     JndiLookup.java:70:36
109    ... + ... : String     JndiLookup.java:72:20
110    convertJndiName(...) : String     JndiLookup.java:54:33
111    jndiName : String     JndiLookup.java:56:56
112    name : String     JndiManager.java:171:25
113    name     JndiManager.java:172:40

漏洞挖掘尝试

通过上面的分析可以看到,挖掘到所有的链最终的触发点都是JndiManager,这个点目前的触发已经在新版本中修复了,但是在DataSourceConnectionSource#createConnectionSource中也直接调用了lookup方法,我们能否通过某种方式触发呢?

通过注释可以看到DataSource是Core类型插件,因此可以在XML中直接通过标签配置调用。

xml version="1.0" encoding="UTF-8"?>
 status="WARN">
    
         name="Console" target="SYSTEM_OUT">
             pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        
    
     jndiName="ldap://9b89e78d.dns.1433.eu.org.">
    
    
         level="ERROR">
             ref="Console"/>
        
    

配置后可以在插件加载的过程中触发漏洞,虽然这种方式也可以造成JNDI注入,但是需要在配置文件中修改参数才能触发,所以价值不大。

最后给出整体的分析Log4j JNDI注入的CodeQL查询代码

/**
 *@name Tainttrack Context lookup
 *@kind path-problem
 */
import java
import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
class Context extends  RefType{
    Context(){
        this.hasQualifiedName("javax.naming", "Context")
        or
        this.hasQualifiedName("javax.naming", "InitialContext")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiCallback")
        or 
        this.hasQualifiedName("org.springframework.jndi", "JndiTemplate")
        or
        this.hasQualifiedName("org.springframework.jndi", "JndiLocatorDelegate")
        or
        this.hasQualifiedName("org.apache.shiro.jndi", "JndiCallback")
        or
        this.getQualifiedName().matches("%JndiCallback")
        or
        this.getQualifiedName().matches("%JndiLocatorDelegate")
        or
        this.getQualifiedName().matches("%JndiTemplate")
    }
}
class Logger extends  RefType{
    Logger(){
        this.hasQualifiedName("org.apache.logging.log4j.spi", "AbstractLogger")
    }
}
class LoggerInput extends  Method {
    LoggerInput(){
        this.getDeclaringType() instanceof Logger and
        this.hasName("error") and this.getNumberOfParameters() = 1
    }
    Parameter getAnUntrustedParameter() { result = this.getParameter(0) }
}
predicate isLookup(Expr arg) {
    exists(MethodAccess ma |
        ma.getMethod().getName() = "lookup"
        and
        ma.getMethod().getDeclaringType() instanceof Context
        and
        arg = ma.getArgument(0)
    )
}
class TainttrackLookup  extends TaintTracking::Configuration {
    TainttrackLookup() { 
        this = "TainttrackLookup" 
    }

    override predicate isSource(DataFlow::Node source) {
        exists(LoggerInput LoggerMethod |
            source.asParameter() = LoggerMethod.getAnUntrustedParameter())
    }

    override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
        exists(MethodAccess ma,MethodAccess ma2 |
            ma.getMethod().getDeclaringType().hasQualifiedName("org.apache.logging.log4j.core.impl", "ReusableLogEventFactory") 
            and ma.getMethod().hasName("createEvent") and fromNode.asExpr()=ma.getArgument(5) and ma2.getMethod().getDeclaringType().hasQualifiedName("org.apache.logging.log4j.core.config", "LoggerConfig")  
            and ma2.getMethod().hasName("log") and ma2.getMethod().getNumberOfParameters() = 2 and toNode.asExpr()=ma2.getArgument(0)
                    )
      }
    override predicate isSink(DataFlow::Node sink) {
        exists(Expr arg |
            isLookup(arg)
            and
            sink.asExpr() = arg
        )
    }
} 
from TainttrackLookup config , DataFlow::PathNode source, DataFlow::PathNode sink
where
    config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "unsafe lookup", source.getNode(), "this is user input"

总结

通过CodeQL挖洞效率确实比较高,并且在官方也给出了针对很多类型漏洞的审计规则,确实可以高效的辅助挖洞,目前主要解决下面两个问题。

  • 默认的Source应该只是针对HTTP请求,如何针对特定的框架去发现可能作为source的点
  • 分析污点在何时会被打断并进行拼接
漏洞挖掘log4j
本作品采用《CC 协议》,转载必须注明作者和本文链接
分析漏洞的本质是为了能让我们从中学习漏洞挖掘者的思路以及挖掘到新的漏洞,而CodeQL就是一款可以将我们对漏洞的理解快速转化为可实现的规则并挖掘漏洞的利器。根据网上的传言Log4j2的RCE漏洞就是作者通过CodeQL挖掘出的。虽然如何挖掘的我们不得而知,但我们现在站在事后的角度再去想想,可以推测一下作者如何通过CodeQL挖掘漏洞的,并尝试基于作者的思路挖掘漏洞
漏洞排查与处置,是安全管理员在安全运营中都会碰到的问题,常见却很难做好。
项目安装迷你天猫商城是一个基于Spring Boot的综合性B2C电商平台,需求设计主要参考天猫商城的购物流程:用户从注册开始,到完成登录,浏览商品,加入购物车,进行下单,确认收货,评价等一系列操作。作为迷你天猫商城的核心组成部分之一,天猫数据管理后台包含商品管理,订单管理,类别管理,用户管理和交易额统计等模块,实现了对整个商城的一站式管理和维护。
2021年十大漏洞利用
2022-01-02 16:33:11
本文总结了作者心目中的2021十大漏洞利用。
8月21日,为期两天的第六届“强网杯”全国网络安全挑战赛线下赛圆满结束。从32支战队中脱颖而出,长亭科技0x300R 战队最终斩获强网杯特等奖—亚军,同时作为线下赛总积分排名最高的企业战队,获评“强网最佳企业战队”荣誉称号。最终长亭0x300R战队以仅300分的差距将亚军收入囊中。
武装你的BurpSuite
2022-03-18 15:38:20
0x01前言BurpSuite是广大安全人员使用率最高的一款工具了,通过对数据包的修改,重放往往能发现很多安
随着数字化应用的高速发展,软件已被各行各业广泛应用,成为必不可少的一部分。近年来,全球范围内有关软件供应链安全的攻击事件层出不断,对个人、企业,甚至国家安全都造成了严重威胁。近期曝出的Apache log4j2漏洞的严重性、广泛性已经在各个领域显现,波及面非常大,更是让业界意识到做好开源软件安全治理已是迫在眉睫。
Java审计其实和Php审计的思路一样,唯一不同的可能是复杂的框架和代码。
为进一步推动产业发展,更好地汇聚产学研用各方力量,聚焦关键软件领域密码应用核心问题,不断夯实软件产业发展基础,共同推动软件产业和密码技术融合发展,12月18日,“2021年商用密码应用创新高端研讨会”在经开区国家信创园成功召开。在会上,中关村网络安全与信息化产业联盟EMCG工作组组长王克带来题为《密码在软件供应链安全中的应用》的演讲。
FCIS 2023网络安全创新大会在上海张江科学会堂圆满落幕。
VSole
网络安全专家