-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Check if credentials are transported over an encrypted channel
- Loading branch information
1 parent
26d16d0
commit 493bcd5
Showing
8 changed files
with
192 additions
and
3 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
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,116 @@ | ||
from unittest.mock import Mock | ||
from asyncio import Event | ||
|
||
import respx | ||
import httpx | ||
import pytest | ||
|
||
from wapitiCore.net.web import Request | ||
from wapitiCore.net.crawler import AsyncCrawler | ||
from wapitiCore.attack.mod_http_post import mod_http_post | ||
from wapitiCore.language.vulnerability import _ | ||
from tests import AsyncMock | ||
|
||
|
||
@pytest.mark.asyncio | ||
@respx.mock | ||
|
||
async def test_no_login_form(): | ||
respx.get("http://perdu.com/").mock( | ||
return_value=httpx.Response( | ||
200, | ||
text="<html><head><title>Vous Etes Perdu ?</title></head><body><h1>Perdu sur l'Internet ?</h1> \ | ||
<h2>Pas de panique, on va vous aider</h2> \ | ||
<strong><pre> * <----- vous êtes ici</pre></strong></body></html>" | ||
) | ||
) | ||
persister = AsyncMock() | ||
|
||
request = Request("http://perdu.com/") | ||
request.path_id = 1 | ||
# persister.requests.append(request) | ||
|
||
crawler = AsyncCrawler("http://perdu.com/") | ||
|
||
options = {"timeout": 10, "level": 2} | ||
logger = Mock() | ||
|
||
module = mod_http_post(crawler, persister, logger, options, Event()) | ||
module.verbose = 2 | ||
|
||
await module.attack(request) | ||
|
||
assert not persister.add_payload.call_count | ||
await crawler.close() | ||
|
||
@pytest.mark.asyncio | ||
@respx.mock | ||
async def test_login_form_https(): | ||
url = "https://perdu.com/" | ||
body = """<html> | ||
<body> | ||
<form method="POST"> | ||
<input type="text" name="username" /> | ||
<input type="password" name="pass" /> | ||
</form> | ||
</body> | ||
</html> | ||
""" | ||
|
||
respx.get(url).mock(return_value=httpx.Response(200, text=body)) | ||
|
||
persister = AsyncMock() | ||
request = Request("https://perdu.com/") | ||
request.path_id = 1 | ||
# persister.requests.append(request) | ||
|
||
crawler = AsyncCrawler("https://perdu.com/") | ||
|
||
options = {"timeout": 10, "level": 2} | ||
logger = Mock() | ||
|
||
module = mod_http_post(crawler, persister, logger, options, Event()) | ||
module.verbose = 2 | ||
|
||
await module.attack(request) | ||
assert not persister.add_payload.call_count | ||
await crawler.close() | ||
|
||
@pytest.mark.asyncio | ||
@respx.mock | ||
async def test_login_form_http(): | ||
url = "http://perdu.com/" | ||
body = """<html> | ||
<body> | ||
<form method="POST"> | ||
<input type="text" name="username" /> | ||
<input type="password" name="pass" value="Letm3in_" /> | ||
</form> | ||
</body> | ||
</html> | ||
""" | ||
|
||
respx.get(url).mock(return_value=httpx.Response(200, text=body)) | ||
|
||
persister = AsyncMock() | ||
request = Request( | ||
"http://perdu.com/", | ||
method="POST", | ||
post_params=[["email", "wapiti2021@mailinator.com"], ["password", "Letm3in_"]], | ||
) | ||
request.path_id = 1 | ||
# persister.requests.append(request) | ||
|
||
crawler = AsyncCrawler("http://perdu.com/") | ||
|
||
options = {"timeout": 10, "level": 2} | ||
logger = Mock() | ||
|
||
module = mod_http_post(crawler, persister, logger, options, Event()) | ||
module.verbose = 2 | ||
|
||
await module.attack(request) | ||
assert persister.add_payload.call_count | ||
assert persister.add_payload.call_args_list[0][1]["module"] == "http_post" | ||
assert persister.add_payload.call_args_list[0][1]["category"] == _("POST HTTP") | ||
await crawler.close() |
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
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,32 @@ | ||
from httpx import RequestError | ||
|
||
from wapitiCore.attack.attack import Attack | ||
from wapitiCore.net.web import Request | ||
from wapitiCore.language.vulnerability import MEDIUM_LEVEL, _ | ||
from wapitiCore.definitions.http_post import NAME | ||
|
||
|
||
# This module check the security of transported credentials of login forms | ||
class mod_http_post(Attack): | ||
"""Check if credentials are transported on an encrypted channel.""" | ||
name = "http_post" | ||
|
||
async def must_attack(self, request: Request): | ||
# We leverage the fact that the crawler will fill password entries with a known placeholder | ||
if "https://" in request.url: | ||
return False | ||
|
||
return True | ||
|
||
async def attack(self, request: Request): | ||
|
||
if "Letm3in_" not in request.encoded_data + request.encoded_params: | ||
return | ||
self.finished = True | ||
|
||
await self.add_vuln_medium( | ||
request_id=request.path_id, | ||
category=NAME, | ||
request=request, | ||
info=_("Credentials transported over an Unencrypted Channel on : {0}").format(request.url) | ||
) |
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,31 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
|
||
from wapitiCore.language.language import _ | ||
|
||
TYPE = "vulnerability" | ||
NAME = _("POST HTTP") | ||
SHORT_NAME = NAME | ||
|
||
DESCRIPTION = _( | ||
"The application configuration should ensure that SSL is used for all access controlled pages.\\n)." | ||
) + " " + _( | ||
"If an application uses SSL to guarantee confidential communication with client browsers, " | ||
) + " " + _( | ||
"the application configuration should make it impossible to view any access controlled page without SSL." | ||
) | ||
|
||
SOLUTION = _( | ||
"Force the use of HTTPS for all authentication requests" | ||
) | ||
|
||
REFERENCES = [ | ||
{ | ||
"title": "OWASP: Insecure Transport", | ||
"url": "https://owasp.org/www-community/vulnerabilities/Insecure_Transport" | ||
}, | ||
{ | ||
"title": "Acunetix: Insecure Authentication", | ||
"url": "https://owasp.org/www-project-mobile-top-10/2016-risks/m4-insecure-authentication" | ||
} | ||
] |
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
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
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