mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-27 19:04:15 +01:00
Merge pull request #164 from Mitul16/master
[FIXED 163] Multiple verbose outputs issue and minor fixes
This commit is contained in:
commit
7273e6ad43
@ -14,9 +14,13 @@ and simply didn't have the time to go back and retroactively create one.
|
||||
- Covered edge case in sudo rule parsing for wildcards ([#183](https://github.com/calebstewart/pwncat/issue/183))
|
||||
- Added fallthrough cases for PTY methods in case of misbehaving binaries (looking at you: `screen`)
|
||||
- Fixed handling of `socket.getpeername` when `Socket` channel uses IPv6 ([#159](https://github.com/calebstewart/pwncat/issues/159)).
|
||||
- Fixed verbose logging handler to be __unique__ for every `channel`
|
||||
- Fixed docstrings in `Command` modules
|
||||
### Added
|
||||
- Added alternatives to `bash` to be used during _shell upgrade_ for a _better shell_
|
||||
- Added a warning message when a `KeyboardInterrupt` is caught
|
||||
- Added `--verbose/-V` for argument parser
|
||||
- Added `OSError` for `bind` protocol to show appropriate error messages
|
||||
### Changed
|
||||
- Changed some 'red' warning message color to 'yellow'
|
||||
|
||||
|
@ -80,6 +80,12 @@ def main():
|
||||
metavar="port",
|
||||
help="Alternative port number to support netcat-style syntax",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
"-V",
|
||||
action="store_true",
|
||||
help="Enable verbose output for the remote commands executed by `pwncat`",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Print the version number and exit.
|
||||
@ -90,6 +96,10 @@ def main():
|
||||
# Create the session manager
|
||||
with pwncat.manager.Manager(args.config) as manager:
|
||||
|
||||
if args.verbose:
|
||||
# set the config variable `verbose` to `True` (globally)
|
||||
manager.config.set("verbose", True, True)
|
||||
|
||||
if args.download_plugins:
|
||||
for plugin_info in pwncat.platform.Windows.PLUGIN_INFO:
|
||||
with pwncat.platform.Windows.open_plugin(
|
||||
|
@ -7,6 +7,7 @@ would have been a reverse shell payload.
|
||||
The only required argument for a bind channel is the port number. By default,
|
||||
the channel will listen on all interfaces (bound to ``0.0.0.0``).
|
||||
"""
|
||||
import errno
|
||||
import socket
|
||||
|
||||
from rich.progress import Progress, BarColumn
|
||||
@ -34,7 +35,25 @@ class Bind(Socket):
|
||||
super().__init__(client=None, host=host, port=port, **kwargs)
|
||||
|
||||
self.address = (host, port)
|
||||
self.server = socket.create_server((host, port), reuse_port=True)
|
||||
|
||||
try:
|
||||
self.server = socket.create_server((host, port), reuse_port=True)
|
||||
except OSError as exc:
|
||||
error_message = str(exc)
|
||||
|
||||
if exc.args[0] == errno.EACCES:
|
||||
# See `/proc/sys/net/ipv4/ip_unprivileged_port_start`
|
||||
error_message = (
|
||||
"unable to listen on a privileged port"
|
||||
+ "\nusually ports in the range 0-1023 are restricted"
|
||||
+ "\n[green][TRY][/green]: try to run `pwncat` as `[red]root[/red]`"
|
||||
)
|
||||
elif exc.args[0] == errno.EADDRINUSE:
|
||||
error_message = "port is already in use"
|
||||
elif exc.args[0] == errno.EADDRNOTAVAIL:
|
||||
error_message = "unable to bind on given address"
|
||||
|
||||
raise ChannelError(self, error_message)
|
||||
|
||||
def connect(self):
|
||||
|
||||
|
@ -5,9 +5,11 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Alias an existing command with a new name. Specifying no alias or command
|
||||
"""
|
||||
Alias an existing command with a new name. Specifying no alias or command
|
||||
will list all aliases. Specifying an alias with no command will remove the
|
||||
alias if it exists."""
|
||||
alias if it exists.
|
||||
"""
|
||||
|
||||
def get_command_names(self):
|
||||
return [c.PROG for c in self.manager.parser.commands]
|
||||
|
@ -4,7 +4,9 @@ from pwncat.commands import CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Return to the remote terminal"""
|
||||
"""
|
||||
Return to the remote terminal
|
||||
"""
|
||||
|
||||
PROG = "back"
|
||||
ARGS = {}
|
||||
|
@ -7,8 +7,10 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Create key aliases for when in raw mode. This only works from platforms
|
||||
which provide a raw interaction (such as linux)."""
|
||||
"""
|
||||
Create key aliases for when in raw mode. This only works from platforms
|
||||
which provide a raw interaction (such as linux).
|
||||
"""
|
||||
|
||||
PROG = "bind"
|
||||
ARGS = {
|
||||
|
@ -18,7 +18,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Download a file from the remote host to the local host"""
|
||||
"""
|
||||
Download a file from the remote host to the local host
|
||||
"""
|
||||
|
||||
PROG = "download"
|
||||
ARGS = {
|
||||
|
@ -66,7 +66,8 @@ class Command(CommandDefinition):
|
||||
|
||||
The list command is simply a wrapper around enumerating "escalation.*".
|
||||
This makes the escalation workflow more straightforward, but is not
|
||||
required."""
|
||||
required.
|
||||
"""
|
||||
|
||||
PROG = "escalate"
|
||||
ARGS = {
|
||||
|
@ -10,7 +10,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""List known commands and print their associated help documentation."""
|
||||
"""
|
||||
List known commands and print their associated help documentation.
|
||||
"""
|
||||
|
||||
def get_command_names(self):
|
||||
try:
|
||||
|
@ -10,7 +10,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition, get_module_c
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""View info about a module"""
|
||||
"""
|
||||
View info about a module
|
||||
"""
|
||||
|
||||
PROG = "info"
|
||||
ARGS = {
|
||||
|
@ -6,7 +6,9 @@ from pwncat.commands import CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Run a local shell command on your attacking machine"""
|
||||
"""
|
||||
Run a local shell command on your attacking machine
|
||||
"""
|
||||
|
||||
PROG = "local"
|
||||
ARGS = None
|
||||
|
@ -10,7 +10,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""View info about a module"""
|
||||
"""
|
||||
View info about a module
|
||||
"""
|
||||
|
||||
PROG = "search"
|
||||
ARGS = {
|
||||
|
@ -5,7 +5,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Set variable runtime variable parameters for pwncat"""
|
||||
"""
|
||||
Set variable runtime variable parameters for pwncat
|
||||
"""
|
||||
|
||||
def get_config_variables(self):
|
||||
options = ["state"] + list(self.manager.config.values)
|
||||
@ -84,6 +86,12 @@ class Command(CommandDefinition):
|
||||
if args.variable == "db":
|
||||
# Ensure the database is re-opened, if it was already
|
||||
manager.open_database()
|
||||
if manager.sessions and args.variable == "verbose":
|
||||
# If the user changed the verbose option
|
||||
# then apply it to every `session` to take effect
|
||||
for session_id in manager.sessions:
|
||||
session = manager.sessions[session_id]
|
||||
session.platform.set_verbose(args.value == "True")
|
||||
except ValueError as exc:
|
||||
console.log(f"[red]error[/red]: {exc}")
|
||||
elif args.variable is not None:
|
||||
|
@ -17,7 +17,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Upload a file from the local host to the remote host"""
|
||||
"""
|
||||
Upload a file from the local host to the remote host
|
||||
"""
|
||||
|
||||
PROG = "upload"
|
||||
ARGS = {
|
||||
|
@ -6,7 +6,9 @@ from pwncat.commands import Complete, Parameter, CommandDefinition, get_module_c
|
||||
|
||||
|
||||
class Command(CommandDefinition):
|
||||
"""Set the currently used module in the config handler"""
|
||||
"""
|
||||
Set the currently used module in the config handler
|
||||
"""
|
||||
|
||||
PROG = "use"
|
||||
ARGS = {
|
||||
|
@ -17,6 +17,7 @@ import pwncat
|
||||
from pwncat.db import Fact
|
||||
from pwncat.channel import ChannelError
|
||||
from pwncat.modules import ModuleFailed
|
||||
from pwncat.platform import PlatformError
|
||||
from pwncat.facts.tamper import ( # noqa: F401
|
||||
Tamper,
|
||||
CreatedFile,
|
||||
@ -369,7 +370,7 @@ class PrivateKey(Implant):
|
||||
user=user.name,
|
||||
identity=filp.name,
|
||||
)
|
||||
except ChannelError as exc:
|
||||
except (ChannelError, PlatformError) as exc:
|
||||
manager.log(
|
||||
f"[yellow]warning[/yellow]: {self.source} implant failed; removing implant types."
|
||||
)
|
||||
|
@ -494,8 +494,9 @@ class Platform(ABC):
|
||||
|
||||
self.session = session
|
||||
self.channel = channel
|
||||
self.logger = logging.getLogger(str(channel))
|
||||
self.logger = logging.getLogger(str(id(channel)))
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
self._verbose_logging_handler = None
|
||||
self.name = "unknown"
|
||||
self._current_user = None
|
||||
|
||||
@ -507,8 +508,8 @@ class Platform(ABC):
|
||||
handler.setFormatter(logging.Formatter("%(asctime)s - %(message)s"))
|
||||
self.logger.addHandler(handler)
|
||||
|
||||
if verbose:
|
||||
self.logger.addHandler(RichHandler())
|
||||
# set the logging verbosity
|
||||
self.set_verbose(verbose)
|
||||
|
||||
base_path = self.PATH_TYPE
|
||||
target = self
|
||||
@ -943,6 +944,24 @@ class Platform(ABC):
|
||||
def unlink(self, target: str):
|
||||
"""Remove a link to a file (similar to `rm`)"""
|
||||
|
||||
def set_verbose(self, verbose: bool):
|
||||
"""Enable or disable verbose output
|
||||
If enabled, commands that are executed by `pwncat`
|
||||
are logged in the output for the user
|
||||
otherwise `pwncat` do not show them"""
|
||||
|
||||
# if `verbose` is `True` and there is no handler for it
|
||||
# then we create one and add it to `self.logger`
|
||||
# otherwise if there is a handler for it
|
||||
# then we remove it and set it to `None`
|
||||
|
||||
if verbose and self._verbose_logging_handler is None:
|
||||
self._verbose_logging_handler = RichHandler()
|
||||
self.logger.addHandler(self._verbose_logging_handler)
|
||||
elif not verbose and self._verbose_logging_handler is not None:
|
||||
self.logger.removeHandler(self._verbose_logging_handler)
|
||||
self._verbose_logging_handler = None
|
||||
|
||||
|
||||
def register(platform: Type[Platform]):
|
||||
"""
|
||||
|
@ -836,7 +836,7 @@ class Linux(Platform):
|
||||
while True:
|
||||
try:
|
||||
proc = self.run(
|
||||
"(id -ru;id -u;id -g;id -rg;id -G;)",
|
||||
"(id -ru;id -u;id -rg;id -g;id -G;)",
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
|
Loading…
Reference in New Issue
Block a user