Dev.to Security 🔐 Cybersecurity 👁 0 📖 10 min read

angry-putty

WORK IN PROGRESS: MANY FEATURES MAY BE BROKEN Angry Putty 0.1.6-wip · © Matthew Armstrong · source-available under the PolyForm Noncommercial License 1.0.0: free for personal, non-commercial use; no commercial use wit

angry-putty

WORK IN PROGRESS: MANY FEATURES MAY BE BROKEN

Angry Putty 0.1.6-wip · © Matthew Armstrong · source-available under the
PolyForm Noncommercial License 1.0.0: free for personal, non-commercial use;
no commercial use without permission. Provided as is, with no warranty and no liability.
Only scan networks and log in to computers you own or have permission to use.
Read DISCLAIMER.md before use.

Angry Putty: an angry blob of putty shouting a scan range at a terminal

Angry Putty is an Angry IP Scanner-style network scanner and a
PuTTY-style terminal in one small window,
plus firmware that turns a cheap ESP32-S3 board into a USB dongle: plug it into a PC or
Raspberry Pi and it tells you that computer's address and lets you SSH into it from your phone.

Credit where it's due

The clever part of Angry Putty was done by other people. I have taken their ideas and tried to
make them quicker to use and plug and play.

  • Angry IP Scanner by Anton Keks and its contributors (free, GPL-2.0): the fast, friendly scanner that fills a table with every live device, its name and open ports. Angry Putty's Scan tab is built on that idea.
  • PuTTY by Simon Tatham and the PuTTY team (free, MIT licence): one small window that remembers your sessions and gets you into SSH, telnet or a serial port. Angry Putty's address bar and konsole follow that idea.

Angry Putty is a new program written from scratch: it contains none of their code, and it is not
affiliated with or endorsed by either project. If you want the full-featured originals, use them.
The heavy lifting inside Angry Putty is also done by other people's libraries (paramiko, pyte,
esptool, ESP-IDF, TinyUSB, lwIP, libssh2, xterm.js); see THIRD_PARTY.md.

Status in 0.1.6-wip
Scanner: your own networks as the default range, ping, open ports, names, MAC Works (tested on Linux)
name.local and "find every .local device" (mDNS), also on Windows without Bonjour Works against a test responder; not yet tried on a real LAN
Address bar that remembers the last address and a history; http://ip opens the browser Works
Konsole tabs: SSH (host-key checking), telnet, raw TCP, serial SSH tested against OpenSSH 9.6; telnet/serial unit-tested only
Saved sessions, "open in system terminal" Works on Linux; Windows/Mac terminals not tried
Flash the dongle from the app Works: used on an ESP32-S3-Zero from Linux Mint (13-15 Oct 2026); 0.1.5 keeps the dongle's settings when re-flashing
Dongle firmware: USB network adapter + hotspot + web page + browser konsole (SSH, telnet, serial) Works on an ESP32-S3-Zero (0.1.2): hotspot, phone page, and the plugged-in computer's address on Linux Mint and Windows 11 with no driver install. SSH through the dongle not yet tried
0.1.1: status LED, USB log, restart reasons and crash records, captive portal, capped WiFi power LED, USB log and hotspot seen working on the board (0.1.1); crash records tested in Espressif's ESP32-S3 emulator
Phone/laptop SSH apps through the dongle (port 2222) Written, not yet run on hardware
0.1.4: GadgetDesk option (off by default): cast the Pi's desktop to a phone on 8088, touch pad (double tap = HDMI desktop on/off), on/off from GadgetDesk Builds; gesture logic tested on a PC; works end to end against GadgetDesk with the mock dongle. Not flashed or touched yet

Using it

Scan

Scan tab

  1. The Range box fills in with your own networks (a big office network is trimmed to the /24 around you). Defaults lists every network card, the dongle hotspot and common home ranges.
  2. You can type: 192.168.1.0/24, 192.168.1.10-50, 10.0.0.1-10.0.1.20, single addresses, host names, printer.local, or *.local to find every device that announces itself (Pis, printers, Klipper/Moonraker, ESPHome, Macs...). Mix them with commas.
  3. Start scan. A host counts as alive if it answers ping or any probed port answers (even a refusal proves something is there). Untick Ping on networks that block it.
  4. Double-click a row: SSH if port 22 is open, otherwise its web page. Right-click for SSH, telnet, http://, https://, copy IP/name, or save it as a session. Export CSV saves the table.

(The screenshot uses the built-in --demo data, so the addresses are simulated.)

