Skip to content

Commit b86e88e

Browse files
committed
Java: QL Query Detector for JHipster Generated CVE-2019-16303
1 parent 768e519 commit b86e88e

File tree

12 files changed

+963
-0
lines changed

12 files changed

+963
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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> generated by a <a href="https://www.jhipster.tech/">JHipster</a> version vulnerable to <a href="https://github.com/jhipster/jhipster-kotlin/security/advisories/GHSA-j3rh-8vwq-wh84">CVE-2019-16303</a>.
7+
8+
<p>Using one password reset token from your app combined with the proof of concept (POC) linked below, an attacker can determine all future password reset tokens to be generated by this server.
9+
This allows an attacker to pick and choose what account they would like to takeover by sending account password reset requests for targeted accounts.</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 JHipster.
20+
<sample src="JHipsterGeneratedPRNGVulnerble.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+
<references>
28+
29+
<li>
30+
<a href="https://blog.cloudflare.com/why-randomness-matters/">
31+
Cloudflare Blog: Why secure systems require random numbers
32+
</a>
33+
</li>
34+
<li>
35+
<a href="https://news.ycombinator.com/item?id=639976">
36+
How I Hacked Hacker News (with arc security advisory)
37+
</a>
38+
<li>
39+
<li>
40+
Research (Hacking Apache Commons RandomStringUtils):
41+
<a href="https://web.archive.org/web/20191126104359/https://medium.com/@alex91ar/the-java-soothsayer-a-practical-application-for-insecure-randomness-c67b0cd148cd">
42+
The Java Soothsayer: A practical application for insecure randomness. (Includes free 0day)
43+
</a>
44+
</li>
45+
46+
<!-- LocalWords: CWE random RNG PRNG CSPRNG SecureRandom JHipster -->
47+
48+
</references>
49+
50+
</qhelp>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* @name Detect JHipster Generator Vulnnerability CVE-2019-16303
3+
* @description Detector for the CVE-2019-16303 vulnerability that existed in the JHipster code generator.
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
18+
}
19+
}
20+
21+
private class PredictableApacheRandomStringUtilsMethodAccess extends MethodAccess {
22+
PredictableApacheRandomStringUtilsMethodAccess() {
23+
this.getMethod() instanceof PredictableApacheRandomStringUtilsMethod and
24+
// The one valid use of this type that uses SecureRandom as a source of data.
25+
not this.getMethod().getName() = "random"
26+
}
27+
}
28+
29+
private class VulnerableJHipsterRandomUtilClass extends Class {
30+
VulnerableJHipsterRandomUtilClass() { getName() = "RandomUtil" }
31+
}
32+
33+
private class VulnerableJHipsterRandomUtilMethod extends Method {
34+
VulnerableJHipsterRandomUtilMethod() {
35+
this.getDeclaringType() instanceof VulnerableJHipsterRandomUtilClass and
36+
this.getName().matches("generate%") and
37+
this.getReturnType() instanceof TypeString and
38+
exists(ReturnStmt s, PredictableApacheRandomStringUtilsMethodAccess access |
39+
s = this.getBody().(SingletonBlock).getStmt()
40+
|
41+
s.getResult() = access
42+
)
43+
}
44+
}
45+
46+
from VulnerableJHipsterRandomUtilMethod the_method
47+
select the_method,
48+
"RandomUtil was generated by JHipster Generator version vulnerable to CVE-2019-16303"
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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();
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+
return RandomStringUtils.random(DEF_COUNT, 0, 0, true, true, null, SECURE_RANDOM);
22+
}
23+
24+
/**
25+
* Generate a password.
26+
*
27+
* @return the generated password.
28+
*/
29+
public static String generatePassword() {
30+
return generateRandomAlphanumericString();
31+
}
32+
33+
/**
34+
* Generate an activation key.
35+
*
36+
* @return the generated activation key.
37+
*/
38+
public static String generateActivationKey() {
39+
return generateRandomAlphanumericString();
40+
}
41+
42+
/**
43+
* Generate a reset key.
44+
*
45+
* @return the generated reset key.
46+
*/
47+
public static String generateResetKey() {
48+
return generateRandomAlphanumericString();
49+
}
50+
51+
/**
52+
* Generate a unique series to validate a persistent token, used in the
53+
* authentication remember-me mechanism.
54+
*
55+
* @return the generated series data.
56+
*/
57+
public static String generateSeriesData() {
58+
return generateRandomAlphanumericString();
59+
}
60+
61+
/**
62+
* Generate a persistent token, used in the authentication remember-me mechanism.
63+
*
64+
* @return the generated token data.
65+
*/
66+
public static String generateTokenData() {
67+
return generateRandomAlphanumericString();
68+
}
69+
}
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);
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);
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);
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);
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);
57+
}
58+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* Definitions related to the Apache Commons Exec library. */
2+
import semmle.code.java.Type
3+
4+
class TypeApacheRandomStringUtils extends Class {
5+
TypeApacheRandomStringUtils() {
6+
hasQualifiedName("org.apache.commons.lang", "RandomStringUtils") or
7+
hasQualifiedName("org.apache.commons.lang3", "RandomStringUtils")
8+
}
9+
}
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 | RandomUtil was generated by JHipster Generator version vulnerable to CVE-2019-16303 |
2+
| vulnerable/RandomUtil.java:29:26:29:46 | generateActivationKey | RandomUtil was generated by JHipster Generator version vulnerable to CVE-2019-16303 |
3+
| vulnerable/RandomUtil.java:38:26:38:41 | generateResetKey | RandomUtil was generated by JHipster Generator version vulnerable to CVE-2019-16303 |
4+
| vulnerable/RandomUtil.java:48:26:48:43 | generateSeriesData | RandomUtil was generated by JHipster Generator version vulnerable to CVE-2019-16303 |
5+
| vulnerable/RandomUtil.java:57:26:57:42 | generateTokenData | RandomUtil was generated by JHipster Generator version vulnerable to 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)