teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

変数の表を追加

2019/12/11 04:53

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -13,6 +13,29 @@
13
13
  ---
14
14
  sub() 内の変数の割当がわかり、すっきり原因がわかった。asm さんと違って私は原因を特定することに興味があるので、こちらに書かせてもらう。
15
15
  15バイトの配列に echo -e "AAAAAAAAAAAAAAAAAAA" | .adr と20バイトほど送り込んでいるが
16
- - 20バイトだと溢れたメモリは sub() の中の p と subp 変数に相当する。これらの変数に代入した時点で上書きされるので、溢れたようにみえない。20バイトでは慎ましすぎた。
16
+ - 20バイトだと溢れたメモリは sub() の中の p ~~と subp~~ 変数に相当する。この変数に代入した時点で上書きされるので、溢れたようにみえない。20バイトでは慎ましすぎた。
17
17
  - 40バイトほど送り込めば、溢れた痕跡が見えるだろう。変数と変数の間に4バイトの未使用領域があるので、そこは上書きされずに溢れた値が残るはずだから。
18
- - 60バイトほど送り込めばリターンアドレスを上書きするので、sub() からリターンした時点でセグメントフォールトを起こすだろう。
18
+ - 60バイトほど送り込めばリターンアドレスを上書きするので、sub() からリターンした時点でセグメントフォールトを起こすだろう。
19
+
20
+ sub() が使う変数の割当は次のようです。
21
+
22
+ |変数名|オフセット|サイズ|累積バイト数|
23
+ |:--|:--:|--:|--:|
24
+ |char moji[15]|-0x27〜-0x19|15|15 |
25
+ |int *p|-0x18〜-0x11|8|23|
26
+ |int *subp|-0x10〜-0x09|8|31|
27
+ |(空き)|-0x08〜-0x05|4|35|
28
+ |int ebpofs|-0x04〜-0x01|4|39|
29
+ |old %rbp|0x00〜0x07|8|47|
30
+ |ret address|0x08〜0x0F|8|55|
31
+
32
+
33
+ - オフセットは %rbp のオフセット
34
+ - 累積バイト数は、その変数まで塗りつぶすために流し込むバイト数
35
+
36
+ 46バイト流し込んでコアダンプしたなら old %rbp の8バイトの内、7バイトを書き換えた、ということです。old %rbp の値は sub() からリターンする時に leaveq 命令で %rbp にpopして、(一般的には)呼出し元関数のローカル変数をアクセスするので、この時不正アドレスをアクセスしてしまうのですが、、この場合はたぶんmain() の最後の leaveq 命令が不正アクセスするのでしょう。leaveq 命令はちょっとトリッキーな命令です、いつも使われるとは限らないけど覚えておかないと。
37
+
38
+ コアダンプさせるだけならテキトーな値を流しこめば済むが、乗っ取るにはリターンアドレス(オフセット+8から8バイト)を”正しい”値で上書きする必要があります。その値は普通、moji配列の先頭アドレスでしょうね。スタック上のアドレスです。表示結果を見ると 0x7fffe5320be9 でしょうか。
39
+ このように、スタック領域のメモリアドレス、変数の配置をピンポイントで確定させないと(この方式の)シェルコードは作りようがありません。この表から、この場合のシェルコードのサイズは 55バイトだとわかります。だけどこれらの変数は、コードを修正すればもちろん変化するうえに、**コンパイルする都度、配置が変化する位に思ったほうが良い**ですよ。
40
+ ようやくこういう具体的な話ができるようになった感じですね。そうは言っても、まだ先は長そうだけどね。
41
+ Enjoy!

4

原因特定できた報告

2019/12/11 04:53

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -8,4 +8,11 @@
8
8
  CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。
9
9
 
10
10
  ---
11
- そうですか。溢れないとすると、私には事情がわかりかねます。
11
+ ~~そうですか。溢れないとすると、私には事情がわかりかねます。~~
12
+
13
+ ---
14
+ sub() 内の変数の割当がわかり、すっきり原因がわかった。asm さんと違って私は原因を特定することに興味があるので、こちらに書かせてもらう。
15
+ 15バイトの配列に echo -e "AAAAAAAAAAAAAAAAAAA" | .adr と20バイトほど送り込んでいるが
16
+ - 20バイトだと溢れたメモリは sub() の中の p と subp 変数に相当する。これらの変数に代入した時点で上書きされるので、溢れたようにみえない。20バイトでは慎ましすぎた。
17
+ - 40バイトほど送り込めば、溢れた痕跡が見えるだろう。変数と変数の間に4バイトの未使用領域があるので、そこは上書きされずに溢れた値が残るはずだから。
18
+ - 60バイトほど送り込めばリターンアドレスを上書きするので、sub() からリターンした時点でセグメントフォールトを起こすだろう。

3

大きな字を解消

2019/12/10 15:24

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -5,6 +5,7 @@
5
5
  printf("addr%p price:%08x\n", p + count, p[count]);
6
6
  ```
7
7
  で表示、"A"x30 辺りでコアダンプに至りました。リターンアドレスを上書きされたからに他なりません。
8
- CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。←なぜ大きな字になる??
8
+ CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。
9
+
9
10
  ---
10
11
  そうですか。溢れないとすると、私には事情がわかりかねます。

2

わからない

2019/11/25 14:53

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -5,4 +5,6 @@
5
5
  printf("addr%p price:%08x\n", p + count, p[count]);
6
6
  ```
7
7
  で表示、"A"x30 辺りでコアダンプに至りました。リターンアドレスを上書きされたからに他なりません。
8
- CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。
8
+ CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。←なぜ大きな字になる??
9
+ ---
10
+ そうですか。溢れないとすると、私には事情がわかりかねます。

1

Ubuntu で溢れた

2019/11/25 14:52

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -1,3 +1,8 @@
1
- その実行結果は、示されたコードで表示したものではない。
1
+ ~~その実行結果は、示されたコードで表示したものではない。別のプログラムが表示したのだから、中身も違うのだろう。~~
2
- 別のプログラムが表示したのだから、中身も違うのだろう。
3
- 考えられることは、例えば scanf() で入力したのではなく、fgets() で入力した、とか。それなら普通は配列のサイズ分しか読み込まれない。
2
+ 考えられることは、例えば scanf() で入力したのではなく、fgets() で入力した、とか。それなら普通は配列のサイズ分しか読み込まれない。
3
+ 私は Ubuntu, GCC で
4
+ ```C
5
+ printf("addr%p price:%08x\n", p + count, p[count]);
6
+ ```
7
+ で表示、"A"x30 辺りでコアダンプに至りました。リターンアドレスを上書きされたからに他なりません。
8
+ CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。