[문제]


[풀이]

보호기법 분석

  • 32bits 바이너리
  • 카나리 존재 → bof 불가
  • NX bits 존재
  • PIE 없음

 

소스코드 분석 - passcode.c

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

void login(){
	int passcode1;
	int passcode2;

	printf("enter passcode1 : ");
	scanf("%d", passcode1);
	fflush(stdin); //buffer를 지워줌

	// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
	printf("enter passcode2 : ");
        scanf("%d", passcode2);

	printf("checking...\\n");
	if(passcode1==338150 && passcode2==13371337){
                printf("Login OK!\\n");
                system("/bin/cat flag");
        }
        else{
                printf("Login Failed!\\n");
		exit(0);
        }
}

void welcome(){
	char name[100];
	printf("enter you name : ");
	scanf("%100s", name);
	printf("Welcome %s!\\n", name);
}

int main(){
	printf("Toddler's Secure Login System 1.0 beta.\\n");

	welcome();
	login();

	// something after login...
	printf("Now I can safely trust you that you have credential :)\\n");
	return 0;	
}
  • main 함수에서는 단순히 welcome 함수와 login 함수를 호출함
  • welcome 함수
    • name에 대한 정보를 입력 받는데, 100byte 만큼 입력할 수 있음
  • login 함수

  • 그런데 해당 값을 입력하면 Segmentation Fault가 발생함

 

gdb 분석 - 함수 주소

gdb-peda$ info func
All defined functions:

Non-debugging symbols:
0x080483e0  _init
0x08048420  printf@plt
0x08048430  fflush@plt
0x08048440  __stack_chk_fail@plt
0x08048450  puts@plt
0x08048460  system@plt
0x08048470  __gmon_start__@plt
0x08048480  exit@plt
0x08048490  __libc_start_main@plt
0x080484a0  __isoc99_scanf@plt
0x080484b0  _start
0x080484e0  __do_global_dtors_aux
0x08048540  frame_dummy
0x08048564  login
0x08048609  welcome
0x08048665  main
0x080486a0  __libc_csu_init
0x08048710  __libc_csu_fini
0x08048712  __i686.get_pc_thunk.bx
0x08048720  __do_global_ctors_aux
0x0804874c  _fini

 

gdb 분석 - welcome

gdb-peda$ disass welcome
Dump of assembler code for function welcome:
   0x08048609 <+0>:	push   ebp
   0x0804860a <+1>:	mov    ebp,esp
   0x0804860c <+3>:	sub    esp,0x88
   0x08048612 <+9>:	mov    eax,gs:0x14
   0x08048618 <+15>:	mov    DWORD PTR [ebp-0xc],eax
   0x0804861b <+18>:	xor    eax,eax
   0x0804861d <+20>:	mov    eax,0x80487cb
   0x08048622 <+25>:	mov    DWORD PTR [esp],eax
   0x08048625 <+28>:	call   0x8048420 <printf@plt>
   0x0804862a <+33>:	mov    eax,0x80487dd
   0x0804862f <+38>:	lea    edx,[ebp-0x70]
   0x08048632 <+41>:	mov    DWORD PTR [esp+0x4],edx
   0x08048636 <+45>:	mov    DWORD PTR [esp],eax
   0x08048639 <+48>:	call   0x80484a0 <__isoc99_scanf@plt>
   0x0804863e <+53>:	mov    eax,0x80487e3
   0x08048643 <+58>:	lea    edx,[ebp-0x70] #user name 저장 위치
   0x08048646 <+61>:	mov    DWORD PTR [esp+0x4],edx
   0x0804864a <+65>:	mov    DWORD PTR [esp],eax
   0x0804864d <+68>:	call   0x8048420 <printf@plt>
   0x08048652 <+73>:	mov    eax,DWORD PTR [ebp-0xc]
   0x08048655 <+76>:	xor    eax,DWORD PTR gs:0x14
   0x0804865c <+83>:	je     0x8048663 <welcome+90>
   0x0804865e <+85>:	call   0x8048440 <__stack_chk_fail@plt>
   0x08048663 <+90>:	leave  
   0x08048664 <+91>:	ret    
End of assembler dump.
  • 사용자의 입력 값은 ebp-0x70에 저장됨
    • 임의의 입력값(다수의 a)를 넣었을 때 ebp-0x70에 잘 저장됨을 알 수 있음

 

gdb 분석 - login

