본문으로 바로가기

Level6 문제 분석 -의사 코드

category Security/리버싱 2017. 11. 29. 22:26

ftz.hackerschool.org 의 이미지를 사용하여 실습했습니다. 


-Level6

별 생각없이 ctrl+c 만 눌러서 떡하니 있는 password 파일을 열어 level7의 암호를 알아냈다. 


로그인하자마자 실행되는 파일들과 프로그램 설정방법과 시그널신호를 제어하는 방법에 대해 분석해 본다. 


[level6@ftz level6]$ ls -al

 

합계 104

drwxr-xr-x    4 root     level6       4096  3월  5  2003 .

drwxr-xr-x   35 root     root         4096  8월 19  2014 ..

-rw-r--r--    1 root     root          245  9월 24  2000 .Xdefaults

-rw-------    1 root     root            1  1월 15  2010 .bash_history

-rw-r--r--    1 root     root           12 11월 24  2000 .bash_login

-rw-r--r--    1 root     root           24  2월 24  2002 .bash_logout

-rw-r--r--    1 root     root          224  2월 24  2002 .bash_profile

-rw-r--r--    1 root     root          163  3월  5  2003 .bashrc

-rw-r--r--    1 root     root          400  9월 24  2000 .cshrc

-rw-r--r--    1 root     root         4742  9월 24  2000 .emacs

-r--r--r--    1 root     root          319  9월 24  2000 .gtkrc

-rw-r--r--    1 root     root          100  9월 24  2000 .gvimrc

-rw-r--r--    1 root     root          226  9월 24  2000 .muttrc

-rw-r--r--    1 root     root          367  9월 24  2000 .profile

-rw-r--r--    1 root     root            1  5월  7  2002 .viminfo

-rw-r--r--    1 root     root         4145  9월 24  2000 .vimrc

-rw-r--r--    1 root     root           72 11월 23  2000 hint

-rw-r-----    1 root     level6         36  3월 24  2000 password

drwxr-xr-x    2 root     level6       4096  5월 16  2005 public_html

drwxrwxr-x    2 root     level6       4096  1월 14  2009 tmp

-rwxr-x---    1 root     level6      14910  3월  5  2003 tn

 

 


[참고] 로그인하자마자 실행되는 파일

/etc/profile        -> 모든 사용자가 이 파일을 확인한다.

~/.bash_profile    -> 각 사용자마다 가지고 있으며 로그인시 자신의 홈폴더의 파일을 확인한다.
~/.bashrc            -> 각 사용자마다 가지고 있으며 로그인시 자신의 홈폴더의 파일을 확인한다.


> level5 이전의 사용자로 로그인 할 때는 아무런 동작을 하지 않았으므로 /etc/profile은 확인하지 않아도 된다. 


[level6@ftz level6]$ cat .bash_profile

 

 # .bash_profile


# Get the aliases and functions

if [ -f ~/.bashrc ]; then

        . ~/.bashrc

fi


# User specific environment and startup programs


PATH=$PATH:$HOME/bin

BASH_ENV=$HOME/.bashrc


export BASH_ENV PATH

unset USERNAME

 

> 특별한 것이 없는 것 같다. 


[level6@ftz level6]$ cat .bashrc

 

 # .bashrc


# User specific aliases and functions


# Source global definitions

if [ -f /etc/bashrc ]; then

        . /etc/bashrc

fi

export PS1="[\u@\h \W]\$ "

./tn

logout

 

> ./tn 이라는 프로그램을 실행하고 프로그램이 끝나면 logout 된다. 


[level6@ftz level6]$ file tn

 

 tn: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not stripped


 

> 실행 파일로 되어있다. 


[level6@ftz level6]$ gdb tn

 

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...

(gdb) disas main

Dump of assembler code for function main:

0x080484f8 <main+0>:    push   %ebp

0x080484f9 <main+1>:    mov    %esp,%ebp

0x080484fb <main+3>:    sub    $0x8,%esp

0x080484fe <main+6>:    sub    $0xc,%esp

0x08048501 <main+9>:    push   $0x80486f2

0x08048506 <main+14>:   call   0x8048384 <system>

0x0804850b <main+19>:   add    $0x10,%esp

0x0804850e <main+22>:   call   0x8048354 <getchar>

0x08048513 <main+27>:   sub    $0xc,%esp

0x08048516 <main+30>:   push   $0x80486fb

0x0804851b <main+35>:   call   0x8048384 <system>

0x08048520 <main+40>:   add    $0x10,%esp

0x08048523 <main+43>:   sub    $0xc,%esp

0x08048526 <main+46>:   push   $0x8048720

0x0804852b <main+51>:   call   0x80483c4 <printf>

0x08048530 <main+56>:   add    $0x10,%esp

