1
0
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:
Caleb Stewart 2021-08-31 16:54:06 -04:00 committed by GitHub
commit 7273e6ad43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 102 additions and 20 deletions

View File

@ -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'

View File

@ -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(

View File

@ -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):

View File

@ -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]

View File

@ -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 = {}

View File

@ -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 = {

View File

@ -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 = {

View File

@ -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 = {

View File

@ -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:

View File

@ -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 = {

View File

@ -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

View File

@ -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 = {

View File

@ -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:

View File

@ -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 = {

View File

@ -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 = {

View File

@ -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."
)

View File

@ -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]):
"""

View File

@ -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,