ログイン
編集不可のページディスカッション情報添付ファイル
"ytoku/Slides/Pwn勉強会"の差分

MMA
1と12のリビジョン間の差分 (その間の編集: 11回)
2015-04-27 20:48:40時点のリビジョン1
サイズ: 2190
編集者: ytoku
コメント:
2015-05-06 01:36:43時点のリビジョン12
サイズ: 5467
編集者: ytoku
コメント:
削除された箇所はこのように表示されます。 追加された箇所はこのように表示されます。
行 4: 行 4:
== Tools == = Tools =
行 10: 行 10:
  * nasm
行 20: 行 21:
== Shellcode == = 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 =
 * システムコールとは
  * プログラムがカーネルとやりとりする一元化された窓口
 * プログラムの動作権限
  * ユーザモード
   * 普通のプログラムが動作
   * 基本的にプロセスのメモリ内で計算しかできない.
   * それ以外のことをするためにはシステムコールを呼ぶ
  * カーネルモード
   * カーネルが動作
  * 任意の操作が可能

{{attachment:systemcall.png}}

= How to call System calls =
システムコールの呼び出し方

 * x86
  * int 0x80
   * INTerrupt (ソフトウェア割り込み命令)
  * システムコール番号: eax
  * 引数: ebx, ecx, edx, esi, edi, ebp
 * x86-64
  * syscall命令
  * システムコール番号: rax
  * 引数: rdi, rsi, rdx, r10, r8, r9

||<rowclass="header"> 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 ||

= システムコール番号 =

||<rowclass="header"> 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機能
 * シェルコードの生成
 * アセンブラ/ディスアセンブラ
 * 攻撃対象アーキテクチャに合わせたバイトオーダ・定数

= Pwntools example =
{{{#!highlight python
# -*- coding: utf-8 -*-
from pwn import *
## exploit対象のアーキテクチャ
context(arch = 'i386', os = 'linux')
# context(arch = "amd64", os = "linux")
## 攻撃のサーバに接続
conn = process("./example")
# conn = remote("example.com", 10000)
## ROPを構成
rop = ""
rop += p32(0x8048330) # mprotect
rop += p32(0x804855d) # skip 3 words
rop += p32(0x20000000) # buf
...
## シェルコードをアセンブル
shellcode = asm(shellcraft.sh())
## ログ表示
p = log.waitfor("Pwning")
## ": "を受信するまでrecv
conn.recvuntil(": ")
## エクスプロイトを送信
conn.send(rop)
time.sleep(0.5)
conn.send(shellcode)
## ログ表示
p.success("OK")
## コンソールの入出力を攻撃対象に接続
conn.interactive()
}}}

= Shellcode =
行 24: 行 130:
#include <stdio.h>
行 28: 行 133:
    fread(buf, 1, 4096, stdin);     write(1, "Send me shellcode: ", 19);
    read(0, buf, 1024);
行 33: 行 139:
== x86/x86-64 ABI ==
チートシート

== System call ==
システムコールの呼び出し方

== Shellcode(slightly modified) ==
{{{#!highlight c
// gcc -z execstack -fno-stack-protector -o baby2 baby2.c
// -m32 / -m64 両方やってもらうよ!
#include <stdio.h>
typedef void func();
int main() {
    char buf[1024];
    scanf("%1023s", buf);
    ((func *)buf)();
}
}}}


== Return-to-plt ==
= Shellcode(no /bin/sh) =
 * chroot環境
 * /bin/shが無いのでopen, read, writeを自分で行う


= x86/x86-64 ABI =
[[http://d.sunnyone.org/2012/09/x86x8664.html|x86/x86_64関数呼び出しチートシート]]

= Return-to-plt =
行 59: 行 153:
int main() { int f() {
行 65: 行 159:
}}}

== ASLR ==
int main() { return f(); }
}}}

= ASLR =
行 70: 行 165:
== Return-to-libc == = Return-to-libc =
行 74: 行 169:
int main() { int f() {
行 80: 行 175:
}}}


== Return-to-plt revisited(x86-64) with tiny ROP ==
{{{#!highlight c
// gcc -m64 -fno-stack-protector -o baby5 baby5.c
int main() { return f(); }
}}}


