문제에서 코드가 주어지고 코드의 맨 윗줄 주석에 // compiled with : gcc -o memcpy memcpy.c -m32 -lm 컴파일 명령어가 적혀있다. 코드를 복사하고 컴파일을 진행하면 memcpy 파일이 생긴다. 필자의 리눅스 환경은 64bit로 아래와 같이 잘 작동한다.
하지만 문제 서버에서 memcpy를 실행하면 아래와 같이 experiment 5의 fast_memcpy 함수에서 Segmentation fault가 일어나서 프로그램이 종료된다.
char* fast_memcpy(char* dest, const char* src, size_t len)
{
size_t i; // 64-byte block fast copy
if(len >= 64)
{
i = len / 64;
len &= (64-1);
while(i-- > 0)
{
__asm__ __volatile__ (
"movdqa (%0), %%xmm0\n"
"movdqa 16(%0), %%xmm1\n"
"movdqa 32(%0), %%xmm2\n"
"movdqa 48(%0), %%xmm3\n"
"movntps %%xmm0, (%1)\n"
"movntps %%xmm1, 16(%1)\n"
"movntps %%xmm2, 32(%1)\n"
"movntps %%xmm3, 48(%1)\n"
::"r"(src),"r"(dest):"memory");
dest += 64;
src += 64;
}
}
// byte-to-byte slow copy
if(len) slow_memcpy(dest, src, len);
return dest;
}
위 코드는 fast_memcpy 함수이다. 함수에는 __asm__ __volatile__ 안에 어셈블리 언어가 있는데 movdqa와 movntps하는 명령어가 있다. 명령어 사용법은 아래와 같다.
movdqa xmm [메모리] => [메모리]에 있는 128bit(16바이트) 데이터를 xmm 레지스터로 한번에 전송한다.
movdqa [메모리] xmm => xmm 레지스터에 있는 128bit(16바이트) 데이터를 메모리로 한번에 전송한다.
movntps [메모리] xmm => xmm 레지스터에 있는 128bit(16바이트)를 메모리로 복사한다.
문제 서버의 /tmp/test01 디렉토리에 memcpy.c를 만들고 컴파일해서 memcpy 실행파일을 gdb로 열어줍니다.
movdqa가 시작하는 0x080487b9에 브레이크를 걸어주고 실행합니다. 그리고 문제가 발생하는 지점을 찾습니다.
문제가 발생하는 지점은 128이 fast_memcpy인자로 들어갔을때 movntps가 실행될때 Segmentation fault가 발생합니다. 발생하기 직전 edx 값을 보면 0x804c4a8입니다. 여기서 오류가 발생하는 이유는 xmm은 128비트 크기를 가지는 레지스터로 기본단위가 128bit(16바이트)인데 edx는 메모리 주소 끝이 0x10 단위가 아닌 0x8이 있기 때문에 오류가 발생합니다. 따라서 128 인자가 들어가기 전 64 인자가 들어갈 때 값을 72로 변경하면 128 인자가 들어가는 순서일 때 edx 값은 0x804c4b0으로 8바이트가 증가하여 16바이트 단위 조건을 만족하게 됩니다.
64비트 환경에서는 잘 동작하는 파일이 문제 서버에서는 오류가 발생하는 것으로 봐서 문제 서버는 32bit를 사용하고 메모리 할당 단위가 64bit의 절반인 8바이트라서 이런 문제가 발생하는 것 같습니다. 이후 입력값들도 모두 8씩 더한값을 입력하면 플래그가 출력됩니다.
'시스템 해킹 > pwnable.kr' 카테고리의 다른 글
[Pwnable.kr] horcruxes (1) | 2021.08.03 |
---|---|
[Pwnable.kr] asm (0) | 2021.08.01 |
[Pwnable.kr] uaf (0) | 2021.07.30 |
[Pwnable.kr] blukat (0) | 2021.07.29 |
[Pwnable.kr] cmd2 (0) | 2021.07.29 |
댓글