[해커스쿨FTZ] Level11
attackme에 level12권한이 걸려있다.
힌트에 소스코드가 나와있다.
tmp디렉토리로 가서 이 소스로 프로그램을 만들고 디버깅을 해보자.
vi에디터로 힌트 소스를 그대로 써준다.
gcc -o test test.c로 컴파일 해준 뒤, gdb로 붙여서 디버깅해보도록 한다.
소스에는 str[256]으로 크기를 만들었는데,
<main+51>부분을 보면 264 byte 만큼 할당한다.
8 byte의 dummy가 생겼다고 볼 수 있다.
스택 구조는
버퍼 + dummy + SFP + RET의 구조인데,
SFP와 RET는 각각 4 byte의 크기를 갖는다.
따라서, 256 byte buffer + 8 byte dummy + 4 byte SFP
= 268 byte 크기 이후에 RET으로 들어갈 수 있다.
RET에 내가 원하는 쉘 코드의 주소 등을 넣어줘서 공략할 수 있을 것 같다.
NOP Sled 방식으로 풀어보려고 했는데,
ASLR이 걸려 있어 정확한 주소로 때릴 수가 없어서 찾아봤다.
RTL공격을 이용할 수 있을 것 같다.
RTL이란, Return To Library로,
RET에 라이브러리 함수를 덮어씌워 실행되도록 하는 공격기법이다.
공유 라이브러리가 올라오는 주소는 바뀌지 않으므로, 정확한 주소를 페이로드에 넣을 수 있다는 장점이 있다.
즉, NOP Sled 방식을 이용하려면 적당한 임의의 ret 주소를 설정해야 하는데,
시스템에서는 메모리 주소를 계속 바꿔주므로 Segmentation Fault가 발생한다.
적당한 주소를 계속 보내면 운좋게 풀 수도 있을 것이다.
아무튼, RTL 공격을 이용하면 '정확한'공격이 가능하다.
일단 268 byte는 "A"라는 문자열로 넣어줄 생각이고, 그 이후에 우리는
/bin/sh를 '실행'시켜야 한다.
따라서 system함수를 이용할 수 있을 것이다.
system("/bin/sh")의 형태로 입력시키고, system함수의 주소를 ret에 덮어씌우면 될 것 같다.
우선 system함수의 라이브러리 주소를 알아야 한다.
gdb test
b *main
으로 브레이크포인트를 걸고 gdb에서
print system을 입력해 system 주소를 반환하도록 한다.
그렇게 얻어낸 시스템 함수의 주소는 0x4203f2c0 이다.
이후에는 "/bin/sh"라는 문자열의 주소를 알아내야 한다.
그러나 system함수는 내부적으로 execve함수를 사용한다.
그런데 이 execve라는 함수는 /bin/sh라는 문자열을 실행하는 것이다.
그러니까, system함수 내부의 execve함수 내부에는 "/bin/sh"라는 문자열이 '이미'존재한다는 것이다.
간단한 코드를 돌려 "/bin/sh"문자열의 주소를 찾아보도록 한다.
addr은 위에서 찾은 system함수의 주소이다.
이 코드를 vi에디터로 만들어 컴파일하고 실행하면,
"/bin/sh" 문자열의 주소를 얻을 수 있다.
"/bin/sh"문자열의 주소 : 0x42127ea4
이제 payload를 작성해보자.
./attackme `python -c 'print "A"*268+"\xc0\xf2\x03\x42"+"A"*4+"\xa4\x7e\x12\x42"'`
로 넘겨주면 쉘을 획득할 수 있다.
이에 대한 설명은 다음과 같다.
ret 주소에는 system함수의 주소를 넣어줘서 system함수를 호출하게 한다.
4 Byte의 빈 공간 이후에 인자가 들어가기 때문에 A를 4번 넣어줘서 4 Byte를 채우고,
인자로 들어갈 문자열의 주소를 채워준다.
4 바이트의 빈 공간이 생기는게 잘 이해가 되지 않아서 찾아보니
EBP에서 명령어까지 8 byte가 떨어지게 되는데, EBP의 길이가 4 byte라서,
남은 4 byte만 (A로) 채워주면 된다고 한다.