power-girl0-0

[pwnable] mistake 풀이 본문

War game/pwnable.kr

[pwnable] mistake 풀이

power-girl0-0 2022. 2. 16. 01:48
728x90

 

Hello~ 안녕하세요!  o(*°▽°*)o


1. 문제

flag, mistake, password의 바이너라 파일이 존재하고, mistake에 대한 c코드가 주어진다.

#include <stdio.h>
#include <fcntl.h>

#define PW_LEN 10
#define XORKEY 1

void xor(char* s, int len){
        int i;
        for(i=0; i<len; i++){
                s[i] ^= XORKEY;
        }
}

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

        int fd;
        if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
                printf("can't open password %d\n", fd);
                return 0;
        }

        printf("do not bruteforce...\n");
        sleep(time(0)%20);

        char pw_buf[PW_LEN+1];
        int len;
        if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
                printf("read error\n");
                close(fd);
                return 0;
        }

        char pw_buf2[PW_LEN+1];
        printf("input password : ");
        scanf("%10s", pw_buf2);

        // xor your input
        xor(pw_buf2, 10);

        if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
                printf("Password OK\n");
                system("/bin/cat flag\n");
        }
        else{
                printf("Wrong Password\n");
        }

        close(fd);
        return 0;
}

 

2. 풀이

위 코드를 살펴보면, 크게 3가지 조건이 존재하는 것을 알 수 있다.

① password파일을 open후, read함수를 통해 10byte값만큼 읽어, pw_buf에 저장한다. 
② 10byte만큼 값을 입력받은 후, xor한다. 그 값은 pw_buf2배열에 존재한다.
③ pw_buf와 pw_buf2의 값이 같으면, flag값이 출력된다.

하지만, 아래 코드를 자세히 살펴봐야한다.

if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
             printf("can't open password %d\n", fd);
             return 0;
 }

if조건문에서 연산자 우선순위에 의해, =보다 <가 먼저 실행된다.

즉, open함수에 대한 return값과 0을 비교해서 나온 결과값 false가 fd에 들어가게 되는 것이다.

 

따라서, read함수의 fd값은 0이 되어서 password를 읽어오는 것이 아니라 값을 입력받게 되는 것이다.

그래서 pw_buf에 공격자가 원하는 값을 삽입할 수 있게 되는 것이다.

 

이후 pw_buf에 넣은 값을 xor하여 입력값으로 넣으면,

pw_buf와 pw_buf2의 값이 같아지게 되어서 flag를 얻을 수 있는 것이다.


아래는 디컴파일하면서, 공부했던 것이다.

기록해두고, 나중에 참고하려고 적어둔다. ( 부분만 가져온 것임. )

(gdb) disas main
Dump of assembler code for function main:
   0x00005555555549a1 <+0>:     push   rbp
   0x00005555555549a2 <+1>:     mov    rbp,rsp
   0x00005555555549a5 <+4>:     sub    rsp,0x40
   0x00005555555549a9 <+8>:     mov    DWORD PTR [rbp-0x34],edi
   0x00005555555549ac <+11>:    mov    QWORD PTR [rbp-0x40],rsi
   0x00005555555549b0 <+15>:    mov    rax,QWORD PTR fs:0x28
   0x00005555555549b9 <+24>:    mov    QWORD PTR [rbp-0x8],rax


   0x00005555555549bd <+28>:    xor    eax,eax
   0x00005555555549bf <+30>:    mov    edx,0x100
   0x00005555555549c4 <+35>:    mov    esi,0x0
   0x00005555555549c9 <+40>:    lea    rdi,[rip+0x208]        # 0x555555554bd8
   0x00005555555549d0 <+47>:    mov    eax,0x0
   0x00005555555549d5 <+52>:    call   0x555555554810 <open@plt>
   '''
      (gdb) x/s $rip+0x208
      0x555555554bd8: "/home/mistake/password"

      eax            0x3      3  //open함수의 리턴값은 3임.  
   '''

   0x00005555555549da <+57>:    shr    eax,0x1f  
   ''' eax에는 0값이 들어감. :: 참고로 0x1f는 31임.  

       ※ 중요 ※
          양수인지, 음수인지 shr 31 로 알 수 있다.
          왜냐하면 컴퓨터는 1과 0만 알기 때문에,  shr31만으로도 양수인지 음수인지 알 수 있는 것이다.  
          즉, eax에서 shr 31하면, 0이 나오게 된다.
          // 1은 음수, 0은 양수를 의미함.
   '''

   0x00005555555549dd <+60>:    movzx  eax,al
   0x00005555555549e0 <+63>:    mov    DWORD PTR [rbp-0x28],eax
   0x00005555555549e3 <+66>:    cmp    DWORD PTR [rbp-0x28],0x0
   0x00005555555549e7 <+70>:    je     0x555555554a09 <main+104>
   ''' cmp했을 때 두 수의 값이 0으로 같기 때문에, <main + 104>로 이동함. '''

   0x00005555555549e9 <+72>:    mov    eax,DWORD PTR [rbp-0x28]
   0x00005555555549ec <+75>:    mov    esi,eax
   0x00005555555549ee <+77>:    lea    rdi,[rip+0x219]        # 0x555555554c0e
   0x00005555555549f5 <+84>:    mov    eax,0x0
   0x00005555555549fa <+89>:    call   0x5555555547d0 <printf@plt>
   //   "can't open password %d\n"  

   0x00005555555549ff <+94>:    mov    eax,0x0
   0x0000555555554a04 <+99>:    jmp    0x555555554b39 <main+408>
   0x0000555555554a09 <+104>:   lea    rdi,[rip+0x216]        # 0x555555554c26
   0x0000555555554a10 <+111>:   call   0x5555555547a0 <puts@plt>
  
   '''
      (gdb) x/s $rip+0x216
      0x555555554c26: "do not bruteforce..."
   '''


   0x0000555555554a15 <+116>:   mov    edi,0x0
   0x0000555555554a1a <+121>:   mov    eax,0x0
   0x0000555555554a1f <+126>:   call   0x555555554800 <time@plt>
   // time(0)

 

3. flag 획득

필자는 pw_buf에 'hellohello' 값을 넣어주고,

pw_buf2에 'hellohello' xor연산한 'idmmnidmmn'값을 입력하여 flag를 획득하였다.


Bye~ 안녕히계세요!  ヽ(≧□≦)ノ

 

728x90

'War game > pwnable.kr' 카테고리의 다른 글

[pwnable] cmd2 풀이  (0) 2022.02.21
[pwnable] cmd1 풀이  (0) 2022.02.20
[pwnable] random 풀이  (0) 2022.02.13
[pwnable] flag 풀이  (0) 2022.02.12
[pwnable] collision 풀이  (0) 2022.02.09
Comments