본문 바로가기

Learning/└◆Reversing

07_Level7 -> Level8[FTZ] 암호학(2진수 <->10진수 <-> 16진수)


 ■ Level7 -> Level8


 

 

■ 목적

암호학

printf() 함수를 사용할 때 메모리에 2진수로 값이 저장되어 있지만 사람이 이해하기 쉽도록 하기 위해서 %c를 지정하면 한글자가 보이고, %d로 지정하면 모니터에 정수가 출력된다.

메모리상에는 101010101으로 되어있는 있다. 이것을 캐릭터타입, 인트타입 방식으로 읽어들이것.

  

반대로 사용자가 메모리에 원하는 문자를 저장하려면 아스키 테이블을 보고, 그 문자에 해당하는 16진수 값을 저장해야 한다.

 

 

■ Level7 풀이

 

level7 사용자 로그인

-> ID/PASS : level7/come together

 

우선 hint를 확인한다

$ cat hint

/bin/level7 명령을 실행하면, 패스워드 입력을 요청한다.

 

1. 패스워드는 가까운곳에..

2. 상상력을 총동원하라.

3. 2진수를 10진수를 바꿀 수 있는가?

4. 계산기 설정을 프로그래머용으로 바꾸어라.

 

$ find / -name level7 2>/dev/null

/bin/level7
/home/level7  

 

$ find / -user level8 -perm -4000 2>/dev/null

/bin/level7 

 

$ ls -l /bin/level7

-rws--x----          1   level8     level7        12312     8월     19    12:58   /bin/level7

 

 

$ /bin/level7

Insert The Password : 0000
올바르지 않은 패스워드 입니다.
    패스워드는 가까운곳에...
--_--_- --____- ---_-__ --__-_- 

 

'-' '_' 를 이용한 2진수 를 나타낸 값이다.

1101101  1100001  1110100  1100101

 

계산기를 이용해서 변환

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

구분         표기    예                             아스키문자열

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

 2진수(Bin): 1101101 1100001 1110100 1100101         ?

10진수(Dec): 109     97      116     101             mate

16진수(Hex): 6d      61      74      65              mate

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

$man ascii 를 활용하여 아스키 문자열이 mate라는 것을 알아냈다. 

 

ascii 코드중에서 16진수 41은 알파벳 대문자 A 이고

16진수 61은 소문자 a 이다. 이것을 기준점으로 알고 있으면 유용하니 외워두자.

 

$ /bin/level7

Insert The Password : mate

Congratulation! next password is "break the world".

 


 

■ exploit 공격용 코드 개발

 

bin(2진수)

dec(10진수)

hex(16진수)

 

$ cd tmp ; vi conversion.c

#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];

        char cmd[5]={"\n"};


        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';    NULL처리 구문

                ptr++;

        }


        dec[i] = '\0';    NULL처리가 된 값까지 읽어드린다.

        printf("Changed binary : %s %s %s %s\n", &dec[0], &dec[8], &dec[16], &dec[24]);

                                                     NULL값을 지정

        printf("Changed decimal : ");

        for(i=0; i<MAXARRAY; i++)

        {

                decimal[i] = binToInt(&dec[i*8]);

                printf(" %d ", decimal[i]);

        }

        printf("\n");


        printf("Chaged ascii :");

        for(i=0; i<MAXARRAY; i++)

                printf(" %c ", decimal[i]);

        printf("\n");

 

      sprintf(cmd, "(printf \"%c%c%c%c\" ; cat) | /bin/level7", decimal[0], decimal[1], decimal[2], decimal[3]);       

                        mate를 %c%c%c%c에 넣어서 /bin/level7에 집어넣어서 암호가 나온다.

                        중간에서 한번 멈추려고 cat을 쓰고 뒤에 아무것도 적지 않는다. (대기상태)

                        cat 화면을 잠깐 멈추기 위함

        system(cmd);

}


