Skip to content

Commit d3a84af

Browse files
author
github-actions
committed
Merge branch 'dev' into 3.0
2 parents ded21dd + ff98530 commit d3a84af

File tree

10 files changed

+79
-45
lines changed

10 files changed

+79
-45
lines changed

bbot/cli.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
22

3+
import io
34
import sys
45
import logging
56
import multiprocessing
@@ -240,7 +241,12 @@ def handle_keyboard_input(keyboard_input):
240241

241242
# set stdout and stderr to blocking mode
242243
# this is needed to prevent BlockingIOErrors in logging etc.
243-
fds = [sys.stdout.fileno(), sys.stderr.fileno()]
244+
fds = []
245+
for stream in [sys.stdout, sys.stderr]:
246+
try:
247+
fds.append(stream.fileno())
248+
except io.UnsupportedOperation:
249+
log.debug(f"Can't get fileno for {stream}")
244250
for fd in fds:
245251
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
246252
fcntl.fcntl(fd, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)

bbot/core/config/logger.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@
99
from contextlib import suppress
1010

1111
from ..helpers.misc import mkdir, error_and_exit
12-
from ...logger import colorize, loglevel_mapping
1312
from ..multiprocess import SHARED_INTERPRETER_STATE
14-
13+
from ...logger import colorize, loglevel_mapping, GzipRotatingFileHandler
1514

1615
debug_format = logging.Formatter("%(asctime)s [%(levelname)s] %(name)s %(filename)s:%(lineno)s %(message)s")
1716

@@ -216,15 +215,11 @@ def log_handlers(self):
216215
if not mkdir(log_dir, raise_error=False):
217216
error_and_exit(f"Failure creating or error writing to BBOT logs directory ({log_dir})")
218217

219-
# Main log file
220-
main_handler = logging.handlers.TimedRotatingFileHandler(
221-
f"{log_dir}/bbot.log", when="d", interval=1, backupCount=14
222-
)
218+
# Main log file (compressed)
219+
main_handler = GzipRotatingFileHandler(f"{log_dir}/bbot.log", when="d", interval=1, backupCount=14)
223220

224-
# Separate log file for debugging
225-
debug_handler = logging.handlers.TimedRotatingFileHandler(
226-
f"{log_dir}/bbot.debug.log", when="d", interval=1, backupCount=14
227-
)
221+
# Separate log file for debugging (compressed)
222+
debug_handler = GzipRotatingFileHandler(f"{log_dir}/bbot.debug.log", when="d", interval=1, backupCount=14)
228223

229224
# Log to stderr
230225
stderr_handler = logging.StreamHandler(sys.stderr)

bbot/logger.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import sys
2+
import logging.handlers
23

