'isec 2009'에 해당되는 글 2건

  1. 2010.08.23 ISEC 2009 Challenge 12 Solution
  2. 2010.08.22 ISEC 2009 Challenge6 with GOT OverWrite

2010.08.23 01:01 WarGame

저번 문제와 같이 바이너리를 얻을 수 없는 관계로

vnsecurity에서 작성한 문서를 토대로 제가 이해한 내용을 써내려가는 식의 포스팅을 하도록 하겠습니다


문제는 대략 메모를 남기는 프로그램을 Overflow 취약점을 이용해 쉘을 따는것 같습니다

여기서 핵심은 메모를 남기는 buffer의 크기가 매우 작아서, 쉘 코드가 들어갈 수 없다는 것입니다

쉘 코드를 나눠서 메모를 여러번 남김으로써, Exploit 하는 문제죠

먼저 문제 코드를 살펴보겠습니다


한가지 특이점은 29번째 줄의 

 if ( !setjmp(exception_env) )   


38번째 줄의
 
longjmp(exception_env, 1);   


라는 코드가 쓰인 것입니다

setjmp / longjmp 문에 대한 설명은

http://studyfoss.egloos.com/5275830 에서 얻을 수 있었습니다


setjmp/longjmp는 프로그램의 흐름을 비정상적으로 제어하는 것으로 이른바 nonlocal goto라고 불린다.
nonlocal이라고 하는 것은 일반 goto와 달리 함수 밖의 위치로 이동할 수 있기 때문이다.
하지만 아무런 제한없이 아무 함수로나 움직일 수 있는 것은 아니며
이동할 위치의 stack frame이 보존된 상태여야 한다.
(즉, 해당 함수가 아직 실행되고 있는 상태에야 한다.)
일반적으로 중첩된 함수 호출내에서 예외 상황이 발생한 경우
상위의 예외 처리 루틴으로 바로 제어를 넘겨서 실행할 수 있도록 구현할 수 있다.

그러니까 요약하자면

setjmp에서 저장한 레지스트리 값, 스택 구조는 복원하되, 스택 내용은 복원되지 않는다

라는 것이군요

먼저 한번의 메모 기록에 들어갈 수 있는 쉘 코드의 크기는 17byte 입니다

전체 메모 크기가 30 byte 지만

44번째 줄의

" Memo : < Shellcode> , size : <Code size> "

의 부가 설명 덕분에 13byte가 빠지게 됩니다

여기서 우리가 Shellcode 를 넣으려고 하는 Buffer는

memo_array[30][30] 이고 , 첫번째 기록한 메모와 두번째 메모와의 Gap 은 13byte 가 되므로

쉘코드 뒤에 JMP 13 명령어를 넣어주어야 할 것입니다

대략


<그림 1. 메모 1개 기록 할때의 memo_array[n][30] 구조>

그리고 메모를 모두 기록했다면, 마지막으로 memo_array의 주소로 JMP 해야 합니다

여기서 바로 longjmp 가 쓰이게 됩니다

longjmp를 조작해서 setjmp 가 아닌 Shellcode 가 들어있는 memo_array 의 주소로 JMP 하면

일사 천리로 진행되겠죠

37번째 줄의 OverFlow 를 이용합시다

여기서 메모리 구조를 살펴보면


<그림2. bss 구역의 메모리 구조>

buf[4]와 setjmp 에서 저장된 jmp_buf_tag 는 24byte 만큼 떨어져있습니다

정확히 24byte가 OverFlow 되므로 Exploit하는데 문제는 없어 보이는군요

정리해보죠

Shellcode를 한번 메모 기록에 15byte 씩 집어넣습니다

각 기록시 JMP 13 를 붙여 총 17 byte를 입력합니다

이렇게 잘라서 Shellcode를 삽입하고

마지막으로는 24byte를 OverFlow 시켜서 쉘코드의 초기주소로 점프 합니다

이 때 초기주소는 char buf[4] 가 0x0804AD48 이니까

900만큼 빼줘야겠죠 16진수로 384니까 이를 빼주면 0x804A9C0 입니다.

여기서 Memo : 수식부분 앞 꼬리 7 byte 를 건너 뛰면

0x804A9C7 이 됩니다


이를 이용해 vnsecurity 에서 짠 Exploit 코드는 다음과 같습니다



