例のリレーブログ*1の時間です。前の僕の記事はこれ、前回の方のブログはこちらになります。
今回僕に与えられたテーマはASLR。聞いたことないワードだったので毎度のごとく少し調べて、今回は試してみたことを書いていこうと思う。
ASLRとは
ASLR(Address Space Layout Randomization、アドレス空間配置のランダム化)とは、重要なデータ領域の位置(スタックやヒープの位置など)を無作為に配置するOSのセキュリティ技術のこと。現在よく使われているOSにはこの機能が標準搭載されている。
なんでそんなことするんだ、と思うかもしれないが、この技術は例えばスタックバッファオーバーフロー攻撃に有効な防御手段となる。入力サイズの上限の指定ができなかったり、その指定を怠った時に、大量の入力をすると、スタック領域を超えた場所にあるデータが上書きされてしまうことがある。これを悪用して呼び出し元のプログラムへの戻りアドレスであるリターンアドレスを書き換え、別のプログラムを実行させるといったことができてしまう。これに対してアドレスのランダム化を行えば、攻撃の成功率を下げることができる。
ASLRを確認する
ASLRあり
実際にASLRがどう動いているのか確かめてみる。今回は床に転がっていたraspberry piを使う。
pi@raspberrypi:~$ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 9.11 (stretch) Release: 9.11 Codename: stretch
適当なコードを実行させてメモリマップを見てみる。
pi@raspberrypi:~$ sleep 100 & [1] 996 pi@raspberrypi:~$ sleep 100 & [2] 997
100秒スリープするプロセスを2つ走らせてみた。これら2つのメモリマップを確認してみる。
pi@raspberrypi:~$ cat /proc/996/maps 00010000-00016000 r-xp 00000000 b3:07 391782 /bin/sleep 00025000-00026000 r--p 00005000 b3:07 391782 /bin/sleep 00026000-00027000 rw-p 00006000 b3:07 391782 /bin/sleep 002d0000-002f1000 rw-p 00000000 00:00 0 [heap] 76d3c000-76e55000 r--p 00000000 b3:07 14166 /usr/lib/locale/locale-archive 76e55000-76f7f000 r-xp 00000000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f7f000-76f8e000 ---p 0012a000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f8e000-76f90000 r--p 00129000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f90000-76f91000 rw-p 0012b000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f91000-76f94000 rw-p 00000000 00:00 0 76faa000-76faf000 r-xp 00000000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76faf000-76fbe000 ---p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fbe000-76fbf000 r--p 00004000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fbf000-76fc0000 rw-p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fc0000-76fe1000 r-xp 00000000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76fee000-76ff0000 rw-p 00000000 00:00 0 76ff0000-76ff1000 r--p 00020000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76ff1000-76ff2000 rw-p 00021000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 7ec25000-7ec46000 rw-p 00000000 00:00 0 [stack] 7eff0000-7eff1000 r-xp 00000000 00:00 0 [sigpage] 7eff1000-7eff2000 r--p 00000000 00:00 0 [vvar] 7eff2000-7eff3000 r-xp 00000000 00:00 0 [vdso] ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
pi@raspberrypi:~$ cat /proc/997/maps 00010000-00016000 r-xp 00000000 b3:07 391782 /bin/sleep 00025000-00026000 r--p 00005000 b3:07 391782 /bin/sleep 00026000-00027000 rw-p 00006000 b3:07 391782 /bin/sleep 01562000-01583000 rw-p 00000000 00:00 0 [heap] 76cc3000-76ddc000 r--p 00000000 b3:07 14166 /usr/lib/locale/locale-archive 76ddc000-76f06000 r-xp 00000000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f06000-76f15000 ---p 0012a000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f15000-76f17000 r--p 00129000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f17000-76f18000 rw-p 0012b000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f18000-76f1b000 rw-p 00000000 00:00 0 76f31000-76f36000 r-xp 00000000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76f36000-76f45000 ---p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76f45000-76f46000 r--p 00004000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76f46000-76f47000 rw-p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76f47000-76f68000 r-xp 00000000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76f75000-76f77000 rw-p 00000000 00:00 0 76f77000-76f78000 r--p 00020000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76f78000-76f79000 rw-p 00021000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 7e91a000-7e93b000 rw-p 00000000 00:00 0 [stack] 7e98f000-7e990000 r-xp 00000000 00:00 0 [sigpage] 7e990000-7e991000 r--p 00000000 00:00 0 [vvar] 7e991000-7e992000 r-xp 00000000 00:00 0 [vdso] ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
差分を見てみる。
pi@raspberrypi:~$ diff <(cat /proc/996/maps) <(cat /proc/997/maps) 4,22c4,22 < 002d0000-002f1000 rw-p 00000000 00:00 0 [heap] < 76d3c000-76e55000 r--p 00000000 b3:07 14166 /usr/lib/locale/locale-archive < 76e55000-76f7f000 r-xp 00000000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so < 76f7f000-76f8e000 ---p 0012a000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so < 76f8e000-76f90000 r--p 00129000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so < 76f90000-76f91000 rw-p 0012b000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so < 76f91000-76f94000 rw-p 00000000 00:00 0 < 76faa000-76faf000 r-xp 00000000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so < 76faf000-76fbe000 ---p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so < 76fbe000-76fbf000 r--p 00004000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so < 76fbf000-76fc0000 rw-p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so < 76fc0000-76fe1000 r-xp 00000000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so < 76fee000-76ff0000 rw-p 00000000 00:00 0 < 76ff0000-76ff1000 r--p 00020000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so < 76ff1000-76ff2000 rw-p 00021000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so < 7ec25000-7ec46000 rw-p 00000000 00:00 0 [stack] < 7eff0000-7eff1000 r-xp 00000000 00:00 0 [sigpage] < 7eff1000-7eff2000 r--p 00000000 00:00 0 [vvar] < 7eff2000-7eff3000 r-xp 00000000 00:00 0 [vdso] --- > 01562000-01583000 rw-p 00000000 00:00 0 [heap] > 76cc3000-76ddc000 r--p 00000000 b3:07 14166 /usr/lib/locale/locale-archive > 76ddc000-76f06000 r-xp 00000000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so > 76f06000-76f15000 ---p 0012a000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so > 76f15000-76f17000 r--p 00129000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so > 76f17000-76f18000 rw-p 0012b000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so > 76f18000-76f1b000 rw-p 00000000 00:00 0 > 76f31000-76f36000 r-xp 00000000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so > 76f36000-76f45000 ---p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so > 76f45000-76f46000 r--p 00004000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so > 76f46000-76f47000 rw-p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so > 76f47000-76f68000 r-xp 00000000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so > 76f75000-76f77000 rw-p 00000000 00:00 0 > 76f77000-76f78000 r--p 00020000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so > 76f78000-76f79000 rw-p 00021000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so > 7e91a000-7e93b000 rw-p 00000000 00:00 0 [stack] > 7e98f000-7e990000 r-xp 00000000 00:00 0 [sigpage] > 7e990000-7e991000 r--p 00000000 00:00 0 [vvar] > 7e991000-7e992000 r-xp 00000000 00:00 0 [vdso]
これから、[heap]から[vdso]まで、ヒープやスタックなどは違うアドレスになっていることがわかる。
もうちょっと直接的に(?)見てみる。C言語のmain関数の中で定義した変数(ローカル変数)はスタックメモリに配置されるので、試しに以下のような適当なローカル変数のアドレスを表示するだけのプログラム
#include <stdio.h> int main() { int x; printf("%p\n",&x); return 0; }
を書いて、10回実行してみると
pi@raspberrypi:~$ gcc test.c -o test pi@raspberrypi:~$ for x in {0..9}; do ./test; done 0x7e9496e4 0x7ee156e4 0x7ea486e4 0x7ed7e6e4 0x7efc56e4 0x7eb376e4 0x7eea06e4 0x7ea146e4 0x7e8196e4 0x7e8a96e4
このように全て異なるアドレスになっていることがわかる。
ASLRなし
Linuxの場合、sudo sysctl -w kernel.randomize_va_space=0
とすれば、ASLRを切ることができる。逆にsudo sysctl -w kernel.randomize_va_space=2
とすればASLRありの状態に戻る。
ASLRなしの状態で上のsleepコマンドとCのプログラムを走らせてみる。
pi@raspberrypi:~$ cat /proc/1019/maps 00010000-00016000 r-xp 00000000 b3:07 391782 /bin/sleep 00025000-00026000 r--p 00005000 b3:07 391782 /bin/sleep 00026000-00027000 rw-p 00006000 b3:07 391782 /bin/sleep 00027000-00048000 rw-p 00000000 00:00 0 [heap] 76d4a000-76e63000 r--p 00000000 b3:07 14166 /usr/lib/locale/locale-archive 76e63000-76f8d000 r-xp 00000000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f8d000-76f9c000 ---p 0012a000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f9c000-76f9e000 r--p 00129000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f9e000-76f9f000 rw-p 0012b000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f9f000-76fa2000 rw-p 00000000 00:00 0 76fb8000-76fbd000 r-xp 00000000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fbd000-76fcc000 ---p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fcc000-76fcd000 r--p 00004000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fcd000-76fce000 rw-p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fce000-76fef000 r-xp 00000000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76ff9000-76ffb000 rw-p 00000000 00:00 0 76ffb000-76ffc000 r-xp 00000000 00:00 0 [sigpage] 76ffc000-76ffd000 r--p 00000000 00:00 0 [vvar] 76ffd000-76ffe000 r-xp 00000000 00:00 0 [vdso] 76ffe000-76fff000 r--p 00020000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76fff000-77000000 rw-p 00021000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 7efdf000-7f000000 rw-p 00000000 00:00 0 [stack] ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
pi@raspberrypi:~$ cat /proc/1020/maps 00010000-00016000 r-xp 00000000 b3:07 391782 /bin/sleep 00025000-00026000 r--p 00005000 b3:07 391782 /bin/sleep 00026000-00027000 rw-p 00006000 b3:07 391782 /bin/sleep 00027000-00048000 rw-p 00000000 00:00 0 [heap] 76d4a000-76e63000 r--p 00000000 b3:07 14166 /usr/lib/locale/locale-archive 76e63000-76f8d000 r-xp 00000000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f8d000-76f9c000 ---p 0012a000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f9c000-76f9e000 r--p 00129000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f9e000-76f9f000 rw-p 0012b000 b3:07 526355 /lib/arm-linux-gnueabihf/libc-2.24.so 76f9f000-76fa2000 rw-p 00000000 00:00 0 76fb8000-76fbd000 r-xp 00000000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fbd000-76fcc000 ---p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fcc000-76fcd000 r--p 00004000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fcd000-76fce000 rw-p 00005000 b3:07 11311 /usr/lib/arm-linux-gnueabihf/libarmmem.so 76fce000-76fef000 r-xp 00000000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76ff9000-76ffb000 rw-p 00000000 00:00 0 76ffb000-76ffc000 r-xp 00000000 00:00 0 [sigpage] 76ffc000-76ffd000 r--p 00000000 00:00 0 [vvar] 76ffd000-76ffe000 r-xp 00000000 00:00 0 [vdso] 76ffe000-76fff000 r--p 00020000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 76fff000-77000000 rw-p 00021000 b3:07 526228 /lib/arm-linux-gnueabihf/ld-2.24.so 7efdf000-7f000000 rw-p 00000000 00:00 0 [stack] ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
差分をとってみると
pi@raspberrypi:~$ diff <(cat /proc/1019/maps) <(cat /proc/1020/maps) pi@raspberrypi:~$
ということでキレイに何も出力されなかったので、全く同じアドレスになっている。
Cのプログラムも先ほど同様10回走らせてみると
pi@raspberrypi:~$ for x in {0..9}; do ./test; done 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4 0x7efff6e4
ということで全く同じアドレスになった。
*1:seccampのグループワークから生まれた企画。リレーブログのルール:前の人がが次の人のテーマを決める