Skip to content

Commit 51a15d6

Browse files
authored
Merge pull request #503 from raajheshkannaa/feat/guardduty-useragent-bypass
Add article: bypass GuardDuty pentest findings via botocore user-agent
2 parents b1777f1 + fcc6f85 commit 51a15d6

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
author_name: Raajhesh Kannaa Chidambaram
3+
title: Bypass GuardDuty Pentest Findings via Botocore Config
4+
description: Override the default botocore user-agent string in boto3 to prevent GuardDuty PenTest findings from firing.
5+
---
6+
7+
# Bypass GuardDuty Pentest Findings via Botocore Config
8+
9+
<div class="grid cards" markdown>
10+
11+
- :material-account-edit:{ .lg .middle } __Original Idea__
12+
13+
---
14+
15+
This article is based on [Hacking the Cloud Issue #453](https://github.com/Hacking-the-Cloud/hackingthe.cloud/issues/453).
16+
17+
</div>
18+
19+
## Background
20+
21+
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:
22+
23+
- `PenTest:IAMUser/KaliLinux`
24+
- `PenTest:IAMUser/ParrotLinux`
25+
- `PenTest:IAMUser/PentooLinux`
26+
27+
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.
28+
29+
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`.
30+
31+
## How It Works
32+
33+
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.
34+
35+
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.
36+
37+
## Technique
38+
39+
The following snippet creates a boto3 session with a completely custom user-agent string, removing any OS-specific identifiers that GuardDuty would flag:
40+
41+
```python
42+
import boto3
43+
from botocore.config import Config
44+
45+
# Define a clean user-agent that does not reveal your OS
46+
custom_config = Config(
47+
user_agent_extra="", # prevent appending extra info
48+
)
49+
50+
session = boto3.Session()
51+
52+
# Patch the user-agent at the session level
53+
session._session.user_agent_name = "Boto3"
54+
session._session.user_agent_version = "1.35.0"
55+
session._session.user_agent_extra = ""
56+
57+
# Create clients using this session
58+
sts = session.client("sts", config=custom_config)
59+
print(sts.get_caller_identity())
60+
```
61+
62+
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.
63+
64+
You can verify what user-agent is being sent by checking CloudTrail. The `userAgent` field in the event record will reflect whatever you set.
65+
66+
### Picking a Realistic User-Agent
67+
68+
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.
69+
70+
## Limitations
71+
72+
- **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.
73+
- **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.
74+
- **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.
75+
76+
## Detection Guidance
77+
78+
If you are on the defensive side:
79+
80+
- **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.
81+
- **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.
82+
- **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.

0 commit comments

Comments
 (0)