Launching Calculator with a Buffer Overflow
Reproducing a Windows buffer overflow end to end, using mona.py to find the offset and land a payload.
윈도우 어플리케이션 버그헌팅을 배우기 위해 추천받은 유튜버 분을 따라 실습을 할려고 한다. 많은 부분을 생략하지만, 전체 순서를 기억해 두기 위해 정리한다.
https://www.youtube.com/watch?v=gdtmbdbcq7U&list=LL&index=1&t=434s
퍼저는 안 돌리고, 그냥 보안 이슈로 윈도우 xp 에서 할것이기 때문에 먼저 xp image 와 vmware tools 를 깔았다. https://www.inflearn.com/
course/%EC%9C%88%EB%8F%84%EC%9A%B0%EC%A6%88-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%B7%A8%EC%95%BD%EC%A0%90?cid=36577

윈도우즈 애플리케이션 취약점 분석 입문부터 활용까지| 보안프로젝트 - 인프런 강의 현재 평점 4.4점 수강생 466명인 강의를 만나보세요. 윈도우 애플리케이션 방어기법 및 우회 공격에 대해 기본 학습부터 활용 방법, 최신 공격 사례 분석까지 다루고 있다. 모의해킹 업무로 진로를 선택했거나, 악성코드 분석으로 진로를 선택한 분들에게 강력하게 추천한다. 윈 www.inflearn.com 유튜버 분은, 여기서 따왔다고 한다. 나중에 봐도 괜찮을듯

우선 취약점 익스플로잇 대상 프로그램은: Easy RM to MP3 Converter 2.7.3.700 이다.

파이썬으로 크래시를 확인할 파일을 만들어줬다. olly debug setting 을 갖추고 다시 돌려보면 디버그 옵션이 나오는데, eip 를 보면 eip address 를 41414141.. (파일 인풋 아스키 값이 41임) 로 덮어 써진것을 볼수있다. 참고로 eip 는 컴퓨 터가 다음에 실행할 주소이다. 즉 오프셋을 디버거로 잘 분석해 인풋을 넣으면, 다음 실행주소를 원하는 주소로 바꿔 쓸수 있다는것이다. (즉 흐름을 망가뜨리는 취약점이 있음을 알수있음)

맞춰 놓은 세팅

디버거 레지스터 창 오프셋을 알아내기 위해서 편하게 immunity debugger 를 사용하겠다. 이뮤니티 디버거는 다른 디버거들보다 익스플로 잇을 좀더 편하게 할수있게 중점이 맞춰져있다.

이뮤니 디버거를 다운로드 해서 파이코맨드로 따라가면, 모나라는 익스플로잇 툴이 제공된다. 이뮤니티 디버거에 !mona 를 통해서 mona 를 실행 해보자.

mona 라는 익스플로잇 툴에 대해서는 따로 설명이 없어 정리해 둔다. mona.py는 익스플로잇 개발(특히 스택 버퍼 오버플로우 분석)을 도와주는 Immunity Debugger용 플러그인입니다. C orelan Team이 만든 도구로, 보안 리서치/CTF/OSCP 같은 교육 과정에서 표준처럼 쓰입니다. 기본 개념: 왜 “패턴”이 필 요한가 이전에 말씀하신 “A”*30000 같은 코드로 프로그램을 크래시시키면, EIP(다음에 실행할 명령어를 가리키는 레지 스터)가 0x41414141 (전부 A)로 덮어써집니다. 문제는 — “A”가 30000개 중 정확히 몇 번째 A가 EIP를 덮었는지 알 수 가 없다는 겁니다. 전부 똑같은 문자니까요. mona.py의 패턴 생성/오프셋 찾기 기능 1.
유니크 패턴 만들기 !mona pattern_create 30000 이렇게 하면 “A” 대신 “Aa0Aa1Aa2Aa3…” 처럼 4바이트마다 겹치지 않는 고유한 패턴을 만들 어줍니다. 이게 De Bruijn 시퀀스라는 수학적 방법입니다. 2. 크래시 후 오프셋 찾기 이 패턴 문자열로 다시 크래시를 일 으키면, EIP에는 그 패턴 중 특정 4바이트 조각이 남습니다. 예를 들어 EIP가 0x69413969 같은 값이 됐다고 하면: !mona pattern_offset 69413969 이렇게 입력하면 mona가 “이 4바이트 조각은 패턴의 정확히 몇 번째 바이트였는지” 계산해줍니다. 그럼 “아, EIP를 덮으려면 정확히 4113바이트가 필요하구나” 같은 걸 알 수 있는 거죠. 왜 이게 중요한가?
버퍼 오버플로우 익스플로잇을 만들 때 보통 이런 구조를 씁니다: [정확한 오프셋만큼의 채우기 바이트] + [EIP를 원하는 주소로 덮기] + [실행시킬 페이로드] 오프셋을 정확히 몰라면 EIP를 원하는 값으로 정밀하게 컨트롤할 수 없습니다. “A”*30000으로는 “크래시가 난다”는 것만 알 뿐, “몇 바이트째에서 EIP가 덮이는지”는 알 수 없어서 다음 단계로 못 넘 어갑니다. mona.py의 다른 유용한 기능들 (참고로) !mona modules — 로드된 DLL들의 보호 기법(ASLR, DEP 등) 여부 확인 !mona find — 메모리에서 특정 opcode(예: jmp esp) 패턴 검색 !mona bytearray — bad character(널바이트 등 페이로드에 쓰면 안 되는 문자) 확인용 바이트 배열 생성 … 라고 하시네요…?

이렇게 패턴을 명령어로 크리에이트 함!

우린 많이 필요하니까, 만개 하면 다 뜨지는 않고 txt 파일에 저장된다. 원래 삼만개를 넣었는데, 왜 만개만 만드냐 할수있 는데, 유튜버 (슨생님) 이 말한 바로는 만개를 넘으면 새로운 패턴을 만드는데 한계가 있어 패턴이 나중에 잘 탐지가 않된 다 하셨다.
그래서 3만개 모두다 패턴으로 채우기 보다는, 걸릴 확률이 좀더 적은 2만개를 앞에 A 로 채우고 뒤에 패턴을 또 만개 추 가하는식으로 페이로드를 짰다.

대충 이렇게 짜주었다

- Pattern Hu3H (0x48337548) found in cyclic pattern at position 6069… 라고 나온다. 즉 오프셋은 6069. 하지만 2만이 껴있었기 때문에 사실상 26069 가 오프셋이다. 오프셋을 알았으면 삽입할 셸 코드들 알아야하는데 MSFvenom 이 라는 Metasploit Framework에 포함된 페이로드(payload) 생성 도구가 있다. 사용할때는 msfvenom -p <페이로드종류> <옵션들> -f <출력형식> -o <출력파일> 이렇게 하면 리버스 쉘 셸코드를 파이썬 바이트 문자열 형식으로 뽑아주고, 이걸 앞서 만드 exploit 스크립트의 페이로드 자리에 붙여넣으면 된다.

나는 그냥 유튜브에서 카피엔 패이스트 했다. 계산기를 띄우는 셸코드고, PoC 는 (proof of concept) 이다.

[20바이트 NOP] + [실제 셸코드(buf)] + [30,000바이트의 A]
• 의미: 공격에 필요한 모든 요소(NOP, 셸코드)를 맨 앞에 미리 배치해 두고, 그 뒤를 엄청나게 긴 “A”로 채워서 프 로그램이 감당할 수 있는 버퍼 크기를 완전히 넘기도록(Overflow) 만듭니다.
NOP는 “No Operation”의 약자로, CPU가 실행해도 특별한 동작을 하지 않고 다음 명령으로 넘어가는것이다. 취약점 연 구 자료에서는 실제 코드 앞에 여러 개의 NOP를 배치해 두는 경우가 있었습니다. 이렇게 하면 실행 위치가 정확히 코드 시작점이 아니더라도, NOP 구간 안 어딘가에 도착한 뒤 순차적으로 실제 코드 쪽으로 이동할 수 있다는 있습니다
payload = payload[:offset] + "CCCC"
이 부분이 핵심입니다. 이전 단계(#2 Reason)에서 유니크한 패턴을 통해 EIP 레지스터가 변조되는 정확한 위치(오프셋 값)를 찾아냈다고 가정합니다. payload[:offset]: 맨 앞부터 오프셋 직전까지의 문자열만 딱 잘라냅니다. 이 잘려진 데이 터 안에는 이미 [NOP * 20 + buf + 일부 A]가 들어가 있습니다. + “CCCC”: 잘라낸 문자열 바로 뒤에 “CCCC”를 붙입니 다. 결과로는전체 페이로드의 정확히 offset 위치(즉, 시스템이 다음 실행할 주소를 읽어오는 RET 자리)에 “CCCC”(\x43\x43\x43\x43)가 배치됩니다.

EIP 를 보면 딱 (\x43\x43\x43\x43) 으로 도배 되었는걸을 알수있다. 즉 저기 90 (NOP) 들의 주소를 C 대신 해서 넣으면, 셸코드가 실행될것이다. 한번 해봅시다.

import struct
• 의미: 파이썬의 struct 모듈은 가상 메모리 주소(숫자)를 시스템이 인식할 수 있는 바이너리(바이트) 형태로 변환 할 때 사용합니다.
그후 그 주소를 언팩해서 넣으면 그 놉이 있는 주소로 넘어가 셸코드를 작성 시킵니다.

그럼 이 파일을 (테스트 5) 넣었을때, 계산기가 뜬다. 이건 계산기를 예제로 띄운거 뿐이고, 여러 다른 프로그램을 실행할수 있다.