-
Notifications
You must be signed in to change notification settings - Fork 561
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 #1072 from blacklanternsecurity/newsletters
Newsletters Module
- Loading branch information
Showing
12 changed files
with
509 additions
and
398 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 |
---|---|---|
@@ -1 +1,2 @@ | ||
__pycache__/ | ||
.coverage* |
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,46 @@ | ||
# Created a new module called 'newsletters' that will scrape the websites (or recursive websites, | ||
# thanks to BBOT's sub-domain enumeration) looking for the presence of an 'email type' that also | ||
# contains a 'placeholder'. The combination of these two HTML items usually signify the presence | ||
# of an "Enter Your Email Here" type Newsletter Subscription service. This module could be used | ||
# to find newsletters for a future email bombing attack and/or find user-input fields that could | ||
# be be susceptible to overflows or injections. | ||
|
||
from .base import BaseModule | ||
import re | ||
from bs4 import BeautifulSoup | ||
|
||
# Known Websites with Newsletters | ||
# https://futureparty.com/ | ||
# https://www.marketingbrew.com/ | ||
# https://buffer.com/ | ||
# https://www.milkkarten.net/ | ||
# https://geekout.mattnavarra.com/ | ||
|
||
deps_pip = ["beautifulsoup4"] | ||
|
||
|
||
class newsletters(BaseModule): | ||
watched_events = ["HTTP_RESPONSE"] | ||
produced_events = ["FINDING"] | ||
flags = ["active", "safe"] | ||
meta = {"description": "Searches for Newsletter Submission Entry Fields on Websites"} | ||
|
||
# Parse through Website to find a Text Entry Box of 'type = email' | ||
# and ensure that there is placeholder text within it. | ||
def find_type(self, soup): | ||
email_type = soup.find(type="email") | ||
if email_type: | ||
regex = re.compile(r"placeholder") | ||
if regex.search(str(email_type)): | ||
return True | ||
return False | ||
|
||
async def handle_event(self, event): | ||
if event.data["status_code"] == 200: | ||
soup = BeautifulSoup(event.data["body"], "html.parser") | ||
result = self.find_type(soup) | ||
if result: | ||
description = f"Found a Newsletter Submission Form that could be used for email bombing attacks" | ||
data = {"host": str(event.host), "description": description, "url": event.data["url"]} | ||
|
||
await self.emit_event(data, "FINDING", event) |
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
57 changes: 57 additions & 0 deletions
57
bbot/test/test_step_2/module_tests/test_module_newsletters.py
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,57 @@ | ||
from .base import ModuleTestBase | ||
|
||
# import logging | ||
|
||
|
||
class TestNewsletters(ModuleTestBase): | ||
found_tgt = "http://127.0.0.1:8888/found" | ||
missing_tgt = "http://127.0.0.1:8888/missing" | ||
targets = [found_tgt, missing_tgt] | ||
modules_overrides = ["speculate", "httpx", "newsletters"] | ||
|
||
html_with_newsletter = """ | ||
<input aria-required="true" | ||
class="form-input form-input-text required" | ||
data-at="form-email" | ||
data-describedby="form-validation-error-box-element-5" | ||
data-label-inside="Enter your email" | ||
id="field-5f329905b4bfe1027b44513f94b50363-0" | ||
name="Enter your email" | ||
placeholder="Enter your email" | ||
required="" | ||
title="Enter your email" | ||
type="email" value=""/> | ||
""" | ||
|
||
html_without_newsletter = """ | ||
<div> | ||
<h1>Example Domain</h1> | ||
<p>This domain is for use in illustrative examples in documents. You may use this | ||
domain in literature without prior coordination or asking for permission.</p> | ||
<p><a href="https://www.iana.org/domains/example">More information...</a></p> | ||
</div> | ||
""" | ||
|
||
async def setup_after_prep(self, module_test): | ||
request_args = dict(uri="/found", headers={"test": "header"}) | ||
respond_args = dict(response_data=self.html_with_newsletter) | ||
module_test.set_expect_requests(request_args, respond_args) | ||
request_args = dict(uri="/missing", headers={"test": "header"}) | ||
respond_args = dict(response_data=self.html_without_newsletter) | ||
module_test.set_expect_requests(request_args, respond_args) | ||
|
||
def check(self, module_test, events): | ||
found = False | ||
missing = True | ||
for event in events: | ||
# self.log.info(f"event type: {event.type}") | ||
if event.type == "FINDING": | ||
# self.log.info(f"event data: {event.data}") | ||
# Verify Positive Result | ||
if event.data["url"] == self.found_tgt: | ||
found = True | ||
# Verify Negative Result (should skip this statement if correct) | ||
elif event.data["url"] == self.missing_tgt: | ||
missing = False | ||
assert found, f"NEWSLETTER 'Found' Error - Expect status of True but got False" | ||
assert missing, f"NEWSLETTER 'Missing' Error - Expect status of True but got False" |
Oops, something went wrong.