はまやんはまやんはまやん

hamayanhamayan's blog

File Library [csictf 2020]

CTFtime.org / csictf 2020 / File Library

This is my file library.
Idon't have a lot of files, but I hope you like the ones I have!
http://chall.csivit.com:30222/
Attachment: server.js

f:id:hamayanhamayan:20200725130218p:plain

奇妙なサイトに飛ばされる。
/getFile?file=ok.jsのようにok.jsとa.cppの閲覧ができるようになっている。

ok.js

console.log('Welcome to my sample javascript program!');

// Let's checkout some funny issues in JS!

[] == ![]; // -> true

false == []; // -> true
false == ![]; // -> true

console.log("b" + "a" + +"a" + "a"); // -> baNaNa

NaN === NaN; // -> false

(![] + [])[+[]] +
  (![] + [])[+!+[]] +
  ([![]] + [][[]])[+!+[] + [+[]]] +
  (![] + [])[!+[] + !+[]];
// -> 'fail'

document.all instanceof Object; // -> true
typeof document.all; // -> 'undefined'

Number.MIN_VALUE > 0; // -> true

[1, 2, 3] + [4, 5, 6]; // -> '1,2,34,5,6'

console.log('View more: https://github.com/denysdovhan/wtfjs');

a.cpp

#include <stdlib.h>
int main() {
    system("cat flag.txt");
}

ディレクトリトラバーサル

/getFile?file=ok.jsのようなURLを見せられたら、まずはディレクトリトラバーサルだろう。
a.cppにもあるようにflag.txtを探してみよう。
File type not allowedと来た。なるほど?
そういえばファイルが与えられていることを忘れていた。

fileパラメタについて3段階のチェックが入っている

  • file.includes(' ') || file.includes('/')がtrueならNG
  • allowedFileType(file)がfalseならNG
  • サイズが5文字以上なら5文字に丸められる
function allowedFileType(file) {
    const format = file.slice(file.indexOf('.') + 1);
    if (format == 'js' || format == 'ts' || format == 'c' || format == 'cpp') {
        return true;
    }
    return false;
}

色々試したけど全然分かんないぞ…ok.jsがヒントだと思うけれど…

解説見る

方針はあってたけど、高度な感じ。なるほどなぁ…サイズ確認を配列ですり抜けるのね…
/getFile?file[]=../../&file[]=../../&file[]=../../&file[]=../../&file[]=../../proc/self/cwd/flag.txt&file[]=.&file[]=jsペイロード

jsでは配列で与えられるので、実質こんな感じ。
file = ['../../', '../../', '../../', '../../', '../../proc/self/cwd/flag.txt', '.', 'js']

  • file.includes(' ') || file.includes('/')がtrueならNG
    • includeは配列なら1要素と比較されているので、'../../'!='/'なので大丈夫。
  • allowedFileType(file)がfalseならNG
    • file.indexOf('.') = 5
    • ちょうど、'.'だけの項が効いている。で、+1の要素が取ってこられるので、formatにはjsが入ることになって、trueが返る
  • サイズが5文字以上なら5文字に丸められる
    • ちょうど、5要素になることを狙って、拡張子チェックで使った、'.'と'js'を削除する

ってことでうまいこと言って、最終的には、../../,../../,../../,../../,../../proc/self/cwd/flag.txtがファイル名となる。

なぜ、/proc/self/cwd/flag.txtを狙っているかというと、Man page of PROCを参照すると、/proc/self/cwdが動いてるプロセスのカレントワーキングディレクトリへのシンボリックリンクとなってるためである。
C++での参照先は相対パスであり、カレントワーキングディレクトリの配下を探すのはそれが理由。