Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions content/aws/avoiding-detection/guardduty-pentest-botocore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
author_name: Raajhesh Kannaa Chidambaram
title: Bypass GuardDuty Pentest Findings via Botocore Config
description: Override the default botocore user-agent string in boto3 to prevent GuardDuty PenTest findings from firing.
---

# Bypass GuardDuty Pentest Findings via Botocore Config

<div class="grid cards" markdown>

- :material-account-edit:{ .lg .middle } __Original Idea__

---

This article is based on [Hacking the Cloud Issue #453](https://github.com/Hacking-the-Cloud/hackingthe.cloud/issues/453).

</div>

## Background

AWS [GuardDuty](https://aws.amazon.com/guardduty/) inspects the `User-Agent` header in AWS API requests (recorded in CloudTrail) to detect calls made from known penetration testing distributions. When it sees user-agent strings containing identifiers for Kali Linux, ParrotOS, or Pentoo Linux, it triggers a [PenTest finding](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-iam.html#pentest-iam-kalilinux) such as:

- `PenTest:IAMUser/KaliLinux`
- `PenTest:IAMUser/ParrotLinux`
- `PenTest:IAMUser/PentooLinux`

The [existing article](guardduty-pentest.md) on this topic covers using Burp Suite as an intercepting proxy to rewrite the `User-Agent` header for the AWS CLI. That approach works but requires setting up a proxy, dealing with TLS certificates, and routing all traffic through Burp.

If you are working directly with the AWS SDK (boto3/botocore), there is a simpler option: override the user-agent string natively using `botocore.config.Config`.

## How It Works

When you create a boto3 session or client, botocore builds a user-agent string that includes your OS, Python version, and botocore version. On Kali Linux, that string will contain something like `kali` in the platform identifier, which is what triggers the GuardDuty finding.

The [`botocore.config.Config`](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html#botocore-config) class accepts a `user_agent_extra` parameter, but more importantly, you can use `user_agent_appid` or directly patch the user-agent to replace the entire string. Starting with newer versions of botocore, you can set `user_agent_appid` in the config, but the most reliable way to fully control the user-agent is to override it at the session level.

## Technique

The following snippet creates a boto3 session with a completely custom user-agent string, removing any OS-specific identifiers that GuardDuty would flag:

```python
import boto3
from botocore.config import Config

# Define a clean user-agent that does not reveal your OS
custom_config = Config(
user_agent_extra="", # prevent appending extra info
)

session = boto3.Session()

# Patch the user-agent at the session level
session._session.user_agent_name = "Boto3"
session._session.user_agent_version = "1.35.0"
session._session.user_agent_extra = ""

# Create clients using this session
sts = session.client("sts", config=custom_config)
print(sts.get_caller_identity())
```

After running this, the `User-Agent` header in your API requests will look something like `Boto3/1.35.0 Python/3.12.0 Botocore/1.35.0` with no mention of Kali, Parrot, or Pentoo.

You can verify what user-agent is being sent by checking CloudTrail. The `userAgent` field in the event record will reflect whatever you set.

### Picking a Realistic User-Agent

To blend in, pick a user-agent value that matches what the target environment likely uses. For example, if the account runs Lambda functions with Python 3.12, a user-agent like `Boto3/1.35.0 Python/3.12.0 Botocore/1.35.0` would look normal in CloudTrail logs. You can reference [Pacu's user-agent list](https://github.com/RhinoSecurityLabs/pacu/blob/master/pacu/user_agents.txt) for realistic values.

## Limitations

- **SDK only.** This technique works for boto3/botocore. The AWS CLI builds its own user-agent string and appends additional metadata (CLI version, command name, etc.) that you cannot control through `botocore.config.Config` alone. For CLI use cases, the [Burp Suite proxy method](guardduty-pentest.md) is still the recommended approach.
- **Internal attribute access.** Setting `session._session.user_agent_name` relies on botocore internals. While this has been stable across many releases, it could change in a future version. Test before relying on it in an engagement.
- **CloudTrail is not the only signal.** GuardDuty uses multiple data sources. Changing your user-agent avoids the PenTest finding specifically, but other findings based on network traffic, DNS logs, or anomalous API behavior will still fire.

## Detection Guidance

If you are on the defensive side:

- **Do not rely solely on GuardDuty PenTest findings.** The user-agent string is attacker-controlled and trivially spoofed. Treat PenTest findings as a bonus signal, not a primary detection.
- **Baseline user-agent patterns.** Build detections in CloudTrail that alert on user-agent strings that are unusual for your environment. A sudden appearance of a generic `Boto3/1.35.0` with no Lambda or SDK context in an account that normally uses the CLI could be suspicious.
- **Monitor for `botocore.config` usage patterns.** If you control the compute environment, watch for code that patches `_session.user_agent_name` or sets unusual `Config` values.