Skip to content

Commit a806a4f

Browse files
authored
Merge pull request #4312 from JLLeitschuh/feat/JLL/java/jhipster_CVE-2019-16303
Java: QL Query Detector for JHipster Generated CVE-2019-16303
2 parents d91ea55 + a9c5551 commit a806a4f

File tree

12 files changed

+977
-0
lines changed

12 files changed

+977
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>This query detects instances of <code>RandomUtil.java</code> that were generated by a <a href="https://www.jhipster.tech/">JHipster</a> version that is vulnerable to <a href="https://github.com/jhipster/jhipster-kotlin/security/advisories/GHSA-j3rh-8vwq-wh84">CVE-2019-16303</a>.</p>
7+
8+
<p>If an app uses <code>RandomUtil.java</code> generated by a vulnerable version of JHipster, attackers can request a password reset token and use this to predict the value of future reset tokens generated by this server.
9+
Using this information, they can create a reset link that allows them to take over any account.</p>
10+
11+
<p>This vulnerability has a
12+
<a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?name=CVE-2019-16303&amp;vector=AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H&amp;version=3.1&amp;source=NIST">
13+
CVSS v3.0 Base Score of 9.8/10
14+
</a>.</p>
15+
</overview>
16+
17+
<example>
18+
19+
<p>The example below shows the vulnerable <code>RandomUtil</code> class generated by <a href="https://www.jhipster.tech/2019/09/13/jhipster-release-6.3.0.html">JHipster prior to version 6.3.0</a>.</p>
20+
<sample src="JHipsterGeneratedPRNGVulnerable.java" />
21+
22+
<p>Below is a fixed version of the <code>RandomUtil</code> class.</p>
23+
<sample src="JHipsterGeneratedPRNGFixed.java" />
24+
25+
</example>
26+
27+
<recommendation>
28+
29+
<p>You should refactor the <code>RandomUtil</code> class and replace every call to <code>RandomStringUtils.randomAlphaNumeric</code>. You could regenerate the class using the latest version of JHipster, or use an automated refactoring. For example, using the <a href="https://github.com/moderneinc/jhipster-cwe-338">Patching JHipster CWE-338</a> for the <a href="https://github.com/openrewrite/rewrite">Rewrite project</a>.
30+
</p>
31+
</recommendation>
32+
33+
<references>
34+
35+
<li>
36+
Cloudflare Blog:
37+
<a href="https://blog.cloudflare.com/why-randomness-matters/">
38+
Why secure systems require random numbers
39+
</a>
40+
</li>
41+
<li>
42+
Hacker News:
43+
<a href="https://news.ycombinator.com/item?id=639976">
44+
How I Hacked Hacker News (with arc security advisory)
45+
</a>
46+
</li>
47+
<li>
48+
Posts by Pucara Information Security Team:
49+
<a href="https://blog.pucarasec.com/2020/05/09/the-java-soothsayer-a-practical-application-for-insecure-randomness-includes-free-0day/">
50+
The Java Soothsayer: A practical application for insecure randomness. (Includes free 0day)
51+
</a>
52+
</li>
53+
54+
<!-- LocalWords: CWE random RNG PRNG CSPRNG SecureRandom JHipster -->
55+
56+
</references>
57+
58+
</qhelp>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* @name Detect JHipster Generator Vulnerability CVE-2019-16303
3+
* @description Using a vulnerable version of JHipster to generate random numbers makes it easier for attackers to take over accounts.
4+
* @kind problem
5+
* @problem.severity error
6+
* @precision very-high
7+
* @id java/jhipster-prng
8+
* @tags security
9+
* external/cwe/cwe-338
10+
*/
11+
12+
import java
13+
import semmle.code.java.frameworks.apache.Lang
14+
15+
private class PredictableApacheRandomStringUtilsMethod extends Method {
16+
PredictableApacheRandomStringUtilsMethod() {
17+
this.getDeclaringType() instanceof TypeApacheRandomStringUtils and
18+
// The one valid use of this type that uses SecureRandom as a source of data.
19+
not this.getName() = "random"
20+
}
21+
}
22+
23+
private class PredictableApacheRandomStringUtilsMethodAccess extends MethodAccess {
24+
PredictableApacheRandomStringUtilsMethodAccess() {
25+
this.getMethod() instanceof PredictableApacheRandomStringUtilsMethod
26+
}
27+
}
28+
29+
private class VulnerableJHipsterRandomUtilClass extends Class {
30+
VulnerableJHipsterRandomUtilClass() {
31+
// The package name that JHipster generated the 'RandomUtil' class in was dynamic. Thus 'hasQualifiedName' can not be used here.
32+
getName() = "RandomUtil"
33+
}
34+
}
35+
36+
private class VulnerableJHipsterRandomUtilMethod extends Method {
37+
VulnerableJHipsterRandomUtilMethod() {
38+
this.getDeclaringType() instanceof VulnerableJHipsterRandomUtilClass and
39+
this.getName().matches("generate%") and
40+
this.getReturnType() instanceof TypeString and
41+
exists(ReturnStmt s |
42+
s = this.getBody().(SingletonBlock).getStmt() and
43+
s.getResult() instanceof PredictableApacheRandomStringUtilsMethodAccess
44+
)
45+
}
46+
}
47+
48+
from VulnerableJHipsterRandomUtilMethod method
49+
select method,
50+
"Weak random number generator used in security sensitive method (JHipster CVE-2019-16303)."
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import org.apache.commons.lang3.RandomStringUtils;
2+
3+
import java.security.SecureRandom;
4+
5+
/**
6+
* Utility class for generating random Strings.
7+
*/
8+
public final class RandomUtil {
9+
private static final SecureRandom SECURE_RANDOM = new SecureRandom(); // GOOD: Using SecureRandom
10+
11+
private static final int DEF_COUNT = 20;
12+
13+
static {
14+
SECURE_RANDOM.nextBytes(new byte[64]);
15+
}
16+
17+
private RandomUtil() {
18+
}
19+
20+
private static String generateRandomAlphanumericString() {
21+
// GOOD: Passing Secure Random to RandomStringUtils::random
22+
return RandomStringUtils.random(DEF_COUNT, 0, 0, true, true, null, SECURE_RANDOM);
23+
}
24+
25+
/**
26+
* Generate a password.
27+
*
28+
* @return the generated password.
29+
*/
30+
public static String generatePassword() {
31+
return generateRandomAlphanumericString();
32+
}
33+
34+
/**
35+
* Generate an activation key.
36+
*
37+
* @return the generated activation key.
38+
*/
39+
public static String generateActivationKey() {
40+
return generateRandomAlphanumericString();
41+
}
42+
43+
/**
44+
* Generate a reset key.
45+
*
46+
* @return the generated reset key.
47+
*/
48+
public static String generateResetKey() {
49+
return generateRandomAlphanumericString();
50+
}
51+
52+
/**
53+
* Generate a unique series to validate a persistent token, used in the
54+
* authentication remember-me mechanism.
55+
*
56+
* @return the generated series data.
57+
*/
58+
public static String generateSeriesData() {
59+
return generateRandomAlphanumericString();
60+
}
61+
62+
/**
63+
* Generate a persistent token, used in the authentication remember-me mechanism.
64+
*
65+
* @return the generated token data.
66+
*/
67+
public static String generateTokenData() {
68+
return generateRandomAlphanumericString();
69+
}
70+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import org.apache.commons.lang3.RandomStringUtils;
2+
3+
/**
4+
* Utility class for generating random Strings.
5+
*/
6+
public final class RandomUtil {
7+
8+
private static final int DEF_COUNT = 20;
9+
10+
private RandomUtil() {
11+
}
12+
13+
/**
14+
* Generate a password.
15+
*
16+
* @return the generated password.
17+
*/
18+
public static String generatePassword() {
19+
return RandomStringUtils.randomAlphanumeric(DEF_COUNT); // BAD: RandomStringUtils does not use SecureRandom
20+
}
21+
22+
/**
23+
* Generate an activation key.
24+
*
25+
* @return the generated activation key.
26+
*/
27+
public static String generateActivationKey() {
28+
return RandomStringUtils.randomNumeric(DEF_COUNT); // BAD: RandomStringUtils does not use SecureRandom
29+
}
30+
31+
/**
32+
* Generate a reset key.
33+
*
34+
* @return the generated reset key.
35+
*/
36+
public static String generateResetKey() {
37+
return RandomStringUtils.randomNumeric(DEF_COUNT); // BAD: RandomStringUtils does not use SecureRandom
38+
}
39+
40+
/**
41+
* Generate a unique series to validate a persistent token, used in the
42+
* authentication remember-me mechanism.
43+
*
44+
* @return the generated series data.
45+
*/
46+
public static String generateSeriesData() {
47+
return RandomStringUtils.randomAlphanumeric(DEF_COUNT); // BAD: RandomStringUtils does not use SecureRandom
48+
}
49+
50+
/**
51+
* Generate a persistent token, used in the authentication remember-me mechanism.
52+
*
53+
* @return the generated token data.
54+
*/
55+
public static String generateTokenData() {
56+
return RandomStringUtils.randomAlphanumeric(DEF_COUNT); // BAD: RandomStringUtils does not use SecureRandom
57+
}
58+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/** Definitions related to the Apache Commons Lang library. */
2+
3+
import java
4+
5+
/*--- Types ---*/
6+
/** The class `org.apache.commons.lang.RandomStringUtils` or `org.apache.commons.lang3.RandomStringUtils`. */
7+
class TypeApacheRandomStringUtils extends Class {
8+
TypeApacheRandomStringUtils() {
9+
hasQualifiedName("org.apache.commons.lang", "RandomStringUtils") or
10+
hasQualifiedName("org.apache.commons.lang3", "RandomStringUtils")
11+
}
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| vulnerable/RandomUtil.java:20:26:20:41 | generatePassword | Weak random number generator used in security sensitive method (JHipster CVE-2019-16303). |
2+
| vulnerable/RandomUtil.java:29:26:29:46 | generateActivationKey | Weak random number generator used in security sensitive method (JHipster CVE-2019-16303). |
3+
| vulnerable/RandomUtil.java:38:26:38:41 | generateResetKey | Weak random number generator used in security sensitive method (JHipster CVE-2019-16303). |
4+
| vulnerable/RandomUtil.java:48:26:48:43 | generateSeriesData | Weak random number generator used in security sensitive method (JHipster CVE-2019-16303). |
5+
| vulnerable/RandomUtil.java:57:26:57:42 | generateTokenData | Weak random number generator used in security sensitive method (JHipster CVE-2019-16303). |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-338/JHipsterGeneratedPRNG.ql
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package test.cwe338.cwe.examples.fixed;
2+
3+
import org.apache.commons.lang3.RandomStringUtils;
4+
5+
import java.security.SecureRandom;
6+
7+
/**
8+
* Utility class for generating random Strings.
9+
*/
10+
public final class RandomUtil {
11+
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
12+
13+
private static final int DEF_COUNT = 20;
14+
15+
static {
16+
SECURE_RANDOM.nextBytes(new byte[64]);
17+
}
18+
19+
private RandomUtil() {
20+
}
21+
22+
private static String generateRandomAlphanumericString() {
23+
return RandomStringUtils.random(DEF_COUNT, 0, 0, true, true, null, SECURE_RANDOM);
24+
}
25+
26+
/**
27+
* Generate a password.
28+
*
29+
* @return the generated password.
30+
*/
31+
public static String generatePassword() {
32+
return generateRandomAlphanumericString();
33+
}
34+
35+
/**
36+
* Generate an activation key.
37+
*
38+
* @return the generated activation key.
39+
*/
40+
public static String generateActivationKey() {
41+
return generateRandomAlphanumericString();
42+
}
43+
44+
/**
45+
* Generate a reset key.
46+
*
47+
* @return the generated reset key.
48+
*/
49+
public static String generateResetKey() {
50+
return generateRandomAlphanumericString();
51+
}
52+
53+
/**
54+
* Generate a unique series to validate a persistent token, used in the
55+
* authentication remember-me mechanism.
56+
*
57+
* @return the generated series data.
58+
*/
59+
public static String generateSeriesData() {
60+
return generateRandomAlphanumericString();
61+
}
62+
63+
/**
64+
* Generate a persistent token, used in the authentication remember-me mechanism.
65+
*
66+
* @return the generated token data.
67+
*/
68+
public static String generateTokenData() {
69+
return generateRandomAlphanumericString();
70+
}
71+
}
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/apache-commons-lang3-3.7
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package test.cwe338.cwe.examples.vulnerable;
2+
3+
import org.apache.commons.lang3.RandomStringUtils;
4+
5+
/**
6+
* Utility class for generating random Strings.
7+
*/
8+
public final class RandomUtil {
9+
10+
private static final int DEF_COUNT = 20;
11+
12+
private RandomUtil() {
13+
}
14+
15+
/**
16+
* Generate a password.
17+
*
18+
* @return the generated password.
19+
*/
20+
public static String generatePassword() {
21+
return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
22+
}
23+
24+
/**
25+
* Generate an activation key.
26+
*
27+
* @return the generated activation key.
28+
*/
29+
public static String generateActivationKey() {
30+
return RandomStringUtils.randomNumeric(DEF_COUNT);
31+
}
32+
33+
/**
34+
* Generate a reset key.
35+
*
36+
* @return the generated reset key.
37+
*/
38+
public static String generateResetKey() {
39+
return RandomStringUtils.randomNumeric(DEF_COUNT);
40+
}
41+
42+
/**
43+
* Generate a unique series to validate a persistent token, used in the
44+
* authentication remember-me mechanism.
45+
*
46+
* @return the generated series data.
47+
*/
48+
public static String generateSeriesData() {
49+
return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
50+
}
51+
52+
/**
53+
* Generate a persistent token, used in the authentication remember-me mechanism.
54+
*
55+
* @return the generated token data.
56+
*/
57+
public static String generateTokenData() {
58+
return RandomStringUtils.randomAlphanumeric(DEF_COUNT);
59+
}
60+
}

0 commit comments

Comments
 (0)