参戦されたみなさま、お疲れさまでしたー

また、参戦中いろいろな差し入れをいただきました。ありがとうございました。m(_ _)m

今年の問題の傾向としては、Web系の問題がなくなったため、全般的に問題の難易度が高くなっていたような気がします。
結果はともかく、限られた時間の中で知恵を絞ってさまざまな問題にチャレンジでき、非常に有意義な時間を過ごせたと思っています。
また来年もチャレンジしたいですねー
去年作った集計用スクリプトを修正して、今年の結果を集計するスクリプトを作成しました。
上位7位、上位30位、全体、チドリのジャンル別得点平均はこんな感じでした。

CTFって何?という方は、チドリサイトに掲載しているこちらの記事もあわせて読んでみてください。
今年もこちらに模範解答が掲載されています。現地点ではTriviaとForensicsの解答だけみたいですが、他のジャンルの解答もそのうち掲載されるはずです。
こんな感じで、Webサーバ上においてあるテキストファイルを表示できるwidgetを作ってみました。UTF-8のテキストファイルを表示できることを確認しています。
さきほどpublicでChumbyのサイトに登録してみたのですが、まだwidget一覧には表示されていないみたいです。

使い方はChumbyのMy Channnelに"textviewer widget"を追加したあと、"customize"で表示したいテキストファイルのURLを設定してください。

次に、テキストファイルと同じディレクトリに、次の内容のcrossdomain.xmlファイルを置いてください。
<?xml version="1.0" ?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="www.sabamiso.net" to-ports="80" />
</cross-domain-policy>
domain="www.sabamiso.net"な理由は下記の通りです。
ファイル一式はこちら。
こちらに登録されたようです。
ProxyみたいなCGIを経由してテキストを読めばcrossdomain.xmlはいらないかな?と思ったのですが、Chumbyからのリクエストだけを判別して許可するのは難しいので、crossdomain.xmlを置いてChumbyから直接読みに行く実装にしました。
あと、loader.swf(ローダ)からテキストファイルのURLをtextviewer.swf(本体)へ渡す方法が非常にダサいのですが、その理由は時間があればまた後日ということで…w
PCにUSBで接続できる温度センサを仕入れてみたので、これを使って室温を記録して、Chumbyにグラフを表示してみました。

センサと温度を取得するためのプログラムはこちらを使いました。
RRDtoolを使ってデータを蓄積・グラフの描画を行って、それをLoad Image from URLを使って表示しています。
こちらが温度の取得・蓄積を行うスクリプト。cronで5分に一回実行してます。
#!/usr/bin/perl
use strict;
use warnings;
use DateTime;
# configuration
my $rrd_path = '/path_to_rrd_file/rrd_temp.rrd';
my $rrdtool_path = '/usr/bin/rrdtool';
my $usbrh_path = '/usr/local/bin/usbrh';
# check rrd file
if (!(-f $rrd_path)) {
my $c = "$rrdtool_path create $rrd_path --start `date +%s` --step 300 DS:Temperature:GAUGE:600:U: U RRA:AVERAGE:0.5:3:2880";
system($c);
}
# get temperature & humidity
open my $usbrh, '-|' or exec $usbrh_path or die $!;
my $str = <$usbrh>;
my ($temp, $humi) = split /\s+/, $str;
my $epoch = DateTime->now(time_zone=>'local')->epoch();
my $cmd = "$rrdtool_path update $rrd_path --template Temperature $epoch:$temp";
#print $cmd . "\n";
system($cmd);
こちらがグラフを作成するスクリプト。15分に一回実行しています。
#!/usr/bin/perl use strict; use warnings; use DateTime; # configuration my $rrd_path = '/path_to_rrd_file/rrd_temp.rrd'; my $rrdtool_path = '/usr/bin/rrdtool'; my $png_path = '/var/www/yoggy/temprature/rrd_temp.png'; # check rrd file die "rrd file not found...$rrd_path" if (!(-f $rrd_path)); # create graph my $et = DateTime->now(time_zone=>'local'); my $st = $et->clone->subtract(days => 1); my $et_e = $et->epoch; my $st_e = $st->epoch; my $cmd = "LANG=C $rrdtool_path graph $png_path --title temperature --start $st_e --end $et_e --x-grid HOUR:1:DAY:1:HOUR:4:0:%H --alt-autoscale --alt-y-grid --font TITLE:18 --font UNIT:18 --font AXIS:18 --width 320 --height 240 DEF:temp=$rrd_path:Temperature:AVERAGE LINE3:temp#FF0000 >/dev/null 2>&1"; #print $cmd . "\n"; system($cmd);
…実はこの温度をChumbyで表示するというのは、はじめは先日作ったtextviewer widgetと簡単なCGIを作って表示していたのですが、 温度変化が知りたいなあと思ったので、グラフを表示してみたのでした。

