Skip to content

Commit 15d87df

Browse files
MashyBaskerunnxt30
authored andcommitted
checker(java): Add miscellaneous checkers for Java (#202)
* checker: add CBC padding oracle vuln checker * chore: modify test comments * add checker for rsa instance creation without padding * detect cipher using ecb mode * detect custom message digest implementation * detect usage of insecure DES and 3DES * detect NullCipher and DefaultHttpClient * detect weak ssl context * detect insecure sha224 usage
1 parent c7fb026 commit 15d87df

18 files changed

+620
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package servlets;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.PrintWriter;
6+
7+
import javax.servlet.ServletException;
8+
import javax.servlet.http.HttpServlet;
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.servlet.http.HttpServletResponse;
11+
import javax.servlet.http.HttpSession;
12+
13+
public class Cls extends HttpServlet
14+
{
15+
private static org.apache.log4j.Logger log = Logger.getLogger(Register.class);
16+
17+
// cf. https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
18+
protected void danger(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
19+
// <expect-error>
20+
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
21+
c.init(Cipher.ENCRYPT_MODE, k, iv);
22+
byte[] cipherText = c.doFinal(plainText);
23+
}
24+
25+
protected void ok(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
26+
// <no-error>
27+
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
28+
c.init(Cipher.ENCRYPT_MODE, k, iv);
29+
byte[] cipherText = c.doFinal(plainText);
30+
}
31+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
language: java
2+
name: cbc-padding-oracle
3+
message: "Using CBC mode with PKCS5Padding can cause padding oracle attacks"
4+
category: security
5+
severity: critical
6+
7+
pattern: >
8+
(method_invocation
9+
object: (identifier) @cipherClass
10+
name: (identifier) @instanceMethod
11+
arguments: (argument_list
12+
(string_literal
13+
(string_fragment) @str))
14+
(#match? @str ".*CBC.*PKCS5Padding")
15+
(#eq? @cipherClass "Cipher")
16+
(#eq? @instanceMethod "getInstance")) @cbc-padding-oracle
17+
18+
19+
exclude:
20+
- "tests/**"
21+
- "vendor/**"
22+
- "**/Test_*.java"
23+
- "**/*Test.java"
24+
25+
description: >
26+
Java applications using CBC mode with PKCS5Padding for encryption are vulnerable to padding oracle attacks, where attackers can distinguish between valid and invalid padding to potentially decrypt sensitive data without knowing the encryption key. This vulnerability is compounded by CBC mode's lack of built-in integrity checks. The recommended approach is using AES/GCM/NoPadding instead, which provides both confidentiality and integrity protection through authenticated encryption.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// <expect-error>
2+
public class MyProprietaryMessageDigest extends MessageDigest {
3+
4+
@Override
5+
protected byte[] engineDigest() {
6+
return "";
7+
}
8+
}
9+
10+
// <no-error>
11+
public class NotMessageDigest {
12+
public NotMessageDigest() {
13+
System.out.println("");
14+
}
15+
}

checkers/java/custom-digests.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: java
2+
name: custom-digests
3+
message: "Implementing custom digests can lead to security issues"
4+
category: security
5+
severity: warning
6+
7+
pattern: >
8+
(class_declaration
9+
superclass: (superclass) @extension (#eq? @extension "extends MessageDigest")) @custom-digests
10+
11+
exclude:
12+
- "tests/**"
13+
- "vendor/**"
14+
- "**/Test_*.java"
15+
- "**/*Test.java"
16+
17+
description: >
18+
A custom message digest implementation risks introducing serious security vulnerabilities, as cryptographic algorithms require precise implementation to be secure. Instead, leverage the established and well-tested message digest implementations already available, such as SHA-256 through Java's MessageDigest API.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// cf. https://mkyong.com/java/the-type-defaulthttpclient-is-deprecated/
2+
3+
package com.exampleweb.controller;
4+
5+
import org.apache.http.Header;
6+
import org.apache.http.HttpResponse;
7+
import org.apache.http.client.HttpClient;
8+
import org.apache.http.client.methods.HttpGet;
9+
import org.apache.http.impl.client.DefaultHttpClient;
10+
11+
public class WebCrawler {
12+
13+
public void crawl(String[] args) throws Exception {
14+
// <expect-error>
15+
HttpClient client = new DefaultHttpClient();
16+
HttpGet request = new HttpGet("http://google.com");
17+
HttpResponse response = client.execute(request);
18+
}
19+
20+
}
21+
22+
public class SecureWebCrawler {
23+
24+
public void crawl(String[] args) throws Exception {
25+
// <no-error>
26+
HttpClient client = new SystemDefaultHttpClient();
27+
HttpGet request = new HttpGet("http://google.com");
28+
HttpResponse response = client.execute(request);
29+
}
30+
31+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: java
2+
name: deprecated-default-httpclient
3+
message: "Detected usage of deprecated `DefaultHttpClient`. Use `HttpClientBuilder` instead"
4+
category: security
5+
severity: warning
6+
7+
pattern: >
8+
(object_creation_expression
9+
type: (type_identifier) @httpclient (#eq? @httpclient "DefaultHttpClient")) @deprecated-default-httpclient
10+
11+
exclude:
12+
- "tests/**"
13+
- "vendor/**"
14+
- "**/Test_*.java"
15+
- "**/*Test.java"
16+
17+
description: >
18+
DefaultHttpClient is deprecated and does not support TLS1.2 connections, creating a significant security vulnerability. Use HttpClientBuilder instead for secure HTTP communications.
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package servlets;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.PrintWriter;
6+
7+
import javax.servlet.ServletException;
8+
import javax.servlet.http.HttpServlet;
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.servlet.http.HttpServletResponse;
11+
import javax.servlet.http.HttpSession;
12+
13+
public class Cls extends HttpServlet
14+
{
15+
private static org.apache.log4j.Logger log = Logger.getLogger(Register.class);
16+
17+
// cf. https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
18+
protected void danger(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
19+
// <expect-error>
20+
Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding");
21+
c.init(Cipher.ENCRYPT_MODE, k, iv);
22+
byte[] cipherText = c.doFinal(plainText);
23+
}
24+
25+
protected void danger2(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
26+
// <expect-error>
27+
Cipher c = Cipher.getInstance("DES");
28+
c.init(Cipher.ENCRYPT_MODE, k, iv);
29+
byte[] cipherText = c.doFinal(plainText);
30+
}
31+
32+
protected void ok(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
33+
// <no-error>
34+
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
35+
c.init(Cipher.ENCRYPT_MODE, k, iv);
36+
byte[] cipherText = c.doFinal(plainText);
37+
}
38+
}
39+
40+
public class Cls extends HttpServlet
41+
{
42+
private static org.apache.log4j.Logger log = Logger.getLogger(Register.class);
43+
44+
// cf. https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
45+
protected void danger(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
46+
// <expect-error>
47+
Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding");
48+
c.init(Cipher.ENCRYPT_MODE, k, iv);
49+
byte[] cipherText = c.doFinal(plainText);
50+
}
51+
52+
protected void ok(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
53+
// <no-error>
54+
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
55+
c.init(Cipher.ENCRYPT_MODE, k, iv);
56+
byte[] cipherText = c.doFinal(plainText);
57+
}
58+
}
59+
60+
@WebServlet(value = "/crypto-00/BenchmarkTest00019")
61+
public class BenchmarkTest00019 extends HttpServlet {
62+
63+
private static final long serialVersionUID = 1L;
64+
65+
@Override
66+
public void doGet(HttpServletRequest request, HttpServletResponse response)
67+
throws ServletException, IOException {
68+
doPost(request, response);
69+
}
70+
71+
@Override
72+
public void doPost(HttpServletRequest request, HttpServletResponse response)
73+
throws ServletException, IOException {
74+
response.setContentType("text/html;charset=UTF-8");
75+
76+
java.io.InputStream param = request.getInputStream();
77+
78+
try {
79+
java.util.Properties benchmarkprops = new java.util.Properties();
80+
benchmarkprops.load(
81+
this.getClass().getClassLoader().getResourceAsStream("benchmark.properties"));
82+
String algorithm = benchmarkprops.getProperty("cryptoAlg1", "DESede/ECB/PKCS5Padding");
83+
javax.crypto.Cipher c = javax.crypto.Cipher.getInstance(algorithm);
84+
85+
// Prepare the cipher to encrypt
86+
// <expect-error>
87+
javax.crypto.SecretKey key = javax.crypto.KeyGenerator.getInstance("DES").generateKey();
88+
c.init(javax.crypto.Cipher.ENCRYPT_MODE, key);
89+
90+
// encrypt and store the results
91+
byte[] input = {(byte) '?'};
92+
Object inputParam = param;
93+
if (inputParam instanceof String) input = ((String) inputParam).getBytes();
94+
if (inputParam instanceof java.io.InputStream) {
95+
byte[] strInput = new byte[1000];
96+
int i = ((java.io.InputStream) inputParam).read(strInput);
97+
if (i == -1) {
98+
response.getWriter()
99+
.println(
100+
"This input source requires a POST, not a GET. Incompatible UI for the InputStream source.");
101+
return;
102+
}
103+
input = java.util.Arrays.copyOf(strInput, i);
104+
}
105+
byte[] result = c.doFinal(input);
106+
107+
java.io.File fileTarget =
108+
new java.io.File(
109+
new java.io.File(org.owasp.benchmark.helpers.Utils.TESTFILES_DIR),
110+
"passwordFile.txt");
111+
java.io.FileWriter fw =
112+
new java.io.FileWriter(fileTarget, true); // the true will append the new data
113+
fw.write(
114+
"secret_value="
115+
+ org.owasp.esapi.ESAPI.encoder().encodeForBase64(result, true)
116+
+ "\n");
117+
fw.close();
118+
response.getWriter()
119+
.println(
120+
"Sensitive value: '"
121+
+ org.owasp
122+
.esapi
123+
.ESAPI
124+
.encoder()
125+
.encodeForHTML(new String(input))
126+
+ "' encrypted and stored<br/>");
127+
128+
} catch (java.security.NoSuchAlgorithmException
129+
| javax.crypto.NoSuchPaddingException
130+
| javax.crypto.IllegalBlockSizeException
131+
| javax.crypto.BadPaddingException
132+
| java.security.InvalidKeyException e) {
133+
response.getWriter()
134+
.println(
135+
"Problem executing crypto - javax.crypto.Cipher.getInstance(java.lang.String,java.security.Provider) Test Case");
136+
e.printStackTrace(response.getWriter());
137+
throw new ServletException(e);
138+
}
139+
}
140+
}

checkers/java/deprecated-des.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
language: java
2+
name: deprecated-des
3+
message: "The DES encryption algorithm is considered insecure. AES is recommended."
4+
category: security
5+
severity: warning
6+
7+
pattern: >
8+
(method_invocation
9+
object: (identifier) @cipher (#eq? @cipher "Cipher")
10+
name: (identifier) @instanceMethod (#eq? @instanceMethod "getInstance")
11+
arguments: (argument_list
12+
(string_literal
13+
(string_fragment) @string (#match? @string "^(DES/.*|DESede/.*|DES)$")))) @deprecated-des
14+
15+
(method_invocation
16+
object: (method_invocation) @method
17+
(#match? @method "\\.[Kk]eyGenerator\\.getInstance")
18+
(#match? @method "\"DES\"")) @deprecated-des
19+
20+
exclude:
21+
- "tests/**"
22+
- "vendor/**"
23+
- "**/Test_*.java"
24+
- "**/*Test.java"
25+
26+
description: >
27+
DES and Triple DES (3DES/DESede) are considered deprecated encryption standards. AES is the recommended cipher for both cases. Organizations should upgrade their systems to use AES instead. For more information about the deprecation of DES, see https://www.nist.gov/news-events/news/2005/06/nist-withdraws-outdated-data-encryption-standard.
28+
29+

checkers/java/ecb-cipher.test.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class ECBCipher {
2+
3+
public void ecbCipher() {
4+
// <expect-error>
5+
Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
6+
c.init(Cipher.ENCRYPT_MODE, k, iv);
7+
byte[] cipherText = c.doFinal(plainText);
8+
}
9+
public void noEcbCipher() {
10+
// <no-error>
11+
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
12+
c.init(Cipher.ENCRYPT_MODE, k, iv);
13+
byte[] cipherText = c.doFinal(plainText);
14+
}
15+
}

checkers/java/ecb-cipher.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
language: java
2+
name: ecb-cipher
3+
message: "Using Cipher with ECB mode gives deterministic output"
4+
category: security
5+
severity: warning
6+
7+
pattern: >
8+
(method_invocation
9+
object: (identifier) @cipher (#eq? @cipher "Cipher")
10+
name: (identifier) @instanceMethod (#eq? @instanceMethod "getInstance")
11+
arguments: (argument_list
12+
(string_literal
13+
(string_fragment) @str (#match? @str ".*ECB.*")))) @ecb-cipher
14+
15+
exclude:
16+
- "tests/**"
17+
- "vendor/**"
18+
- "**/Test_*.java"
19+
- "**/*Test.java"
20+
21+
description: >
22+
Cipher in ECB mode produces identical output for identical input blocks, making it vulnerable to replay attacks where attackers can intercept and reuse encrypted data. Additionally, ECB mode lacks integrity checking mechanisms, which means there's no way to verify if the encrypted data has been tampered with during transmission.

0 commit comments

Comments
 (0)