= Return-to-plt revisited(x86-64) with tiny ROP =
{{{#!highlight c
// gcc -m64 -fno-stack-protector -o baby3 baby3.c
行 89: 行 185:
int main() { int f() {
行 95: 行 191:
}}}



== ROP ==
{{{#!highlight c
// gcc -m32 -static -fno-stack-protector -o baby6 baby6.c
#include <unistd.h>
int main() {
int main() { return f(); }
}}}



= ROP =
{{{#!highlight c
// gcc -m32 -static -fno-stack-protector -o baby5 baby5.c
#include <unistd.h>
int f() {
行 108: 行 205:
}}}

= Pwn勉強会(Stack day 2) =
int main() { return f(); }
}}}

= 実践 =
行 112: 行 210:

= Pwn勉強会(Heap day 1) =
やりたいな

Pwn勉強会(Stack day 1)

Tools

  • Disassembler
    • udcli / ndisasm
    • objdump
    • METASM / Hopper / IDA Pro
  • Assembler
    • nasm
    • Pwntools
    • METASM?
  • Debugger
    • gdb-peda
  • Pwn toolkit
    • Pwntools
    • Ruby系でなにか

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

  • システムコールとは
    • プログラムがカーネルとやりとりする一元化された窓口
  • プログラムの動作権限
    • ユーザモード
      • 普通のプログラムが動作
      • 基本的にプロセスのメモリ内で計算しかできない.
      • それ以外のことをするためにはシステムコールを呼ぶ
    • カーネルモード
      • カーネルが動作
    • 任意の操作が可能

systemcall.png

How to call System calls

システムコールの呼び出し方

  • x86
    • int 0x80
      • INTerrupt (ソフトウェア割り込み命令)
    • システムコール番号: eax
    • 引数: ebx, ecx, edx, esi, edi, ebp
  • 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機能
  • シェルコードの生成
  • アセンブラ/ディスアセンブラ
  • 攻撃対象アーキテクチャに合わせたバイトオーダ・定数

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()

Shellcode

   1 // gcc -z execstack -fno-stack-protector -o baby1 baby1.c
   2 // -m32 / -m64 両方やってもらうよ!
   3 typedef void func();
   4 int main() {
   5     char buf[1024];
   6     write(1, "Send me shellcode: ", 19);
   7     read(0, buf, 1024);
   8     ((func *)buf)();
   9 }

Shellcode(no /bin/sh)

  • chroot環境
  • /bin/shが無いのでopen, read, writeを自分で行う

x86/x86-64 ABI

x86/x86_64関数呼び出しチートシート

Return-to-plt

   1 // gcc -m32 -fno-stack-protector -o baby3 baby3.c
   2 #include <stdio.h>
   3 #include <unistd.h>
   4 char buf2[128];
   5 int f() {
   6     char buf[32];
   7     system("sleep 1");
   8     gets(buf);
   9     return 0;
  10 }
  11 int main() { return f(); }

ASLR

ASLRについて説明

Return-to-libc

   1 // gcc -m32 -pie -fPIE -fno-stack-protector -o baby4 baby4.c
   2 #include <unistd.h>
   3 int f() {
   4     char buf[32];
   5     write(1, buf, 64);
   6     read(0, buf, 1024);
   7     return 0;
   8 }
   9 int main() { return f(); }

Return-to-plt revisited(x86-64) with tiny ROP

   1 // gcc -m64 -fno-stack-protector -o baby3 baby3.c
   2 #include <stdio.h>
   3 #include <unistd.h>
   4 char buf2[128];
   5 int f() {
   6     char buf[32];
   7     system("sleep 1");
   8     gets(buf);
   9     return 0;
  10 }
  11 int main() { return f(); }

ROP

   1 // gcc -m32 -static -fno-stack-protector -o baby5 baby5.c
   2 #include <unistd.h>
   3 int f() {
   4     char buf[32];
   5     read(0, buf, 1024);
   6     return 0;
   7 }
   8 int main() { return f(); }

実践

適当な問題を探す

ytoku/Slides/Pwn勉強会 (最終更新日時 2015-10-07 15:46:40 更新者 nomeaning)