web-dev-qa-db-ja.com

顧客のサイトに大きなmysqlインジェクション攻撃があり、そこから学びたい

友達のオンラインストアを作りました。

私は、データベースエラーが発生したときにいつでもメールで通知するシステムを作成しました。これにより、コードにバグがある場合、それを特定して修正できます。電子メールには、失敗したクエリ、渡されたデータ、セッションデータなどの詳細が含まれています。

今朝の3:05に5分間で約120通のメールが届きました。データベースエラーの場合、何が起こっているのかを見ると、それがmysqlインジェクション攻撃であることがすぐにわかります。攻撃者が試みた一連のことを調べた後、渡そうとしていたSQLコマンドの一部が実際に何を実行するのか疑問に思いました。

データベース全体とサイト上のファイルを調べたところ、何も害されたり、削除されたり、変更されたりしていないことがほぼ99%確信しています。これらのことを防ぐ方法を知るのに十分なPHPの知識があることを知ってうれしく思います。

私の質問は、以下のmysqlコマンドのうち、攻撃者が何をしようとしたのですか?

 or 1=convert(int,(select cast(Char(114)+Char(51)+Char(100)+Char(109)+Char(48)+Char(118)+Char(51)+Char(95)+Char(104)+Char(118)+Char(106)+Char(95)+Char(105)+Char(110)+Char(106)+Char(101)+Char(99)+Char(116)+Char(105)+Char(111)+Char(110) as nvarchar(4000))))--

; if (1=1) waitfor delay \'00:00:07\'--

union all select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null--

999999.9 union all select 0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536--

leachiancs\' and \'x\'=\'x

情報をありがとう。

詳細

すべての攻撃に対して実行されたクエリは単純でした

SELECT * FROM tableName WHERE $phpVar AND price!='sold' ORDER BY id DESC

$ phpVarは、$ _ GETエントリがacceptedTerms配列の用語と一致するかどうかに基づいて入力されます。

したがって、実行中でエラーを返していたリテラルクエリは

SELECT * FROM tableName WHERE AND price!='sold' ORDER BY id DESC

それがフォローを投げたものです

 Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND price!='sold' ORDER BY id DESC' at line 1
9
Ryan

DBが引用されたクエリを実行した(エラーレポートをスローした)だけの事実は、あなたがdo PHPコードにインジェクションの脆弱性があることを意味します。DBを検査するいくつかの方法に注意してください。テーブル構造は、DBがエラーをスローしてHTMLページが壊れるまで、異なるパラメーターで複数のクエリを実行することを含みます。つまり、失敗したクエリは、実行されたすべてのクエリのほんの一部にすぎません。

5つのクエリがあります。

1)「または1 = 1」ステートメントを効果的に追加することにより、以前のすべての制限的なWHEREステートメントを無効にします。

2)別の遅延クエリを追加して、SQLサーバーDBに対するDOS攻撃をチェックします。

3)DBテーブルの列数を検査します。成功したクエリと失敗したクエリ間の変更時のnullの数は、攻撃者が探す1つです。

4)ユーザー認証テーブルについても同様です。存在しない可能性のあるIDでクエリを終了し、列の数を調べます。 null-sはHEX値に置き換えられます。

5)巧妙に細工された$ userをクエリに挿入することによる認証チェックの誤解PHPのような文字列

"SELECT ... WHERE ... AND name = '" + $ user + "'"

(一重引用符と二重引用符の正確なシーケンスに注意してください)ユーザー 'leachiancs'は、以前の調査で実際に取得された可能性があります。

クエリ(1)〜(4)は、本来意図された残りのクエリを無効にし、LIMITまたは他の検証WHERE構文を無効にするために、SQLコメントを最後に運びます。

ここでの主なレッスンは、パラメーター化されたクエリのみを使用し、構文内のすべての可能なバージョンと癖のためにエスケープする適切なDB + PHPの汚い作業のすべてを再現しようとするのではありません。

11
Van Jone

2つのクエリを "デコード"するのが楽しいので、PHP:pで次のように実行しました。

