이번에 S!에서 포너블 스터디를 시작하면서 처음으로 주어진 과제네요.
LOB 풀이를 시작해보겠습니다. 환경 구축은 다음에 숫자 0으로 올려보도록 해야겠네요.
bof의 개념을 알고 hackerschool의 과정을 어느정도 진행했다면 딱히 서론이 필요없을테니 바로 풀이를 시작하겠습니다.
풀이
우선 LOB의 redhat과 xshell을 통해 telnet 연결을 합니다.
id : gate
pw : gate
로 들어가서 gate로 일단 로그인합니다.
ls -l 명령어를 입력합니다. (권한을 보기 위해서)
gremlin 파일과 gremlin.c 파일이 보입니다.
여기서 권한의 rw's' 에서 s 부분은 setuid를 의미하는데, 대문자 S가 들어가면 일반 권한의 -를 의미합니다.
어찌되었든 gate는 gremlin의 권한을 빌려서 gremlin 파일을 실행시킵니다. (rws r-x r-x = 4755) 처럼 s권한이 들어가면 앞에 4를 붙입니다. (https://wogh8732.tistory.com/74)
gremlin.c를 읽어서 보면
buffer의 크기는 256이고 main함수에서 인자를 받아 처리합니다.
strcpy함수가 쓰인 부분에서 bof가 일어납니다.
bof가 일어나면 무엇하나 권한을 얻어야지.
그래서 buffer에 쉘코드를 넣고 ret를 buf주소로 변조해서 쉘 코드를 실행시킬 것입니다(Return to Shellcode)
그러면 buf의 주소를 알아야합니다. gdb로 뜯어보려고 하는데 gremlin은 gate의 소유가 아니므로 gdb로 뜯을 수가 없습니다.
그래서
cp gremlin cremlin
을 입력하여 cremlin이라는 이름으로 복사합니다.
그리고 ls -l을 입력하면
짜잔. cremlin은 gate의 소유가 됩니다.
본격적인 풀이
이제 다 해봤으니 본격적인 풀이를 해보겠습니다.
우선 여기 리눅스에는 python이 설치되어 있습니다.
파이썬 옵션 중에서도 -c에 주목하면 -c를 통해
아래와 같이 터미널에서 실행이 가능합니다.
또한 이를 $()로 감싸면 출력값이 명령어처럼 들어옵니다.
너무 좋다..
그래서 이를 가지고 cremlin에 Buffer Overflow를 할 것입니다.
메모리 구조에서
지역변수인 buf는 스택에 위치하는데,
스택 프레임은 다음과 같습니다. buf뒤에는 sfp인(ebp)가 4바이트, 그 뒤에 RET가 4바이트 존재합니다. (file 명령어를 통해 보면 32bit 파일이므로)
함수별로 서로가 사용하는 스택의 영역을 명확히 구분하기 위해 스택프레임이 사용됩니다.
push ebp
mov ebp, esp
sub esp,~~
call했던 함수의 ebp를 스택에 집어넣고(sfp)
ret는 이미 현재 함수를 call한 시점에서 ret instruction을 실행하면 rip를 이동시켜 흐름을 되돌리기 위함으로 들어가 있습니다.
스택의 프레임이 되는 ebp를 다시 현재 스택부터 해두고
esp에서 공간을 미리 확보해둡니다.
leave
ret
ret는 아까 설명했고
leave는
mov esp, ebp
pop ebp 이므로 (pop는 스택에 있는걸 operand에 저장한다) 스택 프레임을 정리합니다.
그래서 ebp는 B로, RET는 C로 채웠습니다.
위 사진에서 보듯 Segmentation Fault가 발생하며 core파일이 생성되었습니다. core파일은 비정상적으로 프로그램이 종료되었을때 바로 그 상태를 기록해두는 파일로
gdb core 혹은 옵션으로 gdb -c core를 통해 실행합니다. (무슨 차인진 모르겠음)
그러면 ret 자리에 있던 C(0x43)에 대해 알려주는데,
세그폴트가 발생한 시점에서 ret를 하는데에 에러가 났으므로 leave에서 mov esp, ebp 부분까지는 제대로 실행되어 있었을 것.. 그러니까 esp를 스택 프레임의 시작부분이라고 생각하고 충분히 값을 빼서 스택을 검사해봅니다. (esp - 0x150) 버퍼의 크기가 0x100이니까 150은 빼둬야 할듯.
0x41이 시작하는 부분인 0xbffff910 + (8byte) = 0xbffff918이 buf의 시작임을 알 수 있습니다.
이를 ret로 바꾸는데, Little Endian을 사용하므로 0x18 0xf9 0xff 0xbf로 저장되어야 할 테니
그에 맞게 파이썬을 만들어야겠습니다.
shell code는 인터넷에서 가져다가 사용하고. exploit을 합니다.
우선 cremlin으로 exploit해서 shell을 얻을 수 있는지 확인합니다.
./cremlin $(python -c "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'+'\x90'*(256-25+4)+'\x18\xf9\xff\xbf')")
256은 buf의 크기라서, 25는 shellcode의 크기라서, +4는 sfp까지 \x90(NOP)로 덮었습니다.
gremlin으로 다시 실행하면
짜잔.