Hatena::ブログ(Diary)

風柳メモ このページをアンテナに追加 RSSフィード Twitter

2015-01-28

脆弱性案件はかわいいGHOSTの夢を見るか?

glibcのgethostbyname系関数にバッファオーバーフローを引き起こす重大な脆弱性(CVE-2015-0235)が発見されたとして騒ぎになっている。

The Laws of Vulnerabilities: The GHOST Vulnerab... | Qualys Community

Qualys Security Advisory CVE-2015-0235

glibc の脆弱性 CVE-2015-0235(通称:GHOST)についてまとめてみた - piyolog

glibcのgethostbyname関数に存在するCVE-2015-0235(GHOST)脆弱性について - ブログ - ワルブリックス株式会社

JVNVU#99234709: glibc ライブラリにバッファオーバーフローの脆弱性

glibc の脆弱性対策について(CVE-2015-0235):IPA 独立行政法人 情報処理推進機構

こちらの記事には、RedHat Enterprise Linux・CentOS・Debian GNU/Linux等の対処方法も書かれている


脆弱性の概要

glibcは libcのGNUバージョンです。libcはアプリケーションではなく、事実上全てのアプリケーションが利用しているライブラリです。OSの中ではカーネルに次いで重要な部分と言えます。Linuxシステムでは例外なく glibcが使われています。


この glibcに含まれる gethostbyname系関数の実装に 2000年頃から存在したバグが今になって発見され、CVE-2015-0235 通称 GHOSTと命名されました。ネットワークで何らかの通信を行うアプリケーションは必ずこの関数を使用します。

glibcのgethostbyname関数に存在するCVE-2015-0235(GHOST)脆弱性について - ブログ - ワルブリックス株式会社

今回発見されたglibcの問題は、攻撃者がリモートから細工されたホスト名文字列を(例えばURLのホスト名部分などに埋め込んで)与えることによって、アプリケーション側のメモリを数バイト上書きできてしまうことです。

実際に、Exim(メールサーバ)に対して攻撃を行い任意コードの実行が出来る実証コードを作成できたそうです。32bit/64bitの両方が攻略可能で、CPUの不正命令実行防止機構(ASLR, PIE, and NX)は役に立たないとのこと。

glibcのgethostbyname関数に存在するCVE-2015-0235(GHOST)脆弱性について - ブログ - ワルブリックス株式会社

ということで、少なくともLinuxを用いている場合には*1早々に確認の上、必要に応じて対応しなければならない。


……のだが。



え、これは……?

「GHOST」という通称(GetHOSTbynameに由来)もさることながら

GHOST vulnerability

The Laws of Vulnerabilities: The GHOST Vulnerab... | Qualys Community

用意されたこのアイコンのせいで、事態の深刻さと比較して、どうにも危機感が薄まってしまうのは否めない。



これは孔明の罠か?……いやいや、惑わされてはならない。きちんと確認の上、対応しなければ。


脆弱性の確認方法

基本的には、

Qualys Security Advisory CVE-2015-0235

中にある、GHOST.cをコンパイル・実行すると、"vulnerable"か"not vulnerable"か(実行したシステムが脆弱か否か)が表示されるので、"vulnerable"だった場合には対応が必要となる。


ただ、自分のような英弱には、"vulnerable"という単語を見て、即座に「危険だ!」と判断することは困難である。

そこで、脆弱性があった場合の結果を目立たせるように簡単なパッチをあててみた。


ghost.c
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define CANARY "in_the_coal_mine"

struct {
  char buffer[1024];
  char canary[sizeof(CANARY)];
} temp = { "buffer", CANARY };

void ghost(void) {
  int a, b=0, c=10; for (; (a="!nBACAAUBJBPAOANAQALAFBFBCAJAFDDDBCHATBIACAFMGAESFAKCAAHACCEGADBDBAEBLMGCRANCBHBBE"[b++]);) for(;64 < a--;) putchar((++c == 42) ? (c-=32) : (32^(b&1)));
  puts("GHOST IN THE SHELL\n");
}