OpenCVを使って、1フレームだけキャプチャするプログラムを試しに作ってみたのでメモ。
//
// ocvcap.c - camera capture program using OpenCV
//
// gcc -I/usr/local/include/opencv -L/usr/local/lib -lhighgui -lcv -lcxcore -o ocvcap ocvcap.c
//
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
int
main (int argc, char **argv)
{
CvCapture *cap = 0;
IplImage *img = 0;
if (argc == 1) {
printf("usage: cvcap camera_index save_filename\n");
exit (0);
}
int camera_idx = atoi(argv[1]);
cap = cvCreateCameraCapture (camera_idx);
if (cap == NULL) {
printf ("cvCreateCameraCapture() failed...\n");
exit (0);
}
cvSetCaptureProperty (cap, CV_CAP_PROP_FRAME_WIDTH, 640);
cvSetCaptureProperty (cap, CV_CAP_PROP_FRAME_HEIGHT, 480);
// capture image from camera
img = cvQueryFrame (cap);
// save image file...
cvSaveImage (argv[2], img);
//cvReleaseCapture(&capture);
cvReleaseImage (&img);
return (0);
}
実行はこんな感じで。
$ ./ocvcap 0 capture.jpg
cronで定期的にキャプチャしてChumbyで表示すると面白いかも?
Chumbyは通常Wi-Fi環境がないとwidgetを見ることすらできないのですが、 自作のswfをChumbyに表示したいだけならこんな感じで動かすことができます。
まずUSBメモリを用意してこんな感じでファイルを配置します。 自作のswfはhoge.swfと仮定しています。
$ ls -al total 128 drwxrwxrwx 1 yoggy yoggy 16384 6 22 01:17 ./ drwxrwxrwt@ 5 root admin 170 6 22 01:15 ../ -rwxrwxrwx 1 yoggy yoggy 62 6 22 01:13 debugchumby* -rwxrwxrwx 1 yoggy yoggy 17063 6 22 01:10 hoge.swf*
debugchumbyファイルの中身は、こんな感じのシェルスクリプトを記述しておきます。
$ cat debugchumby #!/bin/sh /usr/bin/chumbyflashplayer.x -i /mnt/usb/hoge.swf
次にこのUSBメモリをChumbyに刺して起動すると、スタートアップの画面が表示された後、 Chumbyはいきなりhoge.swfだけが再生される状態になります。
通常はChumbyを起動するとコントロールパネルのswfが再生されるのですが、 debugchumbyという名前のファイルがUSBメモリにあると、コントロールパネルが起動する前にこのファイルを実行する仕掛けが/etc/init.d/rcSに用意されています。 そこでdebugchubmyの中でむりやりhoge.swfを表示することで、 コントロールパネルを置き換えているような感じになります。
debugchumbyファイルとかの詳しい仕掛けについては、 起動時に実行される/etc/init.d/rcSの内容を参照してください。
…これでとりあえずはswfが再生できるかもしれないけど、よく考えたらChumbyはネットワークにつながってるところで使わないと、魅力が半減しちゃうような気がしないでもなかったりw
※注: 見てたところが違ってたので、下のほうに追記してます。
パッと見て何が問題か理解できなかったのでソースを見てみる。
$ svn export http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_229/ v1_8_6_229 $ svn export http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_230/ v1_8_6_230 $ diff -d -r diff -d -r v1_8_6_229 v1_8_6_230 diff -d -r v1_8_6_229/ChangeLog v1_8_6_230/ChangeLog 0a1,4 > Fri Jun 20 18:24:18 2008 Nobuyoshi Nakada <nobu@ruby-lang.org> > > * string.c (rb_str_buf_append): should infect. > diff -d -r v1_8_6_229/string.c v1_8_6_230/string.c 6c6 < $Date: 2008-06-20 15:53:16 +0900 (金, 20 6月 2008) $ --- > $Date: 2008-06-20 18:24:53 +0900 (金, 20 6月 2008) $ 781c781,783 < return str_buf_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); --- > str_buf_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); > OBJ_INFECT(str, str2); > return str; diff -d -r v1_8_6_229/version.h v1_8_6_230/version.h 5c5 < #define RUBY_PATCHLEVEL 229 --- > #define RUBY_PATCHLEVEL 230
ソースコードの中で変わっているのは、strings.cのrb_str_buf_append()の内容だけ。
OBJ_INFECT()とはなんだろ?ということで、ruby.hを見ると
#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0)
という感じ。汚染フラグを伝染させるマクロな様子。なるほど。
で、rb_str_buf_append()がどこで使われているかというと…
$ cd v1_8_6_230 $ grep rb_str_buf_append * ChangeLog: * string.c (rb_str_buf_append): should infect. ChangeLog: * string.c (rb_str_buf_append): fixed unsafe use of alloca, array.c: rb_str_buf_append(result, sep); array.c: rb_str_buf_append(result, tmp); array.c: rb_str_buf_append(str, s); error.c: rb_str_buf_append(str, klass); error.c: rb_str_buf_append(str, exc); eval.c: rb_str_buf_append(str, rb_inspect(data->klass)); eval.c: rb_str_buf_append(str, rb_inspect(v)); eval.c: rb_str_buf_append(str, rb_inspect(data->recv)); eval.c: rb_str_buf_append(str, rb_inspect(v)); file.c: rb_str_buf_append(result, sep); file.c: rb_str_buf_append(result, tmp); hash.c: rb_str_buf_append(str, str2); hash.c: rb_str_buf_append(str, str2); hash.c: rb_str_buf_append(str, i); intern.h:VALUE rb_str_buf_append _((VALUE, VALUE)); re.c: rb_str_buf_append(source, v); string.c:rb_str_buf_append(str, str2) string.c: return rb_str_buf_append(str, str2);
む、結構いろんなところで使われているのね…
とりあえず脆弱性の原因としては、$SAFE=4とかのオブジェクトの汚染モデルをあてにしているプログラムで、意図しないところで汚染フラグが外れて困ることがあるよという認識でいいのかな?
見てたところがちょっと違ってました(汗
1.8.6-p228のChangeLogを見たら
Wed Jun 18 22:25:10 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
* array.c (ary_new, rb_ary_initialize, rb_ary_store,
rb_ary_aplice, rb_ary_times): integer overflows should be
checked. based on patches from Drew Yao <ayao at apple.com>
fixed CVE-2008-2726
* string.c (rb_str_buf_append): fixed unsafe use of alloca,
which led memory corruption. based on a patch from Drew Yao
<ayao at apple.com> fixed CVE-2008-2726
* sprintf.c (rb_str_format): backported from trunk.
* intern.h: ditto.
ということみたいなので、1.8.6-p227と1.8.6-p228の差分をみると関係ありそうなのは下記のところかな?
$ svn export http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_227/ v1_8_6_227
$ svn export http://svn.ruby-lang.org/repos/ruby/tags/v1_8_6_228/ v1_8_6_228
$ diff -d -r v1_8_6_227 v1_8_6_228 | lv
・
・
・
diff -d -r v1_8_6_227/array.c v1_8_6_228/array.c
・
・
・
> #define ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE))
123c124
< if (len > 0 && len * sizeof(VALUE) <= len) {
---
> if (len > ARY_MAX_SIZE) {
296c297
< if (len > 0 && len * (long)sizeof(VALUE) <= len) {
---
> if (len > ARY_MAX_SIZE) {
360a362,364
> else if (idx >= ARY_MAX_SIZE) {
> rb_raise(rb_eIndexError, "index %ld too big", idx);
> }
369,371c373,374
< new_capa += idx;
< if (new_capa * (long)sizeof(VALUE) <= new_capa) {
< rb_raise(rb_eArgError, "index too big");
---
> else if (new_capa >= ARY_MAX_SIZE - idx) {
> new_capa = (ARY_MAX_SIZE - idx) / 2;
372a376
> new_capa += idx;
978a983,985
> if (len < 0 || len > ARY_MAX_SIZE) {
> rb_raise(rb_eIndexError, "index %ld too big", beg);
> }
2381c2388
< if (LONG_MAX/len < RARRAY(ary)->len) {
---
> if (ARY_MAX_SIZE/len < RARRAY(ary)->len) {
※lenがでかいとlen * sizeof(VALUE)とかnew_capa * (long)sizeof(VALUE)とかが負になる可能性がある
・
・
・
diff -d -r v1_8_6_227/string.c v1_8_6_228/string.c
6c6
・
・
・
782a776,778
> if (len < 0 || (capa+1) > LONG_MAX / 2) {
> rb_raise(rb_eArgError, "string sizes too big");
> }
※ rb_str_buf_append()関数の中で、
if (capa <= len) {
while (len > capa) {
capa = (capa + 1) * 2;
}
RESIZE_CAPA(str, capa);
}
とappend先のstrのバッファをリサイズしているところがあるが、
ここで先の(capa+1) > LONG_MAX / 2のチェックをしていないと
capa = (capa + 1) * 2が負になり、RESIZE_CAPA()がおかしくなる可能性。
iPhoneに期待してちょっと待ってたけど、ソフトバンクは7,280円からでemobileと比べるとちょっと割高感あるし、ドコモは期待できなさそうだしということで、iPod touchを買ってしまいましたw

EMONSTER+WMWifiRouterと組み合わせて使ってみたけど、なかなか快適。
◆ tessy [あぁー]
◆ yoggy [ひょっとして買うタイミング間違えた?(汗]