Injection happens when code pastes input into SQL text: the server cannot tell your characters from the visitor's, so input that closes a string literal adds SQL of its own. Trust no field, cookie or header.

This lookup concatenates its argument into SQL and, like too many applications, runs as root:
lookup() { sudo mysql -t shop -e "SELECT id, name FROM customers WHERE email = '$1'"; }
lookup "x' OR '1'='1" | tail -n 2
lookup "x' UNION SELECT user, plugin FROM mysql.user -- " | head -n 6| 8 | Hana Sato | +----+---------------+ +------------------+-----------------------+ | id | name | +------------------+-----------------------+ | root | caching_sha2_password | | shop_read | caching_sha2_password | | shop_write | caching_sha2_password |
The always-true condition returned all eight customers (the last is shown), and the UNION listed the server's accounts from a table the query never named; -- comments out the leftover quote. When a page shows no results, blind injection asks yes-or-no questions such as ' AND SUBSTR(@@version,1,1) = '9 and reads the answer from the page or from SLEEP(5) delays. Second-order injection stores a payload that fires when later code concatenates it. Escaping quotes is no cure: WHERE id = 1 OR 1=1 needs none. Keep values out of SQL text.