본문 바로가기

My Study/Exploit

BOF의 개념 ( Hackerschool level11 )

이번에 알아 볼 것은 BOF( Buffer over flow )이 무엇인지 부터해서 BOF를 이용한 간단한 해킹 방법에 대해서 알아보겠습니다.
해킹 방법에 대해서 설명할 때는 해커스쿨 level11을 대상으로 직접 문제를 풀어보면서 알아보도록 하겠습니다.

BOF란 무엇일까요??
말 그대로 버퍼가 오버플로우 나서 생기는 오류 입니다.
예를 들어보겠습니다.

위와 같은 소스가 있습니다. 딱 봐도 어디가 잘못 된지 보이실 것입니다. 
attack이라는 버퍼에는 널문자 포함해서 30개의 문자가 들어있습니다. 하지만 buf라는 배열의 크기는 10밖에 되질 않으므로
컴파일러도 buf에는 총 10Byte만큼의 공간 밖에 주질 않을 것입니다. 

위 코드를 실행 시키면 어떻게 될까요?? 다들 예상하셨듯이 버퍼 오버플로우가 일어나게 되는 것입니다.
해당 소스를 컴파일 시켜 exe파일을 올디로 직접 스택을 보면서 이야기를 해보겠습니다.

이 부분입니다. 각각 인자를 스택에서 봐보겠습니다.

30개의 문자가 12FF68부터 쌓이기 시작할 것입니다.
하지만 저 위치부터 30개가 쌓이게 되면 ebp는 물론 해당 함수를 빠져나갔을 때 리턴되는 주소가 있는 RET부분까지도 
덮어씌워버리게 될 것입니다. strcpy를 실행 시킨 후의 스택 모습을 봐보겠습니다.

위와 같이 ebp, ret부분까지 30개의 문자가 덮어씌워버린 것을 알 수 있습니다.
이렇게 되면 결국 ret부분에서는 0x38373635라는 주소가 어딘지 몰라 에러가 뜰 것입니다.

버퍼 오버플로우라는 개념이 대충 이런식으로 됩니다.

이런 버퍼 오버플로우라는 취약점을 가진 프로그램이 있다면 어떻게 공격을 할 수 있을까요??
리눅스 상에서 설명을 하도록 하겠습니다.

시나리오는 대충 이렇습니다.
한 리눅스 서버가 있는데 그 서버에는 여러명의 일반 유저들이 있고 서버를 관리하는 root가 있습니다.
root는 일반 유저들에게 프로그램을 하나 만들어 주었습니다. 
그러면 그 파일은 당연히 root에게만 읽기,쓰기,실행 권한이 주어지고 다른 일반 유저들에게는 실행 권한만 주어질 것입니다.
(이 파일은 사용할 때 잠깐 root권한을 얻도록 setuid가 설정되어 있는 프로그램 입니다. )
하지만 한 유저가 그 프로그램에서 버퍼 오버플로우가 나는 코드 부분을 찾았습니다. 그래서 그 유저는 그 취약점을 통해 root권한을 따는 공격을 시작했습니다.


위와같은 시나리오 입니다. 문자열을 입력하면 스택에 들어가게 됩니다. 하지만 문자열에 공격 코드를 넣고 ret까지 문자열을 계속 입력하면서(버퍼 오버플로우) ret부분에는 공격코드가 있는 주소로 덮어씌워주면 됩니다.
만약에 공격 코드
setreuid(0,0)
/bin/sh
였다면 setuid가 걸린 파일을 실행할 때 얻었던 root권한을 다시 얻게 되고 /bin/sh로 root의 쉘을 떨치게 되는 것입니다. 
( setuid가 걸린 파일을 실행시키면 실행할 때만 해당 권한을 얻게되고 
  실행되는 동안은 다시 유저의 권한으로 돌아가게됩니다. )

이제 어떠한 공격방법인지 알았으니 해커스쿨 level11번을 대상으로 직접 공격을 시도해 보겠습니다.
해커스쿨 문제를 안풀어보신 분들을 위해 간략히 해커스쿨 문제 풀이 방법에 대해서 설명해보면
1. 현재 나는 level1에 있다.
2. level2로 가려면 level1에서 level2의 패스워드를 얻어내야한다.
이런 형식 입니다. 현재 저희는 level11에 있으므로 level11에서 level12의 패스워드를 알아내야겠죠.

level11에서 제공해 주는 프로그램이 하나 있습니다.

