ブログ未満のなにか

ブログなのか誰にも分からない

Midnight Sun CTF 2019 Quals writeup

はじめに

Gissa2、 Hfsipc、 Hfs-dosを解いた。 どれも良い問題だったと思う。

Gissa2

stack overflowがあり、 canaryがないのでropができる。 しかしseccomp filterによってシステムコールに制限がかかっている。 設定されるフィルターは以下の通りで、 open/openat/ execve/execeatが塞がれておりフラグを開いたりシェルを立ち上げることができない。

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x01 0x00 0xc000003e  if (A == ARCH_X86_64) goto 0003
 0002: 0x06 0x00 0x00 0x00000000  return KILL
 0003: 0x20 0x00 0x00 0x00000000  A = sys_number
 0004: 0x15 0x00 0x01 0x00000002  if (A != open) goto 0006
 0005: 0x06 0x00 0x00 0x00000000  return KILL
 0006: 0x15 0x00 0x01 0x00000038  if (A != clone) goto 0008
 0007: 0x06 0x00 0x00 0x00000000  return KILL
 0008: 0x15 0x00 0x01 0x00000039  if (A != fork) goto 0010
 0009: 0x06 0x00 0x00 0x00000000  return KILL
 0010: 0x15 0x00 0x01 0x0000003a  if (A != vfork) goto 0012
 0011: 0x06 0x00 0x00 0x00000000  return KILL
 0012: 0x15 0x00 0x01 0x0000003b  if (A != execve) goto 0014
 0013: 0x06 0x00 0x00 0x00000000  return KILL
 0014: 0x15 0x00 0x01 0x00000055  if (A != creat) goto 0016
 0015: 0x06 0x00 0x00 0x00000000  return KILL
 0016: 0x15 0x00 0x01 0x00000101  if (A != openat) goto 0018
 0017: 0x06 0x00 0x00 0x00000000  return KILL
 0018: 0x15 0x00 0x01 0x00000142  if (A != execveat) goto 0020
 0019: 0x06 0x00 0x00 0x00000000  return KILL
 0020: 0x06 0x00 0x00 0x7fff0000  return ALLOW

フィルターをバイパスする方法は単純でx32の方のシステムコールを呼ぶ。 システムコールを呼ぶ際に設定するシステムコール番号を+0x40000000すると、 x32として扱われる。 x32でopenを呼ぶ場合は、 システムコール番号は2+0x40000000で良い。 この時上記のseccomp filterでのsys_numberの制限に引っかかることはない。

x64におけるx32でのシステムコールについては下記のリンクに詳細がある。

RFD: x32 ABI system call numbers [LWN.net]

exploit

システムコールの制限は回避可能なので、 フラグを開いて中身を読むだけである。 Midnight Sun CTF 2019 Quals Gissa2 · GitHub

Hfsipc

Linuxのkernel exploit。 脆弱なLKMがロードされているので、 これを攻略する。 ioctlで諸々の操作ができ、 kernel heap上にオブジェクトを作ったり破棄したり編集したりできる。 扱うオブジェクトの構造は以下のようになっていた。 どのオブジェクトを操作するのかをkeyで指定する。 bufは、 オブジェクトを作成するときに指定するサイズで確保したkmalloc()の返り値が入る。 sizeにそのサイズが入る。

struct obj {
    long key;
    char* buf;
    long size;
};

ioctl()経由で、 オブジェクトのbufの中身を読み書きできる。 書き込む際に、 作成したサイズよりも1byte多く書き込むことができるのでoff-by-one overflowとなっている。

exploit

linux kernelで使用されるSLUB allocatorでは、 解放済みのチャンクがリンクドリストで繋がっている。 off-by-one overflowを利用すると、 リンクドリストのポインタの最下位1byteを書き換えることができる。 これを利用して、 kmalloc()で取得する領域をuserlandに強制することができる。 あとは適当にkernelspaceのアドレスをリークして、 modprobe_pathを改変してrootを取った。

Midnight Sun CTF 2019 Quals Hfsipc · GitHub

Hfs-dos

改変されたCOMMAND.COMが動作するFreeDOSCOMMAND.COMでは、 入力した文字列に対応する文字列を返すようになっている。 削除文字(0x7f)を入力すると、 こちらからの入力を保存するバッファへのポインタをデクリメントすることができる。 このデクリメントに制限がなく、 COMMAND.COMのtext領域まで持っていくことができる。 古い時代のアーキテクチャ(i8086)で動作している、 かつ古のOSであるため、 メモリの保護機構など存在せずtext領域でも書き換えることが可能となっている。

exploit

jmpする先を改変し、 文字列FLAG1をFLAG2に改変した。 jmpする先は、 COMMAND.COMが最初にFLAG1を表示する関数群へと変えており、FLAG1をFLAG2にしているので、 2つ目のフラグを得られる。

Midnight Sun CTF 2019 Quals Hfs-dos · GitHub