Reverse L01
'Wargame > CodeEngn (Basic)' 카테고리의 다른 글
Reverse L06 (0) | 2012.11.17 |
---|---|
Reverse L05 (0) | 2012.11.17 |
Reverse L04 (0) | 2012.11.16 |
Reverse L03 (0) | 2012.11.16 |
Reverse L02 (0) | 2012.11.16 |
Reverse L01
Reverse L06 (0) | 2012.11.17 |
---|---|
Reverse L05 (0) | 2012.11.17 |
Reverse L04 (0) | 2012.11.16 |
Reverse L03 (0) | 2012.11.16 |
Reverse L02 (0) | 2012.11.16 |
Copy On Write
OS는 각 process 별로 가상 주소 공간을 할당합니다.
Task switching을 할 때 OS는 memory의 코드들을 바꿉니다.
Process들은 dll과 같이 서로 같은 코드가 올라가있는 영역이 있습니다.
중복된 코드들을 복사하는 것은 CPU의 자원을 낭비하도록 만듭니다.
그래서 kernel32.dll과 같이 대부분의 process가 공통적으로 사용하는 코드가 들어있는 영역은
Task switching 할 때 복사하지 않고 그대로 남겨둡니다.
그렇다면 kernel32.dll의 코드를 patch하면 다른 process에게도 영향을 미칠 수 있으리라 예상됩니다.
kernel32.dll에 patch를 해보겠습니다.
kernel32.dll 영역에 아무 공간이나 잡고 patch합니다.
patch한 곳의 주소값을 기억하셔야 합니다.
위에서 설명한 논리대로 작동한다면
이제 다른 process에서 해당 주소를 찾아가면 patch된 코드가 있어야 합니다.
다른 process에서 해당 주소를 찾아가 봅니다.
0x90으로 차 있습니다.
분명 kernel32.dll은 수많은 process에서 사용하고
Task switching 할 때 swapping을 하지 않는 공간입니다.
그런데도 다른 process에서의 patch가 적용되지 않았습니다.
이는 Copy On Write라는 기술 때문에 그렇습니다.
Copy on write는 swapping을 하지 않는 공간에 write event가 발생한 경우
Write event가 건드린 영역만 따로 swapping 하는 기술입니다.
Process A에서 특정 library 영역에 write event가 발생합니다.
OS에서는 write event가 발생한 영역만 따로 page로 복사해둡니다.
그리고 process A가 실행 될 때만 저장해둔 page를 swap-in 합니다.
Process A가 아닌 다른 process가 실행 될 때는 해당 page를 swap-out 합니다.
Stack frame (0) | 2012.08.26 |
---|---|
CPU register (0) | 2012.08.18 |
Little endian (0) | 2012.08.16 |
Stack에 변수가 저장되는 방식 (0) | 2012.08.16 |
Format String Bug
printf("Hello World!");
다들 익숙하다 못해 반가우실겁니다.
printf는 c 언어를 배울때 가장 먼저 사용하게 되는 함수일거라 믿어 의심치 않습니다.
printf를 사용하는 모습을 먼저 살펴보도록 하겠습니다.
위의 실행 코드에서 "print int : %d"가 format string 입니다.
Format string은 이름 그대로 출력하려는 string의 format을 지정해줍니다.
위와 같은 코드도 사용하시는 분이 더러 있습니다.
짧고 좋습니다.
당연히 정상적으로 실행이 됩니다.
하지만 악의적인 목적을 가진 사용자에게는 허점을 제공해 준 셈이 됩니다.
printf 함수는 printf(a)에서 a를 format string으로 인식하게 됩니다.
a에 %d같은 형식 지시자가 들어있으면 형식 지시자 수만큼 stack에서 값들이 출력됩니다.
어차피 출력만 되는거면 별 문제없는게 아니냐 생각하시겠지만
%n이라는 다소 생소한 형식 지시자가 있습니다.
%n은 자신이 사용되기 전까지 출력된 문자 개수가 %n이 가리키고 있는 주소에 저장이 됩니다.
원하는 주소에 저장이 가능하다는건
프로그램의 흐름을 바꿀 수 있다는 뜻입니다.
기본적인 Format String Bug 공격을 시도해 보겠습니다.
공격 대상이 되는 데몬의 코드는 다음과 같습니다.
입력받은 string을 출력하고 종료합니다.
BOF 취약점도 보입니다.
해당 데몬은 bugbear라는 유저의 setuid가 걸려있습니다.
gdb로 attackme를 열어봅니다.
권한 문제로 debugging이 불가능하니 코드를 이용해 새로 컴파일한 후 debugging 합니다.
a에 접근하는 printf 주변을 찾아봅니다.
0xbffffa64부터 a가 시작됩니다.
이제 ret의 주소를 찾아보겠습니다.
함수가 끝날 때의 esp를 보면됩니다.
ret의 주소는 0xbffffaec입니다.
이제 format string과 stack에서 추출할 영역의 거리가 어느정도인지 알아봐야합니다.
바로 붙어있는 것을 확인할 수 있습니다.
마지막으로 한가지가 남아있습니다.
%n으로 ret의 값을 바꾸기엔 ret의 값이 너무 큽니다.
그러므로 반씩 잘라서 저장을 해줘야됩니다.
shell code의 시작 주소는 대충 nop slide 중간인 0xbffffa78쯤이 되겠습니다.
이제 공격 코드를 만들도록 하겠습니다.
먼저 형식 지시자가 나오기 전까지의 크기를 정하겠습니다.
%c를 통해 출력할 AAAA
%n을 통해 저장할 ret 주소 1
%c를 통해 출력할 BBBB
%n을 통해 저장할 ret 주소 2
Shell code와 nop slide까지 해서 총 50-byte로 만들겠습니다.
ret 주소 1에 저장할 값은 0xfa78입니다.
0xfa78은 64120입니다.
앞서 출력될 크기인 50을 빼면 64070이 됩니다.
ret 주소 2에 저장할 값은 0xbfff입니다.
0xbfff에서 앞서 출력된 수를 빼면 overflow가 발생합니다.
앞에 1을 붙여주고 계산하도록 합니다.
0x1bfff는 114687입니다.
앞서 출력될 크기를 빼면 50567입니다.
공격 코드
AAAA |
0xbffffaec (ret 1) |
BBBB |
0xbffffaee (ret 2) |
Nop slide + Shell code (34-byte) |
%64070c (0xfa78 - 50) |
%n (ret 1) |
%50567c (0x1bfff - 0xfa78) |
%n (ret 2) |
공격해봅니다.
공격에 성공했습니다.
Return To Library (0) | 2012.11.24 |
---|---|
Race condition (0) | 2012.09.14 |