[FTZ] Level 13
[ Level 13 ]
level13 로그인
ID : level13
PW : have no clue
힌트를 확인하니 이번에도 attackme의 C언어 소스코드가 적혀있는 것 같다.
소스코드를 보니 i 변수의 값이 달라졌을 경우 "Warnning: Buffer Overflow!!!"를 출력하며,
kill함수가 실행되는 것으로 보인다.
※ kill함수란? | |
헤더파일 | signal.h |
함수 원형 | int kill(pid_t pid, int signo); |
반환 | 성공 : 0 / 실패 : -1 |
pid | 의미 |
양의 정수 | 지정한 프로세스 ID에만 시그널 전송 |
0 | 함수를 호출하는 프로세스와 같은 그룹에 있는 모든 프로세스에 시그널을 전송 |
-1 | 함수를 호출하는 프로세스가 전송할 수 있는 권한을 가진 모든 프로세스에 시그널을 전송 |
-1 이외의 음수 | 첫 번째 인수 pid의 절대값 프로세스 그룹에 속하는 모든 프로세스에 시그널을 전송 |
kill함수에 매개변수로 0과 11을 보낸 것을 보아 함수를 호출하는 프로세스와 같은 그룹에 있는
모든 프로세스에 11이라는 시그널을 전송하였다.
SIGNAL 번호 11은 Invalid memory segment access (ANSI) 즉, Segmentation Fault를 전송한다.
우선 이번에도 /bin/sh 쉘 코드를 환경변수에 저장한다.
/bin/sh의 쉘 코드 |
\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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 |
힌트에 있는 소스코드를 복사하여 tmp디렉터리에 attack.c 파일을 만들어 붙여 넣어 준다.
그리고 getenv함수를 이용하여 쉘 코드 환경변수의 주소를 알아내는 c파일을 만들어 준다.
이후, gcc명령어를 이용하여 각각 실행파일을 만들어 준다.
gdb로 attack을 실행한 뒤, set disassembly-flavor intel을 입력하여 intel문법으로 설정해주고, disass main을 입력한다.
어셈블리 코드를 확인해보면, 변수 선언을 위해 0x418(1048)만큼 스택에 공간을 만들어주었다.
DWORD PTR [ebp-12], 0x1234567은 long i = 0x1234567을 의미한다.
( DWORD는 4byte를 의미하고, PTR은 포인터를 의미한다. )
따라서 i가 저장된 스택 위치는 [ebp-12]인 것을 알 수 있다.
또한 strcpy함수를 호출(call) 하기 전에 매개변수들을 push 하게 되는데, 뒤에서 부터 push를 하게 된다.
strcpy(buf, argv[1])이기 때문에 "DWORD PTR [eax]( [ebp+12] + 0x4 )"는 argv[1]에 해당하고,
이다음에 push 되는 [ebp-1048]이 buf를 가리키는 것을 알 수 있다.
이때, buf와 i 사이의 거리가 1024byte가 아닌 1036byte인 것을 알 수 있는데
그 이유는 buf와 i 사이에 12byte만큼의 dummy 공간이 생겼기 때문이다.
또한 i의 자료형은 long이라서 4byte의 공간만을 차지하지만 실제 메모리에서는 EBP와 12byte만큼의 거리를 두고 있다.
이는 i와 EBP 사이에 8byte라는 dummy 공간이 생겼다는 것을 알 수 있다.
그림으로 나타내면 아래와 같다.
buf | 1024byte |
dummy | 12byte |
i | 4byte |
dummy | 8byte |
EBP | 4byte |
RET | 4byte |
Buffer Overflow를 발생시키기 위해서는 i의 값이 0x1234567에서 변함이 없어야 한다.
따라서 "\x90"을 처음에 1036byte만큼 입력하고, 다음으로 "\x67\x45\x23\x01"(0x1234567)을 입력하여
i가 위치한 곳에는 기존에 i에 저장된 값과 똑같은 값을 입력해주고, 뒤따라 "\x90"을 12byte만큼 입력시켜준 뒤
RET에는 쉘 코드 환경변수의 주소를 입력해주면 쉘 코드가 실행되면서, Buffer Overflow 시킬 수 있을 것이다.
이제 getenv실행파일을 실행하여 쉘 코드 환경변수의 주소를 알아내고,
( 쉘 코드 환경변수의 주소 : 0xbffffc17 )
실제로 실행이 되는지 테스트해보기 위해서 tmp디렉터리에 있는 attack에서 실행한다.
( sh 상태에서 나가고 싶다면, "exit"를 입력하면 된다. )
실행이 잘되는 것을 확인하였으니, 이제 attackme로 실행한다.
/bin/sh가 실행되면, my-pass 명령어를 통해 level14의 password를 알아낸다!