SQL Injectionを学ぶためにSQLiPuzzleというサービスを作ってみた

SQLiPuzzle

SQL Injectionについての知識が足りなかったので、ちょろっと作ってみた。まだすべての問題を用意できていないので未完成。
難易度としては初級レベルで、知っている人ならすぐに解ける。TODO: SQLインジェクションゴルフ - なんと3文字で認証回避が可能に | 徳丸浩の日記


それとHerokuでアプリを動かしたかったからというのもある。
構成はAmon2でゴリゴリ書くといった感じで、Herokuのbuildpackにはmiyagawaさんのmiyagawa/heroku-buildpack-perl · GitHubを使っている。
とりあえず軽く動かしてみたけど、悪くはない。git pushするだけでデプロイしてすぐに動くし、無料でここまでできるのは素晴らしい。

とりあえず動かしてみたので、あとでコードをGithubに置く予定。

Skype に issue 番号に反応する bot がいると捗る

"IRC に issue 番号に反応する bot がいると捗る" らしいので - @soh335 memo より

use strict;
use warnings;
use Skype::Any;
use AnyEvent::HTTP;
use JSON::XS;
use Try::Tiny;
use HTTP::Request::Common;

my $owner;
my $repos;

my $github_user;
my $github_password;

my $skype = Skype::Any->new(name => 'issue-chan');

$skype->message_received(sub {
    my ($msg) = @_;
    my @numbers = $msg->body =~ /#(\d+)/g;

    for my $number ( @numbers ) {
        my $req = GET sprintf(
            "https://api.github.com/repos/%s/%s/issues/%d",
            $owner,
            $repos,
            $number
        );
        $req->authorization_basic($github_user, $github_password);
        my %headers = map { $_ => $req->header($_) } $req->headers->header_field_names;

        my $g; $g = http_get $req->uri, headers => \%headers, sub {
            my ($body, $hdr) = @_;
            return unless $hdr->{Status} =~ /^2/;

            try {
                my $json = decode_json $body;
                $msg->chat->send_message(
                    sprintf "#%d %s %s", $json->{number}, $json->{title}, $json->{html_url}
                );
            }
            catch {
                warn $_;
            }
            finally {
                undef $g;
            };
        };
    }
});

$skype->run;

Skype::Any、ちょろっと書き直したやつを手元のリポジトリに放置しているのでひどい。
あとSkype botをうまく運用する方法とかまとめておきたいけど気力がなくて、これも放置しております。

sudoをしっかり読もう

あなたが初めてsudoコマンドを実行したときに出力されたメッセージを(読みました|覚えています)か?

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

以下の通り。

  1. 他人のプライバシーを尊重しよう
  2. 入力する前によく考えよう
  3. 「大いなる力には、大いなる責任が伴う」*1

sudoは何でもできてしまうということです。他人を傷つけてしまうかもしれないし、自分を殺してしまうかもしれない。

perl-5.18のhash randomizationについて

perl-5.18.0がリリースされました。

大きな変更点としてhash randomization(ハッシュのランダム化)が挙げられます。each(), keys(), values()の出力結果がランダムになるというものです。ちなみにprint %hash;したときもランダムになります。これによってテストがこけると言われていますが、ただテストがこけるだけなのか、そうではないとかというのが疑問だと思います。
実際にはほとんど問題ありません(テストがこけるだけかもしれません)。しかし、(ときどき)動かなくなるものも存在します。気をつけるポイントはひとつです。ハッシュはできる限りsortしてから扱うことです。

実例

Test::Difflet::is_deeply()にはhash randomizationに関するバグがありました。Data-Difflet-0.08ではすでにfixされています。

  • Data::Dumperの出力結果を比較することでデータ構造の比較を実現している
  • hash randomizationによってData::Dumperの出力結果がランダムになった
    • 配慮しているつもりだったが、SortkeysとするところをSortKeysとしていた
--- a/lib/Test/Difflet.pm
+++ b/lib/Test/Difflet.pm
@@ -41,7 +41,7 @@ sub _eq_deeply {
     my ($a, $b) = @_;
     local $Data::Dumper::Terse = 1;
     local $Data::Dumper::Indent = 0;
-    local $Data::Dumper::SortKeys = 1;
+    local $Data::Dumper::Sortkeys = 1;
     return Dumper($a) eq Dumper($b);
 }


蛇足ですが、Data::Dumperの出力がランダムになったのでデバッグするときにData::Dumperを使ってるんだよねーといった人は戸惑うかもしれません。
local $Data::Dumper::Sortkeys = 1;しておくようなsnippetを書いておくと捗りそうです。

snippet dumper
    use Data::Dumper; local $Data::Dumper::Sortkeys = 1; warn Dumper(${1:code});

特定のWi-Fiに接続したときにあることをしよう

335さんの記事(minilla を使って cocoa な xs module を書く - soh335 memo)を見て、手軽にCocoaなXS moduleが書けるようになったらしいことを知ったのでさらっと書いてみた。
akiym/Cocoa-NetworkChange · GitHub
自宅のWi-Fiに接続したらsyncしたいとか、認証するといったときに便利。

