回答編集履歴

5

変数の表を追加

2019/12/11 04:53

投稿

rubato6809
rubato6809

スコア1380

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

4

原因特定できた報告

2019/12/11 04:53

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -18,4 +18,18 @@
18
18
 
19
19
  ---
20
20
 
21
- そうですか。溢れないとすると、私には事情がわかりかねます。
21
+ ~~そうですか。溢れないとすると、私には事情がわかりかねます。~~
22
+
23
+
24
+
25
+ ---
26
+
27
+ sub() 内の変数の割当がわかり、すっきり原因がわかった。asm さんと違って私は原因を特定することに興味があるので、こちらに書かせてもらう。
28
+
29
+ 15バイトの配列に echo -e "AAAAAAAAAAAAAAAAAAA" | .adr と20バイトほど送り込んでいるが
30
+
31
+ - 20バイトだと溢れたメモリは sub() の中の p と subp 変数に相当する。これらの変数に代入した時点で上書きされるので、溢れたようにみえない。20バイトでは慎ましすぎた。
32
+
33
+ - 40バイトほど送り込めば、溢れた痕跡が見えるだろう。変数と変数の間に4バイトの未使用領域があるので、そこは上書きされずに溢れた値が残るはずだから。
34
+
35
+ - 60バイトほど送り込めばリターンアドレスを上書きするので、sub() からリターンした時点でセグメントフォールトを起こすだろう。

3

大きな字を解消

2019/12/10 15:24

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -12,7 +12,9 @@
12
12
 
13
13
  で表示、"A"x30 辺りでコアダンプに至りました。リターンアドレスを上書きされたからに他なりません。
14
14
 
15
- CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。←なぜ大きな字になる??
15
+ CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。
16
+
17
+
16
18
 
17
19
  ---
18
20
 

2

わからない

2019/11/25 14:53

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -12,4 +12,8 @@
12
12
 
13
13
  で表示、"A"x30 辺りでコアダンプに至りました。リターンアドレスを上書きされたからに他なりません。
14
14
 
15
- CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。
15
+ CentOSを使ってないので断言はしないけど、scanf() はCライブラリ関数にふくまれ、仕様が違うとは考えにくい。scanf() を使う限り溢れると思いますが。←なぜ大きな字になる??
16
+
17
+ ---
18
+
19
+ そうですか。溢れないとすると、私には事情がわかりかねます。

1

Ubuntu で溢れた

2019/11/25 14:52

投稿

rubato6809
rubato6809

スコア1380

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