[3] Buffer Overflow 공격

2017. 6. 3. 12:28SystemHacking/System


 


 

해당 게시글의 내용은 해커스쿨-도서관 에서 다운받은 파일을 기반으로 저의 공부를 위해 작성했습니다

" 해커 지망자들이 알아야 할 Buffer Overflow Attack의 기초 " By 달고나 님의 pdf의 사진과 글을 요약 정리했습니다


공격을 위해 먼저 취약점이 있는 프로그램을 하나 생성하도록 하겠습니다

< 그림 1 >


strcpy()함수를 이용해 인자로 넘어온 문자열을 buffer 문자열배열에 저장하는 소스코드입니다

[1],[2] 에서 배웠던 내용을 토대로 쉽게 이해 할 수 있을겁니다

1024byte의 버퍼공간을 쉘 생성코드와 NOP로 채우고 base pointer있는 SFP(4byte) 공간에도 NOP로 채웁니다

마지막으로 return address 가 들어있는 RET주소에 쉘 생성코드가 저장되어 있는 주소를 덮어 씌우면 쉘이 떨어져 공격 성공입니다



< 그림 2 >


해당 실행파일의 소유자 권한을 root 로 바꾸고 setuid() 설정을 걸어줍니다 ( 해당 파일 실행시 root 권한으로 실행 된다 )

하지만 해당 실행파일 내에서 setreuid함수가 없다면 해당 권한을 얻을 수 없다 

=> why ? 소유자의 권한(root)을 그대로 상속받지 못했기 때문이다

=> 쉘 생성코드에 setreuid()함수의 코드를 추가시켜 주어야한다 

=> 이 세가지 조건이 만족되어야 해당 파일의 권한을 그대로 상속받을 수 있다


취약점이 있는 프로그램을 생성했고 어떤 식으로 공격해야할 지도 알았습니다.

그럼 return address대신 RET주소에 넣을 쉘 코드가 저장되어 있는 주소를 알아내야 합니다 



[ 방법1 ] : NOP를 이용한 고전적인 방법 ( 현재 거의 사용 x )


NOP란 ? No Operation의 약자입니다. " \x90 " 으로 표현할 수 있습니다.

CPU는 NOP를 만나게 되면 아무런 수행을 하지않고 유효한 instruction을 만날 때까지 한 바이트씩 이동합니다

쉘 코드가 저장되어 있는 주소를 정확히 알 기 힘므로 NOP를 사용해서 공격을 시도합니다

아래 그림을 보시죠


< 그림 3 >


" \x90 " 은 NOP입니다. 1028byte만큼 버퍼오버플로우 시킨 후 RET값을 변질시킵니다

RET주소에 주소X와 주소A 사이의 아무 값이나 넣습니다 그러면 " ret " 명령에 의해서 EIP에 RET주소에 있는 주소값으로 이동한다

주소X 가 저장되어있다고 가정하면, 주소X로 이동한 다음 NOP를 거쳐서 아무런 수행도 하지않고 계속 1byte씩 이동한다

결국에 쉘 생성코드가 있는 주소A에 도착하게 되고 쉘 생성코드가 실행됩니다.  공격 성공 !



[ 방법2 ] 환경변수를 이용하는 방법 ★★★


환경변수는 메모리 어딘가에 항상 저장되어 있다. 우리는 환경변수를 포인터를 이용해서 사용할 수 있다

따라서 환경변수에 쉘 생성코드를 넣어주고 그 주소를 알아내어 사용하면 됩니다

환경변수에 쉘생성코드를 넣는 방법과 환경 변수가 위치한 주소를 알아내는 좋은 프로그램이 있습니다.

바로 에그쉘이라고 불리우는 프로그램입니다 ㅡ 그림 4,5 참고

#vi eggshell.c


< 그림 4 >

< 그림 5 >


해당 소스파일을 컴파일 한 후 실행시키면 ESP주소가 출력되고 쉘이 떨어집니다

$gcc -o eggshell eggshell.c

$./eggshell


< 그림 6 >


에그쉘에서 사용한 get_esp()함수는 어셈블리 코드를 이용하여 ESP레지스터가 가르키는 곳의 주소를 EAX레지스터에 넣는 역할을 한다

이것만으로 EAX레지스터의 값이 리턴된다. 에그쉘의 키 포인트는 " 대부분의 프로그램들의 스텍 시작점은 같다 " 이다

어떤 함수가 실행될 때 이전 함수의 base pointer를 저장하고 스텍 포인터가 main함수의 base pointer가 된다

그리고 실행한 함수의 지역변수들이 스택에 쌓이기 시작한다. 함수가 종료되면 base pointer로 복귀된다.

이런 방식으로 같은 쉘 환경에서 프로그램이 실행되면 main함수에서 만나는 스텍포인터는 같을 수 밖에 없다

