scapy 사용시에는 반드시 IDA를 관리자 권한으로 실행할 것


오류 발견

처음 오류는

WinPcap을 설치하지 않았다고 해서 설치하려는데 다음과 같은 오류 발생

 

 

이를 찾아보니까 Windows 10부터 지원하지 않는다고 공식 사이트에서 나와있어서 최신 Npcap을 설치 하고 실행해보니 다음과 같이 오류 발생

 

 

이 오류는 winpcap이 설치되어 있지 않다고 나와 있는데 (winpcap is not installed) Npcap이 제대로 설치가 안되었거나 무슨 문제가 있는 것이 분명하다고 생각했고 천천히 와이어샤크 Windows ARM 버전용으로 설치를 진행하였다. (MAC OS apple silicon, windows 11)

Npcap의 최신 버전인 1.79버전이 아닌 1.78이 자동으로 설치되도록 나와있어서 1.78로 설치를 진행함

 

이후에도 같은 에러가 나타남


문제 원인

문제의 원인은 IDA와 NPCAP이 아닌 Python에 문제가 있었다.

https://bugs.python.org/issue41100

 

Issue 41100: Support macOS 11 and Apple Silicon Macs - Python tracker

Issue41100 Created on 2020-06-24 11:51 by ronaldoussoren, last changed 2022-04-11 14:59 by admin. This issue is now closed. File name Uploaded Description Edit build.log harlantc, 2021-04-15 15:38 build log for ARM M1 Big Sur URL Status Linked Edit PR 2111

bugs.python.org

위 사이트에서 해당 오류를 확인해 볼 수 있는데 요약하자면

애플 실리콘 아키텍처에서 3.10, 3.9, 3.8 버전의 파이썬을 사용하면 라이브러리를 제대로 가져오지 못하는 문제가 발생(컴파일 오류 였다.)

즉 파이썬을 3.11 이상인 최신버전을 이용하면 해결이 되는 문제였다.

따로 윈도우 데스크탑에서 똑같은 환경으로 테스트 해보니 정상 작동이 되었다.

 

그럼 애플 실리콘 윈도우에선 안되는 걸까?

 


해결 방법

IDA Pro 7.6버전은 공식적으로 3.9.0~1 버전까지만 지원된다.

1. IDA Pro 7.6은 3.9.1까지만 지원하여 파이썬 버전을 올릴 수 없으니 IDA Pro 버전을 올리면 된다. IDA Pro 올리면 자연스레 Python도 최신 버전을 설치하게 된다.

2. 그냥 인텔 아키텍처 사용 -> 너무 간단하지만 확실하다

3. 공유? 라이브러리 설정 <- 이부분은 저도 잘 모르겠습니다. 1번과 2번으로 원만한 합의 보시길..

 

 

 

 

 

 

 

추가적으로 해결 방법이 존재하신다면 피드백 주시면 감사하겠습니다.

 

 

 

 

 

 

 

mssecsvc.exe 파일 대상으로 진행

 

 

socket 예제

import idautils
import idc
import re
import socket #도메인을 IP로 가져오기 위한 모듈 선언

def find_network_iocs():
    """
    전체 바이너리에서 네트워크 관련 IOC를 찾아 출력합니다. 이에는 IP 주소와 도메인 이름이 포함됩니다.
    """
    ip_pattern = re.compile(r'\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b') #IP관련 요소 추출 정규식 표현 패턴
    domain_pattern = re.compile(r'\b(?:http?:\/\/)?(?:www\.)?([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\.(com|net|org|info|biz|gov|edu))\b')
    #도메인 http:www.a-z.com혹은 net,org 추출인데 http, www 부분은 있으면 추출되고 없어도 뒤에 패턴으로 추출하는 것
    print("네트워크 IOC 추출:")

    for seg in idautils.Segments(): #세그먼트 전체 순회하기 위한 for 문
        for head in idautils.Heads(idc.get_segm_start(seg), idc.get_segm_end(seg)): #첫 번째 부터 마지막까지 순회
            disasm = idc.GetDisasm(head)                 #해당하는 명령어나 메모리 주소를 디스어셈블 결과를 disasm에 저장
            ip_matches = ip_pattern.findall(disasm)      # ip 패턴을 findall로 다 찾는다 disasm에서 그 결과를 ip_matches에 저장
            domain_matches = [match[0] for match in domain_pattern.findall(disasm)]
            #findall로 튜플형태로 반환하는데 전체 도메인 형식만을 추출하기 위해서 match[0]을 함
            #반환 되는 값이 idnsajn.com, com 으로 반환 되기 때문이다.

            if ip_matches or domain_matches:   #도메인 이나 IP 가 있다면 for
                print(f"명령어 주소: {hex(head)}")
                if ip_matches:
                    print(f"  IP 주소: {', '.join(ip_matches)}")
                if domain_matches:
                    print(f"  도메인 주소: {', '.join(domain_matches)}")
                    for domain in domain_matches:   # 도메인 인 경우에 IP를 가져오기 위한 반복
                        try:
                            ip_address = socket.gethostbyname(domain)
                            print(f"    도메인으로부터 얻은 IP 주소: {ip_address}")
                        except socket.gaierror:
                            print(f"    해당 도메인에는 IP주소가 존재하지 않습니다.: {domain}")

