generated from Ostorlab/template_agent
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #125 from Ostorlab/feature/CVE_2024_9164
Add version based detection for CVE-2024-9164
- Loading branch information
Showing
2 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
"""Agent Asteroid implementation for CVE-2024-9164""" | ||
|
||
import datetime | ||
import re | ||
from urllib import parse as urlparse | ||
|
||
import requests | ||
from requests import exceptions as requests_exceptions | ||
|
||
from agent import definitions | ||
from agent import exploits_registry | ||
from agent.exploits import webexploit | ||
|
||
MAX_REDIRECTS = 2 | ||
DEFAULT_TIMEOUT = datetime.timedelta(seconds=90) | ||
|
||
VULNERABILITY_TITLE = "Gitlab Run pipelines on arbitrary branches." | ||
VULNERABILITY_REFERENCE = "CVE-2024-9164" | ||
VULNERABILITY_DESCRIPTION = ( | ||
"An issue was discovered in GitLab EE affecting all versions starting from 12.5 prior to 17.2.9," | ||
"starting from 17.3, prior to 17.3.5, and starting from 17.4 prior to 17.4.2, which allows running pipelines on arbitrary branches." | ||
) | ||
RISK_RATING = "CRITICAL" | ||
|
||
VULN_VERSIONS_HASHES = [ | ||
"eb078ffe61726e3898dc9d01ea7955809778bde5be3677d907cbd3b48854e687", | ||
"1626b2999241b5a658bddd1446648ed0b9cc289de4cc6e10f60b39681a0683c4", | ||
"70ce56efa7e602d4b127087b0eca064681ecdd49b57d86665da8b081da39408b", | ||
"40d8ac21e0e120f517fbc9a798ecb5caeef5182e01b7e7997aac30213ef367b3", | ||
"ed4780bb05c30e3c145419d06ad0ab3f48bd3004a90fb99601f40c5b6e1d90fd", | ||
"1084266bd81c697b5268b47c76565aa86b821126a6b9fe6ea7b50f64971fc96f", | ||
"7310c45f08c5414036292b0c4026f281a73cf8a01af82a81257dd343f378bbb5", | ||
"473ef436c59830298a2424616d002865f17bb5a6e0334d3627affa352a4fc117", | ||
"4448d19024d3be03b5ba550b5b02d27f41c4bdba4db950f6f0e7136d820cd9e1", | ||
"ae0edd232df6f579e19ea52115d35977f8bdbfa9958e0aef2221d62f3a39e7d8", | ||
"bf1c397958ee5114e8f1dadc98fa9c9d7ddb031a4c3c030fa00c315384456218", | ||
"c923fa3e71e104d50615978c1ab9fcfccfcbada9e8df638fc27bf4d4eb72d78c", | ||
"655ad8aea57bdaaad10ff208c7f7aa88c9af89a834c0041ffc18c928cc3eab1f", | ||
"81c5f2c7b2c0b0abaeb59585f36904031c21b1702c24349404df52834fbd7ad3", | ||
"30a9dffe86b597151eff49443097496f0d1014bb6695a2f69a7c97dc1c27828f", | ||
"b50bfeb87fe7bb245b31a0423ccfd866ca974bc5943e568ce47efb4cd221d711", | ||
"ac9b38e86b6c87bf8db038ae23da3a5f17a6c391b3a54ad1e727136141a7d4f5", | ||
"e2578590390a9eb10cd65d130e36503fccb40b3921c65c160bb06943b2e3751a", | ||
"015d088713b23c749d8be0118caeb21039491d9812c75c913f48d53559ab09df", | ||
"0993beabc8d2bb9e3b8d12d24989426b909921e20e9c6a704de7a5f1dfa93c59", | ||
"62e4cc014d9d96f9cbf443186289ffd9c41bdfe951565324891dcf38bcca5a51", | ||
"d0850f616c5b4f09a7ff319701bce0460ffc17ca0349ad2cf7808b868688cf71", | ||
"08858ced0ff83694fb12cf155f6d6bf450dcaae7192ea3de8383966993724290", | ||
"4990bb27037f3d5f1bffc0625162173ad8043166a1ae5c8505aabe6384935ce2", | ||
"6ae610d783ba9a520b82263f49d2907a52090fecb3ac37819cea12b67e6d94fb", | ||
"27d2c4c4e2fcf6e589e3e1fe85723537333b087003aa4c1d2abcf74d5c899959", | ||
"e355f614211d036d0b3ffac4cd76da00d89e05717df61629e82571e20ac27488", | ||
"a624c11e908db556820e9b07de96e0a465e9be5d5e6b68cdafe6d5c95c99798b", | ||
"515dc29796a763b500d37ec0c765957a136c9e1f1972bb52c3d7edcf4b6b8bbe", | ||
"c91127b2698c0a2ae0103be3accffe01995b8531bf1027ae4f0a8ad099e7a209", | ||
"383b8952f0627703ada7774dd42f3b901ea2e499fd556fce3ae0c6d604ad72b7", | ||
"e539e07c389f60596c92b06467c735073788196fa51331255d66ff7afde5dfee", | ||
"2ea7e9be931f24ebc2a67091b0f0ff95ba18e386f3d312545bb5caaac6c1a8be", | ||
"5df2cb13ec314995ea43d698e888ddb240dbc7ccb6e635434dc8919eced3e25f", | ||
"a4333a9de660b9fc4d227403f57d46ec275d6a6349a6f5bda0c9557001f87e5d", | ||
"ff058b10a8dce9956247adba2e410a7f80010a236b2269fb53e0df5cd091e61d", | ||
"1d765038b21c5c76ff8492561c29984f3fa5c4b8cfb3a6c7b216ac8ab18b78c7", | ||
"301b60d2c71a595adfb65b22edee9023961c5190e1807f6db7c597675b0a61f0", | ||
"6fa9fec63ba24ec06fcae0ec30d1369619c2c3323fe9ddc4849af86457d59eef", | ||
"f8ba2470fbf1e30f2ce64d34705b8e6615ac964ea84163c8a6adaaf8a91f9eac", | ||
"6eb5eaa5726150b8135a4fd09118cfd6b29f128586b7fa5019a04f1c740e9193", | ||
"6a58066d1bde4b6e661fbd5bde83d2dd90615ab409b8c8c36e04954fbd923424", | ||
"1ae98447c220181b7bd2dfe88018cb6e1b1e4d12d7b8c224d651a48ed2d95dfe", | ||
"a6d68fb0380bece011b0180b2926142630414c1d7a3e268fb461c51523b63778", | ||
"95ae8966ec1e6021f2553c7d275217fcfecd5a7f0b206151c5fb701beb7baf1e", | ||
"1e3d7f89df5b5446401d669796adf858c6742cb23a3d41b53f51a3c312c798cc", | ||
"1caf2b894e48f649fcfd6b20de756e07ce64c1a756b9a20ff4505caeffa1a361", | ||
"5a73588c1bf39ca7421dff5d8a03b887f0ebcb4897d6c136dfe03fa63a11b1ad", | ||
"0ac028d3833c573c3e7cd054219213d6b36474cb4531a251238d9fa25831d97a", | ||
"badd1d1762b624e5c7d251e045a3b2a3693054edbcb0115eb3cc64758fa62e92", | ||
"7ac3b54e2ee2a129462d6702c9857a04f1a405f7254b89a2b3dfc7e73e80a489", | ||
"dac7d8befc64f632fac344ebdca56066e013a4e260c3bdfb375fcf6dd30c3c56", | ||
"f6b592d2e7570ce5d28f3dbf7170c0b3aa19dcb951f8c9e9ebe6cd5ec44691e8", | ||
"c19a43b56f2b869d14e8b8865f2673e99e95a3f9912c95776e2aa44d0de56416", | ||
"e7b1efce983de69e755cecf958ad52fe9c578fee502ec2046fbe4d418e12c237", | ||
"a727ffdf1055442288d2fbc8b2ab23c38185697594725ea899f9faa653fad748", | ||
"fb3d9b8e0a1937690eb35bd8b7a8686b51f36226bc9c29f0ea1621d568030c1a", | ||
"ad779fabb121ac9d0c594b996d2fddb1fee9ce36c886c73c3d0e6fe10233819b", | ||
"106174ae025caa47e54ebda6fb32a305a86857c1a808ab1a76a697e8a286166c", | ||
"198963a1fcb2babf24b04c7c3a57fe439f453a90e1820ef7228d23a420b137ec", | ||
"6687cea99d08705f41c22ba6c0f625668940d80a47e99488bf0d3d4bafa9d398", | ||
"1d30846db8d63a25cb7d1a54a8ef11af9382c4d5e95fcc6ba7c8f34f9581d51d", | ||
"c10b409df4222d166bfe9b34b787e05a671f9116b47ee10265029bfda6c5305b", | ||
"f79ed5a6b0dfecf39281aeefcdd5b15d7cc6d871a3ae20e60c40d6a718377704", | ||
"7649badc780fc4e44c1b7063c6153b3c216a5f6f0d7907eed714fac2a39ede73", | ||
"47ec6054e1998d4cb2623b09faa02993de5f7cc92d34ba60dad2646b3b92a83e", | ||
"e357f1b1a6812a8e72a4aec06b3761062a281129d621bf2e580806a8fca6302d", | ||
"aecafb937628c9745dc285b2cb2c41d8a57846c934c2168b0cfec35b3d44e51f", | ||
"73616daa0479bf77369c603146e745cc4cb9874b3b38f81fb2993818049dbf1a", | ||
"58ebcd8f96ecc2ebf7f29122395e38ee28dc833dfc6d08fb667d2655da971df6", | ||
"05a4322b27a3352f9638610b6a2528a03f90070a19fdb9e0499bb0412aad92fb", | ||
"1b91aa4fc5e5ae49577087b2b42821ac87b863ba4de61cdccdd6b3620f587608", | ||
"64ec030272495820a69a90e76affc1d0c47377c80f267ed21fa039c40404d4c9", | ||
"22918e5e48d718e0977422d6c63347ce3199ac16206c958518b968c239529900", | ||
] | ||
|
||
POTENTIALLY_VULN_VERSIONS_HASHES = [ | ||
"6479d7d7b19cce99a8971e85a3756ea6f1debe89b68d0a86e69cc9c6e7414d7d", | ||
"b52d3dd3b307bb936ad862671cae67163327a698f3dc2c4f232173d621af2a87", | ||
"6a54b783019af16f39492a7c048d885d232d3940d8e5528940d70b6a6d2d0eb0", | ||
] | ||
|
||
|
||
@exploits_registry.register | ||
class CVE20249164Exploit(webexploit.WebExploit): | ||
accept_request = definitions.Request(method="GET", path="/users/sign_in") | ||
check_request = definitions.Request(method="GET", path="/users/sign_in") | ||
accept_pattern = [re.compile("GitLab")] | ||
|
||
metadata = definitions.VulnerabilityMetadata( | ||
title=VULNERABILITY_TITLE, | ||
description=VULNERABILITY_DESCRIPTION, | ||
reference=VULNERABILITY_REFERENCE, | ||
risk_rating=RISK_RATING, | ||
) | ||
|
||
def check(self, target: definitions.Target) -> list[definitions.Vulnerability]: | ||
"""Rule to detect specific vulnerability on a specific target. | ||
Args: | ||
target: Target to scan | ||
Returns: | ||
List of identified vulnerabilities. | ||
""" | ||
session = requests.Session() | ||
session.max_redirects = MAX_REDIRECTS | ||
session.verify = False | ||
|
||
target_endpoint = urlparse.urljoin(target.origin, self.check_request.path) | ||
|
||
try: | ||
req = requests.Request( | ||
method=self.check_request.method, | ||
url=target_endpoint, | ||
data=self.check_request.data, | ||
).prepare() | ||
resp = session.send(req, timeout=DEFAULT_TIMEOUT.seconds, verify=False) | ||
except requests_exceptions.RequestException: | ||
return [] | ||
|
||
for version_hash in VULN_VERSIONS_HASHES: | ||
pattern = re.compile(version_hash) | ||
if pattern.search(resp.text) is not None: | ||
vulnerability = self._create_vulnerability(target) | ||
return [vulnerability] | ||
|
||
for version_hash in POTENTIALLY_VULN_VERSIONS_HASHES: | ||
pattern = re.compile(version_hash) | ||
if pattern.search(resp.text) is not None: | ||
self.metadata = definitions.VulnerabilityMetadata( | ||
title=VULNERABILITY_TITLE, | ||
description=VULNERABILITY_DESCRIPTION, | ||
reference=VULNERABILITY_REFERENCE, | ||
risk_rating="POTENTIALLY", | ||
) | ||
vulnerability = self._create_vulnerability(target) | ||
return [vulnerability] | ||
|
||
return [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
"""Unit tests for Agent Asteriod: CVE-2024-9164""" | ||
|
||
import requests_mock as req_mock | ||
|
||
from agent import definitions | ||
from agent.exploits import cve_2024_9164 | ||
|
||
|
||
def testCVE20249164_whenVulnerable_reportFinding( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Test exploit report finding when version is vulnerable.""" | ||
target = definitions.Target("https", "localhost", 8080) | ||
requests_mock.get( | ||
target.url + "users/sign_in", | ||
status_code=200, | ||
text="<title>Sign in · GitLab</title>" | ||
'<link rel="preload" href="' | ||
'/assets/application-22918e5e48d718e0977422d6c63347ce3199ac16206c958518b968c239529900.css"' | ||
' as="style" type="text/css">', | ||
) | ||
|
||
exploit_instance = cve_2024_9164.CVE20249164Exploit() | ||
accept = exploit_instance.accept(target) | ||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert accept is True | ||
assert len(vulnerabilities) > 0 | ||
vulnerability = vulnerabilities[0] | ||
|
||
assert vulnerability.entry.title == "Gitlab Run pipelines on arbitrary branches." | ||
assert ( | ||
vulnerability.technical_detail | ||
== "https://localhost:8080 is vulnerable to CVE-2024-9164, Gitlab Run pipelines on arbitrary branches." | ||
) | ||
assert vulnerability.risk_rating.name == "CRITICAL" | ||
|
||
|
||
def testCVE20249164_whenPotentiallyVulnerable_reportFinding( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Test exploit report finding when version is potentially vulnerable.""" | ||
target = definitions.Target("https", "localhost", 8080) | ||
requests_mock.get( | ||
target.url + "users/sign_in", | ||
status_code=200, | ||
text="<title>Sign in · GitLab</title>" | ||
'<link rel="preload" href="' | ||
'/assets/application-b52d3dd3b307bb936ad862671cae67163327a698f3dc2c4f232173d621af2a87.css"' | ||
' as="style" type="text/css">', | ||
) | ||
|
||
exploit_instance = cve_2024_9164.CVE20249164Exploit() | ||
accept = exploit_instance.accept(target) | ||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert accept is True | ||
assert len(vulnerabilities) > 0 | ||
vulnerability = vulnerabilities[0] | ||
|
||
assert vulnerability.entry.title == "Gitlab Run pipelines on arbitrary branches." | ||
assert ( | ||
vulnerability.technical_detail | ||
== "https://localhost:8080 is vulnerable to CVE-2024-9164, Gitlab Run pipelines on arbitrary branches." | ||
) | ||
assert vulnerability.risk_rating.name == "POTENTIALLY" | ||
|
||
|
||
def testCVE20249164_whenNotVulnerable_reportNoFinding( | ||
requests_mock: req_mock.mocker.Mocker, | ||
) -> None: | ||
"""Test exploit don't report finding.""" | ||
target = definitions.Target("https", "localhost", 8080) | ||
requests_mock.get( | ||
target.url + "users/sign_in", | ||
status_code=200, | ||
text="<title>Sign in · GitLab</title>" | ||
'<link rel="preload" href="' | ||
'/assets/application-8276cea79ef526c83539dd54f72382f170a49fbe45332e2f2c132a38880e38ff.css"' | ||
' as="style" type="text/css">', | ||
) | ||
|
||
exploit_instance = cve_2024_9164.CVE20249164Exploit() | ||
accept = exploit_instance.accept(target) | ||
vulnerabilities = exploit_instance.check(target) | ||
|
||
assert accept is True | ||
assert len(vulnerabilities) == 0 |