Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc bugfixes, asyncio speed optimizations #1051

Merged
merged 41 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d8a6418
don't create asyncio tasks for dns stuff
TheTechromancer Feb 2, 2024
ce75405
fixed resolve_batch bug
TheTechromancer Feb 2, 2024
60e095f
multiprocessize collapse_url
TheTechromancer Feb 2, 2024
b6babc7
logging for wildcards
TheTechromancer Feb 2, 2024
a060815
make sure things are awaited
TheTechromancer Feb 2, 2024
0e6254e
fix bug in dns.py
TheTechromancer Feb 2, 2024
bf539b3
flaked
TheTechromancer Feb 2, 2024
19fe685
fix rare dns bug, verbosify abort_if
TheTechromancer Feb 2, 2024
126e39b
limit anubisdb due to excessive garbage results
TheTechromancer Feb 2, 2024
99042a8
clean up code
TheTechromancer Feb 2, 2024
9c92e93
blacked
TheTechromancer Feb 2, 2024
43133a1
remove custom cache, use cachetools
TheTechromancer Feb 2, 2024
d2fbaf5
increase max dnscommonsrv handlers, small masscan bugfix
TheTechromancer Feb 2, 2024
2958a3b
massdns speed optimizations
TheTechromancer Feb 3, 2024
fd984cd
dnscommonsrv rework, spellchecking
TheTechromancer Feb 3, 2024
d32d98d
fix tests
TheTechromancer Feb 3, 2024
d11ad06
fix scope accuracy tests
TheTechromancer Feb 3, 2024
5da0e43
just telerik things
TheTechromancer Feb 4, 2024
834ed0c
increase dnscommonsrv threads
TheTechromancer Feb 4, 2024
9bbd6d4
limit massdns brute force depth
TheTechromancer Feb 4, 2024
cab606d
small wildcard tweak
TheTechromancer Feb 4, 2024
bca67d8
internetdb speed optimization
TheTechromancer Feb 4, 2024
ed36be5
massdns tweaks
TheTechromancer Feb 5, 2024
d89cda2
fix internetdb bug
TheTechromancer Feb 5, 2024
4be75af
fix \s warning
TheTechromancer Feb 5, 2024
1c5a234
increase massdns qsize
TheTechromancer Feb 5, 2024
86c0171
increase qsize for speculate and excavate
TheTechromancer Feb 6, 2024
e02c686
log version command: verbose() --> trace()
TheTechromancer Feb 6, 2024
e9cb4fd
allow independent http/dns debugging (without needing -d)
TheTechromancer Feb 6, 2024
bfef473
fix trace
TheTechromancer Feb 6, 2024
2f788d7
default qsize --> 1000, unlimited qsize for speculate & excavate
TheTechromancer Feb 7, 2024
ae25d8a
fix aioconsole bug
TheTechromancer Feb 9, 2024
c151411
more aioconsole bugfixing
TheTechromancer Feb 9, 2024
381f12a
fixed console logic
TheTechromancer Feb 9, 2024
9498117
remove unneeded cancel logic
TheTechromancer Feb 9, 2024
a1d4f0d
flaked
TheTechromancer Feb 9, 2024
7ec6e9f
debug --> verbose for batch event handling
TheTechromancer Feb 12, 2024
07eea20
keyboard listen logic fix
TheTechromancer Feb 12, 2024
29dce2f
debug massdns mutations
TheTechromancer Feb 12, 2024
ce95ce8
add debug statements for mutations
TheTechromancer Feb 13, 2024
28f24ac
restore wildcard rdtype optimization
TheTechromancer Feb 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 50 additions & 39 deletions bbot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import asyncio
import logging
import traceback
from aioconsole import ainput
from omegaconf import OmegaConf
from contextlib import suppress
from aioconsole import stream

# fix tee buffering
sys.stdout.reconfigure(line_buffering=True)
Expand All @@ -20,6 +20,7 @@
from bbot import __version__
from bbot.modules import module_loader
from bbot.core.configurator.args import parser
from bbot.core.helpers.misc import smart_decode
from bbot.core.helpers.logger import log_to_stderr
from bbot.core.configurator import ensure_config_files, check_cli_args, environ

Expand Down Expand Up @@ -301,46 +302,56 @@ async def _main():

if not options.dry_run:
log.trace(f"Command: {' '.join(sys.argv)}")
if not options.agent_mode and not options.yes and sys.stdin.isatty():
log.hugesuccess(f"Scan ready. Press enter to execute {scanner.name}")
input()

def handle_keyboard_input(keyboard_input):
kill_regex = re.compile(r"kill (?P<module>[a-z0-9_]+)")
if keyboard_input:
log.verbose(f'Got keyboard input: "{keyboard_input}"')
kill_match = kill_regex.match(keyboard_input)
if kill_match:
module = kill_match.group("module")
if module in scanner.modules:
log.hugewarning(f'Killing module: "{module}"')
scanner.manager.kill_module(module, message="killed by user")
else:
log.warning(f'Invalid module: "{module}"')
else:
toggle_log_level(logger=log)
scanner.manager.modules_status(_log=True)

async def akeyboard_listen():
allowed_errors = 10
while 1:
keyboard_input = "a"
if sys.stdin.isatty():
if not options.agent_mode and not options.yes:
log.hugesuccess(f"Scan ready. Press enter to execute {scanner.name}")
input()