1)or 1=convert(int,(select cast(Char(114)+Char(51)+Char(100)+Char(109)+Char(48)+Char(118)+Char(51)+Char(95)+Char(104)+Char(118)+Char(106)+Char(95)+Char(105)+Char(110)+Char(106)+Char(101)+Char(99)+Char(116)+Char(105)+Char(111)+Char(110) as nvarchar(4000))))--

それでは、このコードを変数にコピーすることから始めましょう。

_$str = 'Char(114)+Char(51)+Char(100)+Char(109)+Char(48)+Char(118)+Char(51)+Char(95)+Char(104)+Char(118)+Char(106)+Char(95)+Char(105)+Char(110)+Char(106)+Char(101)+Char(99)+Char(116)+Char(105)+Char(111)+Char(110)';
preg_match_all('/\d+/', $str, $m); // Some regex Fu to get the numbers
$sql = implode('', array_map(function($v){return chr($v);}, $m[0])); // converting the numbers to letters
echo $sql; // output
_

これは私にr3dm0v3_hvj_injectionを与え、そして mysql変換とキャスト構文をチェックする の後でここではめちゃくちゃになっているようですが、私は違います確かに、しかしこれは基本的に難読化方法であり、その意図は_or 1=1_で終わることでした。


2); if (1=1) waitfor delay \'00:00:07\'--

まあ_;_はステートメントの終わりを宣言し、残りは 時間ベースの攻撃 のようです。 phpのmysql apiは2つのクエリを同時に実行できないため、これは役に立たないようです。 _--_残りのクエリにコメントを付けます。


3)_union all select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null--_

役に立たないようですが、nullの数が列の数と一致しない場合にエラーがスローされるため、列の数を決定できます。


4)_999999.9 union all select 0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536--_

さて、これらの16進変数を変数にコピーして、php-fuを実行してみましょう。

_$str = '0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536,0x31303235343830303536';

$result = implode(',', array_map('hex2str', explode(',', str_replace('0x', '', $str)))); // PHP-Fu
echo $result;// output

// function hex to ascii
function hex2str($v){
    $r = '';$l = strlen($v)-1;
    for($i=0;$i <= $l;$i+=2){
        $r .= chr(hexdec($v[$i].$v[$i+1]));
    }
    return $r;
}
_

これは私に与えました:_1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056,1025480056_

これは奇妙ですが、すべて同じなので、16進数から文字列に再変換しましょう。

_echo hex2str('1025480056');
_

出力は_%HV_であり、通常の16進エディターでは、他に2つのobscure文字があります。

さて、目的は攻撃と同じかもしれないと思います#3難読化されているだけです。


5)_leachiancs\' and \'x\'=\'x_

単純な_where a=b and x=x_クエリ。


結論:

Le wildr3dm0v3_hvj_injectionおよび%HVが表示され、5分以内に120通のメールが送信されますIこれは、この攻撃が 自動化されたSQLiツールHavij で実行された証拠であることを強く疑っています。

防止:

[〜#〜] pdo [〜#〜] または MySQLi準備されたステートメント とともに使用します。

10
HamZa

これらのことを防ぐ方法を知るのに十分なPHPの知識があることを知ってうれしく思います。

これは、この事件を取り除くために非常に危険な考え方です。

攻撃者がデータを削除していないように見えても、必要なデータがread読み取られなかったわけではありません。そして、データベースエラーを引き起こした入力を入力できたという事実は、あなたが知らない実際にこれらのことを防ぐ方法を知っているという証拠を非難します- 準備されたステートメントとパラメーター化されたクエリ は、それさえも妨げていただろう。

提供されたクエリ自体については、ほとんどの場合、そもそもSQLインジェクションの脆弱性を見つけようとする試みのようです。

6
Stephen Touset

攻撃者は発見した脆弱性を利用して、どのような攻撃が可能であるかを調査しようとしたようです。

とにかく;レッスンは常に同じです。パラメーター化されたクエリを使用します。 データを引用してエスケープすることを忘れないようにする必要がある場合は、間違っています。

典型的なSQLインジェクション攻撃のしくみについて詳しく知りたい場合は、このタイプの攻撃に通常使用されるburp suiteなどの自動化ツールを調べてください。

3
tylerl