[Enterprise Security] Automating the Destruction of Bind Shells

TRY HARDER: A Blog About Discovery


Author: Brennan Turner @BLTSEC
[Enterprise Security] Automating the Destruction of Bind Shells

Scenario: A web developer goes to his local coffee shop and connects to the open WiFi network and starts browsing for Bootstrap website themes. An attacker has deauthenticated clients from the legitimate coffee shop network and jammed the coffee shop’s access point in order to redirect the clients to his malicious network which has the same name as the legitimate network. The attacker is running an arp spoofing and DNS spoofing attack on the network that redirects traffic from HTTP domain names that contain bootstrap to his malicious site that offers free bootstrap themes. The site has a link to “try” Bootstrap and once the link is clicked the client downloads a macOS dmg that contains what appears to be a “Bootstrap Installer” app. The app executes the attacker’s malicious payload and spawns 4 bind shells on the target while staying fully undetectable by the host’s Sophos anti-virus. A bind shell allows an attacker to gain access to the target by connecting to the listening port established by the payload. The client issues a Dictation command which starts a macOS Automator workflow. This workflow gives the client audio feedback as a Python script executes. This Python script is a port scanner that looks for listening ports and once a port is found it will find the associated process id and terminate that process which kills the bind shell.

Disclaimer: This is a test environment and the methods shown below shouldn’t be done in a production environment without proper authorization and documentation. Use these techniques responsibly and ethically and always test every flag, switch, command, and exploit in your own test environment prior to running in a customer’s environment. I would also like to state that even though quite a few Red Team techniques are used in the attack phase of this scenario I will not be covering how to perform these attacks. This is an article on Enterprise Security so I will not deviate from that topic but I did want to provide context by showing a real-world example of how quickly an unsuspecting user could become compromised.

Breakdown: This week I’ve been looking at macOS’s Automator application. Automator is a tool included with OS X which allows you to build custom workflows to perform both simple and complex tasks, such as renaming files in a folder, combining multiple PDF documents, or converting movies from one format to another using QuickTime. In this example, I created a simple Dictation workflow that executes a Python script and provides audio feedback. Before you start creating a Dictation Automator workflow you will need to enable Dictation enhanced commands. The screenshot below shows the entire workflow which was created after opening Automator -> File -> New and then selecting the Dictation document type. Once you save the document a Dictation command is added to the available commands to call when you open the Dictation prompt.

The Python script is a port scanning tool that looks for open ports that are listening for incoming connections and once the port is found the script will find the associated process id and terminate the process which will kill the malicious bind shell established by the attacker’s payload when the “Bootstrap Installer” app executed.

#!/usr/bin/python3
#
# bind_destroyer - Python listening port scanner and destroyer 
#
# Written by: Brennan Turner (@BLTSEC)
#
# Usage: python bind_destroyer.py
# Usage: python3 bind_destroyer.py
#
#
from subprocess import Popen, PIPE
from os import system
import argparse
import os
import signal
import socket

flag = 1
ports = ""

# reads the contents of the port whitelist
def read_whitelist(whitelist):
    with open(whitelist) as f:
        accetable_ports = f.read().splitlines()
    return accetable_ports

# uses the macOS lsof command to find open listening ports
def get_process(i):
    p1 = Popen(['lsof', '-n', '-i4TCP:{}'.format(i)], stdout=PIPE)
    p2 = Popen(['grep', 'LISTEN'], stdin=p1.stdout, stdout=PIPE)
    return (p1,p2)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--whitelist', dest='file',
                        help='Path to the whitelisted ports file')
    args = parser.parse_args()
    file = args.file
    if file:
        ports = read_whitelist(file)
    # loops through a range of ports
    for i in range(10000, 12000):
        # skip whitelisted ports
        if str(i) in ports:
            system('say -v Daniel Skipping white listed port {}'.format(i))
            continue
        # creates a client socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        result = s.connect_ex(('127.0.0.1', i))

        # if the result returns 0 the port is open
        if result == 0:
            flag = 0
            system('say -v Daniel Port {} is open'.format(i))  
            # finds the associated pid and terminates the process
            try:
                p1, p2 = get_process(i)
                pid = str(p2.communicate()[0]).split(" ")[2]
                os.kill(int(pid), signal.SIGTERM)
                system('say -v Daniel Process {} was terminated'.format(pid))
            # disconnecting from the socket may cause the proc to die eg netcat
            except IndexError:
                system('say -v Daniel The process died automatically.')
            # the pid may not be at a different index value, this finds the pid
            except ValueError:
                inc = 1
                while pid == '':
                    p1, p2 = get_process(i)
                    pid = str(p2.communicate()[0]).split(" ")[2+inc]
                    inc += 1
                    if pid != '':
                        os.kill(int(pid), signal.SIGTERM)
                        system('say -v Daniel Process {} was terminated'.format(pid))
            system('say -v Daniel The scan will now continue.')
        # closes the socket
        s.close()

    if flag == 1:
        system('say -v Daniel No anomalies were detected.')
system('say -v Daniel The port scan has completed.')

Please watch the video below for a demonstration and see the attacker establish a foothold onto the target and see the client’s Automator job destroy the bind shells established by the malicious macOS app.

Sources: