#3 Crawling Cipher
以下の常設CTFの問題です。
無理すぎる
(」・ω・)」うー!(/・ω・)/にゃー!encodeって知ってますか?
これがキーとなります。
とりあえず色々試してみる
とりあえず色々送信してみたが、何も起こらない。
jqueryが正しく作動してない!
これは意図的なのか時の流れのせい(13年前に作成された問題)なのかわかりません。
とりあえずソースコードを取得して、自分の環境で書き替えます。
http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
↓
https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
http
をhttps
に変えて、もう一度色々送信すると動作するようになりました。
ソースコードを見てみてみると、**(」・ω・)」うー!(/・ω・)/にゃー!**が大量発生していました。
これらは実行することができるそうなので、console.log
で出力してみました。
/ᆞωᆞ/ -0 /ᆞωᆞ/ 1 2 3 4 5 6 7 8 9 '' 'true' 'false' '[object Object]' 'undefined' -0 'a' 'b' 'c' 'd' 'e' 'f' 'n' 'o' 'r' 's' 't' 'u' '/""ω""//\\\\ω\\\\/' '"' '\\' '\\u' '\\u00' 'constructor' 'return"\\u0024\\u0028\\u0066\\u0075\\u006e\\u0063\\u0074\\u0069\\u006f\\u006e\\u0028\\u0029\\u007b\\u0024\\u0028\\u0022\\u0066\\u006f\\u0072\\u006d\\u0022\\u0029\\u002e\\u0073\\u0075\\u0062\\u006d\\u0069\\u0074\\u0028\\u0066\\u0075\\u006e\\u0063\\u0074\\u0069\\u006f\\u006e\\u0028\\u0029\\u007b\\u0076\\u0061\\u0072\\u0020\\u0074\\u003d\\u0024\\u0028\\u0027\\u0069\\u006e\\u0070\\u0075\\u0074\\u005b\\u0074\\u0079\\u0070\\u0065\\u003d\\u0022\\u0074\\u0065\\u0078\\u0074\\u0022\\u005d\\u0027\\u0029\\u002e\\u0076\\u0061\\u006c\\u0028\\u0029\\u003b\\u0076\\u0061\\u0072\\u0020\\u0070\\u003d\\u0041\\u0072\\u0072\\u0061\\u0079\\u0028\\u0037\\u0030\\u002c\\u0031\\u0035\\u0032\\u002c\\u0031\\u0039\\u0035\\u002c\\u0032\\u0038\\u0034\\u002c\\u0034\\u0037\\u0035\\u002c\\u0036\\u0031\\u0032\\u002c\\u0037\\u0039\\u0031\\u002c\\u0038\\u0039\\u0036\\u002c\\u0038\\u0031\\u0030\\u002c\\u0038\\u0035\\u0030\\u002c\\u0037\\u0033\\u0037\\u002c\\u0031\\u0033\\u0033\\u0032\\u002c\\u0031\\u0034\\u0036\\u0039\\u002c\\u0031\\u0031\\u0032\\u0030\\u002c\\u0031\\u0034\\u0037\\u0030\\u002c\\u0038\\u0033\\u0032\\u002c\\u0031\\u0037\\u0038\\u0035\\u002c\\u0032\\u0031\\u0039\\u0036\\u002c\\u0031\\u0035\\u0032\\u0030\\u002c\\u0031\\u0034\\u0038\\u0030\\u002c\\u0031\\u0034\\u0034\\u0039\\u0029\\u003b\\u0076\\u0061\\u0072\\u0020\\u0066\\u003d\\u0066\\u0061\\u006c\\u0073\\u0065\\u003b\\u0069\\u0066\\u0028\\u0070\\u002e\\u006c\\u0065\\u006e\\u0067\\u0074\\u0068\\u003d\\u003d\\u0074\\u002e\\u006c\\u0065\\u006e\\u0067\\u0074\\u0068\\u0029\\u007b\\u0066\\u003d\\u0074\\u0072\\u0075\\u0065\\u003b\\u0066\\u006f\\u0072\\u0028\\u0076\\u0061\\u0072\\u0020\\u0069\\u003d\\u0030\\u003b\\u0069\\u003c\\u0070\\u002e\\u006c\\u0065\\u006e\\u0067\\u0074\\u0068\\u003b\\u0069\\u002b\\u002b\\u0029\\u0069\\u0066\\u0028\\u0074\\u002e\\u0063\\u0068\\u0061\\u0072\\u0043\\u006f\\u0064\\u0065\\u0041\\u0074\\u0028\\u0069\\u0029\\u002a\\u0028\\u0069\\u002b\\u0031\\u0029\\u0021\\u003d\\u0070\\u005b\\u0069\\u005d\\u0029\\u0066\\u003d\\u0066\\u0061\\u006c\\u0073\\u0065\\u003b\\u0069\\u0066\\u0028\\u0066\\u0029\\u0061\\u006c\\u0065\\u0072\\u0074\\u0028\\u0022\\u0028\\u300d\\u30fb\\u03c9\\u30fb\\u0029\\u300d\\u3046\\u30fc\\u0021\\u0028\\u002f\\u30fb\\u03c9\\u30fb\\u0029\\u002f\\u306b\\u3083\\u30fc\\u0021\\u0022\\u0029\\u003b\\u007d\\u0069\\u0066\\u0028\\u0021\\u0066\\u0029\\u0061\\u006c\\u0065\\u0072\\u0074\\u0028\\u0022\\u004e\\u006f\\u0022\\u0029\\u003b\\u0072\\u0065\\u0074\\u0075\\u0072\\u006e\\u0020\\u0066\\u0061\\u006c\\u0073\\u0065\\u003b\\u007d\\u0029\\u003b\\u007d\\u0029\\u003b"' '' ƒ Function() { [native code] } -0 `$(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;});});` undefined -0 1 2 3 4 5 6 7 8 9 -0
return"\\u0024\\u0028\\u0066\\・・・
と文字コードらしき16進数が続いていたので変換プログラムを書きました。
strings = input("Unicodeに変換したい16進数を入力してください:")
split = input("区切り文字を入力してください:")
def anotherWord(a):
if a == "Y":
return int(input("何文字文切り取る必要がありますか?:"))
elif a != "n" and a != "Y":
anotherWord(input("文字コードの先頭に他の文字が存在しますか?:[Y/n]"))
else:
return 0
rm = anotherWord(input("文字コードの先頭に他の文字が存在しますか?:[Y/n]"))
s = strings.split(split)
print(s)
result = "以下が変換された文字です:"
for i in range(len(s)):
result += (chr(int(s[i][rm:],16)))
print(result)
汎用性高めるために無駄な入力を増やしました。自分の知識のみでコードを書いたので、改善できるところはたくさんあると思いますが目を瞑ってください。
実行すると以下の結果が出てきました。
以下が変換された文字です:
$(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;});});
まさかのすでにconsole.log
で出てきてました…
インデントなどを加えて、見やすくしましょう。
$(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;
});
});
このコードからわかるのは
-
t
は入力する文字 -
p.length == t.length
にならない問答無用でとalert("No")
-
p.length = 21
である - 入力する文字(t)の長さは21文字
-
-
t.charCodeAt(i) * (i + 1) != p[i]
を満たすtを入力する必要がある-
t.charCodeAt(i)
はi文字目の文字コードを表します
-
これらを満たすtを導きましょう!
p= [70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449]
t = "これを入力すればflagをゲットできます:"
for i in range(len(p)):
tmp = int(p[i]/(i+1))
t += chr(tmp)
print(t)
実行結果はFLAG_hogehoge
でした
まとめ
うにゃー!は絶対わかりません。
世代の問題ですか?