작년에 한동안 학교다니면서 짬짬히 했었던거. 쏟은 시간에 비해 결과물은 비루하다. 오랜만에 파일정리하고있었는데 나오드라. 나중에 시간되면 갖고있는 나머지도 다 해봐야될듯. 근데 이거 두 개 하고서는 꽤나 어셈에 대한 두려움이 없어져갖고 신기했었다. 뭐든지 다 읽을 수 있는기분ㅋ
"To analyze strace's output you must know that the first keyword in a line of output from strace is always a syscall like open or read. Then, in parantheses, the arguments follow, then the result. "
우선 strace의 출력의 첫 키워드는 시스템콜이고, 괄호안에는 전달되는 인자라네여. 그리고 뒤에 결과가 따른다고 합니다. 아마 뒤에 = 한게 결과겠죠?
ㅋㅋ맞다고 써있네요.
"Every line follows the syntax
syscall(arguments) = return value
친절하게 시스템콜이 어떤 동작을 하는지 모르겠다면 man 2 <systemcall>이렇게 찾아보라고도 하네요.
brk(0) = 0x8049548 //changes the end of the data segment to addr
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000 /*maps files&&devices into memory- pages may be read, written, a private copy is made*/
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
근데 old_mmap랑 mmap 랑 munmap 랑 같은거 같은데 뭘 하는지는 잘 감이 잡히지 않네요. 근데 왜 그동안 strace..이걸 안쓰려고 했나 모르겠ㅅ브니다. 역시 하고봐야 되는듯. 그동안 무서워서 못건드렸거든옄ㅋㅋㅋㅋㅋㅋㅋㅋ 이런..
++) mmap는 근데 메모리에 어떤 장치가 사용할 메모리를 할당해주는 것인 것 같은데, 그렇다면 각각 함수, 즉 open 이나 read, write같은 함수가 사용하는 공간을 만들어주는 것인가요? 위에 strace를 보면 각각 함수들 실행시키기 전에 하나씩 있는걸 보니..
이렇게 되게 된다. (스택이 자라는 방향: 낮은주소 ← 높은주소, 스택은 LIFO(Last-In-First-Out))
*)SFP(Saved Frame Pointer)란?- 처음에 함수 프롤로그(push %ebp)에 의해 저장된 EBP의 값이다 (함수에서 지역변수들이 사용될 때 그 기준으로 EBP가 쓰이는데 타 함수로 넘어갈 경우 다시 돌아왔을 때 ebp를 복귀시켜야 하니 저장해두는 값. 함수가 시작했을때 당시 최초의 EBP 주소를 가리키고 있다)
*)RET(Return Address)란?- EIP(Extended Instruction Pointer)가 가리킬 곳을 가르쳐주는 주소값. EIP는 프로그램이 끝난 후 돌아갈 주소를 가지고 있다.
위의 소스에서 strcpy때문에 버퍼오버플로우가 생기게 되는데, 만약에 버퍼(유저입력으로) 48바이트를 넣는다면 유저의 입력이 버퍼인 40바이트 뿐만아니라 버퍼 뒤에 있는 SFP와 RET까지 덮어버려 프로그램의 실행을 바꾸기 때문이다. RET는 EIP, 즉 함수 실행이 끝난 뒤 어디로 EIP가 가야 할 지 가르쳐주는 역할을 가지고 있기 때문에 만약에 사용자가 RET를 덮어쓴다면 사용자가 입력한 주소로 프로그램의 실행이 계속 되게 된다. 이를 이용해 버퍼에 쉘코드를 넣고 RET를 버퍼의 시작 주소값 또는 NOPSLED 중 하나의 주소값으로 설정한다면 EIP는 버퍼로 가 쉘코드를 그대로 실행하게 된다.
*)NOPSLED란?- NOP(No OPeration)는 (Intel x86 CPU기준으로)"\x90"을 뜻하는데, 이 명령은 아무 동작도 하지 않고 다음 명령으로 넘어가라는 뜻이다. 만약에 NOP가 900개 있고 그 후에 쉘코드가 있다면 ESP(Extended Stack Pointer- 실행하는 명령을 가르키는 포인터)는 NOPSLED(미끄럼틀같이) 아무 명령도 실행하지 않고 계속 진행하다가 마지막에 있는 쉘코드를 실행하게 된다.
*)Little Endian이란?- 엔디안은 메모리에 수를 저장하는 방식인데, 차이점은 빅 엔디안과 리틀 엔디안에 12345678을 넣게 된다면, 빅 엔디안(이 방식을 쓰는 컴퓨터는 별로 없다)은 12 34 56 78로 메모리에 적재하는 반면 리틀 엔디안은 뒤에서부터 78 56 34 12 이렇게 두바이트씩 끊어 거꾸로 넣게 된다. 고로 리턴 어스레스 같은 경우에도 페이로드에 거꾸로 뒤집어 준 후 넣어야 한다. \x~~\x~~\xff\xbf <- 이런 식
만약에 위와 같은 코드에 strcpy를 두번, system을 한번 이렇게 연속으로 실행하고 싶다고 가정해보자.(걍 머리에 떠오르는 함수,...)
그렇다면 이것들을 어떻게 실행시켜야 할까?
strcpy의 인자는 2개(char *dest, const char *source)이다. 인자가 하나라면 (function) (function) (argv) (argv) 이렇게 끼워서 두 번 실행시킬 수 있겠지만, 늘 함수 주소 뒤의 4바이트를 인자로 참조하기 때문에 인자가 2개인 strcpy는 1번 이상 사용할 수 없다.
pop- Stack에서 데이터를 빼는 것 말고도 pop는 esp+4를 하게 되기 때문에 다음 인스트럭션을 가르키게 된다. 이 경우에는 가젯이 pop pop ret이기 때문에 strcpy를 실행하고 인자를 두 개 전달한 뒤, pop pop ret을 이용해 두 인자를 건너뛰고 그 뒤에 있는 두 번째 strcpy의 주소를 ret하여 다시 실행하게 되는 것이다.
*)가젯(Gadget)이란?- 프로그램 내부의(함수에) 기계어로 된 ret로 끝나는 코드의 조각으로써 필요한 가젯을 찾아 공격자의 마음대로 사용하면 된다
만약에 건너뛰어야 하는 인자가 3개라면, pop pop pop ret, 하나라면 pop ret을 찾아 사용하면 되는 것이다.