mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-30 12:24:14 +01:00
Added prompt command to fix your prompt in the event of a simple shell like dash
This commit is contained in:
parent
d0e0179fda
commit
8dea0b61e8
14
README.md
14
README.md
@ -132,9 +132,15 @@ terminal escape sequences which `pwncat` adds, so you may get a very long termin
|
|||||||
\[\033[01;31m\](remote)\[\033[00m\] \[\033[01;33m\]\u@\h\[\033[00m\]:\[\033[01;36m\]\w\[\033[00m\]$
|
\[\033[01;31m\](remote)\[\033[00m\] \[\033[01;33m\]\u@\h\[\033[00m\]:\[\033[01;36m\]\w\[\033[00m\]$
|
||||||
```
|
```
|
||||||
|
|
||||||
We are currently trying to figure out an acceptible way of handling with. `dash` (and other
|
Currently, the only workaround is to use the `prompt` command at the local `pwncat` prompt.
|
||||||
minimalist shells) are capable of handling terminal escape sequences for color, but inserting
|
The command allows you to modify the prompt which `pwncat` will automatically set whenever
|
||||||
things like user and host name automatically are unsupported.
|
resetting the remote terminal. Two options are provided: "basic" and "fancy". The "fancy"
|
||||||
|
prompt is the default which causes the above output in Dash. To switch to the basic prompt
|
||||||
|
you can use the following command at the `pwncat` prompt:
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
prompt --basic
|
||||||
|
```
|
||||||
|
|
||||||
While this is inconvenient, it does not affect the behaviour of `pwncat`. All `pwncat`
|
While this is inconvenient, it does not affect the behaviour of `pwncat`. All `pwncat`
|
||||||
features will continue to function properly.
|
features will continue to function properly no matter what your prompt looks like.
|
45
pwncat/commands/prompt.py
Normal file
45
pwncat/commands/prompt.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import pwncat
|
||||||
|
from pwncat.commands.base import CommandDefinition, Parameter, Complete, Group
|
||||||
|
|
||||||
|
|
||||||
|
class Command(CommandDefinition):
|
||||||
|
"""
|
||||||
|
Reset the prompt used for shells in pwncat. This allows you to choose
|
||||||
|
between the fancier colored prompt and more basic prompt. You can
|
||||||
|
also specify a custom prompt if you'd like.
|
||||||
|
|
||||||
|
This is mainly useful for basic shells such as /bin/sh or /bin/dash
|
||||||
|
which do not support the nicer prompts by default.
|
||||||
|
"""
|
||||||
|
|
||||||
|
PROG = "prompt"
|
||||||
|
GROUPS = {"mutex": Group(mutex=True, required=True)}
|
||||||
|
ARGS = {
|
||||||
|
"--basic,-b": Parameter(
|
||||||
|
Complete.NONE,
|
||||||
|
group="mutex",
|
||||||
|
action="store_true",
|
||||||
|
help="Set a basic prompt with no color or automatic system information",
|
||||||
|
),
|
||||||
|
"--fancy,-f": Parameter(
|
||||||
|
Complete.NONE,
|
||||||
|
group="mutex",
|
||||||
|
action="store_true",
|
||||||
|
help="Set a fancier prompt including auto-user, hostname, cwd information",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
def run(self, args):
|
||||||
|
|
||||||
|
if args.fancy:
|
||||||
|
pwncat.victim.remote_prefix = "\\[\\033[01;31m\\](remote)\\[\\033[00m\\]"
|
||||||
|
pwncat.victim.remote_prompt = (
|
||||||
|
"\\[\\033[01;33m\\]\\u@\\h\\[\\033[00m\\]:\\["
|
||||||
|
"\\033[01;36m\\]\\w\\[\\033[00m\\]\\$ "
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pwncat.victim.remote_prefix = "(remote)"
|
||||||
|
pwncat.victim.remote_prompt = f"{pwncat.victim.host.ip}:$PWD\\$ "
|
||||||
|
|
||||||
|
pwncat.victim.reset(hard=False)
|
@ -89,9 +89,7 @@ def enumerate() -> Generator[FactData, None, None]:
|
|||||||
|
|
||||||
for i in range(0, len(data), 5):
|
for i in range(0, len(data), 5):
|
||||||
if i >= (len(data) - 4):
|
if i >= (len(data) - 4):
|
||||||
print(data[i:])
|
|
||||||
break
|
break
|
||||||
print(data[i : i + 4])
|
|
||||||
name = data[i + 2].strip().rstrip(".service")
|
name = data[i + 2].strip().rstrip(".service")
|
||||||
pid = int(data[i].strip())
|
pid = int(data[i].strip())
|
||||||
if "[not set]" in data[i + 1]:
|
if "[not set]" in data[i + 1]:
|
||||||
|
@ -707,6 +707,9 @@ class Finder:
|
|||||||
# Attempt to escalate with the local persistence method
|
# Attempt to escalate with the local persistence method
|
||||||
if persist.escalate(target_user):
|
if persist.escalate(target_user):
|
||||||
|
|
||||||
|
# Stabilize the terminal
|
||||||
|
pwncat.victim.reset(hard=False)
|
||||||
|
|
||||||
# The method thought it worked, but didn't appear to
|
# The method thought it worked, but didn't appear to
|
||||||
if pwncat.victim.update_user() != target_user:
|
if pwncat.victim.update_user() != target_user:
|
||||||
if pwncat.victim.getenv("SHLVL") != shlvl:
|
if pwncat.victim.getenv("SHLVL") != shlvl:
|
||||||
@ -738,6 +741,7 @@ class Finder:
|
|||||||
tech, exit_command = self.escalate_single(
|
tech, exit_command = self.escalate_single(
|
||||||
techniques[target_user], shlvl
|
techniques[target_user], shlvl
|
||||||
)
|
)
|
||||||
|
pwncat.victim.reset(hard=False)
|
||||||
pwncat.victim.update_user()
|
pwncat.victim.update_user()
|
||||||
chain.append((tech, exit_command))
|
chain.append((tech, exit_command))
|
||||||
return chain
|
return chain
|
||||||
@ -753,6 +757,11 @@ class Finder:
|
|||||||
f"checking local persistence implants: {persist.format(user)}"
|
f"checking local persistence implants: {persist.format(user)}"
|
||||||
)
|
)
|
||||||
if persist.escalate(user):
|
if persist.escalate(user):
|
||||||
|
|
||||||
|
# Ensure history and prompt are correct
|
||||||
|
pwncat.victim.reset(hard=False)
|
||||||
|
|
||||||
|
# Update the current user
|
||||||
if pwncat.victim.update_user() != user:
|
if pwncat.victim.update_user() != user:
|
||||||
if pwncat.victim.getenv("SHLVL") != shlvl:
|
if pwncat.victim.getenv("SHLVL") != shlvl:
|
||||||
pwncat.victim.run("exit", wait=False)
|
pwncat.victim.run("exit", wait=False)
|
||||||
@ -780,6 +789,8 @@ class Finder:
|
|||||||
try:
|
try:
|
||||||
tech, exit_command = self.escalate_single(techs, shlvl)
|
tech, exit_command = self.escalate_single(techs, shlvl)
|
||||||
chain.append((tech, exit_command))
|
chain.append((tech, exit_command))
|
||||||
|
pwncat.victim.reset(hard=False)
|
||||||
|
pwncat.victim.update_user()
|
||||||
except PrivescError:
|
except PrivescError:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
@ -22,7 +22,7 @@ class Method(BaseMethod):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
for fact in pwncat.victim.enumerate.iter("system.service"):
|
for fact in pwncat.victim.enumerate.iter("system.service"):
|
||||||
if "ssh" in fact.data.name and fact.data.running:
|
if "ssh" in fact.data.name and fact.data.state == "running":
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise PrivescError("no sshd service running")
|
raise PrivescError("no sshd service running")
|
||||||
|
@ -1459,13 +1459,17 @@ class Victim:
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def reset(self):
|
def reset(self, hard: bool = True):
|
||||||
"""
|
"""
|
||||||
Reset the remote terminal using the ``reset`` command. This also restores
|
Reset the remote terminal using the ``reset`` command. This also restores
|
||||||
your prompt, and sets up the environment correctly for ``pwncat``.
|
your prompt, and sets up the environment correctly for ``pwncat``.
|
||||||
|
|
||||||
|
:param hard: whether to actually call the `reset` command.
|
||||||
|
This prevents a long pause when we simply need to reset other
|
||||||
|
things such as the prompt, aliases or history control.
|
||||||
"""
|
"""
|
||||||
self.run("reset", wait=False)
|
if hard:
|
||||||
|
self.run("reset", wait=False)
|
||||||
self.has_cr = True
|
self.has_cr = True
|
||||||
self.has_echo = True
|
self.has_echo = True
|
||||||
self.run("unset HISTFILE; export HISTCONTROL=ignorespace")
|
self.run("unset HISTFILE; export HISTCONTROL=ignorespace")
|
||||||
|
Loading…
Reference in New Issue
Block a user