Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
brightio committed Dec 18, 2022
1 parent a566a50 commit ad273a3
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 39 deletions.
73 changes: 40 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# penelope

Penelope is an advanced shell handler. Its main aim is to replace netcat as shell catcher during exploiting RCE vulnerabilities.
It works on Linux and macOS and the only requirement is Python >= 3.6. It is a single script, it needs no installation or any 3rd party dependency and hopefully it will stay that way.
Penelope is a shell handler designed to be easy to use and intended to replace netcat when exploiting RCE vulnerabilities. It is compatible with Linux and macOS and requires Python 3.6 or higher. It is a standalone script that does not require any installation or external dependencies, and it is intended to remain this way.

Among the main features are:
- Auto-upgrade shells to PTY (auto-resize included)
- Auto-upgrade shells to PTY (realtime resize included)
- Logging interaction with the targets
- Download files from targets
- Upload files to targets
- Upload preset scripts to targets
- Download files/folders from targets
- Upload local/remote files/folders to targets
- Run scripts on targets and get output on a local file in real time.
- Spawn shells on multiple tabs and/or hosts
- Maintain X amount of active shells per host no matter what
- Multiple sessions
Expand All @@ -17,36 +15,41 @@ Among the main features are:

Penelope can work in conjunction with metasploit exploits by disabling the default handler with `set DisablePayloadHandler True`

