반응형

login as : level7

password : come together

 


 

 


 find / -user level8 -perm +6000 -exec ls -l {} \; 2>/dev/null

 

find 명령으로 위와 같이 명령을 내리면 /bin/level7 파일이 나온다.

 

/bin/level7 파일을 gdb로 분석하려면 level8 권한이 필요한 것 같으니 먼저 비밀번호를 알아내고 나서 gdb를 통한 분석을 한다.

 

 

level7 프로그램을 실행하면 hint에서 말했던 것처럼 비밀번호를 입력하라고 뜬다.

 

아무 글자나 입력하고 Enter를 누르면 /bi/wrong.txt 파일이 없다고 뜬다?

 


풀이

 

su root

vi /bin/wrong.txt

cat /bin/wrong.txt
--_--_- --____- ---_-__ --__-_-

 

FTZ 서버를 직접 구축했을 경우 /bin/wrong.txt 파일이 없다고 한다.

 

본래 wrong.txt에서는 위의 모스 부호같이 생긴 힌트가 있었다고 한다.

 

그러니 위와 같이 직접 파일을 만들어주면 된다.

 

 

그러면 level7 프로그램을 실행하고 비밀번호를 입력했을 때 위와 같이 나온다.

 

이전에 힌트에서 3번과 4번 문구 즉 2진수를 10진수를 바꿀 수 있는가와 공학용 계산기를 이용하라는 것을 바탕으로 생각해봤을 때 위의 모스 부호같이 생긴 것은 2진수로 했을 때 1과 0으로 보인다.

- : 1

_ : 0

 

그리고 자세히 보면 중간에 공백들이 있다.

 

0110 1101 : 6D == m

0110 0001 : 61 == a

0111 0100 : 74 == t

0110 0101 : 65 == e

 

위의 힌트를 2진수와 16진수 그리고 각 16진수에 맞는 ascii 코드로 표현하면 위와 같다.

 

break the world

 

그리고 다시 level7 프로그램을 실행하고, mate를 입력하면 위와 같이 level8의 비밀번호가 뜬다.

 


분석

 

su level8

pw : break the world

 

su 명령을 이용해 level8 계정으로 전환 후 /bin/level7 프로그램을 분석해본다.

 

0x08048454 <main+0>:    push   %ebp
0x08048455 <main+1>:    mov    %esp,%ebp
0x08048457 <main+3>:    sub    $0x8,%esp
0x0804845a <main+6>:    and    $0xfffffff0,%esp
0x0804845d <main+9>:    mov    $0x0,%eax
0x08048462 <main+14>:   sub    %eax,%esp
0x08048464 <main+16>:   sub    $0xc,%esp
0x08048467 <main+19>:   push   $0x64
0x08048469 <main+21>:   call   0x8048344 <malloc>
0x0804846e <main+26>:   add    $0x10,%esp
0x08048471 <main+29>:   mov    %eax,0xfffffffc(%ebp)
0x08048474 <main+32>:   sub    $0xc,%esp
0x08048477 <main+35>:   push   $0x80485c0
0x0804847c <main+40>:   call   0x8048384 <printf>
0x08048481 <main+45>:   add    $0x10,%esp
0x08048484 <main+48>:   sub    $0x4,%esp
0x08048487 <main+51>:   pushl  0x8049744
0x0804848d <main+57>:   push   $0x64
0x0804848f <main+59>:   pushl  0xfffffffc(%ebp)
0x08048492 <main+62>:   call   0x8048354 <fgets>
0x08048497 <main+67>:   add    $0x10,%esp
0x0804849a <main+70>:   sub    $0x4,%esp

0x0804849d <main+73>:   push   $0x4
0x0804849f <main+75>:   push   $0x80485d7
0x080484a4 <main+80>:   pushl  0xfffffffc(%ebp)
0x080484a7 <main+83>:   call   0x8048364 <strncmp>
0x080484ac <main+88>:   add    $0x10,%esp
0x080484af <main+91>:   test   %eax,%eax
0x080484b1 <main+93>:   jne    0x80484cd <main+121>
0x080484b3 <main+95>:   sub    $0xc,%esp
0x080484b6 <main+98>:   push   $0x80485e0
0x080484bb <main+103>:  call   0x8048384 <printf>
0x080484c0 <main+108>:  add    $0x10,%esp
0x080484c3 <main+111>:  sub    $0xc,%esp
0x080484c6 <main+114>:  push   $0x0
0x080484c8 <main+116>:  call   0x8048394 <exit>
0x080484cd <main+121>:  sub    $0xc,%esp
0x080484d0 <main+124>:  push   $0x8048617
0x080484d5 <main+129>:  call   0x8048334 <system>
0x080484da <main+134>:  add    $0x10,%esp
0x080484dd <main+137>:  leave
0x080484de <main+138>:  ret
0x080484df <main+139>:  nop
End of assembler dump.


main 함수의 대략적인 동작 원리는 아래와 같다.

1. 스택을 구성하고, malloc() 함수로 메모리 공간을 할당한다.

2. printf() 함수로 문자열을 출력한다.

3. fgets() 함수로 문자열을 입력받는다.

4. strncmp() 함수로 3번에서 입력받은 문자열을 비교한다.

5. 비교 결과에 따라 printf() 함수를 호출하고 종료할 지, system() 함수로 명령어를 실행할 지 달라진다.

 

main 함수의 동작 원리를 자세히 봐본다.

 

