Skip to content

Commit 30d7796

Browse files
Jami CogswellJami Cogswell
authored andcommitted
Java: copy out of experimental
1 parent 5722084 commit 30d7796

File tree

11 files changed

+367
-0
lines changed

11 files changed

+367
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>Spring Boot is a popular framework that facilitates the development of stand-alone applications
5+
and micro services. Spring Boot Actuator helps to expose production-ready support features against
6+
Spring Boot applications.</p>
7+
8+
<p>Endpoints of Spring Boot Actuator allow to monitor and interact with a Spring Boot application.
9+
Exposing unprotected actuator endpoints through configuration files can lead to information disclosure
10+
or even remote code execution vulnerability.</p>
11+
12+
<p>Rather than programmatically permitting endpoint requests or enforcing access control, frequently
13+
developers simply leave management endpoints publicly accessible in the application configuration file
14+
<code>application.properties</code> without enforcing access control through Spring Security.</p>
15+
</overview>
16+
17+
<recommendation>
18+
<p>Declare the Spring Boot Starter Security module in XML configuration or programmatically enforce
19+
security checks on management endpoints using Spring Security. Otherwise accessing management endpoints
20+
on a different HTTP port other than the port that the web application is listening on also helps to
21+
improve the security.</p>
22+
</recommendation>
23+
24+
<example>
25+
<p>The following examples show both 'BAD' and 'GOOD' configurations. In the 'BAD' configuration,
26+
no security module is declared and sensitive management endpoints are exposed. In the 'GOOD' configuration,
27+
security is enforced and only endpoints requiring exposure are exposed.</p>
28+
<sample src="pom_good.xml" />
29+
<sample src="pom_bad.xml" />
30+
<sample src="application.properties" />
31+
</example>
32+
33+
<references>
34+
<li>
35+
Spring Boot documentation:
36+
<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">Spring Boot Actuator: Production-ready Features</a>
37+
</li>
38+
<li>
39+
VERACODE Blog:
40+
<a href="https://www.veracode.com/blog/research/exploiting-spring-boot-actuators">Exploiting Spring Boot Actuators</a>
41+
</li>
42+
<li>
43+
HackerOne Report:
44+
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
45+
</li>
46+
</references>
47+
</qhelp>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* @name Insecure Spring Boot Actuator Configuration
3+
* @description Exposed Spring Boot Actuator through configuration files without declarative or procedural
4+
* security enforcement leads to information leak or even remote code execution.
5+
* @kind problem
6+
* @problem.severity error
7+
* @precision high
8+
* @id java/insecure-spring-actuator-config
9+
* @tags security
10+
* experimental
11+
* external/cwe/cwe-016
12+
*/
13+
14+
/*
15+
* Note this query requires properties files to be indexed before it can produce results.
16+
* If creating your own database with the CodeQL CLI, you should run
17+
* `codeql database index-files --language=properties ...`
18+
* If using lgtm.com, you should add `properties_files: true` to the index block of your
19+
* lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction)
20+
*/
21+
22+
import java
23+
import semmle.code.configfiles.ConfigFiles
24+
import semmle.code.xml.MavenPom
25+
26+
/** The parent node of the `org.springframework.boot` group. */
27+
class SpringBootParent extends Parent {
28+
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
29+
}
30+
31+
/** Class of Spring Boot dependencies. */
32+
class SpringBootPom extends Pom {
33+
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }
34+
35+
/** Holds if the Spring Boot Actuator module `spring-boot-starter-actuator` is used in the project. */
36+
predicate isSpringBootActuatorUsed() {
37+
this.getADependency().getArtifact().getValue() = "spring-boot-starter-actuator"
38+
}
39+
40+
/**
41+
* Holds if the Spring Boot Security module is used in the project, which brings in other security
42+
* related libraries.
43+
*/
44+
predicate isSpringBootSecurityUsed() {
45+
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
46+
}
47+
}
48+
49+
/** The properties file `application.properties`. */
50+
class ApplicationProperties extends ConfigPair {
51+
ApplicationProperties() { this.getFile().getBaseName() = "application.properties" }
52+
}
53+
54+
/** The configuration property `management.security.enabled`. */
55+
class ManagementSecurityConfig extends ApplicationProperties {
56+
ManagementSecurityConfig() { this.getNameElement().getName() = "management.security.enabled" }
57+
58+
/** Gets the whitespace-trimmed value of this property. */
59+
string getValue() { result = this.getValueElement().getValue().trim() }
60+
61+
/** Holds if `management.security.enabled` is set to `false`. */
62+
predicate hasSecurityDisabled() { this.getValue() = "false" }
63+
64+
/** Holds if `management.security.enabled` is set to `true`. */
65+
predicate hasSecurityEnabled() { this.getValue() = "true" }
66+
}
67+
68+
/** The configuration property `management.endpoints.web.exposure.include`. */
69+
class ManagementEndPointInclude extends ApplicationProperties {
70+
ManagementEndPointInclude() {
71+
this.getNameElement().getName() = "management.endpoints.web.exposure.include"
72+
}
73+
74+
/** Gets the whitespace-trimmed value of this property. */
75+
string getValue() { result = this.getValueElement().getValue().trim() }
76+
}
77+
78+
/**
79+
* Holds if `ApplicationProperties` ap of a repository managed by `SpringBootPom` pom
80+
* has a vulnerable configuration of Spring Boot Actuator management endpoints.
81+
*/
82+
predicate hasConfidentialEndPointExposed(SpringBootPom pom, ApplicationProperties ap) {
83+
pom.isSpringBootActuatorUsed() and
84+
not pom.isSpringBootSecurityUsed() and
85+
ap.getFile()
86+
.getParentContainer()
87+
.getAbsolutePath()
88+
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
89+
exists(string springBootVersion | springBootVersion = pom.getParentElement().getVersionString() |
90+
springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4
91+
not exists(ManagementSecurityConfig me |
92+
me.hasSecurityEnabled() and me.getFile() = ap.getFile()
93+
)
94+
or
95+
springBootVersion.matches("1.5%") and // version 1.5
96+
exists(ManagementSecurityConfig me | me.hasSecurityDisabled() and me.getFile() = ap.getFile())
97+
or
98+
springBootVersion.matches("2.%") and //version 2.x
99+
exists(ManagementEndPointInclude mi |
100+
mi.getFile() = ap.getFile() and
101+
(
102+
mi.getValue() = "*" // all endpoints are enabled
103+
or
104+
mi.getValue()
105+
.matches([
106+
"%dump%", "%trace%", "%logfile%", "%shutdown%", "%startup%", "%mappings%", "%env%",
107+
"%beans%", "%sessions%"
108+
]) // confidential endpoints to check although all endpoints apart from '/health' and '/info' are considered sensitive by Spring
109+
)
110+
)
111+
)
112+
}
113+
114+
deprecated query predicate problems(Dependency d, string message) {
115+
exists(SpringBootPom pom |
116+
hasConfidentialEndPointExposed(pom, _) and
117+
d = pom.getADependency() and
118+
d.getArtifact().getValue() = "spring-boot-starter-actuator"
119+
) and
120+
message = "Insecure configuration of Spring Boot Actuator exposes sensitive endpoints."
121+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#management.endpoints.web.base-path=/admin
2+
3+
4+
#### BAD: All management endpoints are accessible ####
5+
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
6+
7+
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
8+
management.security.enabled=false
9+
10+
# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything
11+
management.endpoints.web.exposure.include=*
12+
13+
14+
#### GOOD: All management endpoints have access control ####
15+
# safe configuration (spring boot 1.0 - 1.4): exposes actuators by default
16+
management.security.enabled=true
17+
18+
# safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators
19+
management.security.enabled=true
20+
21+
# safe configuration (spring boot 2+): exposes health and info only by default, here overridden to expose one additional endpoint which we assume is intentional and safe.
22+
management.endpoints.web.exposure.include=beans,info,health
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>spring-boot-actuator-app</groupId>
8+
<artifactId>spring-boot-actuator-app</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<maven.compiler.source>1.8</maven.compiler.source>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
</properties>
16+
17+
<parent>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-starter-parent</artifactId>
20+
<version>2.3.8.RELEASE</version>
21+
<relativePath/>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-actuator</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-devtools</artifactId>
36+
</dependency>
37+
38+
<!-- BAD: No Spring Security enabled -->
39+
<!-- dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-starter-security</artifactId>
42+
</dependency -->
43+
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-test</artifactId>
47+
</dependency>
48+
</dependencies>
49+
50+
</project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>spring-boot-actuator-app</groupId>
8+
<artifactId>spring-boot-actuator-app</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
<maven.compiler.source>1.8</maven.compiler.source>
14+
<maven.compiler.target>1.8</maven.compiler.target>
15+
</properties>
16+
17+
<parent>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-starter-parent</artifactId>
20+
<version>2.3.8.RELEASE</version>
21+
<relativePath/>
22+
</parent>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-actuator</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-devtools</artifactId>
36+
</dependency>
37+
38+
<!-- GOOD: Enable Spring Security -->
39+
<dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-starter-security</artifactId>
42+
</dependency>
43+
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-test</artifactId>
47+
</dependency>
48+
</dependencies>
49+
50+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| pom.xml:29:9:32:22 | dependency | Insecure configuration of Spring Boot Actuator exposes sensitive endpoints. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import org.springframework.stereotype.Controller;
2+
import org.springframework.web.bind.annotation.RequestParam;
3+
import org.springframework.web.bind.annotation.RequestMapping;
4+
5+
@Controller
6+
public class SensitiveInfo {
7+
@RequestMapping
8+
public void handleLogin(@RequestParam String username, @RequestParam String password) throws Exception {
9+
if (!username.equals("") && password.equals("")) {
10+
//Blank processing
11+
}
12+
}
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#management.endpoints.web.base-path=/admin
2+
3+
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
4+
5+
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
6+
management.security.enabled=false
7+
8+
# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything
9+
management.endpoints.web.exposure.include=*
10+
management.endpoints.web.exposure.exclude=beans
11+
12+
management.endpoint.shutdown.enabled=true
13+
14+
management.endpoint.health.show-details=when_authorized
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x

0 commit comments

Comments
 (0)