SH1R0_HACKER
stack 2 본문
stack2.c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
char *variable;
variable = getenv("GREENIE");
if(variable == NULL) {
errx(1, "please set the GREENIE environment variable\n");
}
modified = 0;
strcpy(buffer, variable);
if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
이 프로그램은 실행하면 GREENIE 환경 변수가 없다며 프로그램이 종료된다.
코드를 분석해보면 modified (4byte), variable (4byte), buffer (64byte)를 선언한다.
getenv 함수는 variable에 시스템 환경 변수 GREENIE에 저장된 값을 가져온다.
variable == NULL 이라면 오류를 띄우고 종료한다.
GREENIE 환경변수를 만들고 modified를 0x0d0a0d0a로 만들어주어야 할 것 같다.
[ 취약점 파악 및 분석 ]
아래는 어셈블리어 해석이다.
0x08048494 <+0>: push ebp
0x08048495 <+1>: mov ebp,esp
0x08048497 <+3>: and esp,0xfffffff0
0x0804849a <+6>: sub esp,0x60
0x0804849d <+9>: mov DWORD PTR [esp],0x80485e0
0x080484a4 <+16>: call 0x804837c <getenv@plt>
// esp 레지스터에 0x80485e0를 전달하고 getenv 함수를 실행한다.
// x/s 0x80485e0 : "GREENIE"
0x080484a9 <+21>: mov DWORD PTR [esp+0x5c],eax
0x080484ad <+25>: cmp DWORD PTR [esp+0x5c],0x0
// [esp+0x5c] 메모리와 0을 비교한다. (환경변수에서 아무것도 안가지고오면 0)
// variable 변수 : esp+0x5c
0x080484b2 <+30>: jne 0x80484c8 <main+52>
0x080484b4 <+32>: mov DWORD PTR [esp+0x4],0x80485e8
0x080484bc <+40>: mov DWORD PTR [esp],0x1
0x080484c3 <+47>: call 0x80483bc <errx@plt>
// x/s 0x80485e8 "please set the GREENIE environment variable\n"
0x080484c8 <+52>: mov DWORD PTR [esp+0x58],0x0
// [esp+0x58]에 0을 넣는다.
// modified 변수 : esp+0x58
0x080484d0 <+60>: mov eax,DWORD PTR [esp+0x5c]
0x080484d4 <+64>: mov DWORD PTR [esp+0x4],eax
0x080484d8 <+68>: lea eax,[esp+0x18]
// buffer 변수 : esp+0x18
0x080484dc <+72>: mov DWORD PTR [esp],eax
0x080484df <+75>: call 0x804839c <strcpy@plt>
0x080484e4 <+80>: mov eax,DWORD PTR [esp+0x58]
0x080484e8 <+84>: cmp eax,0xd0a0d0a
// modified 변수와 0x0d0a0d0a를 비교한다.
0x080484ed <+89>: jne 0x80484fd <main+105>
0x080484ef <+91>: mov DWORD PTR [esp],0x8048618
0x080484f6 <+98>: call 0x80483cc <puts@plt>
// x/s 0x8048618 "you have correctly modified the variable\n"
0x080484fb <+103>: jmp 0x8048512 <main+126>
0x080484fd <+105>: mov edx,DWORD PTR [esp+0x58]
0x08048501 <+109>: mov eax,0x8048641
0x08048506 <+114>: mov DWORD PTR [esp+0x4],edx
0x0804850a <+118>: mov DWORD PTR [esp],eax
0x0804850d <+121>: call 0x80483ac <printf@plt>
// x/s 0x8048641 "Try again, you got 0x%08x\n"
0x08048512 <+126>: leave
0x08048513 <+127>: ret
variable의 위치 : esp+0x5c
modified의 위치 : esp+0x58
buffer의 위치 : esp+0x18
[ 취약점 파악 및 분석 ]
우선 프로그램을 실행시키기 위해선 "GREENIE" 라는 환경변수가 필요하다.
이 환경변수가 스택을 다 채우고 modified 변수를 0x0d0a0d0a로 만들어 버리게 하면 된다.
먼저 buffer와 modified의 거리부터 알아보자.
길이가 대략적으로 100보다 작을거라고 생각하고 길이 100의 패턴을 만든다.
그 후 export (환경변수명)='(패턴 값)' 형태로 입력하여 환경변수를 만들어준다.
그러면 이제 프로그램은 GREENIE 환경변수를 참고하여 실행된다.
브레이크 포인트를 main+84에 걸어준다.
modified 변수와 0x0d0a0d0a를 비교하는 부분이다.
레지스터에 저장된 패턴값을 보면 EAX : 0x41644141 ('AAdA') 부분을 볼 수 있다.
현재 브레이크 포인트인 main+84번은 modified 변수를 eax에 넣고 비교하기 직전이다.
따라서 현재 eax에 들어있는 값이 modified에 들어있는 패턴값으로 볼 수 있다.
즉, GREENIE 환경변수에 설정한 패턴 100개가 buffer (64byte)를 모두 채우고
modified(4byte)로 넘어온 부분이 'AAdA' 라는 것이다.
이 부분을 오프셋 명령어의 인자값에 입력하면
사진 삭제
사진 설명을 입력하세요.
buffer변수와 modified변수의 거리는 64바이트라는 결과를 얻을 수 있다.
[ Exploit ]
이제 buffer변수와 modified변수의 거리도 알았으니 공격을 해보자.
대표사진 삭제
사진 설명을 입력하세요.
0x0d0a0d0a를 ASCII 코드로 변환하여 입력하려면 문자열이 아닌 개행, 줄바꿈이기 때문에 문자열이 아닌
파이썬을 통해 값을 입력해야 한다.
$ 표시와 () 를 사용하면 파이썬 실행 결과를 커맨드라인에 문자열로 넣을 수 있다.
형태 : $(python -c '코드')
메모리 입출력 방식이 리틀 엔디안이기 때문에 0x0a0d0a0d 순으로 입력하면 된다.