use strict;
use warnings;
use Cocoa::EventLoop;
use Cocoa::NetworkChange;

on_network_change(sub {
    my ($wlan) = @_;
    # on connected
    if ($wlan->{ssid} && $wlan->{ssid} =~ /aterm/) {
        # ...
    }
}, sub {
    # on disconnected
});

Cocoa::EventLoop->run;

メモ

  • minil buildするときにはgit addし忘れていないか確認する
  • XSUtilでいうcc_src_pathsを指定したいとき、Module::Buildではc_sourceを指定するが、.mに対応していないのでinclude_dirsとobjectsを個別に指定する

tkbctf1 writeup #2

fairy (Challenge 9)

割と解いた人が少なかった問題でした。

We need to access a thin client to get trade secret of rival company.
However the client needs to be unlocked at boot sequence. Can you unlock?
This file may help you.

中身はtcpdumpのキャプチャファイルです。

% file 250d3a31dee7f62d57ea3d17f544b5e4750e8039
250d3a31dee7f62d57ea3d17f544b5e4750e8039: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)

Wiresharkで開いてみたところ、TFTPでinitrd.gzとかを送信しているみたいです。
f:id:akiym:20130506165006p:plain
pxelinux.config/defaultにパスワードのハッシュがありました。
f:id:akiym:20130506165020p:plain

default menu.c32

label debian
	menu passwd $4$OVtcFw7z$9S2RpE0jMdbV1Z/+daXh2RGQtDM$
        kernel linux
        append initrd=initrd.gz

あとはjohn the ripperに投げるだけですが、このままの形では無理なのでうまく整形します。

use strict;
use warnings;
use utf8;
use MIME::Base64;

my $flag = '$4$OVtcFw7z$9S2RpE0jMdbV1Z/+daXh2RGQtDM$';

my ($salt, $hash) = $flag =~ /\$4\$(.+)\$(.+)\$/;
$hash = decode_base64($hash);
$hash = unpack 'H*', $hash;

print "\$SHA1p\$$salt\$$hash";
% john --format=sha1-gen --show password.john
?:goodluck

1 password hash cracked, 0 left

となるので、goodluckがflagでした。

tkbctf1 writeup

tkbctf1にikachanとして参加してきました。こういったCTFに参加するのは初めてでしたが、とても楽しめました。
運営の皆様大変お疲れ様でした。

Good Old Days (Challenge 7)

個人的にツボでした。問題文はこちら。

[ADVANCED]
I need the "Message" to continue my game but I forgot the secret command!!!
Can you get the "Message"? I remember that the "Message" was alphanumeric characters.

渡されたファイルの中身はなんとファミコンのROMでした。

% file cb0c3d0f55b9b627b831f4fbbc153846
cb0c3d0f55b9b627b831f4fbbc153846: iNES ROM dump, 2x16k PRG, 1x8k CHR, [Vert.], [SRAM]

f:id:akiym:20130506005116j:plain
キー入力ができるようになっていて、それに対して出力される文字が変化する。
f:id:akiym:20130506005224j:plain
f:id:akiym:20130506005240j:plain
おもむろにデバッガ起動。
f:id:akiym:20130506005811j:plain
ブレークポイントを設定、上方向キーを入力。
f:id:akiym:20130506005838j:plain
f:id:akiym:20130506005906j:plain
上方向キーを入力した場合、0xC9でXORされていますね。すべてのキーで調べたところ、

A: 0x36でXOR
B: 0x5CでXOR
↑: 0xC9でXOR
↓: 0xA3でXOR
←: 左ローテート
→: 右ローテート

となっていることがわかりました。
$6000-$6007が順番にキーの入力によって変わるみたいですね。
f:id:akiym:20130506010239j:plain
キー入力後:
f:id:akiym:20130506005347j:plain
大体のことは分かったので、ちょろっとスクリプトを書きます。条件として、メッセージは英数字なのである程度の見当はつくはずです。

use strict;
use warnings;
use utf8;

my %control = (
    a     => sub { $_[0] ^ 0x36 },
    b     => sub { $_[0] ^ 0x5c },
    up    => sub { $_[0] ^ 0xc9 },
    down  => sub { $_[0] ^ 0xa3 },
    left  => sub { $_[0] << 1 },
    right => sub { $_[0] >> 1 },
);

for my $c (0xbe, 0x60, 0xa4, 0xa5, 0x88, 0x64, 0x03, 0x6a) {
    for my $key (keys %control) {
        my $output = chr($control{$key}->($c));
        if ($output =~ /^[A-Za-z0-9]$/) {
            print "$key\t: $output\n";
        }
    }
    print "\n";
}

実行すると、いくつか候補が出てくるのでいい感じに組み合わせると "w0RlD256" がflagだとわかります。
f:id:akiym:20130506010152j:plain