8946 Take#18
今回は「http://www.hackerschool.jp/hack/」の正答率が8番目に高い(2019/08/04現在)「Take#18」を解いていきたいと思います。
http://www.hackerschool.jp/hack/www.hackerschool.jp
環境
- Windows10
- Google Chrome
Take#18
Take#18にアクセスすると、下図のような「パスワード」を入力するフォームがあるページが出てくると思います。今回は、パスワードを入手しなければならないようですね。
手始めに、「突破する!」を押すとどのような動作をするのかを確認していこうと思います。
「[F12]」(もしくは、右クリックをして「検証」)を押して、デベロッパーツールを開き、「突破する!」のボタンの箇所を特定します。
デベロッパーツールが出たら、突破する!のタグがどこにあるかを確認します。上図左上にある赤枠のマウスのカーソルのようなマークをクリックして、「突破する!」をクリックします。すると、「突破する!」の箇所がハイライトされるはずです。
ここで、onclick属性に注目してみると「fnFormSubmit()」という関数が指定されていて、ボタンが押されるとこの関数を実行するようになっているようです。この関数がどのようなものなのか、確認していきましょう。
このHTML内で関数を検索するために、「fnFormSubmit()」をダブルクリックして選択した状態にし、「[Ctrl]+[F]」を押します。すると、自動的に検索バーに文字が入力されます。
この状態で「Enter」を押下すると、、、
今回のJavaScriptは結構長めですが、最終的に正解かどうかの判断をするif文をみると「ans変数とseikai変数の値が等しいか」を評価しています。
ということは、「ans」と「seikai」に何が代入されているのかが分かれば突破できます!
//パスワードチェック function fnFormSubmit(){ /**********************************************************/ var seikai = 'angou_value'; //暗号化した答え /**********************************************************/ var pass = document.form1.input_id.value; var ans = ''; var x = ''; var y = ''; //入力された文字を1文字ずつ暗号化していく for (i=0; i<=pass.length-1; i++){ x=pass.charAt(i); y=''; if (x=='a') {y='z'} if (x=='b') {y='y'} if (x=='c') {y='x'} if (x=='d') {y='w'} if (x=='e') {y='v'} if (x=='f') {y='u'} if (x=='g') {y='t'} if (x=='h') {y='s'} if (x=='i') {y='r'} if (x=='j') {y='q'} if (x=='k') {y='p'} if (x=='l') {y='o'} if (x=='m') {y='n'} if (x=='n') {y='m'} if (x=='o') {y='l'} if (x=='p') {y='k'} if (x=='q') {y='j'} if (x=='r') {y='i'} if (x=='s') {y='h'} if (x=='t') {y='g'} if (x=='u') {y='f'} if (x=='v') {y='e'} if (x=='w') {y='d'} if (x=='x') {y='c'} if (x=='y') {y='b'} if (x=='z') {y='a'} if (x==' ') {y='_'} ans+=y; } //入力された文字「ans」を暗号化し、それがangou_valueと一致したら正解 if (ans==seikai) { alert('Congratulations! 正解!!'); document.form1.submit(); } else { alert('残念!'); document.form1.input_id.value = ""; document.form1.submit(); } }
コードを上から見ていくと、一つ目のお目当てである「seikai」変数が出てきました。代入されている値は「angou_value」のようです。しかも、コメントで「暗号化した答え」と書かれていますが、これは何なんでしょう?
var seikai = 'angou_value'; //暗号化した答え
次に「pass」変数にフォームで入力した値が入るようです。
var pass = document.form1.input_id.value;
そして、「ans」変数と「x」変数、「y」変数を空文字で初期化しています。まだ、ansには値は入らないようですね。
var ans = ''; var x = ''; var y = '';
ここで、for文が出てきますがそのコメントで「入力された文字を1文字ずつ暗号化していく」と書かれています。
このコメントと先程の「暗号化した答え」というコメント、for文内の「大量のif文」から察するに、入力した文字列が暗号化されて「angou_value」になればいいようですね!
念のため、for文内で何をしているのか確認します。
//入力された文字を1文字ずつ暗号化していく for (i=0; i<=pass.length-1; i++){ x=pass.charAt(i); y=''; if (x=='a') {y='z'} if (x=='b') {y='y'} if (x=='c') {y='x'} if (x=='d') {y='w'} if (x=='e') {y='v'} if (x=='f') {y='u'} if (x=='g') {y='t'} if (x=='h') {y='s'} if (x=='i') {y='r'} if (x=='j') {y='q'} if (x=='k') {y='p'} if (x=='l') {y='o'} if (x=='m') {y='n'} if (x=='n') {y='m'} if (x=='o') {y='l'} if (x=='p') {y='k'} if (x=='q') {y='j'} if (x=='r') {y='i'} if (x=='s') {y='h'} if (x=='t') {y='g'} if (x=='u') {y='f'} if (x=='v') {y='e'} if (x=='w') {y='d'} if (x=='x') {y='c'} if (x=='y') {y='b'} if (x=='z') {y='a'} if (x==' ') {y='_'} ans+=y; }
まずfor文は「条件にマッチする間処理を繰り返す」ものです。
今回の条件は「iが0から入力された文字数-1した数以下の間繰り返し、1回実行するたびにiが1増える」というものです。
for(i=0; i<=pass.length-1; i++){ ... }
今度はfor文の内容を見ていきます。
最初に「x」変数に、入力された文字列のi番目の文字を代入しています。(※iは0から始まっていますが、プログラムでは一文字目は0番、二文字目は1番・・・N文字目はN-1番、という風に数えられています)
そして、「y」変数は空文字が代入されています。
x=pass.charAt(i);
y='';
変数への代入のあとに大量のif文があります。
ここでは、「x」変数に代入されている文字と一致する文字をif文で探し、一致したif文で「y」変数に文字を代入しています。
if (x=='a') {y='z'} if (x=='b') {y='y'} if (x=='c') {y='x'} if (x=='d') {y='w'} if (x=='e') {y='v'} if (x=='f') {y='u'} if (x=='g') {y='t'} if (x=='h') {y='s'} if (x=='i') {y='r'} if (x=='j') {y='q'} if (x=='k') {y='p'} if (x=='l') {y='o'} if (x=='m') {y='n'} if (x=='n') {y='m'} if (x=='o') {y='l'} if (x=='p') {y='k'} if (x=='q') {y='j'} if (x=='r') {y='i'} if (x=='s') {y='h'} if (x=='t') {y='g'} if (x=='u') {y='f'} if (x=='v') {y='e'} if (x=='w') {y='d'} if (x=='x') {y='c'} if (x=='y') {y='b'} if (x=='z') {y='a'} if (x==' ') {y='_'}
for文の最後では、「y」変数に代入された文字を「ans」変数に付け加えています。(ans+=y;
はans=ans+y;
と同等です)
ans+=y;
これでどういった処理が行われて「ans」変数の値が決まるかが分かったので、あとは「seikai」変数の「angou_value」を暗号化の処理とは逆の処理(復号)をするだけです。
私は今回のプログラム(一部修正)を再度通すことで暗号化前の文字列を取得しました!
<script> //拡張子を「.html」で保存して、ブラウザで表示してみください //passに入力した文字列ではなく暗号化した文字列を代入 var pass = 'angou_value'; var ans = ''; var x = ''; var y = ''; //入力された文字を1文字ずつ暗号化していく for (i=0; i<=pass.length-1; i++){ x=pass.charAt(i); y=''; if (x=='a') {y='z'} if (x=='b') {y='y'} if (x=='c') {y='x'} if (x=='d') {y='w'} if (x=='e') {y='v'} if (x=='f') {y='u'} if (x=='g') {y='t'} if (x=='h') {y='s'} if (x=='i') {y='r'} if (x=='j') {y='q'} if (x=='k') {y='p'} if (x=='l') {y='o'} if (x=='m') {y='n'} if (x=='n') {y='m'} if (x=='o') {y='l'} if (x=='p') {y='k'} if (x=='q') {y='j'} if (x=='r') {y='i'} if (x=='s') {y='h'} if (x=='t') {y='g'} if (x=='u') {y='f'} if (x=='v') {y='e'} if (x=='w') {y='d'} if (x=='x') {y='c'} if (x=='y') {y='b'} if (x=='z') {y='a'} //xと比較する文字を「 (半角スペース)」から「_」に修正 //yに代入する文字を「_」から「 (半角スペース」に修正 if (x=='_') {y=' '} ans+=y; } document.write(ans); </script>
これで答えが分かったので、突破しましょう!
できました!!
あとは、解説を読みましょう。