diff 32bit vs 64bit
diff 32bit vs 64bit
General BOF
EBP-8에 할당되어 있는 변수를 오버플로우 한다고 가정하였을때,
EBP에는 SFP가 존재하고, EBP+4에는 RET이 존재한다.
32bit system에서는 SFP가 4byte크기를 갖기 때문에 RET 변조를 위해서는 최소 스택 + 4 byte의 더미를 주고 RET에 접근한다.
하지만 64bit system의 경우에는 4byte 주소를 사용하던 32bit와는 달리 8byte 주소를 사용한다.
따라서, SFP가 8byte이므로 스택 + 8byte만큼의 더미를 주어야 한다.
RTL and ROP
이에 대해 학습하기 이전에는
Calling Convention에 대한 이해가 필요하다.콜링 컨벤션은 크게 3가지 존재하며 여기서 주목할 것은
cdecl과fastcall이다.두 가지의 호출규약의 가장 큰 차이는 인자를 전달하는 방식이다.
cdecl: 스택 ,fastcall: 레지스터 를 사용하여 인자를 전달한다.32bit system에서의 RTL Payload는 아래와 같다. (ebp-8 Overflow)
payload = '' payload += 'A' * (8 + 4) payload += p32(system) payload += 'A' * 4 payload += p32(binsh)EBP까지의 거리 + SFP 크기의 더미를 주어 RET에 접근하기 위해 스택을 채우고 RET위치를
system함수의 주소로 Overwrite한다. 그 이후 4byte는system함수가 호출된 이후 호출 될 주소를 의미한다.그리고 그 다음 4byte는
system이 끝나고 호출 될 주소이다. (위 예시에서는binsh의 주소)그 뒤 4byte는 첫번째 인자로 들어간다.
64bitSystem에서는 어떠한 레지스터에 몇번째 인자가 들어가는지 알고있어야 한다.
RDI, RSI, RDX, RCX순으로 인자가 들어간다.이를 바탕으로
64bitSystem에서의 RTL Payload를 펴보자. (ebp-8 Overflow)payload = '' payload += 'A' * (8 + 8) payload += p64(pr) # pop rdi, ret , 첫번째 인자 pop payload += p64(binsh) payload += p64(system)64 bit 체제에서는
ret에 바로 함수 주소를 쓸 수 없기 때문에,gadget을 이용해야한다.(만일, 인자가 없는 함수의 경우에는 그냥 써도 무방하다.)
위 예시에서 쓰인
system함수는 인자가 하나인 함수이며 따라서 첫 번째 인자가 들어갈 레지스터인RDI를pop해줘야 한다.먼저,
pop을 이용해서 첫 번쨰 인자가 위치할rdi내부 값을 빼주고,binsh문자열을 넣은 뒤,system함수를 호출한다.