attackme라는 프로그램 입니다. 프로그램 정보를 봐보니
level11은 읽고, 실행만 가능합니다.
level12는 읽고,쓰기,실행,setuid 까지 전부 있습니다.
level12권한으로 setuid가 걸려있는 것을 보니 저 프로그램 안에서 쉘을 떨치면 되겠다라는 시나리오가 나오게 됩니다.

어떤 식으로 동작하는지 확인해 보겠습니다.

단순히 인자로 전달했던 문자열을 다시 출력만 해주고 종료되버립니다.
해당 파일을 gdb로 봐보겠습니다. ( 소스 코드가 있지만 보지 않고 하는게 더욱 도움이 되기 때문에 언급하지 않겠습니다. )

코드는 별거 없었습니다. setreuid로 프로그램이 실행되는 동안 level12권한을 잠시 얻고 있고 main함수 인자로 전달했던 argv[1]을 buf에 넣고 있고 넣었던 buf를 출력 해주는 과정이 전부 입니다. 저기서 어떻게 버퍼오버플로우를 일으킬까요??
딱 보니 취약한 함수가 보입니다. strcpy 이 함수는 몇 글자를 버퍼에 복사할지 정하지 않습니다. 널 문자를 만날 때까지 모든 문자를 버퍼에 넣어버리죠. 그렇게 되버리니 버퍼오버플로우가 일어나게 되는 것입니다. 이제 저 함수를 가지고 level12의 쉘을 떨쳐보겠습니다.

위에서 나왔던 그림 입니다. 다시 한번 보여드리겠습니다. 문자열이 복사될 때 문자열 안에 공격 코드를 넣어두고 리턴 값까지 덮어 씌우면서 리턴 값을 공격코드 있는 곳으로 돌리면 됩니다.
공격 코드는 단순 합니다.
이미 소스코드 안에 setreuid가 존재하므로 우리는 쉘만 떨쳐주면 되는 것입니다.

char shell[2];
shell[0] = "/bin/sh";
shell[1] = NULL;

execve("/bin/sh",shell,0);

위와 같은 코드를 문자열로 넣을 수 있게 쉘코드로 만들어 주면 됩니다. ( 25 글자 )
\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
위와 같은 쉘 코드 입니다. 쉘 코드를 만드는 과정은 따로 올리겠습니다.
http://ezbeat.tistory.com/150

이제 공격을 하기 전에 몇글자를 입력해야 되고 ret부분에 어떤 주소를 넣어야 하는지를 모릅니다.
구해보겠습니다.
위 어셈코드를 보시면 스택이 대충 그려질 것입니다.

총 리턴값까지 써야만 공격코드가 완성되므로 전달해야하는 공격코드는 총 272byte가 되겠습니다.
그리고 어셈코드를 보면 main함수 호출 시 인자로 전달되서 오는 것이기 때문에 오버플로우가 일어날 만큼의 크기를 전달할 경우 main함수에서의 ebp가 달라지게 됩니다. 왜냐하면 문자열을 main함수에서 받는 것이 아니라 문자열을 main함수 인자로 push하고 main함수 스택이 시작되기 때문입니다. 그러면 총 272자를 넣은 후 ebp값을 봐보겠습니다.

ebp값은 0xbffff9f8이고 strcpy에서 첫번째 인자로 전달되는 주소는 0x108을 뺀 0xbffff8f0
이 되겠습니다. 그러면 리턴 주소를 0xbffff8f0으로 주고 공격을 하면 되는 것입니다.

쉘코드 + 리턴 주소  를 제외한 나머지 부분에는 그냥 아무 문자나 넣어주시면 됩니다.
계산 결과 243자는 아무 문자가 넣어주면 됩니다.

완성된 공격 인자
`perl -e 'print "\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","A"x243,"\xf0\xf8\xff\xbf"'`

이제 다시 인자를 전달해보겠습니다. ( 잘 안보이실 태니 클릭~! )

uid를 보니 level12입니다. 쉘 따기 성공입니다.

지금까지 설명한것이 BOF의 개념과 기초적인 공격방법입니다.
해커스쿨의 리눅스 버전을 보면 redhat 9버전으로 스택에서 코드실행이 가능했습니다.
하지만 페도라 core2에서는 스택에서 코드실행을 막도록 되어있는거 같았습니다.

저도 공부하는 입장이라 하나하나 알아가면서 문서 작성을 하도록 하겠습니다.

'My Study > Exploit' 카테고리의 다른 글

Hackerschool level15  (0) 2010.03.23
Hackerschool level14  (0) 2010.03.22
Hackerschool level13  (0) 2010.03.22
Hackerschool level12  (3) 2010.03.22
shell 코드 만들어 보기  (14) 2010.03.19