'WarGame' 카테고리의 다른 글

Padocon 2011 Twit Bot 문제 풀이  (0) 2011.02.27
Hackjam level3 Solution - Game of life  (0) 2010.08.28
ISEC 2009 Challenge 12 Solution  (0) 2010.08.23
ISEC 2009 Challenge6 with GOT OverWrite  (0) 2010.08.22
[ CodeGate 2010 ] Challlenge 15 풀이  (0) 2010.07.06
[ CodeGate 2010 ] Challenge 8  (0) 2010.06.22
Posted by LinkC

2010.08.22 00:08 WarGame

*이 풀이는 Vnsecurity 에 올라온 ISEC 2009 Challenge6 풀이를 제 나름대로 정리하여 포스팅한 글임을 알립니다

ISEC 2010 일정이 최근에 공개 되었습니다

지난해 ISEC에 참여는 못했지만 CTF 풀이 문서는 남아 있을 것 같아서

뒤적 거렸더니 풀이 문서는 발견할 수 있었습니다

아쉽게도 문제 링크는 다 죽었더군요 -.-

풀이중에 GOT를 Overwrite 해서 그것도 꽤 특이한 방법을 쓴 것이 있어서

정리하여 둡니다

6번 문제는 Remote BOF 문제라고 합니다

핵심이 되는 주요 함수는 다음과 같습니다



23번째 줄에 있는 strcpy가 첫번째 관문입니다

이후에 있는 34번째 줄의 strncmp의 조건을 만족하기 위해서 이를 활용해야겠죠

randbuf 는 이후로 memset에 의해 초기화가 되니 이를 손댈수는 없고

randnum을 손대야 합니다

buf128에서 32byte를 입력받고

16byte의 destbuf16에 strcpy를 하니까 16byte가 Overflow 됩니다

여기서 randnum을 수정해줘야 하는데

소스상으로 약간 잘못된거 같네요

풀이자가 hand ray 로 풀어낸 모양입니다

아무튼 , 사실 randnum이 destbuf16보다 먼저 선언 되어 있어서

덮어쓸수 있다는 거죠

Dummy byte를 포함해서 쭉 덮어씌워야 합니다

속편하게 32byte 쭉 채워주면 되겠죠

첫번째 입력은 32byte만큼 특정 값을 채워줍니다

그 다음에 32번째에서 다시한번 입력을 받는데요

이번엔 128byte만큼 받습니다

바로 이곳이 Core 라는 겁니다

strncmp로 조금 전에 넣어두었던 randnum에 일치하는 수를 넣어줍니다

예를 들어 A로 채워주었다면

buf128에도 A를 채워넣어주면 되겠죠

는 풰이크고 사실 25번째 줄

snprintf(randbuf12, 5, "%d", randnum)

 에서 5자리만큼 잘려들어갔기 때문에

16337 이 들어갔을 겁니다

사실 randnum 에는 AAAA가 들어갔다고 했을 때 , 1633771873 이라는 값이 들어갔을 것이고

이는 int형의 MAX 값. 2^31-1 = 2147483647 을 넘지 않기 때문에 고스란히 들어갔겠죠

여기서 5자리가 잘려서 16337이 됩니다

또 34번째

if ( strncmp(buf128, randbuf12, 4) ) 

 에서 앞 4자리만 비교를 하게 되니

1633만 넣어주면 되겠죠

처음 4byte 는 1633 입니다

그 다음이 문젠데요

키를 읽어놓고 정작 출력을 해주지 않습니다

황당하기 그지 없는 경우죠

여기서 주목해야 할 점은 printf문 앞의 두 strcpy 문입니다

  strcpy(randbuf12, buf128);  
  strcpy(buf_ptr, buf128);

괜히 집어 넣은게 아니겠죠

buf_ptr이 가리키는게 없던것도 걸립니다

두번째에는 buf_ptr의 값을 맘대로 변경할 수 있게 했구요

네, 그러니까 buf_ptr는 '어디든지 문'이라고 보시면 됩니다

마법의 포인터죠

buf_ptr가 가리키고자 하는 곳의 주소를 입력하면

그 후의 strcpy에서 그 값을 바꿀수 있게 합니다

정말 멋집니다

이제 뭘 해야 할까요?


....




Local 이라면 이것저것 해보겠는데 Remote 라는게 뭐 어쩔 수가 없네요

