티스토리 뷰
최초 작성일 : 2015 - 10 - 24 20:38
최종 주성일 : 2015 - 10 - 24 23:37
주의: 완성된 포스팅이 아닙니다. 사실확인이 되어 있지 않으며 잘못된 정보일 수 있습니다.
root@Ubuntu:~# ldd LIBC_RANDOM
linux-gate.so.1 => (0xb7718000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7540000)
/lib/ld-linux.so.2 (0xb7719000)
root@Ubuntu:~# ldd LIBC_RANDOM
linux-gate.so.1 => (0xb772b000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7553000)
/lib/ld-linux.so.2 (0xb772c000)
root@Ubuntu:~# ldd LIBC_RANDOM
linux-gate.so.1 => (0xb7700000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7528000)
/lib/ld-linux.so.2 (0xb7701000)
위와 같이, 기본적으로 Ubuntu 15.04 버전에서는 ASLR이 적용되어 있다.
하지만 우리가 익히 알고 있듯,
ulimit -s unlimited
명령어를 사용하면 ASLR이 꺼지게 돼있다. 그렇다면 왜 그런지 알아보도록 하자.
reference : http://security.cs.pub.ro/hexcellents/wiki/kb/exploiting/home
Linux/arch/x86/mm/mmap.c에 이 부분에 관하여 정의하고 있다고 한다.
https://github.com/torvalds/linux/blob/master/arch/x86/mm/mmap.c
/* | |
* Flexible mmap layout support | |
* | |
* Based on code by Ingo Molnar and Andi Kleen, copyrighted | |
* as follows: | |
* | |
* Copyright 2003-2009 Red Hat Inc. | |
* All Rights Reserved. | |
* Copyright 2005 Andi Kleen, SUSE Labs. | |
* Copyright 2007 Jiri Kosina, SUSE Labs. | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
*/ | |
#include <linux/personality.h> | |
#include <linux/mm.h> | |
#include <linux/random.h> | |
#include <linux/limits.h> | |
#include <linux/sched.h> | |
#include <asm/elf.h> | |
struct va_alignment __read_mostly va_align = { | |
.flags = -1, | |
}; | |
static unsigned long stack_maxrandom_size(void) | |
{ | |
unsigned long max = 0; | |
if ((current->flags & PF_RANDOMIZE) && | |
!(current->personality & ADDR_NO_RANDOMIZE)) { | |
max = ((-1UL) & STACK_RND_MASK) << PAGE_SHIFT; | |
} | |
return max; | |
} | |
/* | |
* Top of mmap area (just below the process stack). | |
* | |
* Leave an at least ~128 MB hole with possible stack randomization. | |
*/ | |
#define MIN_GAP (128*1024*1024UL + stack_maxrandom_size()) | |
#define MAX_GAP (TASK_SIZE/6*5) | |
static int mmap_is_legacy(void) | |
{ | |
if (current->personality & ADDR_COMPAT_LAYOUT) | |
return 1; | |
if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) | |
return 1; | |
return sysctl_legacy_va_layout; | |
} | |
unsigned long arch_mmap_rnd(void) | |
{ | |
unsigned long rnd; | |
/* | |
* 8 bits of randomness in 32bit mmaps, 20 address space bits | |
* 28 bits of randomness in 64bit mmaps, 40 address space bits | |
*/ | |
if (mmap_is_ia32()) | |
rnd = (unsigned long)get_random_int() % (1<<8); | |
else | |
rnd = (unsigned long)get_random_int() % (1<<28); | |
return rnd << PAGE_SHIFT; | |
} | |
static unsigned long mmap_base(unsigned long rnd) | |
{ | |
unsigned long gap = rlimit(RLIMIT_STACK); | |
if (gap < MIN_GAP) | |
gap = MIN_GAP; | |
else if (gap > MAX_GAP) | |
gap = MAX_GAP; | |
return PAGE_ALIGN(TASK_SIZE - gap - rnd); | |
} | |
/* | |
* Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64 | |
* does, but not when emulating X86_32 | |
*/ | |
static unsigned long mmap_legacy_base(unsigned long rnd) | |
{ | |
if (mmap_is_ia32()) | |
return TASK_UNMAPPED_BASE; | |
else | |
return TASK_UNMAPPED_BASE + rnd; | |
} | |
/* | |
* This function, called very early during the creation of a new | |
* process VM image, sets up which VM layout function to use: | |
*/ | |
void arch_pick_mmap_layout(struct mm_struct *mm) | |
{ | |
unsigned long random_factor = 0UL; | |
if (current->flags & PF_RANDOMIZE) | |
random_factor = arch_mmap_rnd(); | |
mm->mmap_legacy_base = mmap_legacy_base(random_factor); | |
if (mmap_is_legacy()) { | |
mm->mmap_base = mm->mmap_legacy_base; | |
mm->get_unmapped_area = arch_get_unmapped_area; | |
} else { | |
mm->mmap_base = mmap_base(random_factor); | |
mm->get_unmapped_area = arch_get_unmapped_area_topdown; | |
} | |
} | |
const char *arch_vma_name(struct vm_area_struct *vma) | |
{ | |
if (vma->vm_flags & VM_MPX) | |
return "[mpx]"; | |
return NULL; | |
} |
static int mmap_is_legacy(void) | |
{ | |
if (current->personality & ADDR_COMPAT_LAYOUT) | |
return 1; | |
if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) | |
return 1; | |
return sysctl_legacy_va_layout; | |
} |
mmap_is_legacy() 함수를 보면
if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
return 1;
이런 부분을 볼 수 있다. unlimited 로돼 있으면 return 1;을 해준다.
그리고 같은 파일에서 mmap_is_legacy 함수를 참조하는 다른 함수들을 확인해보자.
*return 1이 실행 안됐을 시에 리턴 해주는 sysctl_legacy_va_layout은 아래 파일에서 0으로 정의 되어 있음
*http://lxr.free-electrons.com/source/include/linux/mm.h
/* | |
* This function, called very early during the creation of a new | |
* process VM image, sets up which VM layout function to use: | |
*/ | |
void arch_pick_mmap_layout(struct mm_struct *mm) | |
{ | |
unsigned long random_factor = 0UL; | |
if (current->flags & PF_RANDOMIZE) | |
random_factor = arch_mmap_rnd(); | |
mm->mmap_legacy_base = mmap_legacy_base(random_factor); | |
if (mmap_is_legacy()) { | |
mm->mmap_base = mm->mmap_legacy_base; | |
mm->get_unmapped_area = arch_get_unmapped_area; | |
} else { | |
mm->mmap_base = mmap_base(random_factor); | |
mm->get_unmapped_area = arch_get_unmapped_area_topdown; | |
} | |
} |
*arch_pick_mmap_layout에서 참조함
mmap_is_legacy 함수를 실행하여 참이면 mm->mmap_base를 mmap_legacy_base()함수를 사용하여
대입해준다. mmap_legacy_base() 함수안에서 32비트인지 확인해주는 코드가 있고
32비트이면 그냥 TASK_UNMAPPED_BASE를 리턴해주고 64비트이면 TASK_UNMAPPED_BASE에 랜덤한 값을 더해준
값을 리턴해준다.
/* | |
* Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64 | |
* does, but not when emulating X86_32 | |
*/ | |
static unsigned long mmap_legacy_base(unsigned long rnd) | |
{ | |
if (mmap_is_ia32()) | |
return TASK_UNMAPPED_BASE; | |
else | |
return TASK_UNMAPPED_BASE + rnd; | |
} |
mmap_is_ia32는 32비트인지 확인하는 함수이며, 이부분을 통해 왜 64비트에서는 ASLR이 풀리지 않는지 알 수 있다.
(이 부분은 mmap_legacy_base 함수의 주석부분에서도 확인 할 수 있다.)
/*
* Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64
* does, but not when emulating X86_32
*/
* 수정되었습니다.
(mmap_is_ia32() 함수는 elf.h에서 확인 할 수 있습니다.)
주석으로 보아 32비트이거나 64비트에서 32비트 에뮬레이션일 경우 true를 반환해주는 것 같습니다.
대충 요약해보자면,
1. unlimited인지 mmap_is_legacy() 함수에서 확인함.
2. mmap_is_legacy 함수를 arch_pick_mmap_layout 함수에서 사용하여 참이면 mmap_base를 mmap_legacy_base() 함수를
이용하여 대입해줌
3. mmap_legacy_base() 함수는 32비트인지 64비트인지 확인하고 32비트면 랜덤을 적용하지 않고 base를 설정하고
64비트면 mmap_rnd(); 함수를 통하여 랜덤적용을 해줌.
root@Ubuntu:~# ulimit -s unlimited
root@Ubuntu:~# ldd LIBC_RANDOM
linux-gate.so.1 => (0x40026000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x40042000)
/lib/ld-linux.so.2 (0x40000000)
root@Ubuntu:~# ldd LIBC_RANDOM
linux-gate.so.1 => (0x40026000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x40042000)
/lib/ld-linux.so.2 (0x40000000)
root@Ubuntu:~# ldd LIBC_RANDOM
linux-gate.so.1 => (0x40026000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x40042000)
/lib/ld-linux.so.2 (0x40000000)
REFERENCES
http://security.cs.pub.ro/hexcellents/wiki/kb/exploiting/home
http://lxr.free-electrons.com/source/include/linux/mm.h
https://github.com/torvalds/linux/blob/master/arch/x86/mm/mmap.c\
'Pwnable > System 잡지식' 카테고리의 다른 글
Pwnable 워게임 사이트, 문서 정리 (2) | 2015.01.28 |
---|---|
ASLR 활성/비활성 (2) | 2014.10.04 |