{"id":13841490,"url":"https://github.com/stealth/psc","last_synced_at":"2025-04-05T19:13:13.323Z","repository":{"id":9291548,"uuid":"11126762","full_name":"stealth/psc","owner":"stealth","description":"E2E encryption for multi-hop tty sessions or portshells + TCP/UDP port forward","archived":false,"fork":false,"pushed_at":"2024-11-07T10:00:12.000Z","size":146,"stargazers_count":120,"open_issues_count":1,"forks_count":22,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T18:08:13.449Z","etag":null,"topics":["anti-censorship","censorship-resistance","console","dialup","e2e","encryption","modem","pentesting","portshell","proxy","pty","screen","socks-proxy","ssh","tcp","tmux","uart","udp"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stealth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-07-02T14:35:38.000Z","updated_at":"2025-01-09T11:30:19.000Z","dependencies_parsed_at":"2023-01-11T17:35:02.455Z","dependency_job_id":"2818f4db-788b-4717-96cd-661197ae512a","html_url":"https://github.com/stealth/psc","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2Fpsc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2Fpsc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2Fpsc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2Fpsc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stealth","download_url":"https://codeload.github.com/stealth/psc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247386265,"owners_count":20930619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anti-censorship","censorship-resistance","console","dialup","e2e","encryption","modem","pentesting","portshell","proxy","pty","screen","socks-proxy","ssh","tcp","tmux","uart","udp"],"created_at":"2024-08-04T17:01:12.164Z","updated_at":"2025-04-05T19:13:13.296Z","avatar_url":"https://github.com/stealth.png","language":"C++","readme":"PortShellCrypter -- PSC\n=======================\n\nThis project - as well as its sister project [crash](https://github.com/stealth/crash) - belongs\nto my anti-censorship tool-set that allows to setup fully working encrypted shells and TCP/UDP\nforwarding in hostile censoring environments. It is also useful for forensics to dump data from\ndevices via UART or adb when no other means are available.\n\n[![asciicast](https://asciinema.org/a/383043.svg)](https://asciinema.org/a/383043)\n*DNS lookup and SSH session forwarded across an UART connection to a Pi*\n\nPSC allows to e2e encrypt shell sessions, single- or multip-hop, being\nagnostic of the underlying transport, as long as it is reliable and can send/receive\nBase64 encoded data without modding/filtering. Along with the e2e pty that\nyou receive (for example inside a port-shell), you can forward TCP and UDP\nconnections, similar to OpenSSH's `-L` parameter. This works transparently\nand without the need of an IP address assigned locally at the starting\npoint. This allows forensicans and pen-testers to create network connections\nfor example via:\n\n* UART sessions to a device\n* `adb shell` sessions, if the OEM `adbd` doesn't support TCP forwarding\n* telnet sessions\n* modem dial-ups without ppp\n* other kinds of console logins\n* mixed SSH/telnet/modem sessions\n* ...\n\nJust imagine you would have an invisible ppp session inside your shell session,\nwithout the remote peer actually supporting ppp.\n\nIt runs on *Linux, Android, OSX, Windows, FreeBSD, NetBSD* and (possibly) *OpenBSD*.\n\nPSC also includes *SOCKS4* and *SOCKS5* proxy support in order to have actual\nweb browsing sessions via port-shells or modem dial-ups remotely.\n\nBuild\n-----\n\nEdit the `Makefile` to reflect your pre shared keys, as defined at the top of the `Makefile`.\n\nThen just type `make` on *Linux* and *OSX*.\n\nOn *BSD* you need to install *GNU make* and invoke `gmake` instead.\n\nOn *Windows* you need to install [cygwin](https://cygwin.com/install.html) and select\nthe appropriate `gcc, gcc-g++, make` and `git` packages.\n\nOn *Linux*, PSC will use *Unix98* pseudo terminals, on other systems it will use *POSIX*\npty's but that should be transparent to you. I once added *4.4BSD* pty and *SunOS*\nsupport back in the stone age for a particular reason, so it may or may not\nbuild even with *Solaris*.\n\n*proudly sponsored by:*\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/c-skills/welcome\"\u003e\n\u003cimg src=\"https://github.com/c-skills/welcome/blob/master/logo.jpg\"/\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n\nUsage\n-----\n\nPlain and simple. On your local box, execute `pscl`, and pass any\nTCP or UDP ports you want to forward *from* the remote site to a particular\naddress. For example:\n\n```\nlinux:~ \u003e ./pscl -T 1234:[192.168.0.254]:22 -U 1234:[8.8.8.8]:53\n\nPortShellCrypter [pscl] v0.60 (C) 2006-2020 stealth -- github.com/stealth/psc\n\npscl: set up local TCP port 1234 to proxy to 192.168.0.254:22 @ remote.\npscl: set up local UDP port 1234 to proxy to 8.8.8.8:53 @ remote.\n\npscl: Waiting for [pscr] session to appear ...\nlinux:~ \u003e\n\n[ UART / SSH / ... login to remote side ... ]\n```\n\nOn the remote site (the last hop) with the shell session, no matter if its in\na port-shell, SSH, console login etc, you execute `pscr`:\n\n\n```\nlinux:~ \u003e ./pscr\n\nPortShellCrypter [pscr] v0.60 (C) 2006-2020 stealth -- github.com/stealth/psc\n\n\npscl: Seen STARTTLS sequence, enabling crypto.\nlinux:~ \u003e\n```\n\nOnce you execute `pscr`, both ends establish a crypto handshake and lay an additional\nprotocol over your existing session that is transparent for you. You can then\nconnect to `127.0.0.1:1234` on your local box to reach `192.168.0.254:22` via\nTCP or the `8.8.8.8` resolver via UDP. This also works with [IPv6] addresses,\nif the remote site has IPv6 connectivity. Actually, you can even use it to translate\nIPv4 software to IPv6, since you always connect to `127.0.0.1` on the local side.\n\nYou can pass multiple `-T` and `-U` parameters. If you lost track if your session\nis already e2e encrypted, you can send a `SIGUSR1` to the local `pscl` process, and it\nwill tell you.\n\nPSC is also useful if you want to use tor from a remote SSH shell, where you\ncan forward the socks5 and the DNS port to the remote hosts `127.0.0.1` address.\nSince SSH does not forward UDP packets, you would normally use two `socat` connectors\nor similar to resolve via the tor node. PSC has the advantage of keeping the UDP\ndatagram boundaries, while `socat` over `SSH -L` may break datagram boundaries\nand create malformed DNS requests.\n\nThe session will be encrypted with `aes_256_ctr` of a PSK that you choose in the\n`Makefile`. This crypto scheme is malleable, but adding AAD or OAD data blows up\nthe packet size, where every byte counts since on interactive sessions and due to\nBase64 encoding, each typed character already causes much more data to be sent.\n\nUART sessions may be used via `screen` but for example not via `minicom` since\nminicom will create invisible windows with status lines and acts like a filter\nthat destroys PSC's protocol. PSC tries to detect filtering and can live with\ncertain amount of data mangling, but in some situations it is not possible to recover.\nSimilar thing with `tmux`. You should avoid stacking pty handlers with PSC that\nmess/handle their incoming data too much.\n\nThe `SHELL` environment variable needs to be set for both `pscl` and `pscr` in order\nfor PSC to know which shell to execute on the pty. `SHELL` is set in most environments\nby default, but in case it isn't, PSC needs to be executed like `SHELL=/bin/bash pscl`\netc.\n\n\nSOCKS4 and SOCKS5 support\n-------------------------\n\n`pscl` also supports forwarding of TCP connections via *SOCKS4* (`-4 port`) and *SOCKS5*\n(`-5 port`). This sets up *port* as SOCKS port for TCP connections, so for instance you\ncan browse remote networks from a port-shell session without the need to open any other\nconnection during a pen-test. If you pass `-N` to `pscl`, it enables DNS name resolution\non the remote side, so you can also use chrome with it. But be warned: There is a privacy\nproblem with browsers that try to resolve a sequence of DNS names upon startup that\nis not under your control. Also, if your remote side has a broken DNS setup, your typing\nshell may block for several seconds if DNS reply packets are missing. There are no good\nasync resolver functions which are embeddable and portable so I had to rely on\n`getaddrinfo()` in the single thread at the price of possible blockings for several seconds\nif DNS problems exist. Thats why name resolving has to be enabled explicitly. `pscr`\ntries to minimize this potential problem with DNS lookup caches though, so in most\nsituation it should just work painlessly.\nIf you pass `-X IP-address` (must be the first argument), you can bind your local proxy\nto an address different from `127.0.0.1`, so you can share the proxy in your local network.\n\n\nBounce commands\n---------------\n\n*psc* features allow TCP-connections or binary data blobs being forwarded from/to remote\ndevices across multiple hops even if it is not possible to install the `pscr` binary at\nthe remote site. This is very useful for forensic purposes if you do not have any means\nto otherwise download artefacts from the device (which can be an UART connected phone for example)\nor need to forward connections without touching the FS to not destroy evidence on the system\nor when the root-FS is ro mounted and you can't upload your tool-set.\n\nThis is a really cool feature, as you can see your TCP connection hop through your local tty\nto a remote box without the need to install anything remotely.\n\nThis solely works by local pty punkrock and handing over a bounce-command to `pscl` that it will\ndrop on the remote shell (without `pscr` running) and some state engine magic that filters out\nand handles the data at the local side. Usually this requires to set the remote pty to raw mode\nat first before issuing the actual command and some other details that are passed to `-B`. The\nargument is split into the following parts:\n\n* The local port to trigger the command upon connect, followed by `:`, e.g. `1234:`.\n* The cmd that sets the remote tty to raw mode, usually `stty -echo raw` or\n  `python -c \"import tty;tty.setraw(0)\"` (take care to get the quotes right, as `-B` also needs\n  to be quoted) or anything similar.\n* A \"GO\" marker issued by remote that tells `pscl` to start sending data to avoid a race between\n  `stty` actually happen and the start of the cmd, e.g. a `echo GO` is perfect.\n* The trigger command itself, e.g. `nc 127.0.0.1 22` to bounce local port 1234 to remote's SSH\n  server\n* optionally a FIN marker issued by remote so you notice that trigger command has been finished\n  i.e. you can kill your local connection to port 1234, which allows `pscl` to reset its tty state.\n  `echo FIN` will do it. Recommended, as otherwise you can have trouble recognizing the end of\n  your command.\n* All four previous commands are separated by `;` and enclosed in brackets.\n\nExamples:\n\nIf you want to forward a TCP connection, this example requires `stty` and `nc` installed on the\ndevice, but it could theoretically be anything else that does equivalent.\n\nStart a local session:\n\n`./pscl -B '1234:[stty -echo raw;echo GO;nc example.com 22;echo FIN]'`\n\nThis will issue the command `stty -echo raw;echo GO;nc example.com 22;echo FIN` to the remote\ndevice if you connect locally to port 1234 and then just forwards any data it sees back and forth\nand rate-limiting the traffic so it will not exceed the devices' tty speed (115200 is the default).\n\nWhen the pscl session is started, connect to the remote device by UART, `ssh -e none ...` or\nwhatever it is and once you have the remote shell, also type locally:\n\n`ssh root@127.0.0.1 -p 1234` to bounce the SSH connection from your local box across the remote\ndevice to the `example.com` destination. Of course the `pscr` variant is preferred as `-B` can only\nbounce a single connection at a time (although you can pass multiple `-B` commands for various\nforwards) and theres a chance to hang the shell after the TCP session since the pty is in `raw -echo`\nmode and depending on whether the final remote peer also closes the connection, it might be\nthat the shell just hangs after that. If you happen to find a pscl notification that the connection\nhas finished and see a prompt, you should `reset` it, so that a new connection can be started.\nWhile data is being forwarded, you will see 7bit ASCII `\u003c` and `\u003e` notifications in `pscl` which\nare just local for easier debugging and progress detection.\n\nNote that the connection to the remote site has to be 8bit clean, i.e. the ssh, telnet, UART or\nwhatever channel *must not handle escape sequences* (unlike when using `pscr`). For ssh connections\nthis means you have to use `ssh -e none` in the `pscl` session.\n\nNext, following some examples to handle binary file xfer where *rfile* denotes the remote file and\n*lfile* the local file.\n\nTo start a session to drop remote files, locally:\n\n`./pscl -B '1234:[stty -echo raw;echo GO;dd of=rfile.bin bs=1 count=7350;echo FIN]'`\n\nWhere you need to specify the amount of data that the remote side is expecting. It would also\nwork without (e.g. `cat\u003e...`) but then the session will hang after transmission has finished as\n`cat` is endlessly expecting input. By using `dd count=...`, you will get a clean exit and be notified\nabout it by the FIN marker.\n\nThen, ssh or whatever is necessary to get a shell on the remote device from within the just\nstarted `pscl` session. On a second terminal locally:\n\n`dd if=lfile.bin|nc 127.0.0.1 1234`\n\nwhich will connect to `pscl`'s local port 1234 and trigger the dump command on the remote side,\nforwarding the binary data of the local `lfile.bin` to remotes `rfile.bin`. Due to rate-limiting\nthis can take a while and you *only trust your psc progress screen* whether the transfer is finished.\nThe local `dd ...|nc ...` command will only show you the local status which can eat entire files\nin msecs due to local TCP buffers while the file is still being transfered through the pty.\nSo make sure you only press `Ctrl-C` when the *pscl* screen tells you it is finished or you see\nthe `FIN` end marker being echoed back to you on the `dd ...|nc ...` session.\n\nLikewise, similar commands could be used to transfer binary data from a remote device to the\nlocal box for forensic purposes. Again, start of the session locally:\n\n`./pscl -B '1234:[stty -echo raw;echo GO;dd if=rfile.bin]'` or\n\n`./pscl -B '1234:[stty -echo raw;echo GO;cat rfile.bin]'`\n\nThen, ssh to remote device to get the shell, then again locally:\n\n`nc 127.0.0.1 1234|dd of=lfile.bin bs=1 count=7350`\n\nTo obtain `rfile.bin` of size 7350 copied to local file `lfile.bin`\n\nIf `stty -echo raw` is not available on the device, something like\n`python -c \"import tty;tty.setraw(0)\"` also works. Note that on the remote device you need to have\na tty (not just a port-shell) when using bounce commands, since the `stty` command to set raw mode\nrequires a real tty.\n\n\nUART / modems / Flow Control\n----------------------------\n\nIf *psc* runs across a serial connection, lost bits can kill all your fun. If you run\nwithout HW FC you will eventually experience bitloss and hung connections, in particular\nas there is no throttling when the device is sending data in your direction when using\n*bounce commands*. Dumping data to the device works better as this data goes through\nthe `pscl` rate limits.\n\nHowever, here are some tips that worked for me under circumstances when it is not\npossible to use `pscr` on the device and HW FC. This only applies when using UARTs, as this\nis a potentially unreliable transport channel.\n\n* do not enable soft FC, as this would tamper the 8-bit channel\n* when possible use HW FC - or if not - you have to disable FC alltogether\n* Use `pscr` on the device so you can set rate limiting for data being sent into your direction.\n  As the direction towards the device is always rate limited, you can use bounce commands to\n  dump a cross-compiled `pscr` binary to the device and start a two-way rate limited session with it.\n* use high quality cables with proper shielding and UART chipsets with large buffers\n* apply the tio-limit patch from the contrib folder, as tio is buffering input bytes which could\n  lead to writing-peeks that exceed the set rate\n* use `tio -o 1` or `-o 2` to add delays between sent output-bytes\n* use a conservative rate limitig (i.e. prefer `38400` although serial line has set `115200`)\n* compile `psc` with `-DRESPECT_UART_BUFSIZE=4096`, however this will make the session very slow\n\nInside the `contrib` folder you will also find a `tio-noprefix` patch to disable escape-character\nprocessing but this patch is only necessary for older versions, as upstream already accepted and\nintegrated this patch. I really recommend using `tio` when using UARTs.\n\n\nWhen using bounce commands across *tio*, you have to add to your `~/.tioconfig` file:\n\n```\n[default]\n\nprefix-ctrl-key = none\n```\n\nwhich disables ESC-handling and gives you an 8-bit clean channel.\n\n\nSIGUSR1 / SIGUSR2\n-----------------\n\nYou can send `SIGUSR1` to `pscl` so it tells you whether the session is encrypted. If the remote\n`pscr` dies or exits without possibility to signal that to the local part, `pscl` will stay\nin encryption mode and therefore hang. In this case you can force a reset to plaintext mode\nby sending `SIGUSR2`, so a new session can be started.\n\nScripting\n---------\n\nAs of version 0.64, *psc* supports scripting-sockets so you no longer need `screen` to\nget/put files or dump paste buffers to the remote console. Instead, you start your local\nsession like so:\n\n```\n~ \u003e ./pscl -S ~/psc.script_sock\n```\n\nYou can then go ahead and use it as before. If you need to 'paste' something you do like:\n\n```\n~ \u003e ./pscsh -S ~/psc.script_sock -f script_/helloworld\n```\n\nThis will 'type' the content of `script_/helloworld` to the console. While scripting,\nthe stdin of `pscl` is blocked so that the injected input does not mix up with any\ntyping. If `-S` is omitted in `pscsh`, `~/psc.script_sock` is used automatically.\nFor safety reasons, scripts must start with the `script_` prefix.\n\nAs a bonus, `pscr` now contains the ability to base64 en/decode files, even with CR\nembedded characters for convenience. It is compatible to `uuencode -m`.\n\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstealth%2Fpsc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstealth%2Fpsc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstealth%2Fpsc/lists"}