0x08048454 <main+0>:    push   %ebp
0x08048455 <main+1>:    mov    %esp,%ebp
0x08048457 <main+3>:    sub    $0x8,%esp
0x0804845a <main+6>:    and    $0xfffffff0,%esp
0x0804845d <main+9>:    mov    $0x0,%eax
0x08048462 <main+14>:   sub    %eax,%esp
0x08048464 <main+16>:   sub    $0xc,%esp
0x08048467 <main+19>:   push   $0x64
0x08048469 <main+21>:   call   0x8048344 <malloc>
0x0804846e <main+26>:   add    $0x10,%esp
0x08048471 <main+29>:   mov    %eax,0xfffffffc(%ebp)
0x08048474 <main+32>:   sub    $0xc,%esp

 

함수 프롤로그 작업을 거친 뒤 스택을 구성하는데, 0x64(10진수로 100)을 스택에 넣고 malloc() 함수를 호출한다.

 

즉, 힙 공간에 100byte 만큼의 공간을 확보하는 것이다.

 

그리고 malloc() 함수의 반환값을 ebp-c 주소에 저장한다.

 

0x08048477 <main+35>:   push   $0x80485c0
0x0804847c <main+40>:   call   0x8048384 <printf>
0x08048481 <main+45>:   add    $0x10,%esp
0x08048484 <main+48>:   sub    $0x4,%esp

 

"Insert The Password : " 문자열을 스택에 넣고 화면에 출력한다.

 

0x08048487 <main+51>:   pushl  0x8049744
0x0804848d <main+57>:   push   $0x64
0x0804848f <main+59>:   pushl  0xfffffffc(%ebp)
0x08048492 <main+62>:   call   0x8048354 <fgets>
0x08048497 <main+67>:   add    $0x10,%esp
0x0804849a <main+70>:   sub    $0x4,%esp

 

stdin과 0x64 그리고 ebp-c를 스택에 넣고 fgets() 함수를 호출해 사용자에게 입력을 받는다.

 

0x0804849d <main+73>:   push   $0x4
0x0804849f <main+75>:   push   $0x80485d7
0x080484a4 <main+80>:   pushl  0xfffffffc(%ebp)
0x080484a7 <main+83>:   call   0x8048364 <strncmp>
0x080484ac <main+88>:   add    $0x10,%esp
0x080484af <main+91>:   test   %eax,%eax
0x080484b1 <main+93>:   jne    0x80484cd <main+121>
0x080484b3 <main+95>:   sub    $0xc,%esp
0x080484b6 <main+98>:   push   $0x80485e0
0x080484bb <main+103>:  call   0x8048384 <printf>
0x080484c0 <main+108>:  add    $0x10,%esp
0x080484c3 <main+111>:  sub    $0xc,%esp
0x080484c6 <main+114>:  push   $0x0
0x080484c8 <main+116>:  call   0x8048394 <exit>

 

0x4와 "mate" 그리고 ebp-c를 스택에 넣고 strncmp() 함수를 호출해 비교한다.

 

즉, 사용자가 입력한 값에서 4글자만 "mate"와 비교한다.

 

비교해서 같으면  "Congratulation! next password is "break the world"." 문자열을 띄우고 종료한다.

 

같지 않으면 0x80484cd 주소로 점프한다.

 

0x080484cd <main+121>:  sub    $0xc,%esp
0x080484d0 <main+124>:  push   $0x8048617
0x080484d5 <main+129>:  call   0x8048334 <system>
0x080484da <main+134>:  add    $0x10,%esp
0x080484dd <main+137>:  leave
0x080484de <main+138>:  ret
0x080484df <main+139>:  nop

 

0x80484cd 주소로 점프하면 "cat /bin/wrong.txt" 문자열을 스택에 넣고 system() 함수를 호출한다.

 

#include <stdio.h>
#include <malloc.h>

int main(void)
{
    char *input;
    char *pw = "mate";

    input = (char*)malloc(0x64);

    printf("Insert The Password : ");

    fgets(input, 0x64, stdin);

    if(strncmp(input, pw, 0x4) == 0)
    {
        printf("\nCongratulation! next password is \"break the world\".\n\n");
        exit(0);
    }
    else
        system("cat /bin/wrong.txt");

    free(input);

    return 0;
}

 

분석 내용을 통합하여 의사 코드로 작성하면 위와 같다.

 


exploit 코드

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

#define MAXARRAY 4

int binToInt(char *bin);

int main()
{
        int i, decimal[MAXARRAY];

        char *bin = "--_--_- --____- ---_-__ --__-_-";

	char *ptr = bin;
        char dec[MAXARRAY*8];
	char ascii[MAXARRAY];


	printf("Resvered signals : --_--_- --____- ---_-__ --__-_-\n");
	
	for(i=0; i<strlen(bin); i++)
	{
		if( *ptr == '-' )
			dec[i] = '1';
		else if( *ptr == '_' )
			dec[i] = '0';
		else if( *ptr == ' ' )
			dec[i] = '\0';
		ptr++;
	}
	
	dec[i] = '\0';

	printf("Changed binary : %s %s %s %s\n", &dec[0], &dec[8], &dec[16], &dec[24]);
	
	
	
	printf("Changed decimal :");
	for(i=0; i<MAXARRAY; i++)
	{
		decimal[i] = binToInt(&dec[i*8]);
		printf( " %d ", decimal[i] );
	}
	printf("\n");
	
	printf("Changed ascii :");
	for(i=0; i<MAXARRAY; i++)
	{
		printf( " %c ", decimal[i] );
	}
	printf( "\n" );
}


int binToInt(char *bin) {
  int i = 0;
  int count = 0;

  while (bin[count])
    i = (i << 1) | (bin[count++] - '0');

  return i;
}

반응형

+ Recent posts