Advanced SQL injection is less about the first obvious payload and more about understanding how applications store, transform, and later reuse attacker-controlled input. These notes focus on second-order SQL injection and filter bypass techniques such as character encoding, no-quote injection, and whitespace substitution.
Second-order SQL injection happens when attacker-controlled input is stored safely enough to avoid immediate breakage, then later reused in a different SQL context without proper parameterization. The payload does not need to fire during insertion. It only needs to survive long enough to execute during retrieval or update.
Why it is dangerous: the vulnerable step is often far away from the original input point, which makes the issue harder to spot through basic input testing alone.
Consider a book application where user input is inserted with real_escape_string() and later reused in an update query.
$ssn = $conn->real_escape_string($_POST['ssn']);
$book_name = $conn->real_escape_string($_POST['book_name']);
$author = $conn->real_escape_string($_POST['author']);
$sql = "INSERT INTO books (ssn, book_name, author) VALUES ('$ssn', '$book_name', '$author')";
This may stop some immediate injection attempts, but it does not solve the deeper issue: stored data is still attacker-controlled and later may be concatenated into another SQL statement.
$ssn = $_POST['ssn_' . $unique_id];
$new_book_name = $_POST['new_book_name_' . $unique_id];
$new_author = $_POST['new_author_' . $unique_id];
$update_sql = "UPDATE books SET book_name = '$new_book_name', author = '$new_author' WHERE ssn = '$ssn'; INSERT INTO logs (page) VALUES ('update.php');";
If the stored ssn contains an injected payload such as:
12345'; UPDATE books SET book_name = 'Hacked'; --
then the later update operation may execute attacker-controlled SQL when the record is edited.
Escaping functions reduce risk in some contexts, but they are not a reliable substitute for parameterized queries. They are also especially weak against second-order cases because the dangerous moment may happen later, in a completely different query shape.
The correct defense is parameterized SQL at every point where stored or fresh input is reintroduced into a query.
Applications and WAFs often block obvious patterns such as OR, AND, UNION, quotes, or literal spaces. Advanced SQLi requires adapting the payload to the parser behavior instead of assuming one stock string will always work.
Encoding can hide payload structure from weak filters while still being interpreted correctly after decoding.
Special characters can be percent-encoded so a naive filter misses them before the server decodes them.
Strings can sometimes be represented in hex rather than quoted directly.
Unicode escape forms may bypass filters that only focus on direct ASCII patterns.
Suppose the application strips keywords like OR, AND, UNION, and SELECT before building the query.
$book_name = $_GET['book_name'] ?? '';
$special_chars = array("OR", "or", "AND", "and", "UNION", "SELECT");
$book_name = str_replace($special_chars, '', $book_name);
$sql = "SELECT * FROM books WHERE book_name = '$book_name'";
A standard payload may fail, but a carefully encoded payload can still succeed if the server reconstructs it before SQL parsing. The main lesson is not the specific string, but that weak keyword removal is not equivalent to safe query construction.
If quotes are filtered or escaped, the injection may still be possible using:
CONCAT() or character constructors,The key question is always: does the SQL grammar at this position actually require a quoted string, or can another syntactic form produce the same effect?
If spaces are blocked, SQL may still parse correctly when separators are replaced with comments or alternate whitespace characters.
/**/ inline comments%09 horizontal tab%0A line feed%0D carriage return%0C form feed%A0 non-breaking space in some contextsIf the SQL parser treats the substitute as whitespace, the payload may still execute even though the filter removed normal spaces.
Consider a username filter that strips spaces and common SQL keywords:
$special_chars = array(" ", "AND", "and", "or", "OR", "UNION", "SELECT");
$username = str_replace($special_chars, '', $username);
$sql = "SELECT * FROM user WHERE username = '$username'";
If normal spaces are removed, a payload using alternate whitespace such as %0A may still parse successfully after decoding and SQL interpretation. Again, this is why blacklist filtering is brittle and parameterized queries are the real fix.
| Scenario | Bypass Idea |
|---|---|
| Keyword blocked | mixed case, inline comments, alternate syntax |
| Spaces blocked | comments or alternate whitespace characters |
| Quotes blocked | numeric contexts, functions, or quote-free expressions |
| Logical operators blocked | equivalent operators or expression rewrites |
| String literals filtered | hex, char constructors, concatenation, or encoding |