def handle_keyboard_input(keyboard_input):
kill_regex = re.compile(r"kill (?P<module>[a-z0-9_]+)")
if keyboard_input:
log.verbose(f'Got keyboard input: "{keyboard_input}"')
kill_match = kill_regex.match(keyboard_input)
if kill_match:
module = kill_match.group("module")
if module in scanner.modules:
log.hugewarning(f'Killing module: "{module}"')
scanner.manager.kill_module(module, message="killed by user")
else:
log.warning(f'Invalid module: "{module}"')
else:
toggle_log_level(logger=log)
scanner.manager.modules_status(_log=True)

# Reader
reader = stream.StandardStreamReader()
protocol = stream.StandardStreamReaderProtocol(reader)
await asyncio.get_event_loop().connect_read_pipe(lambda: protocol, sys.stdin)

async def akeyboard_listen():
try:
keyboard_input = await ainput()
except Exception:
allowed_errors -= 1
handle_keyboard_input(keyboard_input)
if allowed_errors <= 0:
break

try:
keyboard_listen_task = asyncio.create_task(akeyboard_listen())

await scanner.async_start_without_generator()
finally:
keyboard_listen_task.cancel()
with suppress(asyncio.CancelledError):
await keyboard_listen_task
allowed_errors = 10
while 1:
keyboard_input = None
try:
keyboard_input = smart_decode((await reader.readline()).strip())
allowed_errors = 10
except Exception as e:
log_to_stderr(f"Error in keyboard listen loop: {e}", level="TRACE")
log_to_stderr(traceback.format_exc(), level="TRACE")
allowed_errors -= 1
if keyboard_input is not None:
handle_keyboard_input(keyboard_input)
if allowed_errors <= 0:
break
except Exception as e:
log_to_stderr(f"Error in keyboard listen task: {e}", level="ERROR")
log_to_stderr(traceback.format_exc(), level="TRACE")

asyncio.create_task(akeyboard_listen())

await scanner.async_start_without_generator()

except bbot.core.errors.ScanError as e:
log_to_stderr(str(e), level="ERROR")
Expand Down
11 changes: 5 additions & 6 deletions bbot/core/helpers/async_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
import threading
from datetime import datetime
from queue import Queue, Empty
from cachetools import LRUCache
from .misc import human_timedelta
from contextlib import asynccontextmanager

log = logging.getLogger("bbot.core.helpers.async_helpers")

from .cache import CacheDict


class ShuffleQueue(asyncio.Queue):
def _put(self, item):
Expand All @@ -32,20 +31,20 @@ class NamedLock:
"""
Returns a unique asyncio.Lock() based on a provided string

Useful for preventing multiple operations from occuring on the same data in parallel
Useful for preventing multiple operations from occurring on the same data in parallel
E.g. simultaneous DNS lookups on the same hostname
"""

def __init__(self, max_size=1000):
self._cache = CacheDict(max_size=max_size)
self._cache = LRUCache(maxsize=max_size)

@asynccontextmanager
async def lock(self, name):
try:
lock = self._cache.get(name)
lock = self._cache[name]
except KeyError:
lock = _Lock(name)
self._cache.put(name, lock)
self._cache[name] = lock
async with lock:
yield

Expand Down
83 changes: 0 additions & 83 deletions bbot/core/helpers/cache.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import os
import time
import logging
from contextlib import suppress
from collections import OrderedDict

from .misc import sha1

Expand Down Expand Up @@ -53,84 +51,3 @@ def is_cached(self, key, cache_hrs=24 * 7):

def cache_filename(self, key):
return self.cache_dir / sha1(key).hexdigest()


_sentinel = object()


class CacheDict:
"""
Dictionary to store cached values, with a maximum size limit
"""

def __init__(self, max_size=1000):
self._cache = OrderedDict()
self._max_size = int(max_size)

def get(self, name, fallback=_sentinel):
name_hash = self._hash(name)
try:
return self._cache[name_hash]
except KeyError:
if fallback is not _sentinel:
return fallback
raise
finally:
with suppress(KeyError):
self._cache.move_to_end(name_hash)
self._truncate()

def put(self, name, value):
name_hash = self._hash(name)
try:
self._cache[name_hash] = value
finally:
with suppress(KeyError):
self._cache.move_to_end(name_hash)
self._truncate()

def _truncate(self):
if not self or len(self) <= self._max_size:
return
for nh in list(self._cache.keys()):
try:
del self._cache[nh]
except KeyError:
pass
if not self or len(self) <= self._max_size:
break

def keys(self):
return self._cache.keys()

def values(self):
return self._cache.values()

def items(self):
return self._cache.items()

def clear(self):
return self._cache.clear()

def _hash(self, v):
if type(v) == int:
return v
return hash(str(v))

def __contains__(self, item):
return self._hash(item) in self._cache

def __iter__(self):
return iter(self._cache)

def __getitem__(self, item):
return self.get(item)

def __setitem__(self, item, value):
self.put(item, value)

def __bool__(self):
return bool(self._cache)

def __len__(self):
return len(self._cache)
4 changes: 2 additions & 2 deletions bbot/core/helpers/depsinstaller/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ async def pip_install(self, packages, constraints=None):
command = [sys.executable, "-m", "pip", "install", "--upgrade"] + packages

if constraints:
contraints_tempfile = self.parent_helper.tempfile(constraints, pipe=False)
constraints_tempfile = self.parent_helper.tempfile(constraints, pipe=False)
command.append("--constraint")
command.append(contraints_tempfile)
command.append(constraints_tempfile)

process = None
try:
Expand Down
Loading
Loading