int binToInt(char *bin)

{

        int i=0;

        int count=0;


        while (bin[count])

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


        return i;

}

 

$ gcc -o conversion conversion.c

$ ./conversion

Resvered signals : --_--_- --____- ---_-__ --__-_-

Changed binary : 1101101 1100001 1110100 1100101

Changed decimal : 109 97 116 101

Chaged ascii : m a t e

<ENTER>

Insert The Password :

Congratulation! next password is "break the world".

<ENTER>

 

 

디스어셈블러

 

$ gdb /bin/level7

(gdb) disas main
Dump of assembler code for function 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


malloc(0x64)라는 코드가 실행되 힙 공간에 100바이트 만큼의 공간을 확보한다.


0x08048471 <main+29>:   mov    %eax,0xfffffffc(%ebp)
0x08048474 <main+32>:   sub    $0xc,%esp
0x08048477 <main+35>:   push   $0x80485c0                               “Insert The Password :"
0x0804847c <main+40>:   call   0x8048384 <printf>       문자열을 스택에 올리고 printf를 호출.

 

0x08048481 <main+45>:   add    $0x10,%esp

 

 

 

0x08048484 <main+48>:   sub    $0x4,%esp

0x08048487 <main+51>:   pushl  0x8049744             0과 100을 스택에 올리고 fgets 함수 호출.
0x0804848d <main+57>:   push   $0x64                  여기서 0은 STDIN을 의미한다.(Standard Input)
0x0804848f <main+59>:   pushl  0xfffffffc(%ebp)       즉, fgets(input, 0x64, STDIN) 코드가 실행되어
0x08048492 <main+62>:   call   0x8048354 <fgets>    패스워드를 100바이트까지 받는다는 것이다.
0x08048497 <main+67>:   add    $0x10,%esp
0x0804849a <main+70>:   sub    $0x4,%esp

 

0x0804849d <main+73>:   push   $0x4                    0x4를 스택에 올리고 mate라는 문자열을 스택에 올리고
0x0804849f <main+75>:   push   $0x80485d7              또 변수공간을 메모리에 올린다. 그 후,
0x080484a4 <main+80>:   pushl  0xfffffffc(%ebp)         strncmp(input, "mate", 0x4) 코드가 실행되어
0x080484a7 <main+83>:   call   0x8048364 <strncmp>  입력받은 값의 4자리가 “mate"인지 비교한다.
0x080484ac <main+88>:   add    $0x10,%esp             그런데 바로 앞에서 패스워드를 100바이트 까지
                                                     받을 수 있었으므로 가장 앞에서부터 4자리가 mate 이기만 하면
                                                     뒤에오는 문자들은 상관없이 무조건 패스워드를 얻는다.


0x080484af <main+91>:   test   %eax,%eax                  앞에서 입력한 문자열이 mate인지 아닌지 비교
0x080484b1 <main+93>:   jne    0x80484cd <main+121>  mate가 아닐 경우, main+121로 점프
0x080484b3 <main+95>:   sub    $0xc,%esp                 아닐 경우엔 그대로 이어서 진행.
0x080484b6 <main+98>:   push   $0x80485e0
0x080484bb <main+103>:  call   0x8048384 <printf>   main+75 "mate"를 입력했을 경우
0x080484c0 <main+108>:  add    $0x10,%esp           패스워드 출력
0x080484c3 <main+111>:  sub    $0xc,%esp            mate를 입력했을 경우
0x080484c6 <main+114>:  push   $0x0                     스워드를 출력하고 프로그램 종료
0x080484c8 <main+116>:  call   0x8048394 <exit>
0x080484cd <main+121>:  sub    $0xc,%esp            mate가 아닐 경우 121로 점프
0x080484d0 <main+124>:  push   $0x8048617            /bin/wrong.txt 파일 출력
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.

 

 

$ wrong.txt

