-
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 #1942 from blacklanternsecurity/postgres
New Module: Postgres Output
- Loading branch information
Showing
10 changed files
with
177 additions
and
27 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
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,49 @@ | ||
from bbot.modules.templates.sql import SQLTemplate | ||
|
||
|
||
class Postgres(SQLTemplate): | ||
watched_events = ["*"] | ||
meta = {"description": "Output scan data to a SQLite database"} | ||
options = { | ||
"username": "postgres", | ||
"password": "bbotislife", | ||
"host": "localhost", | ||
"port": 5432, | ||
"database": "bbot", | ||
} | ||
options_desc = { | ||
"username": "The username to connect to Postgres", | ||
"password": "The password to connect to Postgres", | ||
"host": "The server running Postgres", | ||
"port": "The port to connect to Postgres", | ||
"database": "The database name to connect to", | ||
} | ||
deps_pip = ["sqlmodel", "asyncpg"] | ||
protocol = "postgresql+asyncpg" | ||
|
||
async def create_database(self): | ||
import asyncpg | ||
from sqlalchemy import text | ||
from sqlalchemy.ext.asyncio import create_async_engine | ||
|
||
# Create the engine for the initial connection to the server | ||
initial_engine = create_async_engine(self.connection_string().rsplit("/", 1)[0]) | ||
|
||
async with initial_engine.connect() as conn: | ||
# Check if the database exists | ||
result = await conn.execute(text(f"SELECT 1 FROM pg_database WHERE datname = '{self.database}'")) | ||
database_exists = result.scalar() is not None | ||
|
||
# Create the database if it does not exist | ||
if not database_exists: | ||
# Use asyncpg directly to create the database | ||
raw_conn = await asyncpg.connect( | ||
user=self.username, | ||
password=self.password, | ||
host=self.host, | ||
port=self.port, | ||
) | ||
try: | ||
await raw_conn.execute(f"CREATE DATABASE {self.database}") | ||
finally: | ||
await raw_conn.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
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
74 changes: 74 additions & 0 deletions
74
bbot/test/test_step_2/module_tests/test_module_postgres.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,74 @@ | ||
import time | ||
import asyncio | ||
|
||
from .base import ModuleTestBase | ||
|
||
|
||
class TestPostgres(ModuleTestBase): | ||
targets = ["evilcorp.com"] | ||
skip_distro_tests = True | ||
|
||
async def setup_before_prep(self, module_test): | ||
process = await asyncio.create_subprocess_exec( | ||
"docker", | ||
"run", | ||
"--name", | ||
"bbot-test-postgres", | ||
"--rm", | ||
"-e", | ||
"POSTGRES_PASSWORD=bbotislife", | ||
"-e", | ||
"POSTGRES_USER=postgres", | ||
"-p", | ||
"5432:5432", | ||
"-d", | ||
"postgres", | ||
) | ||
|
||
import asyncpg | ||
|
||
# wait for the container to start | ||
start_time = time.time() | ||
while True: | ||
try: | ||
# Connect to the default 'postgres' database to create 'bbot' | ||
conn = await asyncpg.connect( | ||
user="postgres", password="bbotislife", database="postgres", host="127.0.0.1" | ||
) | ||
await conn.execute("CREATE DATABASE bbot") | ||
await conn.close() | ||
break | ||
except asyncpg.exceptions.DuplicateDatabaseError: | ||
# If the database already exists, break the loop | ||
break | ||
except Exception as e: | ||
if time.time() - start_time > 60: # timeout after 60 seconds | ||
self.log.error("PostgreSQL server did not start in time.") | ||
raise e | ||
await asyncio.sleep(1) | ||
|
||
if process.returncode != 0: | ||
self.log.error(f"Failed to start PostgreSQL server") | ||
|
||
async def check(self, module_test, events): | ||
import asyncpg | ||
|
||
# Connect to the PostgreSQL database | ||
conn = await asyncpg.connect(user="postgres", password="bbotislife", database="bbot", host="127.0.0.1") | ||
|
||
try: | ||
events = await conn.fetch("SELECT * FROM event") | ||
assert len(events) == 3, "No events found in PostgreSQL database" | ||
scans = await conn.fetch("SELECT * FROM scan") | ||
assert len(scans) == 1, "No scans found in PostgreSQL database" | ||
targets = await conn.fetch("SELECT * FROM target") | ||
assert len(targets) == 1, "No targets found in PostgreSQL database" | ||
finally: | ||
await conn.close() | ||
process = await asyncio.create_subprocess_exec( | ||
"docker", "stop", "bbot-test-postgres", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE | ||
) | ||
stdout, stderr = await process.communicate() | ||
|
||
if process.returncode != 0: | ||
raise Exception(f"Failed to stop PostgreSQL server: {stderr.decode()}") |
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