第78回でMySQLプロトコルのハンドシェイクパケットを眺めてみましたが、
実行環境
MySQLは5.
MySQLパケットについて
実際にパケットを送る前に、
MySQLにはサーバ/
簡単に形式をすると、FF FF FF
になるのですが、FF FF FF
を最大値とし、FF FF FF
でなくなるまで繰り返し送ります。
続いてシーケンス番号が1バイトで送られてきます。最後にpayload
ハンドシェイクレスポンスを作ってみる
さて、
今回の環境ではHandshakeResponse41が問題なく使えるので、
HandshakeResponse41のペイロードに関して
MySQLの公式のドキュメントからハンドシェイクレスポンスの形式を引用したものが、
4 capability flags, CLIENT_PROTOCOL_41 always set 4 max-packet size 1 character set string[23] reserved (all [0]) string[NUL] username if capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA { lenenc-int length of auth-response string[n] auth-response } else if capabilities & CLIENT_SECURE_CONNECTION { 1 length of auth-response string[n] auth-response } else { string[NUL] auth-response } if capabilities & CLIENT_CONNECT_WITH_DB { string[NUL] database } if capabilities & CLIENT_PLUGIN_AUTH { string[NUL] auth plugin name } if capabilities & CLIENT_CONNECT_ATTRS { lenenc-int length of all key-values lenenc-str key lenenc-str value if-more data in 'length of all key-values', more keys and value pairs }
if文が入っていて少しわかりにくいですが、
Capabilityのフラグに関しては、
今回は、
4 capability flags, CLIENT_PROTOCOL_41 always set 4 max-packet size 1 character set string[23] reserved (all [0]) string[NUL] username 1 length of auth-response string[n] auth-response
というわけで、
CLIENT_SECURE_CONNECTIONの接続方法に関して
上記のペイロードの説明で
ハンドシェイクパケットのauth_
20バイトのランダムデータをサーバから送ってもらって、
SHA1(password) XOR SHA1( "サーバから送られてきた20バイトのランダムデータ" <文字列結合> SHA1( SHA1( password ) ) )
このようなパラメータを使うことで、
実際に接続を行ってみる(簡易版)
はじめは設定を簡単にして接続を行ってみようと思います。
user名がrootでパスワードが設定されていないアカウントを事前に用意します。そしてCapabilitiesにCLIENT_
require 'socket'
socket = TCPSocket.open("localhost", 3306)
data = [0x00000200, 1024 * 3, 33, "", 'root', ''].pack("VVa*Ca23Z*a")
socket.sync = true
socket.write [data.length % 256, data.length / 256, 1].pack("CvC")
socket.write data
socket.flush
p socket.readpartial(11)
さて上から順に説明をしていきますと、require 'socket'
で今回接続に利用するSocket通信用のライブラリを読み込みます。次の行ではTCP接続を行っています。
dataが今回定義するレスポンスパケットの中身です。capabilitiesに先程書いたとおりにCLIENT_
注意しないといけないのは、
実行すると、
"\a\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
こちらですが、\x00\x00\x00\x02\x00\x00\x00
となります。最初の1バイトがヘッダですが、00
なのでOKとなります。
今度はユーザ名を存在しないユーザに変更して試してみましょう。root
の部分をuser
と書き換えて実行してみると、
"G\x00\x00\x02\xFF\x15\x04#280"
こちらも最初の4バイトを取り除くと\xFF\x15\x04#280
となっています。こちらはエラーパケットと呼ばれるパケットで、ff
から始まる場合はエラーが発生しているので、
まとめ
今回は、