0x08048533 <main+59>:   sub    $0xc,%esp

0x08048536 <main+62>:   push   $0x8048760

0x0804853b <main+67>:   call   0x80483c4 <printf>

0x08048540 <main+72>:   add    $0x10,%esp

0x08048543 <main+75>:   sub    $0xc,%esp

0x08048546 <main+78>:   push   $0x80487a0

---Type <return> to continue, or q <return> to quit---

0x0804854b <main+83>:   call   0x80483c4 <printf>

0x08048550 <main+88>:   add    $0x10,%esp

0x08048553 <main+91>:   sub    $0xc,%esp

0x08048556 <main+94>:   push   $0x8048760

0x0804855b <main+99>:   call   0x80483c4 <printf>

0x08048560 <main+104>:  add    $0x10,%esp

0x08048563 <main+107>:  sub    $0xc,%esp

0x08048566 <main+110>:  push   $0x8048760

0x0804856b <main+115>:  call   0x80483c4 <printf>

0x08048570 <main+120>:  add    $0x10,%esp

0x08048573 <main+123>:  sub    $0xc,%esp

0x08048576 <main+126>:  push   $0x80487e0

0x0804857b <main+131>:  call   0x80483c4 <printf>

0x08048580 <main+136>:  add    $0x10,%esp

0x08048583 <main+139>:  sub    $0xc,%esp

0x08048586 <main+142>:  push   $0x8048820

0x0804858b <main+147>:  call   0x80483c4 <printf>

0x08048590 <main+152>:  add    $0x10,%esp

0x08048593 <main+155>:  sub    $0xc,%esp

0x08048596 <main+158>:  push   $0x8048760

0x0804859b <main+163>:  call   0x80483c4 <printf>

0x080485a0 <main+168>:  add    $0x10,%esp

0x080485a3 <main+171>:  sub    $0xc,%esp

---Type <return> to continue, or q <return> to quit---

0x080485a6 <main+174>:  push   $0x8048860

0x080485ab <main+179>:  call   0x80483c4 <printf>

0x080485b0 <main+184>:  add    $0x10,%esp

0x080485b3 <main+187>:  sub    $0x8,%esp

0x080485b6 <main+190>:  push   $0x80484e0

0x080485bb <main+195>:  push   $0x2

0x080485bd <main+197>:  call   0x8048374 <signal>

0x080485c2 <main+202>:  add    $0x10,%esp

0x080485c5 <main+205>:  sub    $0xc,%esp

0x080485c8 <main+208>:  push   $0x80488a0

0x080485cd <main+213>:  call   0x80483c4 <printf>

0x080485d2 <main+218>:  add    $0x10,%esp

0x080485d5 <main+221>:  sub    $0x8,%esp

0x080485d8 <main+224>:  lea    0xfffffffc(%ebp),%eax

0x080485db <main+227>:  push   %eax

0x080485dc <main+228>:  push   $0x80488c3

0x080485e1 <main+233>:  call   0x8048394 <scanf>

0x080485e6 <main+238>:  add    $0x10,%esp

0x080485e9 <main+241>:  cmpl   $0x1,0xfffffffc(%ebp)

0x080485ed <main+245>:  jne    0x80485ff <main+263>

0x080485ef <main+247>:  sub    $0xc,%esp

0x080485f2 <main+250>:  push   $0x80488c6

0x080485f7 <main+255>:  call   0x8048384 <system>

---Type <return> to continue, or q <return> to quit---

0x080485fc <main+260>:  add    $0x10,%esp

0x080485ff <main+263>:  cmpl   $0x2,0xfffffffc(%ebp)

0x08048603 <main+267>:  jne    0x8048615 <main+285>

0x08048605 <main+269>:  sub    $0xc,%esp

0x08048608 <main+272>:  push   $0x80488db

0x0804860d <main+277>:  call   0x8048384 <system>

0x08048612 <main+282>:  add    $0x10,%esp

0x08048615 <main+285>:  cmpl   $0x3,0xfffffffc(%ebp)

0x08048619 <main+289>:  jne    0x804862b <main+307>

0x0804861b <main+291>:  sub    $0xc,%esp

0x0804861e <main+294>:  push   $0x80488f1

0x08048623 <main+299>:  call   0x8048384 <system>

0x08048628 <main+304>:  add    $0x10,%esp

0x0804862b <main+307>:  cmpl   $0x1,0xfffffffc(%ebp)

0x0804862f <main+311>:  je     0x804864d <main+341>

0x08048631 <main+313>:  cmpl   $0x2,0xfffffffc(%ebp)

0x08048635 <main+317>:  je     0x804864d <main+341>

0x08048637 <main+319>:  cmpl   $0x3,0xfffffffc(%ebp)

