FTZ level6 시스템 인터럽트 ( System Interupt )

2017. 5. 23. 14:05SystemHacking/FTZ

 

 

 

level6문제 풀이에 앞서 알아야할 개념부터 설명하겠습니다


[1]

시스템은 신호와 메시지로 정보를 교환합니다

메시지는 Protocol정보규약에 따라서 정의되어 사용되고 리눅스에서 신호는 미리 약속되어있는 signal을 제공합니다


#kill -l signal    명령어를 통해서 신호의 이름과 고유번호를 알 수 있습니다 ㅡ 그림 6.1

#kill -[Signal] [PID]    해당 PID에 해당하는 프로세스에게 신호를 전달합니다                

ex)    #kill -SGIKILL 100 or   #kill -9 100

-> PID가 100번인 프로세스를 종료시키는 신호를 보냄으로써 종료시킨다

각 신호들은 번호가 있고 신호의 이름대신 번호를 사용해서 신호를 보낼 수 있다


< 그림 6.1 >


[2]

추가로 키보드의 입력을 통해서 시그널을 발생시킬 수 있다

1> Ctrl + c = SIGINT(2)           해당 프로세스를 stop시키는 신호

2> Ctrl + z = SIGTSTP(20)        해당 프로세스를 백그라운드로 보낸다    

3> Ctrl + \ = SIGQUIT(3)         해당 프로세스를 종료시킨다


[3]

명령어와 키보드로 시그널을 보내는 방법 뿐아니라 소스코드 상에서 시그널을 전달할 수 있다

signal()함수를 알아보자 signal함수는 세가지의 형태로 작동한다


1>  signal( 시그널 번호 , SIG_DFL )    (default)

신호를 받은 프로세스는 해당 시그널의 기본 실행동작을 수행한다

signal( SIGINT, SIG_DFL )    =>    SIGINT 시그널 실행 : 해당 프로세스 중지됨

2> signal( 시그널 번호, SIG_IGN )    (ignore)

신호를 받은 프로세스는 해당 시그널의 신호가 와도 무시하여 아무런 동작을 하지 않는다

signal( SIGINT, SIG_IGN )    =>    SIGINT 시그널 무시 : 아무런 반응없음


3> signal( 시그널 번호, handler함수 )

신호를 받은 프로세스는 해당 시그널 신호가 오면 handler함수에 지정한 함수를 실행시킨다

signal( SIGINT , handler)    =>    SIGINT가 입력되면 handler함수 실행한다


* 첫입력시 신호에 함수 적용 , 두번째 신호 입력시함수의 내용을 실행 즉, 신호를 두번 보내야 handler함수가 실행된다



문제풀이 시작하겠습니다


< 그림 6.2 >


1을 입력해도 .. 2를 입력해도 .. 아무런 결과가 출력되지 않고 접속이 끊겨버립니다


< 그림 6.3 >


ctrl + \ 신호를 주면 해당 프로세스는 종료되고 다른 신호를 보내면 아무 반응도 일어나지 않습니다

ctrl + c (SIGINT) 신호를 보내주면 " Can't use ctrl+c " 가 출력됩니다 

SIGINT신호에 대해서 handler 함수를 지정해주었고 신호가 오면 handler함수가 실행됨을 알 수 있다


< 그림 6.4 >


level6의 시작지점에서 ctrl+c 를입력해서 중단시켯더니 level6의 쉘이 떨어졌습니다 !

무슨 파일들이 있는지 확인해 보면 " tn " 실행파일과 " password " 파일이 있습니다

"password" 파일을 통해 level7계정의 비밀번호를 확인할 수 있고 "tn" 실행파일은 우리를 혼란스럽게 했던 프로그램입니다 !


문제의 해답은 쉽게 알았지만 어떻게 이렇게 동작하는지 " tn " 실행파일을 분석해봅시다

분석량이 좀 많지만 천천히 읽으면 쉽게 이해할 수 있습니다


< 그림 6.5 >


gdb를 실행하고 " tn " 파일을 읽어들인다


< 그림 6.6 >


[1] <main+14>:    call    <system>

system("cat hint");    => "hint - 인포샵 bbs의 텔넷 접속 메뉴에서 많이 사용되던 해킹 방법이다" 출력


