GuardDuty is Amazon Web Service’s (AWS) built in solution for detecting attacks against your environment using machine learning. It can detect a number of common attacks and is an excellent way to quickly boost your security.
If you are a Penetration Tester working in an environment that uses AWS/GuardDuty there are a number of common findings you need to be aware of. While causing alerts during traditional whitebox penetration testing is not a huge deal, it is often a good idea to be courteous to your blue team friends and reduce the number of alerts you cause.
Previously I wrote about how to bypass the UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration finding. Another common finding type you may run into are the PenTest findings.
The PenTest finding type covers when GuardDuty detects API invocations coming from a penetration testing Linux distribution. These are Kali Linux, Parrot Linux, and Pentoo Linux.
While we should all be using the one true Linux distribution (Arch), there can be any number of reasons a Penetration Tester may be required to use one of the aforementioned penetration testing Linux distributions. As such, the following describes how this detection works and how it can be bypassed.
Note: This has been covered before elsewhere and is even a feature of Pacu, however the following is my explanation.
First, how does GuardDuty pick up on this finding? The answer lies in the AWS API User-Agent string. According to the Botocore library (a part of the official AWS Python SDK) every request to the AWS API will include a User-Agent string of the following format.
<agent_name>/<agent_version> Python/<py_ver> <plat_name>/<plat_ver> <exec_env>
This provides us with a good bit of information. The key piece we are looking for is that third part, the platform information. This will inform GuardDuty the type of operating system we are using (for example, Linux) as well as the "platform version".
Looking at the code, this information comes from the following chunk of code.
Bingo, we have our informant. The AWS CLI (and tools built using boto3) inform AWS of what version of Linux we are using. On Kali Linux the following is the release information.
From here all AWS has to do is detect “kali” and it will trigger the GuardDuty alert.
To prevent this from happening, we have a few options. One would be to do monkey patching to change the release before calling API functionality. This is effective if you are writing a script and calling the API through that way, however it does not apply to the AWS CLI.
The method I have chosen to go with (and what I think is the simplest way) is to instead modify your installed botocore package and hard code a specific user agent. This way, you can make use of the regular AWS CLI without having to do any proxying or other magic. Note: It's likely better to do Monkey patching if you are shipping a tool or a one off script.
The steps to do this may differ on what OS you’re using and how you’ve installed botocore/aws cli (pip3/pip/apt/aur/pacman/etc.). Regardless of the OS, you are looking to modify the "session.py" file of your botocore package. On a default Kali Linux install this can be found at /usr/local/lib/python3.7/dist-packages/botocore/session.py.
From here you will want to scroll down to line 456 (at the time of this writing) and change "platform.release()" to a string of your choosing (for this article I have changed it to "Neat agent string").
From here that string should be your new User-Agent string. I’d encourage you to test this in your own environment to ensure it is working as intended and it is not picked up on by GuardDuty (I take no responsibility if your opsec gets blown!). If you’d like to see it going over the wire you can set your AWS CLI to go through a proxy (like Burp Suite) by running "export https_proxy=https://proxy_ip:8080". This should give you something like the following.
If you’d like to set a more stealthy User-Agent string, you can choose any of the following samples. These were taken from Pacu (they are legitimate User-Agent strings). Consider modifying the platform.system() call as well.
Linux/4.15.0-45-generic
Windows/10
Mac_OS_X/10.14.2