if __name__ == "__main__":
    find_network_iocs()

socket 핵심은 gethostbyname함수로 해당 함수 내에 도메인 문자열을 넣어주면 IP주소로 반환해줍니다.

이 코드 예제에서는 domain에 해당하는 도메인 주소가 담겨있기 때문에 domain을 넣어주었습니다.

자세한 코드 분석은 코드에 달아두었습니다.

 

실행 결과는 다음과 같습니다.

해당 도메인에 대응되는 IP 주소를 획득할 수 있습니다.

 

 

whois 모듈

socket 예제에서 다음과 같이 수정 해주면 됩니다.

try:
    domain_info = whois.whois(domain)
    print(f"    도메인 WHOIS 정보: {domain_info}")
except Exception as e:
    print(f"    WHOIS 조회 실패: {e}")

다음과 같이 결과를 확인할 수 있습니다.

whois 사이트는 다음과 같습니다.

https://whois.domaintools.com/

 

Whois Lookup, Domain Availability & IP Search - DomainTools

 

whois.domaintools.com

 

 

 

 

 

 

참조 :

https://wikidocs.net/4308#mn

 

08-2 정규 표현식 시작하기

정규 표현식에서는 메타 문자(meta characters)를 사용한다. 먼저 메타 문자가 무엇인지 알아보자. [TOC] ## 정규 표현식의 기초, 메타 문자 메타 문자란 원…

wikidocs.net

https://hotel-iu.tistory.com/321

 

파이썬 python 정규표현식 (정규식) 문자열 추출 예제 정리

파이썬 python 정규표현식 (정규식) 문자열 추출 예제 정리 Python에서 정규 표현식은 re 모듈에서 지원됩니다. 파이썬에서 정규 표현식을 사용하려면 먼저 import re를 사용하여 re 모듈을 가져와야 합

hotel-iu.tistory.com

https://whois.domaintools.com/

 

Whois Lookup, Domain Availability & IP Search - DomainTools

 

whois.domaintools.com

 

1. 간단한 인터프리터 예제

2. 간단한 실제 사용 예제

 

 

1. 간단한 인터프리터 예제

1.1 현재 위치 주소

1.2 최소 최대 주소

 

1.1 here() : 현재 위치의 주소를 리턴한다.(현재 커서에 있는 위치)

hex(here())
here()

 

1.2 idc.get_inf_attr(idc.INF_최대,최소_EA) : IDA 데이터 베이스에서 바이너리의 전체 범위에 대한 최대와 최소 주소값 반환

idc.get_inf_attr(idc.INF_MIN_EA)
idc.get_inf_attr(idc.INF_MAX_EA)

 

 

2. 간단한 실제 사용 예제

2.1 세그먼트별 주소 출력 예제

2.2 함수 목록 출력 예제

2.3 전체 명령어 추출 스크립트 예제

2.4 전체 주석 추출 스크립트 예제

2.5 IP 주소와 도메인 이름 추출 예제

 

2.1 세그먼트별 주소 출력 예제

# 세그먼트의 개수와 세부 정보를 출력
for n in range(idaapi.get_segm_qty()):
    seg = idaapi.getnseg(n)  # n번째 세그먼트 정보를 가져옴
    if seg:
            # 세그먼트 이름, 시작 주소, 끝 주소를 가져와서 출력
        segname = idc.get_segm_name(seg.start_ea)
        start_address = seg.start_ea
        end_address = seg.end_ea
        print(f"Segment Name: {segname}, Start: {hex(start_address)}, End:{hex(end_address)}")

 

2.2 함수 목록 출력 예제

import idautils

def print_functions():
    # 모든 함수들을 순회
    for func in idautils.Functions():
        # 함수의 시작 주소를 가져옴
        start_address = func
        # 함수의 이름을 가져옴
        func_name = ida_funcs.get_func_name(start_address)
        
        # 함수의 시작 주소와 이름을 출력
        print(f"Function Name: {func_name}, Start Address: {hex(start_address)}")