0x0804863b <main+323>:  je     0x804864d <main+341>

0x0804863d <main+325>:  sub    $0xc,%esp

0x08048640 <main+328>:  push   $0x8048920

0x08048645 <main+333>:  call   0x80483c4 <printf>

0x0804864a <main+338>:  add    $0x10,%esp

---Type <return> to continue, or q <return> to quit---

0x0804864d <main+341>:  leave

0x0804864e <main+342>:  ret

0x0804864f <main+343>:  nop

End of assembler dump.

 

> 길어 보이지만 printf 문이 많기 때문에 겁먹지 말자. 


 

0x08048501 <main+9>:    push   $0x80486f2

0x08048506 <main+14>:   call   0x8048384 <system>

 


 

 (gdb) x/s 0x80486f2

0x80486f2 <_IO_stdin_used+46>:   "cat hint"

 

> 프로그램이 시작하자마자 힌트파일을 보여준다. 


 

0x0804850b <main+19>:   add    $0x10,%esp

0x0804850e <main+22>:   call   0x8048354 <getchar>

 

> 문자 입력을 받는다.(문자 입력을 기다린다.) --> 힌트파일을 보여주고 기다린 이유가 여기에 있다. 


 

0x08048516 <main+30>:   push   $0x80486fb

0x0804851b <main+35>:   call   0x8048384 <system>

 


 

(gdb) x/s 0x80486fb

0x80486fb <_IO_stdin_used+55>:   "clear"

 

> 화면을 싹 정리한다. 

 

 


  #####################################

  ##                                 ##

  ##         텔넷 접속 서비스        ##

  ##                                 ##

  ##                                 ##

  ##     1. 하이텔     2. 나우누리   ##

  ##     3. 천리안                   ##

  ##                                 ##

  #####################################


접속하고 싶은 bbs를 선택하세요 :


 

> 실행 했을 때를 확인해보면 뒤에 이어진 printf 명령은 아마 이런것을 출력하는 문장일 것이다. 


 

0x080485a6 <main+174>:  push   $0x8048860

0x080485ab <main+179>:  call   0x80483c4 <printf>

 


 

(gdb) x/s 0x8048860

0x8048860 <_IO_stdin_used+412>:  "  ", '#' <repeats 37 times>, "\n"

 

> 마지막 printf 문만 확인해보니 #을 37번 반복하는 줄이다. 


 

0x080485b6 <main+190>:  push   $0x80484e0

0x080485bb <main+195>:  push   $0x2

0x080485bd <main+197>:  call   0x8048374 <signal>

 

> 2번 시그널을 입력하면 핸들러가 동작하도록 되어있는 것 같다. 


 

 접속하고 싶은 bbs를 선택하세요 : Can't use ctrl+c

 

> 그 핸들러는 아마 Can't use ctrl+c 를 출력해주는 함수일 것이다. 


# man signal

 

 NAME

       signal - ANSI C signal handling


SYNOPSIS

       #include <signal.h>


       typedef void (*sighandler_t)(int);


       sighandler_t signal(int signum, sighandler_t handler);


 


# man 7 signal

 

   Signal     Value     Action   Comment

       -------------------------------------------------------------------------

       SIGHUP        1       Term    Hangup detected on controlling terminal

                                     or death of controlling process

       SIGINT        2       Term    Interrupt from keyboard

       SIGQUIT       3       Core    Quit from keyboard

       SIGILL        4       Core    Illegal Instruction

       SIGABRT       6       Core    Abort signal from abort(3)

       SIGFPE        8       Core    Floating point exception

       SIGKILL       9       Term    Kill signal

       SIGSEGV      11       Core    Invalid memory reference

       SIGPIPE      13       Term    Broken pipe: write to pipe with no readers

       SIGALRM      14       Term    Timer signal from alarm(2)

       SIGTERM      15       Term    Termination signal

       SIGUSR1   30,10,16    Term    User-defined signal 1

       SIGUSR2   31,12,17    Term    User-defined signal 2

       SIGCHLD   20,17,18    Ign     Child stopped or terminated

       SIGCONT   19,18,25    Cont    Continue if stopped

       SIGSTOP   17,19,23    Stop    Stop process

       SIGTSTP   18,20,24    Stop    Stop typed at tty

       SIGTTIN   21,21,26    Stop    tty input for background process

       SIGTTOU   22,22,27    Stop    tty output for background process


 


 

0x080485c8 <main+208>:  push   $0x80488a0

0x080485cd <main+213>:  call   0x80483c4 <printf>

 


 

(gdb) x/s 0x80488a0

0x80488a0 <_IO_stdin_used+476>:  "\n접속하고 싶은 bbs를 선택하세요 : "

 

> 마지막 출력문이다. 


 