[2] <main+22>:    call    <getchar>

getchar();    =>문자 하나를 입력받는다

 

[3] <main+35>:    call    <system>

system("clear")    => clear 명령어 실행


[4]<main+46> ... <main+110>:    call    <printf>

그림 6.6 오른쪽화면에 보이는 문자열들을 화면에 출력한다


< 그림 6.7 >


[5]<main+126> ~ <main+174>:    call    <printf>    

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


[6]<main+197>:call    <signal>

push $0x80484e0    sig_func의 주소

push $0x2              2

=> signal( 2 , sig_func )    => 2번신호는 SIGINT , SIGINT신호가 들어오면 sig_func 함수를 실행해라

[7]<main+233>:    call    <scanf>

scanf( "%s", &input )    => 사용자에게 문자열 하나를 입력 받는다


< 그림 6.8 >


[8] 빨간 상자 부분


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

입력한 값과 1을 비교합니다

<main+245>:    jne    0x80485ff <main+263>
위에서 비교한 결과 일치하지 않다면 main+263으로 점프합니다

<main+250>:    push    $0x80488c6    : " telnet 203.245.15.76 "
입력한 값이 1일때 코드가 그대로 진행되고 system함수의 인자로 push 된다

<main+255>:    call    <system>
system()함수가 호출된다


[9] 하늘색 상자 부분

<main+263>:    cmpl    $0x2,0xfffffffc(%ebp)
입력한 값과 2를 비교합니다

<main+267>:    jne    0x8048615 <main+285>
비교한 결과 일치하지 않다면 main+285부분으로 점프합니다

<main+269> ~ <main+277>

<main+272>:    push    $0x80488db    : " telnet 203.238.129.97 "
입력한 값이 2일때 코드가 그대로 진행되고 system함수의 인자로 push 된다

<main+277>:    call    <system>
system()함수가 호출된다


[10] 파란 상자 부분

<main+285>:    cmpl    $0x3,0xfffffffc(%ebp)
입력한 값과 3을 비교합니다

<main+289>:    jne    0x804862ㅠ <main+307>
비교한 결과 일치하지 않다면 main+307부분으로 점프합니다

<main+291> ~ <main+299>

<main+294>:    push    $0x80488f1    : " telnet 210.120.128.180 "
입력한 값이 3일때 코드가 그대로 진행되고 system함수의 인자로 push 된다

<main+277>:    call    <system>
system()함수가 호출된다


[11] <main+307> ~ <main+323>
입력한 값이 1 or 2 or 3 이면 <main+341>로 점프 , 1 or 2 or 3 이 아니면 코드가 그대로 진행되면서 printf 함수 호출

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

leave , ret => 프로그램 종료



* 추가적으로 signal함수에서 사용한 sig_func 함수에 대한 gdb분석입니다

< 그림 6.9 >


첫 시작 주소가 0x080484e0 입니다 main함수 gdb분석 시 signal함수에서 push한 그 주소입니다

sig_func 분석결과 printf()함수를 호출하고 함수는 종료됩니다


gdb분석을 통해 소스코드의 흐름을 알 수 있었고 복원된 소스코드를 확인해봅시다



< 복원된 소스코드 >



#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("##                                    ##\n");

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

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

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

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


for( i=1 ; i<32 ; i++){                            // 시그널 신호는 1번부터 31번에 대한 설정

if( i== SIGINT ) {

signal( i , sig_func );                  //    SIGINT 시그널 신호가 오면 sig_func실행

} else{

signal(i , SIG_IGN);                    //    다른 신호가 오면 무시 ( ignore )

}                                                 // 왜 gdb에는 else 부분이 없는지 의심할 수 있다

}                                                       // 왜인지는.. 저도 모르겟습니다.. 


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

scanf("%s",&input);


switch ( input ){

case 1 :

system("telnet 203.245.15.76");

break;

case 2 :

system("telnet 203.238.129.97");

break;

case 3 :

system("telnet 201.120.128.180);

break;

default :

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

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

}

}

}



문제풀이와 gdb분석 모두 완료했습니다

추가로 보안할 점이나 이상한 부분이 있다면 댓글 남겨주시길 바랍니다