if __name__ == "__main__":
    print_functions()

 

 

2.3 전체 명령어 추출 스크립트 예제

import idautils
import idc

def find_instructions_with_comments(keyword):
    """
    전체 바이너리에서 특정 명령어를 포함하는 코드를 찾아 그 코드의 주소, 명령어, 주석을 출력합니다.
    :param keyword: 검색할 명령어 키워드
    """
    print(f"Searching for instructions containing '{keyword}':")
    print("-" * 50)
    for seg in idautils.Segments():
        for head in idautils.Heads(idc.get_segm_start(seg), idc.get_segm_end(seg)):
            disasm = idc.GetDisasm(head)
            if keyword in disasm:
                # 명령어에 키워드가 포함되어 있는 경우
                comment = idc.get_cmt(head, 0)  # 일반 주석
                rcomment = idc.get_cmt(head, 1) # 반복 주석
                print(f"Address: {hex(head)} - Instruction: {disasm}")
                if comment:
                    print(f"  Comment: {comment}")
                if rcomment:
                    print(f"  Repeatable Comment: {rcomment}")
                print("-" * 40)

if __name__ == "__main__":
    # 예를 들어, 'call' 명령어를 포함하는 코드를 찾으려면
    find_instructions_with_comments("call")

 

 

2.4 전체 주석 추출 스크립트 예제

import idautils
import idc

def extract_all_comments():
    print("Extracting all comments from the binary:")
    print("-" * 50)
    for seg in idautils.Segments():
        for head in idautils.Heads(idc.get_segm_start(seg), idc.get_segm_end(seg)):
            # 주석 가져오기
            comment = idc.get_cmt(head, 0)  # 일반 주석
            rcomment = idc.get_cmt(head, 1) # 반복 주석
            if comment or rcomment:
                print(f"Address: {hex(head)}")
                if comment:
                    print(f"  Comment: {comment}")
                if rcomment:
                    print(f"  Repeatable Comment: {rcomment}")
                print("-" * 40)

if __name__ == "__main__":
    extract_all_comments()

 

2.5 IP 주소와 도메인 이름 추출 예제

import idautils
import idc
import re

def find_network_iocs():
    """
    전체 바이너리에서 네트워크 관련 IOC를 찾아 출력합니다. 이에는 IP 주소와 도메인 이름이 포함됩니다.
    """
    ip_pattern = re.compile(r'\b(?:\d{1,3}\.){3}\d{1,3}\b')
    domain_pattern = re.compile(r'\b(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}\b')
    print("Searching for Network IOCs (IP Addresses and Domain Names):")
    print("-" * 60)
    for seg in idautils.Segments():
        for head in idautils.Heads(idc.get_segm_start(seg), idc.get_segm_end(seg)):
            disasm = idc.GetDisasm(head)
            comments = idc.get_cmt(head, 0)  # 일반 주석
            rcomments = idc.get_cmt(head, 1) # 반복 주석
            strings = idc.get_strlit_contents(head)
            search_text = f"{disasm} {comments if comments else ''} {rcomments if rcomments else ''} {strings if strings else ''}"

            ip_matches = ip_pattern.findall(search_text)
            domain_matches = domain_pattern.findall(search_text)
            if ip_matches or domain_matches:
                print(f"Address: {hex(head)}")
                if ip_matches:
                    print(f"  IP Addresses: {', '.join(ip_matches)}")
                if domain_matches:
                    print(f"  Domain Names: {', '.join(domain_matches)}")
                print("-" * 60)

if __name__ == "__main__":
    find_network_iocs()

유의미한 정보 추출

 

 

 

 

 

 

 

 

 

 

 

0. 모듈 설명

1. 간단한 사용 방법

2. 예제 코드 및 결과 사진

 

0. 모듈 설명

해당 모듈 경로 - IDA 디렉터리 \ Python 내에 idaapi.py, idautils, idc 파일 3개 존재

 

idaapi : 핵심 API에 접근(직접 임포트 해야함) - 로우 레벨 데이터에 접근할 수 있도록 지원하는 기능 예) 메모리 주소 등등

idc : idc에서 쓸 수 있는 함수 사용 - IDC 함수들을 Wrapping 한 호환 모듈을 포함 예) 명령어 불러오기 등등

idautils : 각종 유틸리티 함수를 제공 - IDA Pro에서 사용가능한 하이 레벨 유틸리티 함수들을 포함 예) 세그먼트 주소 등등

 

1. 간단한 사용 방법

모듈 사용 방법

from idc import *
from idautils import *
from idaapi import *

 

예시 코드 및 결과

ea = here()
print ("0x%x" % (ea))

 

 