0x080485db <main+227>:  push   %eax

0x080485dc <main+228>:  push   $0x80488c3

0x080485e1 <main+233>:  call   0x8048394 <scanf>

 

> scanf 로 1,2,3중 하나를 입력을 받는다. 


 

0x080485e9 <main+241>:  cmpl   $0x1,0xfffffffc(%ebp)

0x080485ed <main+245>:  jne    0x80485ff <main+263>

0x080485ef <main+247>:  sub    $0xc,%esp

0x080485f2 <main+250>:  push   $0x80488c6

0x080485f7 <main+255>:  call   0x8048384 <system>

---Type <return> to continue, or q <return> to quit---

0x080485fc <main+260>:  add    $0x10,%esp

0x080485ff <main+263>:  cmpl   $0x2,0xfffffffc(%ebp)

0x08048603 <main+267>:  jne    0x8048615 <main+285>

0x08048605 <main+269>:  sub    $0xc,%esp

0x08048608 <main+272>:  push   $0x80488db

0x0804860d <main+277>:  call   0x8048384 <system>

0x08048612 <main+282>:  add    $0x10,%esp

0x08048615 <main+285>:  cmpl   $0x3,0xfffffffc(%ebp)

0x08048619 <main+289>:  jne    0x804862b <main+307>

0x0804861b <main+291>:  sub    $0xc,%esp

0x0804861e <main+294>:  push   $0x80488f1

0x08048623 <main+299>:  call   0x8048384 <system>

0x08048628 <main+304>:  add    $0x10,%esp

0x0804862b <main+307>:  cmpl   $0x1,0xfffffffc(%ebp)

0x0804862f <main+311>:  je     0x804864d <main+341>

0x08048631 <main+313>:  cmpl   $0x2,0xfffffffc(%ebp)

0x08048635 <main+317>:  je     0x804864d <main+341>

0x08048637 <main+319>:  cmpl   $0x3,0xfffffffc(%ebp)

0x0804863b <main+323>:  je     0x804864d <main+341>

0x0804863d <main+325>:  sub    $0xc,%esp

0x08048640 <main+328>:  push   $0x8048920

0x08048645 <main+333>:  call   0x80483c4 <printf>


 

> 딱 봐도 조건문이다.  if / else if / else if / else 문 일 수도 있고  switch-case 구문일 수도 있다.


 

(gdb) x/s 0x80488c6

0x80488c6 <_IO_stdin_used+514>:  "telnet 203.245.15.76"

 

> 1을 누르면 나왔던 IP로 telnet 을 시도한다. 

> 나머지도 다 같은 형식이다. 


 

(gdb) x/s 0x8048920

0x8048920 <_IO_stdin_used+604>:  "잘못 입력하셨습니다. 접속을 종료합니다.\n"

 

> 잘못 입력하면 종료된다. 


- 의사코드 


 

#include <stdio.h>

#include <signal.h>


void sig_func(int signo)

{

        printf("Can't use ctrl+c\n");

}


int main()

{

        char input;

        int select, i;


        system("cat hint");

        input = getchar();

        system("clear");


        printf("#####################################\n");

        printf("##                                 ##\n");

        printf("##        텔넷 접속 서비스         ##\n");

        printf("##                                 ##\n");

        printf("##     1. 하이텔   2. 나우누리     ##\n");

        printf("##     3. 천리안                   ##\n");

        printf("##                                 ##\n");

        printf("#####################################\n");


        signal( SIGINT, sig_func );

        printf("\n접속하고 싶은 bbs를 선택하세요 : ");

        switch(input)

        {

                case 1: system("telnet 203.245.15.76"); break;

                case 2: system("telnet 203.238.129.97"); break;

                case 3: system("telnet 210.120.128.180"); break;

                default:

                        if(input !=1 && input !=2 && input !=3)

                                printf("잘못 입력하셨습니다. 접속을 종료합니다.\n");

        }

        return 0;

}

 


> 빨간색으로 표시한 라인을 다음과 같이 바꿔주는 것이 좋다.

 

 for(i=1; i<32; i++)

 {

        if(i == SIGINT) signal(i, sig_func);

        else signal(i, SIG_IGN);

 }

 

> 시그널을 제어할때는 다른 모든 번호들도 막아두는 것이 좋다. 

> 2번 시그널만 sig_func를 실행하고 나머지는 무시(SIG_IGN)한다.


'Security > 리버싱' 카테고리의 다른 글

Level7 문제 응용 (ASCII)  (0) 2017.11.30
Level7 문제 해결  (0) 2017.11.30
Level6 문제 해결  (0) 2017.11.29
Level5 문제 분석 -의사 코드  (0) 2017.11.29
Race Condition(레이스 컨디션)  (0) 2017.11.29