## Server-Side Security - Focus: Remote Attacker - Target the server - Goal: Compromise remote system - Possibly malicious input to remote web server: - Form fields (hidden + visible) - GET/POST parameters - Cookies - HTTP Headers ![](images/web-server-input.png) ### SQL Injection - SQL used for relational databases for - Extraction (`SELECT`) - Insertion (`INSERT INTO`) - Updating (`UPDATE`) - Deletion (`DELETE FROM`) - Problem: Mixing of code + data - SQL Queries are often generated on-the-fly with user input - Attacks: - End literal expression with `'` - Comment rest of query `-- `/`#` - Comment range `/* ... */` (two injection points required) - Leak data with `UNION` statements - Respect union-compatibility - `' UNION (SELECT 1 FROM ...)` - Add tautology: `a' OR 'a'='a`/`' OR 1#` - Column reference - *Name*‌ (e.g., `id`) - *Index* (e.g., `1`) - Guess number of columns: - 1) Try `ORDER BY ` until no error occurs - 2) Try `UNION SELECT ` until no error occurs - e.g., `x' ORDER BY 1,2 -- ` - **Schema Information** - MySQL/PostgreSQL - Contained in table `information_schema.*` - `.schemata`: contains schemata (for MySQL: databases, for PostgreSQL: schemata) - `.tables`: accessible tables - `.columns`: Accessible columns - SQLite `PRAGMA ` - `stats` - `table_info()` - Examples: - `mysql_query("SELECT 1 FROM users WHRE name='".$_GET["name"]."' ...;");` - `a' UNION SELECT table, column FROM information_schema.columns-- ` #### Drupageddon - Real-world example (2014) - Problem: Attack used Dict instead array (`['code' => 1]`) and bypassed the automatic enumeration of the array - Vulnerable line: - `foreach ($data as $i => $value)` - Bypass with `$data = ['fakeKey' => 1]` - Better: `array_values($array)`: return array values #### Blind SQL Injection - Situation: - Query does not return output but amount of rows matched or binary result (*blind*) - e.g., `OK` and `NOT OK` - Attack: Exfiltrate information from DB - **Functions**: - `MID(str, pos, len)`: Extract *len* characters from *str* starting at position *pos* - `ORD(str)`: ASCII code for first char in *str* - `LIKE`: - `%` for arbitrary amount of chars - `_` single char - `IF(condition, then, else)`: - Return *then* if condition is true, *else* otherwise - e.g., `SELECT IF(ORD(str) = 40, 1, 0) FROM ...` - `SLEEP(n)`: Sleep `n` seconds - **Approaches**: - Brute-forcing every single char: `$ O(nm) $` - Length `$ n $` - `$ m $` possible characters - Binary search: - Char to ASCII value - e.g., `ORD(str)` - Apply binary search `$ O(n\log m) $` - Reduce character set with `LIKE` - e.g., `password LIKE '%a%'` - Timing-based: - Exploit timing behavior (if database answer doesn't change) - e.g., use `IF` with `sleep()` - e.g., `IF(cond, sleep(2), 0)` - **Prevention**: - Main problem: Insecure usage of attacker-controlled data - Prepared statements - Separated code/data - Increased performance (query-planner already optimized) - `$prepared = $mysqli->prepare("INSERT INTO test(id) VALUES (?)");` - `$prepared->bind("i", $i)` (`"i"` means integer) - `$prepared->execute()` - Sanitization/escaping - Caution: Error-prone - Escaping function: `mysqli_real_escape_string()` - Database permissions (protection) - Example: - `bob' AND password LIKE 'a%' #` - `bob' AND (SELECT IF(MID(password, 1, 1) = 'a', SLEEP(1), 0) FROM users WHERE user='bob')#` #### NoSQL Injection - *Not Only SQL* - Database types: - Document-based (MongoDB, CouchDB) - Key-value (Redis, BerkeleyDB) - Graph database (Neo4J) - Mostly custom query format - e.g., `db.employees.find({lastname: "Stick"})` - e.g., Negation: `db.employees.find({name: {$ne: "Stick}})` - e.g., Regex: `db.employees.find({name: /tic/})` - e.g., Greater: `db.employees.find({age: {$gt: 30}})` - Note: Parsing GET parameters in PHP: - PHP takes last definition (e.g., GET) - `?foo[]=bla&foo[]=bar` enforces array `foo = [bar, bla]` - Attack: Inject conditions - Using the parsing behavior of PHP for HTTP parameters - e.g., `?user=bob&password[$regex]=.` - Defense: - Type enforcement (e.g., for a *string*) - PHP: `(string) $_GET['name']` - Python `str(request.GET['name'])` ![](images/nosql.png) ### Code Execution Flaws #### Command Injection - Scenario: App executes OS command directly with user input - Known problem: Data and code not separated - Example: - `os.system("htpasswd -b .htpasswd %s %s" % (username, password))` - Attack: Inject malicious parameters into bash - `cmd1; cmd2`: Execute cmd1 and cmd2 - `cmd1 && cmd2`: Execute cmd2 if cmd1 worked - `cmd1 | cmd2`: Pipe result of cmd1 into cmd2 - `cmd1 $(cmd2)`: cmd2 result to cmd1 - Problem: Command and arguments are not separated - Solutions: - Separation of command and argument - Python: `subprocess.call([...])` - Escape shell arguments: - PHP: `escapeshellarg(string $arg)` #### Path Traversal - Scenario: - PHP script reads from storage with user input or copies a certain file - e.g., `return read("downloads/" . $_GET['fn']);` - e.g., `move_uploaded_file(...)` - Use `../` to move on file system - Attack: - Leak information (`/etc/passwd`, `.htpasswd`) - Overwrite information (e.g., PHP file) - Preventions: - Sanitize path/input (focus on `.` and `/`) - Access rights ![](images/path-traversal.png) #### File Inclusion - PHP Parsing: - PHP is HTML preprocessor - Execute code between `` - Include-statements: - `include`: Include, warning if not found - `require`: Include, die if not found - Scenario: - Application code is split across multiple files - `include` call uses user input - e.g., `include($_GET['page'])` - Attack: - Include other files on server - Denial of service: Include loop (`include(index.php)`) - Code Injection: Include remote files (disabled by default) - Prevention: - Use allow-list with allowed files - Sanitize path (e.g., `basename()` resolves traversals) - Restrict directories with `open_basedir` (all files outside this directory are inaccessible) - Use mapping from site ID to include file #### Unrestricted File Upload - Scenario: App allows file upload - Attack: Upload file for remote code execution - Types: - Upload HTML to be display with JavaScript (XSS by upload) - SVG images can contain JavaScript - PHP file being executed - Flash files - `.htaccess`: Overwrite webserver configuration (`AddType` adds executable to server) - Real-life attack: GIFAR - Combination of GIF and JAR - GIF type information at beginning (bypass content sniff) - JAR information at the end (ignores first bytes) - Upload GIFAR to server and send link to uploaded file to user - Prevention: - Type checking/Content sniffing (explicit or implicit) - Images: Remove non-image content/clear meta data (using libraries) - Separate domain for upload #### Deserialization Issues - Scenario: - Non-string data often exchanged between entities by using Serialization - e.g., pickle, serialize - Property Oriented Programming (POP) attack - Idea: Chain together properties of different objects - Attacker controls properties of de-serialized object - Attacker chains together different *magic functions* - Serialization in Python - `pickle.loads()` / `pickle.dumps()` - `loads()` calls `__reduce__` - Attack example: - Server calls `pickle.loads()` on Cookie value - Use pickled object with malicious `__reduce__` function as Cookie value - Attacker sends malicious Cookie to server - e.g. `class Foo: def __reduce__(self): subprocess.call()` - Countermeasures - Avoid serialization of complete objects - Serialize using JSON - Sign Cookies sent by the server (attack can not *inject* malicious code) - Real-world attack: vBulletin 5.x - Attacker could pass code into `eval()` #### Template Injection - Template Systems: - Idea: Separate logic (controller) and rendering (view) - MVC architecture - PHP: Twig, Smarty - Python: Django/Jinja2 - Attack: - Template is combined with parameters, then rendered - Execute code on server side - Read/modify environment variables - Example: - `$twig->render("Hello {first_name}", array('first_name' => ...));` - `first_name = lambda x: ...` - Prevention: - Prohibit user-provided input in generation of templates ### XML (In)security #### XML - Well-structured markup language - Consists of elements - Elements may have attributes - Validity by Document Type Definition (DTD) - DTD defines valid elements - `` - `` - Specifies elements - Defines custom entities - *Entity*: Mapping from element to value - Example: - `` - Usage: `%age;: 32` -> `Alter: 32` - Document Type (``) - Defined by DTD - Refers to DTD (can be external file) - e.g., ` ]>` - `SYSTEM` for external entities - Even within the entity definition - `` - `` #### Attacks - Abusing XML External Entities (XXE) - Goal: Information disclosure (Confidentiality) - Attacker must control XML file (e.g., for login protocol) - Attacker includes sensitive files in `SYSTEM` - `` - Denial of Service (Availability) - Define entities recursively - *XML Billion Laughs* - XPath Injection - Scenario: Database is stored in XML - XPath Injection (attacker could inject XPath query) - Problem: Mixing code and data ![](images/09-xxe.png) ![](images/09-billion-laughs.png) ![](images/09-xpath.png) #### Countermeasures - Entity attacks: - Disable entity loader (`libxml` in PHP) - Python: `etree, xmlrpc, minidom, defusedxml` are safe - Injection attacks: - Whitelisting of characters - Use programmatic checks ### HTTP Parameter Pollution - HTTP Parameters - Series of `name=value` - Separator: `&` - Escaping (percent-encoding): - `& = ; / ? : # @ + $ ,` - Hex-value of ASCII value - e.g., `?attr=123&foo=bar` - Attack: Multiple parameters with same same - Problem: - Web server + application differ in interpretation of parameters - e.g., Result of `?a=1&a=2`? - Keep first: `a=1`? - Keep last: `a=2`? - Array: `a=[1, 2]`? - Concatenation: `a=12`? - Attacks - Problem: Multiple instances interpret the data - SQL Injection - XSS - `?page=SELECT 1,&page=2,3` - Real-world example: blogger.com - Attacker added herself in the author's list - Author was checked on first parameter - Target block was checked on second parameter - Countermeasure - Python: Double-check types of parameters (e.g., string vs. list) - General: Ensure proper encoding ### HTTP Header Injection - Attacker inserts headers into HTTP response - Problem: - Headers are concatenated with user input - e.g., modify Cookies - Insert new headers by line break - Insert malicious content with line breaks - e.g., `\nLocation: attacker.com\nFoo: bar` - **HTTP Response Splitting**: - Inject attacker-controlled response into the actual response (which is cut off) - e.g., `\n\n` - Countermeasure: - Ensure: No new line character allowed - PHP: Only one header per function call ### Server-Side Request Forgery (SSRF) - Use Case: - Preview of resources ensuring privacy for the client - e.g., Twitter shows preview of images, does not deliver original URL to user - Three parties: - Client (C) - Middle server (S) - External server (ES) - Middle server (e.g., firewall, proxy) sends request to external server (target) - Problems: - Attack external server anonymously (attacker's identity is not revealed) - Access private resources behind a firewall (on the middle server) - Deliver malicious content from the external server to client with the origin of the middle server - Possible attacks: - Server-side Request Forgery: - Client wants to attack the external server which is behind a firewall - e.g., `http://10.0.1.1:1234/...` - **Problem**: URL parsing is not consistent - DNS Rebinding - Client attacks external server - Request (with IP) must be executed twice - First time: Check if hostname is allowed - Second time: Rebind DNS to target resource - *Time-to-check-to-time-of-use* attack - Web Origin Laundering (WOL) - Middle server is acting as proxy - Malicious content is sent from attacker server to client with the origin of the middle server - May bypass the *CSP* (if host names are used) - Countermeasure: - Whitelist server - By the same component as taking the request - Due to different parsing rules - `Content-Disposition: attachment`, do not display file inline (mitigate WOL) - DNS pinning (against DNS rebinding) ![](images/09-ssrf.png) ![](images/09-wol.png) ### Execution after Redirect - Problem: Bad programming - Check permissions using PHP - If no permissions exist, set redirect header - Problem: Redirect only at end of script and not immediate (actions can be executed after setting the header) - Finish script using `die()` ![](images/09-execution.png)