코드가 깁니다.
힌트로 RTL을 사용하라고 써있습니다.
하나씩 따라가 보겠습니다.
Return To Library의 개념을 모르시면 다음 글을 읽고 오세요.
-> http://slimv.tistory.com/entry/Return-To-Library
첫번째 popen()을 살펴보겠습니다.
ldd 명령을 통해 /home/giant/assassin의 shared library 관계를 열어봅니다.
grep을 이용해 결과값에서 libc가 포함된 정보들만 뽑아내고
awk를 이용해 네번째 token의 값을 빼옵니다.
ldd 결과값에서 네번째 token은 주소값입니다.
libc.so.6의 주소를 lib_addr에 저장합니다.
두번째 popen()을 살펴보겠습니다.
nm 명령을 통해 /lib/libc.so.6의 symbol list를 가져옵니다.
grep을 이용해 결과값에서 __execve를 찾습니다.
awk를 이용해 첫번째 token의 값을 빼옵니다.
nm 결과값에서 첫번째 token은 해당 함수의 RVA입니다.
__execve의 RVA를 execve_offset에 저장합니다.
execva_addr을 lib_addr과 execve_offset을 더해서 구합니다.
이제 execve_addr에는 execve()의 주소가 저장되었습니다.
argv[1][44]의 값을 ret에 복사한 후 execve_addr과 비교합니다.
공격자가 입력한 ret가 execve()의 주소값이 아닌 경우
execve()를 사용하라는 메시지가 뜨고 종료됩니다.
execve()가 맞다면 정상적으로 buffer에 argv[1]을 복사하고 출력합니다.
execve()의 첫번째 parameter는 실행할 프로그램의 주소
두번째 parameter는 실행할 프로그램에 넘겨줄 parameter array의 주소
세번째 paramter는 실행할 프로그램에 적용할 환경변수 array의 주소입니다.
execve()의 주소를 먼저 얻어야 할 듯 합니다.
gdb로 열어봅니다.
execve()의 주소는 0x400a9d48 입니다.
execve()에 paremeter로 넘겨줄 libc.so6 내부에 있는 "/bin/sh"의 위치를 찾아야 합니다.
귀찮으니 프로그램을 만들고 돌려줍니다.
"/bin/sh"의 주소는 0x400fbff9입니다.
이제 ret를 execve()로 돌려주고
execve()에서 실행할 paremeter로 "/bin/sh"
argv로 사용할 "/bin/sh"를 가리키고 있는 pointer를 넘겨주면 되겠습니다.
argv는 반드시 null로 끝나야 합니다.
하지만 "/bin/sh"를 가리키고 있는 pointer가 없습니다.
Stack에 저장되어있는 프로그램의 접근 경로를 활용하도록 하겠습니다.
gdb로 열어보면 /home/giant/assassin이 없다고 뜹니다.
소스코드에서 ldd 부분을 /home/bugbear/giant로 바꿔주고 다시 gdb로 열어봅니다.
Stack을 뒤져봅니다.
0xbfffffe7에 주소가 보입니다.
Null로 끝나는것도 확인할 수 있습니다.
target의 이름을 "/bin/sh"를 가리키는 pointer로 만들고 공격하면 되겠습니다.
프로그램을 컴파일 해줍니다.
해당 프로그램과 giant를 link해줍니다.
Link된 프로그램에 parameter로
execve() 주소
execve() 종료 후 ret 값
"/bin/sh" 주소
"/bin/sh"를 가리키는 null로 끝나는 pointer
환경변수로 사용할 null pointer를 넣어주면 됩니다.
공격해봅니다.
공격에 성공했습니다.