Gallopsled / Gallopsled/pwntools

SSH keyboard-interactive handler support for ssh() in pwntools

Open
#2,014 0 comments 0 reactions 0 assignees View on GitHub
feature
Dominant language
Python
Stars
13.7k
Forks
1.9k
Avg merge
6d 23h
Merged PRs (30d)
3

Description

Currently I am using Paramiko to keyboard-interactive authenticate against an SSH module. The host I am connecting to does not require a password or private key, but purely a 2-factor authentication module. This works fine, but the old interactive shell from Paramiko is not very good.

I looked into solving the same by using pwntools, but it does not seem like pwntools currently support keyboard-interactive handlers for SSH authentication?

`paramiko.Transport` is purely used for this, and it works fine but provides a poor shell and is why I would prefer using pwntools instead:
```python
import paramiko
import interactive # https://raw.githubusercontent.com/paramiko/paramiko/main/demos/interactive.py

HOST = "127.0.0.1"
PORT = 22
USER = "user"

def handler(title, instructions, prompt_list):
print(title, instructions, prompt_list)
return []

transport = paramiko.Transport((HOST, PORT))
transport.connect(username=USER)
transport.auth_interactive(USER, handler)

try:
channel = transport.open_session() # https://github.com/Gallopsled/pwntools/blob/da8bf2667d735a82ab539898e0cc1b36d40bc3d5/pwnlib/tubes/ssh.py#L109
channel.get_pty()
channel.invoke_shell()
interactive.interactive_shell(channel) # poor quality paramiko shell
finally:
channel.close()
transport.close()
```

I could not find this functionality in the pwntools docs and thought it would be a nice addition to the framework.

This can be solved by setting up the transport **without** a `SSHclient.connect()` [ssh.py#L658](https://github.com/Gallopsled/pwntools/blob/da8bf2667d735a82ab539898e0cc1b36d40bc3d5/pwnlib/tubes/ssh.py#L658), and by letting the Transport connect instead, like in the example above.

I have looked into using the paramiko session with pwntools remote and interactive but have not yet succeeded.

---

**Edit:**

Fixed a bit more and the following `posix_shell` works very well with Paramiko Channels instead of `interactive.interactive_shell(channel)`:
```python
def posix_shell(channel):
oldtty = termios.tcgetattr(sys.stdin)

try:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
channel.settimeout(0.05)

while True:
r, w, e = select.select([channel, sys.stdin], [], [])
if channel in r:
try:
data = channel.recv(1024).decode("utf-8")
if len(data) == 0:
#sys.stdout.write("\r\n*** EOF\r\n")
break
sys.stdout.write(data)
sys.stdout.flush()
except socket.timeout:
pass

if sys.stdin in r:
data = sys.stdin.buffer.raw.read(1) # read in binary mode. thanks https://stackoverflow.com/a/51509414/7152474
if len(data) == 0:
break
channel.send(data)
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) # reset terminal to old terminal settings
```

It would however still be nice to see the equivalent implemented in pwntools.

Contributor guide

Open the contributing guide

Research direction

Start in pwnlib/tubes/ssh.py, especially the SSHclient.connect() path around the referenced line, and compare it with Paramiko Transport.auth_interactive and the transport setup shown in the issue. Done means pwntools' ssh() supports keyboard-interactive authentication and provides the equivalent interactive shell behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
networking
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.