gdb-peda$ disass login
Dump of assembler code for function login:
   0x08048564 <+0>:	push   ebp
   0x08048565 <+1>:	mov    ebp,esp
   0x08048567 <+3>:	sub    esp,0x28
   0x0804856a <+6>:	mov    eax,0x8048770
   0x0804856f <+11>:	mov    DWORD PTR [esp],eax
   0x08048572 <+14>:	call   0x8048420 <printf@plt>
   0x08048577 <+19>:	mov    eax,0x8048783
   0x0804857c <+24>:	mov    edx,DWORD PTR [ebp-0x10] #passcode1
   0x0804857f <+27>:	mov    DWORD PTR [esp+0x4],edx
   0x08048583 <+31>:	mov    DWORD PTR [esp],eax
   0x08048586 <+34>:	call   0x80484a0 <__isoc99_scanf@plt>
   0x0804858b <+39>:	mov    eax,ds:0x804a02c
   0x08048590 <+44>:	mov    DWORD PTR [esp],eax
   0x08048593 <+47>:	call   0x8048430 <fflush@plt>
   0x08048598 <+52>:	mov    eax,0x8048786
   0x0804859d <+57>:	mov    DWORD PTR [esp],eax
   0x080485a0 <+60>:	call   0x8048420 <printf@plt>
   0x080485a5 <+65>:	mov    eax,0x8048783
   0x080485aa <+70>:	mov    edx,DWORD PTR [ebp-0xc] #passcode2
   0x080485ad <+73>:	mov    DWORD PTR [esp+0x4],edx
   0x080485b1 <+77>:	mov    DWORD PTR [esp],eax
   0x080485b4 <+80>:	call   0x80484a0 <__isoc99_scanf@plt>
   0x080485b9 <+85>:	mov    DWORD PTR [esp],0x8048799
   0x080485c0 <+92>:	call   0x8048450 <puts@plt>
   0x080485c5 <+97>:	cmp    DWORD PTR [ebp-0x10],0x528e6
   0x080485cc <+104>:	jne    0x80485f1 <login+141>
   0x080485ce <+106>:	cmp    DWORD PTR [ebp-0xc],0xcc07c9
   0x080485d5 <+113>:	jne    0x80485f1 <login+141>
   0x080485d7 <+115>:	mov    DWORD PTR [esp],0x80487a5
   0x080485de <+122>:	call   0x8048450 <puts@plt>
   0x080485e3 <+127>:	mov    DWORD PTR [esp],0x80487af
   0x080485ea <+134>:	call   0x8048460 <system@plt>
   0x080485ef <+139>:	leave  
   0x080485f0 <+140>:	ret    
   0x080485f1 <+141>:	mov    DWORD PTR [esp],0x80487bd
   0x080485f8 <+148>:	call   0x8048450 <puts@plt>
   0x080485fd <+153>:	mov    DWORD PTR [esp],0x0
   0x08048604 <+160>:	call   0x8048480 <exit@plt>
End of assembler dump.
  • passcode1, passcode2로 입력한 값은 각각 ebp-0x10, ebp-0xc에 저장됨

  • 그러나 해당 위치에 값이 저장되지 않음

  • 임의의 값(다수의 1)을 입력하면 0xffd624c0에 저장됨

  • passcode1에 임의의 값(다수의 1)을 입력하면 Segmemtation Fault가 발생함

  • scanf가 내부적으로 호출하는 _IO_vfscanf 함수에서 에러 발생

  • 그런데 welcome과 login 함수의 ebp 값이 동일함

→ 같은 스택에 데이터를 저장한다!

→ name은 ebp-0x70, passcode1은 ebp-0x10, passcode2는 ebp-0xc에 각각 저장되는 것

  • 전체적인 스택 구조를 그려보면 passcode1이 name에 중첩되어 있음

 

문제 해결

💡 login함수를 살펴보면 passcode1의 입력 값을 받은 후, fflush 함수를 호출하고 있는데 여기서 got주소를 이용할 수 있음. fflush함수를 호출하게 되면 plt 주소에서 got주소를 참조하여 찾아가게 되는데, 이 got 주소를 login+127의 주소로 변경해주면 조건문의 조건을 충족하지 않아도 flag 획득 가능

name에서 96byte만큼의 dummy를 채운 다음 4byte를 fflush함수의 GOT주소를 넣어주고 system 함수의 주소를 넣어주면 system 함수를 실행할 수 있음

즉, [dummy(96)] + [GOT Address(4)] + [system(4)]
  • 정리해보자면, name 100byte 중 passcode1 부분을 name 입력 받을 때 fflush@got으로 변경(scanf("%d", fflush@got)의 형태가 됨)→ 실제 passcode1을 scanf로 받는 부분에서 system 함수 호출 부분을 10 진수 형태로 입력(got 주소가 변경되었기 때문에 fflush 대신 system(”/bin/cat flag”)를 호출함)
    • scanf(”%d”, passcode1)로 받기 때문에 int type으로 입력해줘야 함

  • fflush함수는 리눅스에서는 제 기능을 하지 못함!

+이전에 적었던 풀이 → fflush이외에도 다른 함수로 exploit 하는 방법

  • GOT 주소들은 readelf 명령을 통해 확인해볼 수 있고, printf, fflush, exit 모두 무관하게 이용 가능함


flag

🍒 Sorry mom.. I got confused about scanf usage :(

'Wargame > Pwnable.kr' 카테고리의 다른 글

[Pwnable.kr] input  (2) 2022.10.15
[Pwnable.kr] random  (0) 2022.10.14
[Pwnable.kr] flag  (0) 2022.10.14
[Pwnable.kr] bof  (0) 2022.10.14
[Pwnable.kr] collision  (0) 2022.10.14

+ Recent posts