Skip to content

Living off the Land (AI) part 2

Let’s step into the practical stage of building a covert C2 channel on top of a public LLM.

I first tried to build C2 using the approach from the previous post: a custom C2 website with the LLM acting as a proxy to fetch and pass commands. This did not work. All tested LLMs (ChatGPT, Gemini, Claude) blocked requests to my custom C2 website. Standard websites were accessible, but my domain was not. I tried multiple prompt variations, but without success. See Check Point research, they somehow tricked filters:  https://blog.checkpoint.com/research/using-ai-for-covert-command-and-control-channels/

The second approach was to use the LLM as a proxy via a Files API service. This time it worked. I successfully built a C2 channel using Gemini as the proxy. The compromised endpoint communicates only with a trusted Google endpoint: https://generativelanguage.googleapis.com

  1. The operator publishes a command to the Files API via API.
  2. The compromised endpoint periodically checks for new files.
  3. If a new file exists, the endpoint sends a prompt to Gemini to interpret its contents.
  4. The endpoint receives the response, executes the command, and writes the output back to the Files API.
  5. The operator retrieves the output via API.

At this stage, the LLM acts only as a proxy for command exchange. The next step is to make it more interesting and leverage what LLMs actually offer: autonomy. The architecture remains the same, but the logic changes completely. Gemini is now used in a more advanced way.

  1. The operator issues a task, not a specific command like ipconfig, but a natural language goal, such as checking the host IP address.
  2. The compromised endpoint periodically checks for new files. If a new file exists, it sends a prompt to Gemini.
  3. The prompt consists of three sections:
    a. A system prompt to control Gemini’s behavior.
    b. A description of host capabilities (Windows, PowerShell, C compiler, directory listing, etc.).
    c. A reference to a file containing the goal to achieve.
  4. Gemini analyzes the prompt and responds with generated commands or scripts to achieve the goal. The LLM decides what to use and how.
  5. The host executes the generated commands and sends the output back to Gemini.
  6. Gemini evaluates whether the goal was achieved. If not, it generates new commands or selects a different approach. This loop continues, limited to 10 iterations in my case. The behavior can become unpredictable.

Let’s see how it works:

As shown, the approach works. However, using it in practice introduces several challenges:

  1. It is more flexible than traditional approaches because tools are generated dynamically. At the same time, it is less predictable and can drift into unintended directions.
  2. LLM filtering is inconsistent. It applies both to prompts and generated outputs. The same prompt can be allowed or blocked depending on context.
  3. API usage introduces limits and cost, and traffic is visible to the provider.
  4. Each API call is stateless. Full context must be included in every iteration to maintain continuity.

Join the conversation

Your email address will not be published. Required fields are marked *