int main(void) {
  struct hostent resbuf;
  struct hostent *result;
  int herrno;
  int retval;

  /*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/
  size_t len = sizeof(temp.buffer) - 16*sizeof(unsigned char) - 2*sizeof(char *) - 1;
  char name[sizeof(temp.buffer)];
  memset(name, '0', len);
  name[len] = '\0';

  retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result, &herrno);

  if (strcmp(temp.canary, CANARY) != 0) {
    //puts("vulnerable");
    ghost();
    exit(EXIT_SUCCESS);
  }
  if (retval == ERANGE) {
    puts("not vulnerable");
    exit(EXIT_SUCCESS);
  }
  puts("should not happen");
  exit(EXIT_FAILURE);
}
CVE-2015-0235_GHOST/ghost.c at develop ? furyutei/CVE-2015-0235_GHOST ? GitHub

これを使用しているシステムでコンパイルして

$ gcc -o ghostT ghost.c

実行すると、該当する脆弱性がある場合には、

$ ./ghost

              !! !!! !
           !!          !!
         !               !
        !                 !
       !      !!      !!   !
      !      !!!!    !!!!  !!!
      !                    !!
      !   !      !!!!!!!!!!!!!
     !     !!!!!!!!!!!!!!!!!!!
    !           !!! !        !
 !!!     !!!!!!! !!!!  !!!!  !
   !!            !!!!!!!!!!!!!
     !!!                  !
         !!!  !!!!!!!!  !!     GHOST IN THE SHELL

$ 

このように一目でわかるので、迅速な対応が可能になると思われる。適宜活用されたし。

などと、まじめに対応するつもりでもついついネタに走りたくなってしまうので、脆弱性案件にかわいい通称やアイコンはよくない。


追記:GitHubにも登録

mholzinger/CVE-2015-0235_GHOST ? GitHub

をForkさせてもらい、

furyutei/CVE-2015-0235_GHOST at develop ? GitHub

上のファイルを読み込んで実行できるようになった。

wget で実行
$ wget -q -O - "https://raw.githubusercontent.com/furyutei/CVE-2015-0235_GHOST/develop/build_aa.sh" | bash
not vulnerable
curl で実行
$ curl -skL "https://raw.githubusercontent.com/furyutei/CVE-2015-0235_GHOST/develop/build_aa.sh" | bash
not vulnerable

*1:GNU glibcの問題なので、Linux以外でも影響する場合はある

2015-01-20

mountしたWindows7上のPHPファイルが実行できない?

Linux (CentOS 6.6) で、Windows 7 上のフォルダを mount したとき、Linux 上からそのフォルダ下にある PHP ファイルを実行しようとすると、エラーになってしまう……。

同じフォルダに置いた Python や Ruby 等のスクリプトについては、問題なく実行できる。


今のところ原因が全くわからないので、ご存じの方は教えてほしい。



解決編

改めて検索してみたら、解決策があった。

Add 'noserverino' option, and the problem is settled.

windows - PHP crazy behavior on mount - Super User
[user@linuxhost ~]$ sudo mount -t cifs "//win7host/src" /mnt/src -o username=user,password=pass,uid=500,gid=500,file_mode=0755,dir_mode=0755,noserverino

This doesn't sound like a PHP problem at all. My best guess is that you have a 32/64-bit mismatch here. And PHP doesn't currently support 64-bit inodes.

PHP :: Bug #50150 :: stat() / lstat() does not work on a mounted cifs

使用しているPHPのバージョンが64ビット inode をサポートしていないので、ホスト側(Windows側)が64ビット版の場合にこの問題が起こるらしい。

Inode Numbers

When Unix Extensions are enabled, we use the actual inode number provided by the server in response to the POSIX calls as an inode number.

When Unix Extensions are disabled and "serverino" mount option is enabled there is no way to get the server inode number. The client typically maps the server-assigned "UniqueID" onto an inode number.

Note that the UniqueID is a different value from the server inode number. The UniqueID value is unique over the scope of the entire server and is often greater than 2 power 32. This value often makes programs that are not compiled with LFS (Large File Support), to trigger a glibc EOVERFLOW error as this won't fit in the target structure field. It is strongly recommended to compile your programs with LFS support (i.e. with -D_FILE_OFFSET_BITS=64) to prevent this problem. You can also use "noserverino" mount option to generate inode numbers smaller than 2 power 32 on the client. But you may not be able to detect hardlinks properly.

mount.cifs(8) - Linux man page

なお、64ビット環境のLinuxからmountした場合には、noserverino オプションをつけなくても動作した。




環境

[user@linuxhost ~]$ # === OS バージョン確認
[user@linuxhost ~]$ uname -a
Linux linuxhost.localdomain 2.6.32-504.el6.i686 #1 SMP Wed Oct 15 03:02:07 UTC 2014 i686 i686 i386 GNU/Linux
[user@linuxhost ~]$ cat /etc/redhat-release
CentOS release 6.6 (Final)
[user@linuxhost ~]$ # === PHP バージョン確認
[user@linuxhost ~]$ php -v
PHP 5.4.28 (cli) (built: May  2 2014 18:40:44)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies

不具合発生手順

[user@linuxhost ~]$ # === Windows7 上のフォルダを /mnt/src に mount
[user@linuxhost ~]$ sudo mount -t cifs "//win7host/src" /mnt/src -o username=user,password=pass,uid=500,gid=500,file_mode=0755,dir_mode=0755
[user@linuxhost ~]$ # === /mnt/src に移動
[user@linuxhost ~]$ cd /mnt/src
[user@linuxhost src]$ # === 簡単なPHPファイル作成
[user@linuxhost src]$ echo "<?php echo(\"TEST\n\");" > ./test.php
[user@linuxhost src]$ cat ./test.php
<?php echo("TEST\n");
[user@linuxhost src]$ # === 実行するとエラー
[user@linuxhost src]$ php ./test.php
PHP Fatal error:  Unknown: Failed opening required './test.php' (include_path='.:/usr/share/pear:/usr/share/php') in Unknown on line 0
[user@linuxhost src]$ # === リントでも Warning とエラー
[user@linuxhost src]$ php -l ./test.php
PHP Warning:  Unknown: Failed opening './test.php' for inclusion (include_path='.:/usr/share/pear:/usr/share/php') in Unknown on line 0
Errors parsing ./test.php

なお、上記で作成した /mnt/src/test.php を include() することは出来るので、ますます謎。


[user@linuxhost ~]$ # === mount ディレクトリ以外に移動
[user@linuxhost ~]$ cd ~
[user@linuxhost ~]$ # === /mnt/src/test.php を include() するPHPファイル作成
[user@linuxhost ~]$ echo "<?php include('/mnt/src/test.php');" > ./call_test.php
[user@linuxhost ~]$ cat ./call_test.php
<?php include('/mnt/src/test.php');
[user@linuxhost ~]$ # === ちゃんと実行される
[user@linuxhost ~]$ php ./call_test.php
TEST

2014-12-28

【twSearchFirstTweet】Twitterでキーワードを含む最初のツイートを検索するユーザースクリプトを試作

公式ウェブ版Twitter上で、特定のキーワードを含む最初のツイートが検索できれば、パクツイの元ネタ探しなんかのときに楽かな、と思って作ってみた。

ブックマークレット版はこちら

ダウンロード(GitHubにて公開

【twSearchFirstTweet】Twitterでキーワードを含む最初のツイートを検索するユーザースクリプト

furyutei/twSearchFirstTweet ? GitHub

インストール

Firefox + Greasemonkey
  1. 上記のダウンロードリンクをクリックし、指示に従ってインストール。
Google Chrome + Tampermonkey
  1. 上記のダウンロードリンクをクリックし、指示に従ってインストール。
その他ブラウザ

(未確認)


使い方

ウェブ版Twitterを表示すると、上部にある検索フォームの右側に、虫眼鏡アイコンが追加されている。

検索フォーム中にキーワードを入れるか、もしくは、タイムライン中の語句を範囲選択した状態でこのアイコンをクリックすると、別にタブ/ウィンドウが開いて検索を開始。

f:id:furyu-tei:20141228142409j:image

サンプルに使用したツイートはこちら

f:id:furyu-tei:20141228142410j:image

f:id:furyu-tei:20141228142412j:image

サンプルでヒットしたツイートはこちら

経緯など

などとつぶやいていたところ、GM_K3さん(@)に

と教えて頂く。


実際にno titleを試してみて、おーっ、これは使える、と思っていたところへ、さらに、

という情報が。

なんと、Twitterの since/until 演算子は、

since:2011-03-11_14:46:00_JST until:2011-03-11_14:47:00_JST

のように、日付だけじゃなく、時刻とタイムゾーン(JST・GMT等)も指定できるとか。


「あれ、これ、ユーザースクリプトでもなんとかなるんじゃ」と思ってしまったので、作ってみた次第。


ブックマークレット版

最古ツイート検索 - Hatena::Let


注意

うまく検索にかからないケースもあるようなので(意図的な調整かインデックス漏れなのかは不明)信頼性は高くなく、参考程度にしか使えないかも。


参考サイト

Twitter公式・ユーザーの最初のツイートを検索

Discover your first Tweet

First Tweet - Who Said It First on Twitter

no title

一度検索されたキーワードはサーバー上に残る模様、二度目からは瞬時に表示される。

2014-12-27

Google ChromeへのTampermonkeyのインストールと基本的な使い方

Tampermonkeyは、ユーザースクリプト(特定のウェブサイト(ページ)において表示や機能の拡張等を行うためのスクリプトの総称、FirefoxにおけるGreasemonkey拡張用スクリプトの類)をGoogle Chrome等のブラウザでも使用できるようにするための拡張。

ここでは、Google Chromeへのインストールから基本的な使い方までを示す。

Tampermonkey拡張のインストール

Chrome ウェブストアからインストール

Tampermonkey - Chrome Web Store

f:id:furyu-tei:20141227004908j:image

インストールが完了すると、右上にアイコンが追加される。

f:id:furyu-tei:20141227004909j:image


ユーザースクリプトのインストール

ユーザースクリプトを配布しているページを開き、インストール用のリンクをクリック。

f:id:furyu-tei:20141227004911j:image

Tampermonkeyのインストールタブが開くので、[インストール]ボタンをクリック。

f:id:furyu-tei:20141227004910j:image

インストールタブが閉じられたら、インストール完了

特に完了した旨の通知などはないので、最初は戸惑ってしまうかも……。


ユーザースクリプトの動作確認

インストールしたユーザースクリプトが対象としているページを開き、右上のTampermonkeyのアイコンをクリックして、当該スクリプト名の前に緑色の丸数字が表示されていれば動作中。

f:id:furyu-tei:20141227004912j:image

赤丸がついているものは停止中、丸印をクリックすることで有効/無効を切り替え可能。


その他

設定確認・変更など

右上のTampermonkeyアイコンクリック→ダッシュボードをクリックで開くダッシュボードから、インストールされているユーザースクリプトの確認や有効/無効の切替、アンインストール、その他各種設定を実施できる。

f:id:furyu-tei:20141227004913j:image

2014-12-26

Twitterからのクリスマスプレゼントが酷かった件

クリスマスイブあたり?から、公式のウェブ版Twitterでの謎の挙動(不具合?仕様変更?)に悩まされていた。その状況と対策などをメモしておく。


追記

2015/01/09現在、対応されたものと思われる。


現象

不具合と認識している現象は以下のようなもの。


【その1】テキストの範囲選択(コピー)ができない?

もしかするとコピペによるパクツイ対策なのか?と思わなくもないけれど、ふつうに興味があったりわからなかったりする単語も選択して検索したりがやりにくいので困る。


なお、

  • 範囲選択した後、マウスの左ボタンを押したまま、Ctrl+Cを押すとコピー可能。
  • 同様の状態で、右クリックしてコンテキストメニューからコピーや検索を選択することも可能。
  • 対象となるツイート本文(p.js-tweet-textのテキスト部分)から外れた位置で左ボタンを離すとクリック扱いにはならず、選択も解除されない。

等で対処はできるため、もしコピペ(パクツイ)対策だったとしても、お粗末に過ぎる。


【その2】個別ツイート表示の際、下までスクロールできないことがある

なお、画像を含まない場合でも、リプライが付くなどして縦に長くなっている場合には同様の現象が発生する模様


サポートへの問い合わせも一苦労


その上、問い合わせに対する自動返信メールがまたひどくて……


自動返信にてご連絡しております。プロフィール設定に関する問題は、以下トピック別のよくある質問をご覧ください。

 :

 :※中略(つらつらと、サイト上のよくある質問のトラブルシューティング用リンク等が並んでいる)

 :

もしこちらのメール内容にて問題が解決された場合、このメールにご返信いただく必要はありません。問題が解決しない場合は、詳細とともにご返信ください。担当が対応いたします。


前に問い合わせしたときにも同様のことがあったのを忘れていて、さっきまで返信していなかった……


とりあえず、自前で暫定的に対策

現時点(2014/12/26 19時)でも現象は発生している。

暫定対策用に、ブックマークレット(その1のみ対応)とユーザースクリプト(その1と2の両方対応)を作成してみた。