Printf 문의 "eldhkcalb"  문자열을 keystr 의 주소를 바꾸면 되..

지 않겠네요

포인터로 가리키고 있다면 keystr를 가리키도록 바꾸면 될텐데 직접 문자열로 접근하고 있습니다

주소를 알아봤자 말짱 헛것이라는 거죠

생각해보니 우리가 원하는 것은 printf 문도 아닙니다

그렇다면 소켓으로 keystr을 보내주는 sendsocket 함수를 짜서 보내야될텐데

남은 버퍼에 그것이 다 들어가지도 않을 것이고 , Return Address를 손 댈 상황도 아니며

정확한 Buffer의 주소도 알 수 없습니다






정신을 추스리고 다시 살펴보죠

printf 문의 호출을 다른 함수로 바꿀수 있다면?

Windows의 Hooking 떠오릅니다

여기서 접근 한 것이 GOT 입니다

Global Offset Table의 줄임말로 함수의 정보를 담고 있는 Table 인데요

Windows에서 따지자면 IAT와 같은 역할을 하고 있다고 보시면 됩니다

흡사 Windows 에서 Hooking 하듯이 Linux에 적용해보는 겁니다

다만, 이 경우는 코드의 자유도는 떨어집니다

전에 있던 코드들을 짜깁기 해야만 하죠

흡사 ROP의 개념을 보는 것 같군요

Binary 가 없어서 직접 캡처해서 찍을수 없어 풀이자의 자료를 첨부합니다

<그림1. printf 와 fread의 GOT>

우리의 목적을 먼저 정의해봅시다

sendtosocket(fd , keystr, 32) 함수를 호출 하는 것입니다

이는 fread( keystr, 32, 1 , stream) 과 sendsocket( fd , "~~" );

로 합성될 수 있습니다


마침 인자 순서도 적절하군요

그림1을 보시고 뭔가 감이 오시나요?

printf 문을 호출 할 때 fread의 함수 일부를 호출 - fread를 호출할 때 sendsocket의 일부를 호출

이렇게 연쇄적으로 호출하면 우리가 원하는 목적을 달성할 수 있습니다

이런 류의 문제를 본적이 없어서 이해하는데 꽤 걸려버렸습니다




이를 토대로 Exploit 코드를 짜봅시다

처음 입력 받을 때 a 등의 문자로 32 byte 입력합니다

두번째 입력을 받을 때는 초기 4byte는 첫번째에 넣어주었던 값을 고려해서 strncmp를 통과할 수 있도록 넣어줍니다

이후 code가 핵심인데요

1) buf_ptr 가 우리가 원하는 값을 가리킬수 있도록 dummy byte를 넣어줍니다

<그림2. buf_ptr 하위의 메모리 구조>
* buf_ptr의 값은 아직 미정

2) dummy byte에는 printf의 GOT를 덮어씌울 주소가 들어갑니다

GOT 구조에 따라 이 dummy byte의 구성이 달라집니다

문제 풀이를 보니

0x0804A2FC : waitpid GOT
0x0804A304 : fread GOT
.....
0x0804A316 : printf GOT

이런 식으로 구성이 되어 있는것 같습니다

초기 4byte 때문에 fread 전에 있던 어떤 함수의 GOT부터 수정해 나가야 합니다

그게 바로 waitpid 로군요

이를 토대로 짜보면..

<그림3. Exploit 을 위한 메모리 구조, 변경 전>

그림1 을 참고 했을 때, printf 에는 fread의 일부가

fread 는 sendtosocket이 들어갑니다

<그림3. Exploit 을 위한 메모리 구조, 변경 후>

이를 토대로 짠 Exploit Code 입니다



** 제 나름대로 이해한 방법으로 글을 풀어보았습니다만, 제가 이해를 잘못했다거나 풀이자의 의도를 오해했을 수 있습니다

뭔가 틀린것 같다면 댓글로 남겨주세요 시정하겠습니다 :D
Posted by LinkC
이전버튼 1 이전버튼

블로그 이미지
LinkC

태그목록

Tistory Cumulus Flash tag cloud by BLUEnLIVE requires Flash Player 9 or better.

공지사항

Yesterday49
Today11
Total323,945

달력

 « |  » 2018.12
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

최근에 받은 트랙백

글 보관함


. .