Connect: the address bar and konsole

SSH konsole

Type in Connect to and press Enter. It remembers the last address and keeps a history.

You type It does
192.168.1.20 SSH (or the protocol picked on the left)
[email protected] SSH as pi; .local names are looked up with Angry Putty's own mDNS if the system cannot
ssh://[email protected]:2222 SSH on another port (this one goes through the dongle)
telnet://192.168.1.9 telnet
http://192.168.1.50 opens it in your web browser
COM3, /dev/ttyUSB0, serial:///dev/ttyACM0?baud=9600 serial konsole

The konsole is a real terminal (colours, htop, nano, vim):

htop in the konsole

  • PuTTY habits: selecting text copies it, right-click pastes; Ctrl+Shift+C / Ctrl+Shift+V also work.
  • The mouse wheel scrolls back. A+ / A- change the font size.
  • System terminal opens the same connection in your own terminal with the system ssh.
  • SSH logs in with your SSH agent, your keys in ~/.ssh (id_ed25519, id_ecdsa, id_rsa), then asks for a password. Passwords are never stored.
  • Host keys: the first time you are shown the SHA256 fingerprint (the same one ssh-keygen -lf prints). A changed key gets a loud warning and is never stored over the old one. Trusted keys go into Angry Putty's own known_hosts; your ~/.ssh/known_hosts is read, never written.

(Screenshots: a local OpenSSH test server, 127.0.0.1:2222.)

Sessions

Sessions tab

Save a host as a named session (SSH, telnet, raw, serial, http, https) with port, user,
baud rate and an optional key file. Double-click to open; Open in system terminal uses your own terminal.

Settings live in ~/.config/angry-putty/ (Linux), ~/Library/Application Support/angry-putty/ (macOS)
or %APPDATA%\angry-putty\ (Windows).

The dongle

The dongle is an ESP32-S3 board running Angry Putty's firmware. Plug it into the computer you
want to reach:

 [ PC or Raspberry Pi ] ==USB== [ ESP32-S3 dongle ] ~~~ WiFi hotspot "AngryPutty-XXXX" ~~~ [ phone / laptop ]
   gets 10.66.0.2                10.66.0.1 | 192.168.4.1                                   browser: http://192.168.4.1
  • It appears to that computer as a USB network adapter and gives it the address 10.66.0.2. It offers no gateway and no DNS, so the computer's normal internet is not touched.
  • It reads the computer's DHCP request, so the page can also show its host name (e.g. raspberrypi).
  • It runs its own WiFi hotspot AngryPutty-XXXX (default password angryputty; change it in Settings).
  • http://192.168.4.1 shows the computer's address and a browser konsole: SSH (the dongle itself is the SSH client), telnet, raw TCP, or the serial console wired to the Pi's GPIO pins. Extra keys (Esc, Tab, Ctrl, arrows) are there for phones.
  • Any SSH app can log in through 192.168.4.1 port 2222; the computer's web page (port 80, e.g. Mainsail or OctoPrint) is at 192.168.4.1:8080.
  • GadgetDesk option (plug-in, 0.1.4, off by default). Turn it on with the desktop app's Turn GadgetDesk on button (Dongle tab, 0.1.5) or GadgetDesk desktop in the dongle's Settings to cast a Pi's GadgetDesk web desktop to your phone at 192.168.4.1:8088 (an Open :8088 button appears) and to use the touch pad below. With it off, the dongle has no 8088 forward and no touch pad, as in 0.1.3.
  • Touch pad (part of the GadgetDesk option): a short wire or a piece of foil tape on GPIO4 (any of GPIO1-14 except 3,
    set on the page). With GadgetDesk on the Pi: double tap = HDMI desktop on/off, hold = off.
    Switch the pad off and on from the page's Touch pad card or from GadgetDesk (its Touch button);
    the card also shows the live reading so you can set the sensitivity. It only touches the pin: no
    extra parts, and nothing else happens when GadgetDesk isn't there (3 red LED flashes).

  • Little OLED screen (0.1.6, optional). Wire a 4-pin I2C OLED (SSD1306 / SSD1315 / SH1106,
    128x64 or 128x32) to 3V3, GND, SDA = GPIO8, SCL = GPIO9 and the dongle shows the computer's
    address in big, full-brightness digits, then the hotspot, the ways in from a phone and its own
    details, a few seconds each. Nothing happens if no screen is wired. Wiring, pages, settings and
    troubleshooting: docs/OLED.md. Not run on a real screen yet.

The four OLED pages drawn on a PC by the firmware's own drawing code (not a photo)

