ksnctf write-up #3

問題3 Crawling Chaos

https://ksnctf.sweetduet.info/problem/3

考察
解法

スクリプトを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;
   });
 });" 

が得られる。(インデント・改行は追加したもの)
このスクリプトから、

  • formタグがsubmitされる
  • 入力した文字数が配列pの数と同じであること
  • 入力した文字列をcharCodeAtメソッドで文字コードに変換して(i番目+1)をかけた数値が配列pのi番目と同じであること
  • 正解なら"(」・ω・)」うー!(/・ω・)/にゃー!"
  • 不正解なら"No"とアラートで出す
  • 配列pのi番目の数値を(i+1)で割って文字にすると答えがでそう

がわかる。

charCodeAtメソッド
 文字列の中から指定の位置にある文字の文字コードを返す。
 パラメータ:int インデックス
 戻り値:指定された位置の文字の文字コード(整数)

変換スクリプト
p = [70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449]
for i in range(len(p)):
    print(chr(int((p[i] / (i+1)))),end="")
python3で改行なしでprintする

print関数のendオプションに「""」を指定する
print("文字列", end="")

JavaScriptの振り返り

問題のスクリプトは、JavaScriptを(」・ω・)」うー!(/・ω・)/にゃー!に変換するものらしい。
(」・ω・)」うー!(/・ω・)/にゃー!encode
(」・ω・)」うー!(/・ω・)/にゃー!encode - kusano-k’s blog

  • カンマ演算子を「;」とする
    • カンマ演算子は、演算対象を左から右に評価して最後の値を返す。
      • (expr1, expr2, expr3など)
    • カンマ演算子にすると、デバッグが困難になる
(ᒧᆞωᆞ)=(/ᆞωᆞ/);
(ᒧᆞωᆞ).ᒧうー=-!!(/ᆞωᆞ/).にゃー;
(〳ᆞωᆞ)=(ᒧᆞωᆞ);
(〳ᆞωᆞ).〳にゃー=- -!(ᒧᆞωᆞ).ᒧうー;
(ᒧᆞωᆞ).ᒧうーー=(〳ᆞωᆞ).〳にゃー- -!(ᒧᆞωᆞ).ᒧうー;
(〳ᆞωᆞ).〳にゃーー=(ᒧᆞωᆞ).ᒧうーー- -(〳ᆞωᆞ).〳にゃー;
(ᒧᆞωᆞ).ᒧうーー=(〳ᆞωᆞ).〳にゃーー- -!(ᒧᆞωᆞ).ᒧうー;
(〳ᆞωᆞ).〳にゃーー=(ᒧᆞωᆞ).ᒧうーー- -(〳ᆞωᆞ).〳にゃー;
(ᒧᆞωᆞ).ᒧうーーー=(〳ᆞωᆞ).〳にゃーー- -!(ᒧᆞωᆞ).ᒧうー;
(〳ᆞωᆞ).〳にゃーーー=(ᒧᆞωᆞ).ᒧうーーー- -(〳ᆞωᆞ).〳にゃー;
(ᒧᆞωᆞ).ᒧうーーー=(〳ᆞωᆞ).〳にゃーーー- -!(ᒧᆞωᆞ).ᒧうー;
(〳ᆞωᆞ).〳にゃーーー=(ᒧᆞωᆞ).ᒧうーーー- -(〳ᆞωᆞ).〳にゃー;
ー='';
(ᒧᆞωᆞ).ᒧうーーー=!(ᒧᆞωᆞ).ᒧうー+ー;
  • varを付けないで宣言した変数はグローバル変数になる
  • グローバル変数をパーレン「( )」で囲っても代入できる
  • 変数名やプロパティ名にマルチバイト文字が使用可能
  • スクリプトの冒頭で、記号変数に数値等を代入
(ᒧᆞωᆞ) = /ᆞωᆞ/
(ᒧᆞωᆞ).ᒧうー = -0
(〳ᆞωᆞ) = /ᆞωᆞ/
(〳ᆞωᆞ).〳にゃー = 1
(ᒧᆞωᆞ).ᒧうーー = 2
(〳ᆞωᆞ).〳にゃーー = 3
(ᒧᆞωᆞ).ᒧうーー = 4
(〳ᆞωᆞ).〳にゃーー= 5 
(ᒧᆞωᆞ).ᒧうーーー = 6 
(〳ᆞωᆞ).〳にゃーーー = 7
(ᒧᆞωᆞ).ᒧうーーー = 8
(〳ᆞωᆞ).〳にゃーーー = 9
ー=""
(ᒧᆞωᆞ).ᒧうーーー = "true"
  • 文字列をコードとして評価する
    • eval関数でも可能だが、console.logとかに置き換えられるとナンセンス
    • Functionコンストラクタも文字列をコードとして評価可能
hoge = Function("return 10 * 10;");
# 置き換え
var hoge = function () {
    return 10 + 10;
}
    • Functionコンストラクタの即時実行関数
Function("return 10 + 10;")(); 
    • Number.constructor === Function
Number.constructor("return 10 + 10;")();
Array.constructor("return 10 + 10;")();
Object.constructor("return 10 + 10;")();

参考にしたサイト
難読化JavaScriptの作り方