따라서 공격자는 스텍 포인터의 주소값을 알아내어 거기서 부터 return address를 유추하는 것이다


, 에그쉘(egg파일)을 실행 결과 출력된 stack pointer값은 EGG라는 환경변수가 위치한 범위 내의 어딘가를 가리키고 있다는 것이다

그림으로 표현하면 이해하기 쉽습니다 아래그림을 참고하세요 ㅡ 그림 7


  < 그림 7 >


에그쉘을 실행하기 전에는 ebp와 esp 가 주소 " 0xbfffffa88 " 에 존재하고 있음이 보입니다

에그쉘을 실행한 후에는 0x800 만큼 주소가 아래로 내려갔다. ( 0x800 == 2048byte ) 이것은 egg.c에서 egg배열의 크기이다. 

해당 크기만큼 ebp와 esp가 내려감을 확인 할 수있다.

에그쉘 코드(egg.c) 를 작성 할 때 esp주소를 출력하는 함수는 EGG를 환경변수에 등록하기 전이다

따라서 우리는 egg실행전 esp주소를 알 수 있고 이 주소는 환경변수 EGG가 위치하는 범위 내의 어딘가이다

EGG 안에는 많은 NOP가 들어있기때문에 esp가 정확한 환경변수 EGG의 주소가 아닐지라도 EGG 안의 NOP들에 의해서 instruction pointer가 흘러서 

쉘 생성 코드 시작점까지 도착할 수 있게 된다. 


환경변수가 잘 등록되어있는지도 확인해봅시다


< 그림 8 >


환경변수 EGG가 제대로 들어가있음이 확인됩니다. 그러면 이제 취약 프로그램 vul 에서 어느 지점에 return address가 있는지 확인합시다

그리고 해당 지점에 stack pointer의 값을 넣으면 공격은 성공됩니다


" vul " 프로그램의 main()함수를 디스어셈블해보면 알 수 있습니다


< 그림 9 >


main()함수의 시작부분에서 지역변수 공간을 1040byte만큼 할당해주는 것을 알 수 있습니다

buffer의 크기는 1024 이고 dummy가 16byte만큼을 차지하고 있습니다

따라서 1040byte만큼의 크기와 SFP(base pointer)의 4byte를 합한 1044byte를 버퍼오버플로우 시키면 return address가 위치한

RET 의 공간에 도달하게 됩니다. 해당 공간에 에그쉘프로그램으로 구한 환경변수 EGG의 주소를 덮어 씌우면됩니다

그리고 프로그램이 실행되면 " ret " 명령에 의해 EGG의 주소로 이동해서 해당주소에 있는 쉘생성코드를 실행시킬겁니다

지금까지 이론적으로는 틀린 부분은 없습니다. 하지만 직접 실행하였더니 제대로된 결과가 나오지 않았습니다....

( 작성한 에그쉘과 쉘 실행코드에는 아무런 이상없이 작동합니다. " vul " 프로그램의 주소와 관련되서 이상이 있는거 같다 )


 < 그림 10 >


구글링을 하다보니 에그쉘로 구한 EGG의 주소와 쉘에서 출력한 결과가 다르다는 문서가 있었다

" getAddr.c " 파일을 작성해서 출력해보았더니 서로 주소가 달랐다. ( 이유는 아직 모르겟다... )

두 주소를 모두 공격지점에 넣어보아도 세그멘테이션오류가 나왔다.

세그멘테이션오류가 나오는 이유는 RET지점에 존재하지 않는 주소가 있기 때문에 발생한 결과이다

하지만 EGG변수의 주소 그대로 넣엇는데 왜 이런결과가 나오는지는 모르겠다..

제 서버에서 주소값들이 0x000000000400554 이런식으로 이상하게 나오는데 아마 여기에 이유가 있는것같습니다.

FTZ서버문제풀이에서 다시한번 해당 에그쉘 코드를 사용해서 문제를 풀어보겠습니다


버퍼 오버 플로우의 이론은 여기까지입니다. 실제 결과는 좋지 않았지만 이론은 틀린 부분없이 잘 설명해놓았습니다.

해당 공격이 왜 실패 되었는지는 더 공부해가면서 수정하겠습니다.

에그쉘코드는 구글링하면 바로나옵니다. ( 복사해서 붙여넣으면 바로실행 가능함 )


==================================================



왜 세그멘테이션오류가 나왔는지 알아냈습니다!! 구글링을해서 찾아보니 에그쉘은 거짓말쟁이였습니다

에그쉘이 알려주는 쉘코드의 주소는 진짜가 아닙니다.  자세한 내용은 [4]번 문서에서 제대로 설명해드리겠습니다


[4] 환경변수를 이용한 버퍼 오버플로우 공격  << Click !!