なんと2年ほど脆弱な状態が続いていたという事ですが、その内容は脆弱性をついたコピーができたというものらしい。
おじさんなんかは脆弱性をついたコピーというと、サミーのフラグコピーなんてのを思い出しますが、当時は小童だったので何も分からずでした。
今回は世界中で使われているサービスなので、規模もかなりでかいでしょう。
今回は関わる部分もあるし、ソースじたいは簡単に手に入るし、ソースはC言語で書かれているし、となりますと今ここで触れておかない理由がないっす。ってことで、兎にも角にもそーすに触れておきたいと思います。
使ったバージョンはこちら。ですが、安心してほしいのは1.0.1eを使っているRH系クローンを使ってる人はちゃんとアップデートして最新版のものだったらOKです。
ただし脆弱性のあるときに作ってた証明書はダメ(な可能性が高い)から作り直そう。
% ls -l /home/takeken/openssl-1.0.1f/ssl/d1_both.c -rw-r--r-- 1 takeken takeken 44390 Jan 6 22:47 /home/takeken/openssl-1.0.1f/ssl/d1_both.c % ls -l /home/takeken/openssl-1.0.1g/ssl/d1_both.c -rw-r--r-- 1 takeken takeken 44715 Apr 8 01:54 /home/takeken/openssl-1.0.1g/ssl/d1_both.c
fが脆弱なものでgが修正されたものでございです。
時刻が新しいなあ。
解説サイトをじっくり読みながら調べて書いてとしているので、いつもだけどつたない文章でごめんなさい、頭の中ではそこそこまとまったものを書きたいと思います。
解説サイトで取り上げている関数は、tls1_process_heartbeat(SSL *s)というやつでした。
まずは、どういうもんかを自分なりに調べたことをざっくりと書くと、まず基本的なことはHeartBeat messageというのをサーバ、クライアントでやりとりするらしい。
リクエストが来たら返す。という基本的なもの。ゆえに脆弱だったという事のようです。
そーすを片手に読んでほしいのだけど
これが
unsigned char *p = &s->s3->rrec.data[0], *pl; unsigned int payload; 1464 n2s(p, payload); 1465 pl = p;
これで、これなもんで。
1481 buffer = OPENSSL_malloc(1 + 2 + payload + padding); 1482 bp = buffer; 1486 s2n(payload, bp); 1487 memcpy(bp, pl, payload);
コピーされちゃいます。(memcpyのことは後の方に書いてます。)
payloadのチェックがない状態でした。
そして修正されたものには、payloadをチェックするためのunsigned int write_lengthができたようです。
これが
1471 n2s(p, payload); 1472 if (1 + 2 + payload + 16 > s->s3->rrec.length) 1473 return 0; /* silently discard per RFC 6520 sec. 4 */ 1474 pl = p;
これで、これなもんで。
1479 unsigned int write_length = 1 /* heartbeat type */ + 1480 2 /* heartbeat length */ + 1481 payload + padding; 1491 buffer = OPENSSL_malloc(write_length); 1492 bp = buffer; 1486 s2n(payload, bp); 1487 memcpy(bp, pl, payload);
ここだけ抜粋したプログラムなら同じ初級者でも分かると思う。
n2sならびにs2nは関数形式マクロでコピーの定義がされています。
全体で見ると訳がわかりませんな。でもそこは今は重要じゃないんだ!と言い聞かせる。
んで、さっきのpayloadを悪用すると、メモリ領域の64kバイトをコピーできちゃうという事らしい。
ようは盗まれるという事だね。
ていっても64k~(笑)、って思うかもしれないけど、1回で64kなんで、何回もやればもっと多いのだ。
64kバイトというと、ファミコンのスーパーマリオブラザーズが40kバイトってのを基準にするとわりとでかい(ように感じる)ね。
memcpyを忘れてたね。
名前 memcpy - メモリ領域をコピーする。 書式 #include <string.h> void *memcpy(void *dest, const void *src, size_t n); 説明 memcpy() はメモリ領域 src の先頭 n バイトを メモリ領域 dest にコピーする。 コピー元の領域と コピー先の領域が重なってはならない。重なっている場合は memmove(3) を使うこと。 返り値 memcpy() は dest へのポインタを返す。
ということです。
ネットユーザーについては問題ないかと思いきや、悪意を持ってサーバーを用意しておいて、逆にクライアントからのデータもコピーできちゃうらしい。
という事で、次回もこのネタでいきたいと思います。