2. 간단한 예제 코드 및 결과 사진

악성코드 실행파일 가져온 참조 사이트

https://app.any.run/

 

Interactive Online Malware Analysis Sandbox - ANY.RUN

Cloud-based malware analysis service. Take your information security to the next level. Analyze suspicious and malicious activities using our innovative tools.

app.any.run

다음 사진은 idautils 예제 결과 입니다.

 

다음 사진은 실제 악성코드를 가지고 idaapi를 사용한 간단한 예제입니다.

다음 사진도 실제 악성코드 샘플에서 0x0040CFDA에 존재하는 jmp _CorExeMain 명령어를 가져오는 것을 보여줍니다.

 

마지막으로 해당 파일의 해시 값을 가져오는 스크립트 예제입니다.

 

IDA Python으로 악성코드 분석을 할 때 자동화 할 수 있도록 도와주는 굉장히 유용한 플러그인이기 때문에 해당 플러그인을 설치하는 방법에 대해 정리해보았습니다.

 

IDA Python7.6 플러그인 설치

https://lca.xlog.app/ida-ru-he-an-zhuang-cha-jian

 

How to install plugins in Ida - lca

This repository has many excellent IDA plugins. Taking the GitHub - eset/ipyida: IPython console integration for IDA Pro plugin as an…

lca.xlog.app

위 사이트를 참조 하였고 영어로 되어 있지만 정말 잘 정리 되어 있어서 가져와보았습니다.

 

 

1. Python3.9 설치, pip, Git 환경 구성

1.1 Python3.9

https://www.python.org/downloads/release/python-390/

 

Python Release Python 3.9.0

The official home of the Python Programming Language

www.python.org

위 사이트에서 자신의 아키텍처 32,64에 맞추어 설치 후 시스템 환경 변수에 등록하기

1.2 Git

https://git-scm.com/download/win

 

Git - Downloading Package

Download for Windows Click here to download the latest (2.45.0) 32-bit version of Git for Windows. This is the most recent maintained build. It was released 7 days ago, on 2024-04-29. Other Git for Windows downloads Standalone Installer 32-bit Git for Wind

git-scm.com

위 사이트에서 git 설치 후 시스템 환경 변수에 등록

 

1.3 python 3.9.0 apply

위 1.1, 1.2 과정을 다 마친 환경 상태에서 진행해주시면 됩니다.

이제 자신의 IDA Pro 7.6 버전 파일에 가서 idapyswitch.exe 를 실행 해주고 enter를 누르면 3.9.0버전이 적용이 될 것입니다.

위 사진처럼 되었으면 잘 진행이 되었습니다.

 

1.4 ipyida 모듈 pip로 설치

pip install ipyida

위 코드를 IDA 7.6 폴더에서 입력해주면 디렉터리가 생성되는데 다음 사진과 같은 경로로 들어가서 ipyida_plugin_stub.py를

만일 설치가 안된다면

git clone https://github.com/eset/ipyida.git
cd ipyida

하고

 

2. Plugins 추가

ipyida 디렉토리 내에 있는 ipyida_plugin_stub.py 파일을 IDA 디렉터리 안에 있는 plugins 디렉토리로 복사 해주면 됩니다.

windows 에서는 copy로 linux 에서는 cp로 해도 되고 GUI 환경이면 직접 복사 해서 옮겨도 됩니다.

 

3. 끝

이제 직접 설정이 되었는지 IDA 재시작 해주시면 확인이 가능합니다.

파이썬 test
script command 체크

 

4. 마지막으로 IDA Python 모듈 확인 및  사용 예제 사이트를 가져와보았습니다.

 

IDA python 모듈 모음

https://hex-rays.com//products/ida/support/idapython_docs/

 

https://hex-rays.com//products/ida/support/idapython_docs/

 

hex-rays.com

 

IDA python 사용 예제

https://www.openrce.org/articles/full_view/11

 

OpenRCE

Friday, June 24 2005 10:07.18 CDT Python is a powerful scripting language which has features greatly appreciated by its followers. Versatility, speed of development and readability are among the top ones. IDA provides the advanced user with IDC, a C-like s

www.openrce.org

 

0 개요 :

FBICISA는 사이버 보안 권고(CSA)를 통해 Androxgh0st 악성코드를 배포하는 위협 행위자들과 관련된 알려진 침해 지표(IOCs)와 전술 기법 및 절차(TTPs)를 전파합니다. 다양한 신뢰할 수 있는 제 3자 보고를 통해 이러한 IOCTTP가 수집되었으며, 이는 Androxgh0st 악성코드가 취약한 네트워크를 식별하고 침해할 수 있는 봇넷을 구축할 수 있음을 보여줍니다.

 