It supports Windows shells but autoupgrade is not implemented yet. However it can accept PTY shells from the excellent project [ConPtyShell](https://github.com/antonioCoco/ConPtyShell) of [@antonioCoco](https://github.com/antonioCoco). Autoresize of PTY is implemented.
Currently only Unix shells are fully supported. There is only basic support for Windows shells (netcat-like interaction + logging) and the rest of the features are under way.

## Usage
### Sample Typical Usage
```
./penelope.py # Listening for reverse shells on 0.0.0.0:4444
./penelope.py -a # Listening for reverse shells on 0.0.0.0:4444 and show reverse shell payloads based on the current Listeners
./penelope.py 5555 # Listening for reverse shells on 0.0.0.0:5555
./penelope.py 5555 -i eth0 # Listening for reverse shells on eth0:5555
./penelope.py 1111 2222 3333 # Listening for reverse shells on 0.0.0.0:1111, 0.0.0.0:2222, 0.0.0.0:3333
./penelope.py -c target 3333 # Connect to a bind shell on target:3333
```

### Demonstrating Random Usage

As shown in the below video, within only a few seconds we have easily:
1. A fully functional auto-resizable PTY shell
2. One more such shell in another tab
3. Logging every interaction with the target
4. Uploaded the latest versions of LinPEAS and linux-smart-enumeration
5. Downloaded the whole /etc directory
6. For every shell that may be killed for some reason, automatically a new one is spawned. This gives us a kind of persistence with the target

https://user-images.githubusercontent.com/65655412/151394465-9eb4937d-bfad-45df-b058-3b74164be517.mp4

### Penelope Main Menu Commands
2. Execute the lastest version of Linpeas on the target without touching the disk and get the output on a local file in realtime
3. One more such shell in another tab
4. Logging every interaction with the target
5. Uploaded the latest versions of LinPEAS and linux-smart-enumeration
6. Uploaded a local folder with custom scripts
7. Uploaded an exploit-db exploit directly from URL
8. Downloaded the whole /etc directory
9. For every shell that may be killed for some reason, automatically a new one is spawned. This gives us a kind of persistence with the target

https://user-images.githubusercontent.com/65655412/208298446-fe2f11f6-d8bc-4e85-9f19-94e66593102b.mp4

### Main Menu Commands
Some Notes:
- By default you need to press `F12` to detach the PTY shell and go to the Main Menu. If the upgrade was not possible the you ended up with a basic shell, you can detach it with `Ctrl+C`. This also prevents the accidental killing of the shell.
- The Main Menu supports TAB completion and also short commands. For example instead of `interact 1` you can just type `i 1`.
- The batch command by default uploads predefined privilege escalation scripts. You can add more scripts or modify this and other default behaviours by using a configuration file (See extras/penelope.conf). This file can be speficied with -r in the command line or be placed in ~/.penelope/penelope.conf
- You can add more scripts and modify default behaviours by using a configuration file (See extras/penelope.conf). This file can be speficied with -r in the command line or can be placed in ~/.penelope/penelope.conf

![help](https://user-images.githubusercontent.com/65655412/150849045-110d4bf6-a86d-4b77-a290-075abeee62d4.png)
![Main Menu](https://user-images.githubusercontent.com/65655412/196921489-5d446ff2-1fe9-4789-b6af-11a8ddf81fe7.png)

### Command Line Options
```
Expand All @@ -66,9 +69,9 @@ Verbosity:
-Q, --silent Be a bit less verbose
-d, --debug Show debug messages
Logging:
Session Logging:
-L, --no-log Do not create session log files
-T, --no-timestamps Do not include timestamps on logs
-T, --no-timestamps Do not include timestamps in session logs
Misc:
-r , --configfile Configuration file location
Expand All @@ -80,51 +83,55 @@ Misc:
-U, --no-upgrade Do not upgrade shells
Debug:
-NP, --no-python Simulate python absence on target
-NB, --no-bash Simulate bash absence on target
-N , --no-bins Simulate binary absence on target (comma separated list)
-v, --version Show Penelope version
```

## Extras
There are also included two sample exploit simulation scripts in the extras folder to demonstrate how penelope can be imported and get shell on the same terminal. The illustration below shows how Penelope is imported in a python3 exploit for the Quick machine of Hack The Box.

![exploit](https://user-images.githubusercontent.com/65655412/151350244-3d0b4e60-04a6-494b-8eab-2498cfb8b809.gif)

Furthermore, one bash script is included which automatically upgrades Unix shells to PTY using the xdotool.
Furthermore, a bash script is included which automatically upgrades Unix shells to PTY using the xdotool.

![tty](https://user-images.githubusercontent.com/65655412/151353020-8585e352-2037-41f1-94d6-4fd7d1cb7943.gif)


## Contribution
If you want to contribute to this project please report bugs, unexpected program behaviours and/or new ideas.

## TODO

### Features
* ability to execute a local script on target and get the output on a local file
* remote and local port forwarding
* persistence
* socks & http proxy
* persistence modules
* edit command: open the remote file locally, make changes and upon saving, upload it to the target
* currently download/upload/spawn/upgrade commands are supported only on Unix shells. Will implement those commands for Windows shells too.
* spawn meterpreter sessions
* an option switch for disable all logging, not only sessions.
* main menu autocompletion for short commands
* download/upload progress bar
* download/upload autocompletion
* IPv6
* IPv6 support
* encryption
* UDP support

### Known Issues
* Ctrl-C on main menu has not the expected behavior yet. However can still stop commands like 'download'.
* Main menu: Ctrl-C on main menu has not the expected behavior yet.
* Session logging: when executing commands on the target that feature alternate buffers like nano and they are abnormally terminated, then when 'catting' the logfile it seems corrupted. However the data are still there. Also for example when resetting the remote terminal, these escape sequences are reflected in the logs. I will need to filter specific escape sequences so as to ensure that when 'catting' the logfile, a smooth log is presented.

### Limitations
* For the emojis to be shown correctly, the fonts-noto-color-emoji package should be installed. It is installed by default on many distros but not on parrot OS. May consider removing emojis altogether.
* When downloading files via the download menu command, clickable links with the downloaded files are presented. However the links are not clickable on the qterminal (Kali Linux).
* penelope menu commands and PTY autoresize operate on the same socket. This could be an advantage but it has a side effect that for example if nano is open on target, then detaching the session and attempt a download, penelope copes with that by sending Ctrl-Z -> Ctrl-E -> Ctrl-U. Then must run fg to get the process back. Maybe consider to spawn extra socket for controling the session in the future. However, if before executing a menu command, the target's terminal if left on a clear state, then there is no problem.

## Trivia
Penelope was the wife of Odysseus and she is known for her fidelity for him by waiting years. Since a characteristic of reverse shell handlers is waiting, this tool is named after her.

## Thanks to
* [Cristian Grigoriu - @crgr](https://github.com/crgr) for inspiring me to automate the PTY upgrade process. This is how this project was born.
* [Paul Taylor - @bao7uo](https://github.com/bao7uo) for advising me that penelope should not be shipped without the ability to connect to a bind shell.
* [Longlone - @WAY29](https://github.com/WAY29) for indicating the need for compatibility with previous versions of Python (3.6)
* [Carlos Polop - @carlospolop](https://github.com/carlospolop) for the idea to spawn shells on listeners on fellow systems
* [Paul Taylor - @bao7uo](https://github.com/bao7uo) for the idea to support bind shells.
* [Longlone - @WAY29](https://github.com/WAY29) for indicating the need for compatibility with previous versions of Python (3.6).
* [Carlos Polop - @carlospolop](https://github.com/carlospolop) for the idea to spawn shells on listeners on other systems.
* [@darrenmartyn](https://github.com/darrenmartyn) for indicating an alternative method to upgrade the shell to PTY using the script command.
* [@robertstrom](https://github.com/robertstrom) and [@RamadhanAmizudin](https://github.com/RamadhanAmizudin) for bug reporting.
12 changes: 6 additions & 6 deletions penelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ def default(self, line):
elif line == '.':
return self.onecmd('dir')
elif line in ('recon', 'batch'):
logger.warning("This command is deprecated. Check 'run' command")
logger.warning("This command is deprecated. Check the 'run' command")
else:
parts = line.split()
candidates = [command for command in self.raw_commands if command.startswith(parts[0])]
Expand Down Expand Up @@ -1430,7 +1430,7 @@ def bin(self):
if response:
self._bin.update(dict(zip(missing, response.decode().splitlines())))

for binary in options.black_list_bins:
for binary in options.no_bins:
self._bin[binary] = None

result = "\n".join([f"{b}: {self._bin[b]}" for b in binaries])
Expand Down Expand Up @@ -3255,7 +3255,7 @@ def __setattr__(self, option, value):
show(f"Single Session mode disabled because Maintain is enabled")
value = False

elif option == 'black_list_bins':
elif option == 'no_bins':
if value is None:
value = []
elif type(value) is str:
Expand Down Expand Up @@ -3317,8 +3317,8 @@ def __setattr__(self, option, value):
misc.add_argument("-U", "--no-upgrade", help="Do not upgrade shells", action="store_true")

debug = parser.add_argument_group("Debug")
debug.add_argument("-N", "--black-list-bins", help="Simulate python absence on target")
debug.add_argument("-v", "--version", help="Show Penelope version", action="store_true")
debug.add_argument("-N", "--no-bins", help="Simulate binary absence on target (comma separated list)", metavar='')
debug.add_argument("-v", "--version", help="Show Penelope version", action="store_true")

args = [] if not __name__ == "__main__" else None
parser.parse_args(args, options)
Expand Down Expand Up @@ -3349,7 +3349,7 @@ def __setattr__(self, option, value):
stdout_handler.addFilter(lambda record: True if record.levelno != logging.DEBUG else False)
logger.setLevel('DEBUG')
options.max_maintain = 50
options.black_list_bins = 'python,python3,script'
options.no_bins = 'python,python3,script'

# MAIN
if __name__ == "__main__":
Expand Down

0 comments on commit ad273a3

Please sign in to comment.