올바르지 않은 패스워드 입니다.
    패스워드는 가까운곳에...
--_--_- --____- ---_-__ --__-_

 

 

■ 복원 의사코

$ vi conversion.c

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

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

        if((input = (char *)malloc(0x64)) == NULL)
        {
                printf("malloc() error\n");
                exit(1);
        }
        printf("Insert The Password : ");

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

        return 0;

 

■ 원본 소스코드

 

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

int main()
{
    char *str;
    str = (char *)malloc(100);
    printf( "Insert The Password : " );
    fgets( str, 100, stdin );

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

 

원본 소스의 경로는 iso 이미지 파일을 마운트해서 확인할 수 있다.

 

■ 추측 의사코드 여러가지 예제

추측 의사코드 여러가지 예제

#include <stdio.h>

int main(){

 int putpasswd;
 
 printf("Insert The Password : ");
 fgets(putpasswd, sizeof(putpasswd), stdin);

 if(strncmp(putpasswd, "mate", sizeof(putpasswd)){

     printf("\nCongratulation! next password is \"break the world\".\n\n");
  exit(0);
 }
 else{

  system(cat /bin/wrong.txt);
  exit(1);
 }

}

 

 


참조) http://blog.naver.com/tjy97/220387656078

-------------------------------------------------------------
fgets(입력받을 변수명, 문자열의 최대길이(=변수길이), 스트림);
puts(출력할 변수명, 스트림);

ex)
 char ch[10];

 fgets(ch, sizeof(ch), stdin);
 fputs(ch, stdout);
 
-------------------------------------------------------------
==연산자 : 두 변수의 주소값을 비교
strcmp : char형 두 개를 입력받아 두 문자열이 같으면 int형 반환
         strcmp(비교할 문자열1, 비교할 문자열2)
strncmp : 문자열 중 입력한 길이만큼만 비교
   strncmp(비교할 문자열1, 비교할 문자열2, 비교할 길이)

ex)
int main(void)
{
 char ch1[7] = "Tae";
 char ch2[7] = "Tae";

 if(!strcmp(ch1, ch2))
  puts("equal");
 else
  puts("not equal");

 return 0;
}


ex)

int main(void)
{
 char ch1[7] = "TaeJae";
 char ch2[7] = "TaeYou";

 if(!strncmp(ch1, ch2, 3))
  puts("equal");
 else
  puts("not equal");
 if(!strncmp(ch1, ch2, 6))
  puts("equal");
 else
  puts("not equal");
 return 0;

 

 

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

int main(void)
{
        char cat_wrong[40]="cat /bin/wrong.txt";
        char answer[20]="mate";
        char *string;
        int cmp, i;

        string = (char *)malloc(sizeof(char)*100);

        for(i=0;i<sizeof(char)*100;i++) {
                string[i]=0;
        }

        printf("Insert The Password : ");
        fgets(string, sizeof(char)*100, stdin);

        string[strlen(string)-1]=0;

        cmp = strcmp(string,answer);

        if(cmp == 0) {
                printf("\nCongratulation! next password is \"break the world\".\n\n");
                exit(0);
        }else
                system(cat_wrong);

        return 0;
}

 

 

 

 

#include<stdio.h>

#define buff_size 500

int main()
{
        char origin_pwd[]="mate";
        char *input_pwd = (char*)malloc(buff_size);

        printf("Insert The Password : \n");
        fgets(input_pwd, buff_size, stdin);

        if(strncmp(origin_pwd, input_pwd, strlen(origin_pwd))==0){
                printf("Congratulation! next password is \"break the world\".\n");
        }else{
                system("cat /bin/wrong.txt");
        }

        exit(0);
}

 

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

int main()
{
        int result;
        char *str;      // char str[100];

        str=(char *)malloc(100);
        printf("Insert The Password : ");
        fgets(str,100,stdin);

        result = strncmp(str,"mate",4);

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

        return 0;
}