The dongle page's Touch pad card: switch button, pin, live reading, last gesture

Dongle web page on a phone

(Taken with tools/mock_dongle.py, a pretend dongle on a PC, which shows a purple MOCK banner;
the computer shown is simulated, the SSH session behind it is real.)

The status LED

On the ESP32-S3-Zero the colour LED (GPIO21) shows what the dongle is doing. The same table is on
the dongle's page under What the LED means.

LED Meaning
Red, green, blue once at power-on Colour test. If you see green first, set LED colour order in the page's Settings.
Blue, 1 blink every 2 s Hotspot on, nothing on the USB port
Blue, 2 blinks every 2 s Computer connected by USB, waiting for it to ask for an address
Steady green The computer has its address: ready
White flicker Konsole traffic, or someone joined the WiFi
3 purple flashes after the colour test The last restart was a crash
3 orange flashes after the colour test The last restart was a power dip (brownout)
Fast red blinking The WiFi hotspot failed to start

Other boards: choose a plain LED, another pin, or no LED in Settings.

When something goes wrong: health, log and USB log

  • The page's Dongle health card shows the last restart reason (power on, CRASH, brownout...), how many crashes and power dips there have been, the last crash recorded (task and code address), WiFi channel and power, and free memory.
  • The Log section shows the firmware's log live, and Before the last restart shows the last few KB written before a crash or restart.
  • Plugged into a computer, the dongle's USB port is also a serial port called Angry Putty log carrying the same log (the ESP32-S3-Zero has no USB-serial chip, so this is the only way to read it over a cable). In the app: Dongle tab > USB log. Any serial terminal works too (type help, status, prev or reboot).

USB log window

If the dongle misbehaves, send the log (the window's Save... button) and the health card:
crash addresses can be decoded to the exact line with firmware/debug/angry-putty-<version>.elf.gz.

Flash the dongle

Dongle tab

You need an ESP32-S3 board with a USB port wired to the chip's own USB (most S3 boards;
4 MB flash or more). ESP8266, the original ESP32, ESP32-C3 and C6 cannot do this: they have
no native USB that can act as a network adapter. The app checks the chip and says so.

  1. Hold BOOT, plug the board into the computer running Angry Putty (or tap RESET while holding BOOT), let go.
  2. Dongle tab > Detect chip (it picks the ESP32-S3's port itself and checks the chip and its flash size) > Flash firmware.
  3. Unplug it and plug it in again without BOOT (remove any BOOT jumper or wire on GPIO0). The LED should show red, green, blue. From now on its USB port is a network adapter plus the log port, so to flash it again you always hold BOOT while plugging it in.

Re-flashing keeps the dongle's settings (WiFi name and password, LED, GadgetDesk option). Tick
Erase everything first to go back to the defaults.

Use it

  1. Plug the dongle into the PC or Pi. On a Pi, use a normal USB-A port (or the Zero's USB OTG port with an adapter).
  2. Join the AngryPutty-XXXX WiFi from your phone or laptop (password angryputty). A phone will say Sign in to network (like hotel WiFi): tap it, or open http://192.168.4.1 in your browser. The phone stays connected and keeps using mobile data for the internet.
  3. Open http://192.168.4.1 (or press Refresh in the app's Dongle tab).
  4. Press SSH, type the user name and password. Or connect any SSH app to 192.168.4.1 port 2222.

SSH must be switched on in the computer. On Raspberry Pi OS: Raspberry Pi Imager's settings,
or sudo raspi-config > Interface Options > SSH. On Windows: Settings > Optional features >
OpenSSH Server. No SSH? Use the serial console:

Dongle (ESP32-S3) Raspberry Pi header
TX (GPIO17 by default) pin 10, GPIO15 (RXD)
RX (GPIO18 by default) pin 8, GPIO14 (TXD)
GND pin 6 (GND)

3.3 V logic on both sides; never connect the Pi's 5 V pins. Enable the console with
sudo raspi-config > Interface Options > Serial Port (login shell: yes). The default pins are
arbitrary: set the ones your board has free in the page's Settings.

Build the firmware yourself

See firmware/README.md. In short, with ESP-IDF 5.4:
cd firmware && idf.py set-target esp32s3 build. GitHub Actions also builds it on every push.

More

Tests: python -m pytest (add xvfb-run on Linux for the GUI test; set
ANGRY_PUTTY_TEST_SSH=user:password@host:port to include a live SSH login).

Source code: The-Dorkknight/angry-putty on GitHub

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.