1. Androxgh0st 악성코드 :

Androxgh0st 악성코드는 파이썬으로 작성되었는데 이는 봇넷(T1583.005)를 통해 표적 네트워크에서 피해자를 식별하고 착취합니다.

.env파일을 타겟으로 잡고 민감한 정보(AWS, Microsoft Office 365 )을 포함하는 .env 파일을 대상으로 작동합니다.

PHPUnit을 통해 웹사이트에서 PHP코드를 원격으로 실행할 수 있게 하는 CVE-2017-9841 취약점을 악용하는 것으로 관찰되었습니다. PHPUnit 모듈을 사용하는 웹사이트(/vendor 폴더가 존재해야함) /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php Uniform Resource Identifier (URI) 악의적인 HTTP POST 요청을 받게 됩니다.

PHP 페이지는 POST 요청을 통해 제출된 PHP코드를 실행하며, 이 위협 행위자는 웹사이트에서 코드를 원격으로 실행할 수 있습니다.

 

 

2. Androxgh0st 악성코드의 타겟

- PHPUnit 모듈의 CVE-2017-9841 취약점을 이용해 원격 실행

- 라라벨(Laravel) 프레임워크를 타겟으로 잡아서 .env파일이 노출되었는지 여부 확인 및 추가 서비스 접근하기 위한 자격 증명이 포함되어 있는지 확인

- Apache 웹 서버 타겟을 잡는데 CVE-2021-41773과 관련하여, Apache HTTP서버 버전이 2.4.49, 2.4.50을 실행하는 취약한 웹서버를 스캔합니다.

위 타겟 들 방법을 사용해서 어떤 서비스의 자격 증명을 획득한 경우, 예로 위협 행위자들이 취약한 웹 사이트에서 AWS 자격 증명을 성공적으로 식별하고 침해하는 경우, 새로운 사용자 및 사용자 정책을 만드는 시도가 관찰되었습니다. 또 추가 스캔을 위해 새로운 AWS 인스턴스를 만드는 것이 관찰되었습니다.

 

 

3. 침해 지표(IOC)

                  다음 URI로의 수신 GET POST 요청:

                  /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

                  /.env

                  다음 문자열을 포함하는 수신 POST 요청:

                  [0x%5B%5D=androxgh0st]

                  ImmutableMultiDict([('0x[]', 'androxgh0st')])

위에 나열된 POST 요청 문자열에서 androxgh0st라는 이름은 다른 명칭으로 대체되어 사용된 것으로 관찰되었습니다. 해당 이름 대신해 사용된 이름들이 Ridho, Aws, 0x_0x, x_X, nopebee7 등이 있습니다.

이 외에도 위협 행위자들이 사용하는 많은 추가 URL도 모았습니다.

/info

/phpinfo

/phpinfo.php

/?phpinfo=1

/frontend_dev.php/$

/_profiler/phpinfo

/debug/default/view?panel=config

등등

웹 쉘 드롭을 위한 대상 URL도 많이 모았습니다.

/.env/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

//api/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

//backup/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

//blog/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

등등

 

(허니팟)오픈 프록시를 통한 자격 증명 유출 시도 예 :

POST /.aws/credentials HTTP/1.1

host: www.example.com

user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36

accept-encoding: gzip, deflate

accept: */*

connection: keep-alive

content-length: 20

content-type: application/x-www-form-urlencoded

0x%5B%5D=androxgh0st

 

(허니팟) 오픈 프록시를 통해 시도된 웹 쉘 드롭의 예 :

GET http://www.example.com/lib/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1

host: www.example.com

user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,

like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.76

accept-encoding: gzip, deflate

accept: */*

connection: keep-alive

x-forwarded-for: 200.172.238.135

content-length: 279

 

4. 대응

- 모든 운영체제, 소프트웨어 펌웨어를 최신 상태로 유지, 특히 아파치 서버가 2.4.49, 2.4.50을 실행하고 있는지 확인하기

- 모든 URL 기본 구성이 엑세스 가능해야 하는 특별한 요구가 없는 한 모든 요청을 거부 하는 것인지 확인하기

- 라라벨 프레임워크가 디버그, 테스트 모드에 있지 않은지, .env를 제거 하고 취소하기

- /vendor/phpunit/phpunit/src/Util/PHP파일에서 인식할 수 없는 PHP파일이 있는지 검색

- .php파일을 호스팅 사이로 나가는 GET요청으로 검토하기

 

 

 

 

 

 

참고 :

https://www.cisa.gov/news-events/cybersecurity-advisories/aa24-016a

 

+ Recent posts