雑記

いち情報系大学生

pico CTFでweb問題を解いてみる #5

 残すところあと1問。やっていきたいと思います。

Java Script Kiddie 2

https://play.picoctf.org/practice/challenge/33?category=1&page=2

Java Script Kiddieシリーズの2つ目。
Java Script Kiddie1と同様、ページにはフォームとボタンだけが設置されていて、文字を入力してsubmitボタンを押すと破損したpng画像が出てくる。

早速ソースをみてみる。

<script>
	var bytes = [];
	$.get("bytes", function(resp) {
		bytes = Array.from(resp.split(" "), x => Number(x));
	});

	function assemble_png(u_in){
		var LEN = 16;
		var key = "00000000000000000000000000000000";
		var shifter;
		if(u_in.length == key.length){
			key = u_in;
		}
		var result = [];
		for(var i = 0; i < LEN; i++){
			shifter = Number(key.slice((i*2),(i*2)+1));
			for(var j = 0; j < (bytes.length / LEN); j ++){
				result[(j * LEN) + i] = bytes[(((j + shifter) * LEN) % bytes.length) + i]
			}
		}
		while(result[result.length-1] == 0){
			result = result.slice(0,result.length-1);
		}
		document.getElementById("Area").src = "data:image/png;base64," + btoa(String.fromCharCode.apply(null, new Uint8Array(result)));
		return false;
	}
</script>

先日解いたものと共通している部分がかなり多い。変更点としては、「keyが32桁になっていること」と「assemble_png()の中のshifterの求め方」くらいで、後者について理解できれば解けそうな気がする。

といってもコードを読めば別段難しいことはなくて、変数shifterには、フォームから入力した文字列keyの i*2文字目が入ることになっているよう(つまり、keyの奇数番目の文字には意味が無いっぽい)

そこまでわかれば、前回の問題のようにhttps://jupiter.challenges.picoctf.org/problem/38421/bytesに飛んで、書いてある数字の羅列を16列に整形してからpngのファイルシグネチャを考慮しながら正しい複合キーを求めればよさそう(詳しいことはJava Script kiddy1のwriteupに書いてあります)

整形には、前回書いたコードを使い回し。

// 雑に書いてます。見辛かったらごめんなさい、
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;

int main() {
  int byte_num, count16=0;
  vector<int> splited_bytes;

  while(cin >> byte_num){
    splited_bytes.push_back(byte_num);
  } 

  for (auto it = splited_bytes.begin(); it != splited_bytes.end(); ++it){
    count16++ ;
    cout << setw(3) << *it << " ";
    if(count16  == 16){
      count = 0;
      cout << endl;
    }    
  }

}

f:id:unyamahiro:20201130120216p:plain

これによって、複合キー(奇数番目の数字を除外したもの)は

81497811[a][b][c]85315
([a][c]は2or3or4, [b]は6or7or8or9)

の36通りまで絞り込むことができた。
入力キーが32桁であることを考慮すると、

8010409070801010[a]0[b]0[c]08050301050
のように、奇数番目に適当な文字を挿入しておけばよさそう。

これで総当たりを試すと
80104090708010104080308050301050
を入力した時にpng画像でQRコードが表示された。

f:id:unyamahiro:20201130121533p:plain

これを読み込むと
picoCTF{14fb9aed341eac600d5322c198b64c87}

解けた!

あとがき

picoCTFのweb問題について一通り解き終えることができました。どうしてもわからなくてカンニングしてしまった問題も少しありましたが、思っていた以上に自力で解けた問題が多くて嬉しかったです。

はじめにCTFを解こうと思った理由としては”Webまわりの色んなコードを読みたい”というところだったのですが、正直その部分関しては...十分に達成できたとは言い難いです。"コードを読む"というよりも"知識を得る"がメインになってしまった気がします。

とはいえ、それはそれでよかったと思います。
昨日の夜に、Twitter1章:サーバサイドと仲良くなろう | ソーシャルゲームのクライアントエンジニア入門以前という記事が流れてきました。このページの「認証って何」という項目の中に、”JaWT”という問題にも登場したJWTが登場してました。JWTはweb開発とかにしか使われていない技術だと無意識に思い込んでいたのですが、ゲーム開発の現場とかでも広く使われているものだということを知りました。今回僕はWeb系の問題しか解いていませんでしたが、そこで得た知見は必ずしもwebでしか役立たない というわけではないことを改めて感じました。

楽しかったので、また別の常設ctfでweb問題探して解いてみます。