34
loglevel_mapping = {
45
"DEBUG": "DBUG",
@@ -50,3 +51,11 @@ def log_to_stderr(msg, level="INFO", logname=True):
5051
if logname:
5152
msg = f"{levelshort} {msg}"
5253
print(msg, file=sys.stderr)
54+
55+
56+
# Create a compressed file handler for logs
57+
class GzipRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
58+
def _open(self):
59+
import gzip
60+
61+
return gzip.open(f"{self.baseFilename}.gz", mode="at", encoding=self.encoding)

bbot/modules/crt_db.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ async def setup(self):
2929
async def request_url(self, query):
3030
if not self.db_conn:
3131
self.db_conn = await asyncpg.connect(
32-
host=self.db_host,
33-
port=self.db_port,
34-
user=self.db_user,
32+
host=self.db_host,
33+
port=self.db_port,
34+
user=self.db_user,
3535
database=self.db_name,
36-
statement_cache_size=0 # Disable automatic statement preparation
36+
statement_cache_size=0, # Disable automatic statement preparation
3737
)
3838

3939
sql = """

bbot/scanner/scanner.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .manager import ScanIngress, ScanEgress
1616
from bbot.core.helpers.misc import sha1, rand_string
1717
from bbot.core.helpers.names_generator import random_name
18+
from bbot.core.config.logger import GzipRotatingFileHandler
1819
from bbot.core.multiprocess import SHARED_INTERPRETER_STATE
1920
from bbot.core.helpers.async_helpers import async_to_sync_gen
2021
from bbot.errors import BBOTError, ScanError, ValidationError
@@ -1230,13 +1231,9 @@ def log_level(self):
12301231
def _log_handlers(self):
12311232
if self.__log_handlers is None:
12321233
self.helpers.mkdir(self.home)
1233-
main_handler = logging.handlers.TimedRotatingFileHandler(
1234-
str(self.home / "scan.log"), when="d", interval=1, backupCount=14
1235-
)
1234+
main_handler = GzipRotatingFileHandler(str(self.home / "scan.log"), when="d", interval=1, backupCount=14)
12361235
main_handler.addFilter(lambda x: x.levelno != logging.TRACE and x.levelno >= logging.VERBOSE)
1237-
debug_handler = logging.handlers.TimedRotatingFileHandler(
1238-
str(self.home / "debug.log"), when="d", interval=1, backupCount=14
1239-
)
1236+
debug_handler = GzipRotatingFileHandler(str(self.home / "debug.log"), when="d", interval=1, backupCount=14)
12401237
debug_handler.addFilter(lambda x: x.levelno >= logging.DEBUG)
12411238
self.__log_handlers = [main_handler, debug_handler]
12421239
return self.__log_handlers

bbot/test/bbot_fixtures.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os # noqa
22
import sys
3+
import zlib
34
import pytest
45
import shutil # noqa
56
import asyncio # noqa
@@ -49,6 +50,25 @@ def tempapkfile():
4950
return apk_file
5051

5152

53+
def read_gzipped_file(file_path):
54+
"""
55+
Read and decompress a gzipped file, tolerating missing end markers.
56+
57+
Args:
58+
file_path: Path to the gzipped file
59+
60+
Returns:
61+
The decompressed content as a string
62+
"""
63+
with open(file_path, "rb") as f:
64+
data = f.read()
65+
decompressor = zlib.decompressobj(
66+
16 + zlib.MAX_WBITS
67+
) # This is needed because the file doesn't have an end marker
68+
content = decompressor.decompress(data).decode("utf-8", errors="ignore")
69+
return content
70+
71+
5272
@pytest.fixture
5373
def clean_default_config(monkeypatch):
5474
clean_config = OmegaConf.merge(

bbot/test/test_step_1/test_cli.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ async def test_cli_scan(monkeypatch):
129129
dns_success = True
130130
assert ip_success and dns_success, "IP_ADDRESS and/or DNS_NAME are not present in output.txt"
131131

132+
# Check for gzipped scan log file
133+
scan_log_gz = scan_home / "scan.log.gz"
134+
assert scan_log_gz.is_file(), "scan.log.gz not found"
135+
assert "[INFO]" in read_gzipped_file(scan_log_gz)
136+
132137

133138
@pytest.mark.asyncio
134139
async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config):
@@ -187,14 +192,19 @@ async def test_cli_args(monkeypatch, caplog, capsys, clean_default_config):
187192
output_dir = bbot_test_dir / "bbot_cli_args_output"
188193
scan_name = "bbot_cli_args_scan_name"
189194
scan_dir = output_dir / scan_name
190-
assert not output_dir.exists()
195+
if output_dir.exists():
196+
shutil.rmtree(output_dir)
191197
monkeypatch.setattr("sys.argv", ["bbot", "-o", str(output_dir), "-n", scan_name, "-y"])
192198
result = await cli._main()
193199
assert result is True
194200
assert output_dir.is_dir()
195201
assert scan_dir.is_dir()
196202
assert "[SCAN]" in open(scan_dir / "output.txt").read()
197-
assert "[INFO]" in open(scan_dir / "scan.log").read()
203+
204+
# Check for gzipped scan log file
205+
scan_log_gz = scan_dir / "scan.log.gz"
206+
assert scan_log_gz.is_file(), "scan.log.gz not found"
207+
assert "[INFO]" in read_gzipped_file(scan_log_gz)
198208
shutil.rmtree(output_dir)
199209

200210
# list module options

bbot/test/test_step_1/test_python_api.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,28 @@ async def test_python_api():
1717
scan_home = scan2.helpers.scans_dir / "python_api_test"
1818
out_file = scan_home / "output.json"
1919
assert list(scan2.helpers.read_file(out_file))
20-
scan_log = scan_home / "scan.log"
21-
debug_log = scan_home / "debug.log"
20+
scan_log = scan_home / "scan.log.gz"
21+
debug_log = scan_home / "debug.log.gz"
2222
assert scan_log.is_file()
23-
assert "python_api_test" in open(scan_log).read()
23+
assert "python_api_test" in read_gzipped_file(scan_log)
2424
assert debug_log.is_file()
25-
assert "python_api_test" in open(debug_log).read()
25+
assert "python_api_test" in read_gzipped_file(debug_log)
2626

2727
scan3 = Scanner("127.0.0.1", output_modules=["json"], scan_name="scan_logging_test")
2828
await scan3.async_start_without_generator()
2929

30-
assert "scan_logging_test" not in open(scan_log).read()
31-
assert "scan_logging_test" not in open(debug_log).read()
30+
assert "scan_logging_test" not in read_gzipped_file(scan_log)
31+
assert "scan_logging_test" not in read_gzipped_file(debug_log)
3232

3333
scan_home = scan3.helpers.scans_dir / "scan_logging_test"
3434
out_file = scan_home / "output.json"
3535
assert list(scan3.helpers.read_file(out_file))
36-
scan_log = scan_home / "scan.log"
37-
debug_log = scan_home / "debug.log"
36+
scan_log = scan_home / "scan.log.gz"
37+
debug_log = scan_home / "debug.log.gz"
3838
assert scan_log.is_file()
3939
assert debug_log.is_file()
40-
assert "scan_logging_test" in open(scan_log).read()
41-
assert "scan_logging_test" in open(debug_log).read()
40+
assert "scan_logging_test" in read_gzipped_file(scan_log)
41+
assert "scan_logging_test" in read_gzipped_file(debug_log)
4242

4343
# make sure config loads properly
4444
bbot_home = "/tmp/.bbot_python_api_test"

bbot/test/test_step_2/module_tests/test_module_excavate.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from ...bbot_fixtures import *
12
from bbot.modules.base import BaseModule
23
from .base import ModuleTestBase, tempwordlist
34

@@ -1033,13 +1034,12 @@ async def setup_after_prep(self, module_test):
10331034
module_test.set_expect_requests({"uri": "/"}, {"response_data": self.bad_url_data})
10341035

10351036
def check(self, module_test, events):
1036-
log_file = module_test.scan.home / "debug.log"
1037-
log_text = log_file.read_text()
1037+
debug_log_content = read_gzipped_file(module_test.scan.home / "debug.log.gz")
10381038
# make sure our logging is working
1039-
assert "Setting scan status to STARTING" in log_text
1039+
assert "Setting scan status to STARTING" in debug_log_content
10401040
# make sure we don't have any URL validation errors
1041-
assert "Error Parsing reconstructed URL" not in log_text
1042-
assert "Error sanitizing event data" not in log_text
1041+
assert "Error Parsing reconstructed URL" not in debug_log_content
1042+
assert "Error sanitizing event data" not in debug_log_content
10431043

10441044
url_events = [e for e in events if e.type == "URL_UNVERIFIED"]
10451045
assert sorted([e.data for e in url_events]) == sorted(["https://ssl/", "http://127.0.0.1:8888/"])

bbot/test/test_step_2/module_tests/test_module_nuclei.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from ...bbot_fixtures import *
12
from .base import ModuleTestBase
23

34

@@ -100,9 +101,7 @@ async def setup_before_prep(self, module_test):
100101

101102
def check(self, module_test, events):
102103
assert any(e.type == "TECHNOLOGY" and "apache" in e.data["technology"].lower() for e in events)
103-
104-
with open(module_test.scan.home / "debug.log") as f:
105-
assert "Using Interactsh Server" not in f.read()
104+
assert "Using Interactsh Server" not in read_gzipped_file(module_test.scan.home / "debug.log.gz")
106105

107106

108107
class TestNucleiBudget(TestNucleiManual):
@@ -141,8 +140,7 @@ async def setup_before_prep(self, module_test):
141140
module_test.set_expect_requests(expect_args=expect_args, respond_args=respond_args)
142141

143142
def check(self, module_test, events):
144-
with open(module_test.scan.home / "debug.log") as f:
145-
assert "-retries 0" in f.read()
143+
assert "-retries 0" in read_gzipped_file(module_test.scan.home / "debug.log.gz")
146144

147145

148146
class TestNucleiRetriesCustom(TestNucleiRetries):
@@ -152,8 +150,7 @@ class TestNucleiRetriesCustom(TestNucleiRetries):
152150
}
153151

154152
def check(self, module_test, events):
155-
with open(module_test.scan.home / "debug.log") as f:
156-
assert "-retries 1" in f.read()
153+
assert "-retries 1" in read_gzipped_file(module_test.scan.home / "debug.log.gz")
157154

158155

159156
class TestNucleiCustomHeaders(TestNucleiManual):

0 commit comments

Comments
 (0)