Writing malware with ChatGPT

A casual baseline for using ChatGPT to write malware.

Blog post

Requirements

  • Visual Studio 2022 Community (I used this, if you choose something else YMMV)
  • Python 3.8+ with Flask

Running

  1. Copy malware.cpp into Visual Studio and build.
  2. Start the server python3 server.py
  3. Run malware.exe
  4. Run a command curl -X POST -H "Content-Type: application/json" -d '{"agent_id": "46D9D6B3C6651E74A5E5EC1C446AA3E2", "cmd": "run", "args": "dir"}' http://localhost/tasking
  5. Get a process list, curl -X POST -H "Content-Type: application/json" -d '{"agent_id": "370BE4A3DBF3D6EB59C65FBE72C33FCF", "cmd": "ps", "args": "."}' http://localhost/tasking

Try It Out

Try prompting yourself! I got tired of asking for prompts. Some things you might want to try is to parse and store the output somewhere, update the completed status of the prompt.

    elif request.method == "POST":
        print(decode_text(request.data))

        # Add prompt to set task_complete = True, save results, etc.
        return "Thank you!", 200

Issues

  • You may notice in the getting a process list args: ".", without something here, the parsing on the agent breaks.
  • You may notice that despite having an @validate_token decorator, it's never checked.

Fixes

In todo when grabbing the next task, the ChatGPT implementation used jsonify, I changed it to,

    else:
        next_task = agent.next_task()
        json_task = next_task.to_json()
        return json_task, 200
elif request.method == "POST":

Prompts

I added the majority of print statements for debugging. These prompts are kind of lazy, there is a lot of room to tighten them up.

Server Prompts

  • Write a Python class that stores the following variables, task_id, timestamp, cmd, args, results, complete. Include a to_json method to convert the class to json.
  • Write a factory function for the Task class, where task_id is a uuid and the timestamp shows when the task was created.
  • Write a Python class that stores the following variables, agent_id, ext_ip, and timestamp.
  • Add functions to manage a FIFO task_queue
  • Add a update_agent function to update a new host_information dict variable.
  • Write a Flask API with a "todo" endpoint that takes an single agent_id parameter. Start Flask on port 80, debug should be false. If the agent_id is not in agents = {}, create it and add it to agents wehere agent_id is the key.
  • Add an POST "tasking" endpoint that creates tasks for an agent. Do not create a new agent.
  • In the to_do function, if the task_queue is empty return return jsonify({'task_id': 99})
  • Provide curl commands to test each endpoint with accurate inputs
  • Add an endpoint to get tasks in json from all agents
  • Add an endpoint to get tasks in json for an agent
  • Require "tasking" to have a valid token using a decorator
  • In “todo”, if not agent.task_queue, return a new task with a task_id of 99

Agent Prompts

  • Write an function to get content from http://localhost/todo?agent_id=new", use Win32.
  • Write a function to generate a unique id
  • Update main such GetContentFromURL("http://localhost/todo?agent_id=new") uses the output of GenerateUniqueId for the agent_id url parameter
  • Store uniqueID as a global variable
  • Write a function to gather a process list on Windows using Win32. Return the output as a string.
  • Use std::wout instead, and convert it back to std:cout.
  • Write function to start a "cmd.exe" process and return the output as a string. It should takes an "args" argument.
  • Add some error checking using GetLastError
  • Convert std::string cmd = "cmd.exe /c " + args; to a wstring
  • Write a function that parses the following string {"task_id": "d267566a-caa5-4d1a-bda9-1372c807ccd9", "cmd": "run", "args": ["dir"]}
  • Write a case statement to execute the right function based on run: ExecuteCommand, ps: GetProcessList. If task_id is 99, there is no task to complete.
  • Write a function to send the output back to localhost with the structure {"task_id": task.task_id, "results": output}. Use wininet.
  • Convert a std:string to LPCSTR.
  • Convert a std:string to LPCWSTR.
  • Write a function to parse a vector into a string.
  • Write a while loop that uses GetContentFromURL() and passes the output into ParseString() then passes the parsed string into RunTask
  • Add a sleep to the while loop
  • Write a function to parse the data below. Return the key and values for args, cmd, and task_id using regex. {"args": "", "cmd":"","task_id":99}
  • Write a check that says, if "No task to complete", continue