Skip to content

Java: CWE-016 Query to detect insecure configuration of Spring Boot Actuator #5384

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Query to detect insecure configuration of Spring Boot Actuator
  • Loading branch information
luchua-bc committed Mar 11, 2021
commit eeac7e322ad0d450f8dac1f0dad9195e4d3b8c33
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>Spring Boot is a popular framework that facilitates the development of stand-alone applications
and micro services. Spring Boot Actuator helps to expose production-ready support features against
Spring Boot applications.</p>

<p>Endpoints of Spring Boot Actuator allow to monitor and interact with a Spring Boot application.
Exposing unprotected actuator endpoints through configuration files can lead to information disclosure
or even remote code execution vulnerability.</p>

<p>Rather than programmatically permitting endpoint requests or enforcing access control, frequently
developers simply leave management endpoints publicly accessible in the application configuration file
<code>application.properties</code> without enforcing access control through Spring Security.</p>
</overview>

<recommendation>
<p>Declare the Spring Boot Starter Security module in XML configuration or programmatically enforce
security checks on management endpoints using Spring Security. Otherwise accessing management endpoints
on a different HTTP port other than the port that the web application is listening on also helps to
improve the security.</p>
</recommendation>

<example>
<p>The following examples show both 'BAD' and 'GOOD' configurations. In the 'BAD' configuration,
no security module is declared and sensitive management endpoints are exposed. In the 'GOOD' configuration,
security is enforced and only endpoints requiring exposure are exposed.</p>
<sample src="pom_good.xml" />
<sample src="pom_bad.xml" />
<sample src="application.properties" />
</example>

<references>
<li>
Spring Boot documentation:
<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">Spring Boot Actuator: Production-ready Features</a>
</li>
<li>
VERACODE Blog:
<a href="https://www.veracode.com/blog/research/exploiting-spring-boot-actuators">Exploiting Spring Boot Actuators</a>
</li>
<li>
HackerOne Report:
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
</li>
</references>
</qhelp>
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* @name Insecure Spring Boot Actuator Configuration
* @description Exposed Spring Boot Actuator through configuration files without declarative or procedural security enforcement leads to information leak or even remote code execution.
* @kind problem
* @id java/insecure-spring-actuator-config
* @tags security
* external/cwe-016
*/

import java
import semmle.code.configfiles.ConfigFiles
import semmle.code.java.security.SensitiveActions
import semmle.code.xml.MavenPom

/** The parent node of the `org.springframework.boot` group. */
class SpringBootParent extends Parent {
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
}

/** Class of Spring Boot dependencies. */
class SpringBootPom extends Pom {
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }

/** Holds if the Spring Boot Actuator module `spring-boot-starter-actuator` is used in the project. */
predicate isSpringBootActuatorUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-actuator"
}

/** Holds if the Spring Boot Security module is used in the project, which brings in other security related libraries. */
predicate isSpringBootSecurityUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
}
}

/** The properties file `application.properties`. */
class ApplicationProperties extends ConfigPair {
ApplicationProperties() { this.getFile().getBaseName() = "application.properties" }
}

/** The configuration property `management.security.enabled`. */
class ManagementSecurityEnabled extends ApplicationProperties {
ManagementSecurityEnabled() { this.getNameElement().getName() = "management.security.enabled" }

string getManagementSecurityEnabled() { result = this.getValueElement().getValue() }

predicate hasSecurityDisabled() { getManagementSecurityEnabled() = "false" }

predicate hasSecurityEnabled() { getManagementSecurityEnabled() = "true" }
}

/** The configuration property `management.endpoints.web.exposure.include`. */
class ManagementEndPointInclude extends ApplicationProperties {
ManagementEndPointInclude() {
this.getNameElement().getName() = "management.endpoints.web.exposure.include"
}

string getManagementEndPointInclude() { result = this.getValueElement().getValue().trim() }
}

/** The configuration property `management.endpoints.web.exposure.exclude`. */
class ManagementEndPointExclude extends ApplicationProperties {
ManagementEndPointExclude() {
this.getNameElement().getName() = "management.endpoints.web.exposure.exclude"
}

string getManagementEndPointExclude() { result = this.getValueElement().getValue().trim() }
}

/** Holds if an application handles sensitive information judging by its variable names. */
predicate isProtectedApp() {
exists(VarAccess va | va.getVariable().getName().regexpMatch(getCommonSensitiveInfoRegex()))
}

from SpringBootPom pom, ApplicationProperties ap, Dependency d
where
isProtectedApp() and
pom.isSpringBootActuatorUsed() and
not pom.isSpringBootSecurityUsed() and
ap.getFile()
.getParentContainer()
.getAbsolutePath()
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
exists(string s | s = pom.getParentElement().getVersionString() |
s.regexpMatch("1\\.[0|1|2|3|4].*") and
not exists(ManagementSecurityEnabled me |
me.hasSecurityEnabled() and me.getFile() = ap.getFile()
)
or
s.regexpMatch("1\\.5.*") and
exists(ManagementSecurityEnabled me | me.hasSecurityDisabled() and me.getFile() = ap.getFile())
or
s.regexpMatch("2.*") and
exists(ManagementEndPointInclude mi |
mi.getFile() = ap.getFile() and
(
mi.getManagementEndPointInclude() = "*" // all endpoints are enabled
or
mi.getManagementEndPointInclude()
.matches([
"%dump%", "%trace%", "%logfile%", "%shutdown%", "%startup%", "%mappings%", "%env%",
"%beans%", "%sessions%"
]) // all endpoints apart from '/health' and '/info' are considered sensitive
) and
not exists(ManagementEndPointExclude mx |
mx.getFile() = ap.getFile() and
mx.getManagementEndPointExclude() = mi.getManagementEndPointInclude()
)
)
) and
d = pom.getADependency() and
d.getArtifact().getValue() = "spring-boot-starter-actuator"
select d, "Insecure configuration of Spring Boot Actuator exposes sensitive endpoints."
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#management.endpoints.web.base-path=/admin


#### BAD: All management endpoints are accessible ####
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default

# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=false

# vulnerable configuration (spring boot 2+): exposes health and info only by default
management.endpoints.web.exposure.include=*


#### GOOD: All management endpoints have access control ####
# safe configuration (spring boot 1.0 - 1.4): exposes actuators by default
management.security.enabled=true

# safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=true

# safe configuration (spring boot 2+): exposes health and info only by default
management.endpoints.web.exposure.include=beans,info,health
50 changes: 50 additions & 0 deletions java/ql/src/experimental/Security/CWE/CWE-016/pom_bad.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

<!-- BAD: No Spring Security enabled -->
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>

</project>
50 changes: 50 additions & 0 deletions java/ql/src/experimental/Security/CWE/CWE-016/pom_good.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

<!-- GOOD: Enable Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| pom.xml:29:9:32:22 | dependency | Insecure configuration of Spring Boot Actuator exposes sensitive endpoints. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SensitiveInfo {
@RequestMapping
public void handleLogin(@RequestParam String username, @RequestParam String password) throws Exception {
if (!username.equals("") && password.equals("")) {
//Blank processing
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#management.endpoints.web.base-path=/admin

# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default

# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=false

# vulnerable configuration (spring boot 2+): exposes health and info only by default
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=beans

management.endpoint.shutdown.enabled=true

management.endpoint.health.show-details=when_authorized
47 changes: 47 additions & 0 deletions java/ql/test/experimental/query-tests/security/CWE-016/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>

</project>
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy