
그래프 기반 OSINT 조사 플랫폼으로, 타임라인 분석, 엔터티 관리, AI 기반 변환 기능을 통해 이메일, 사용자 이름, 이미지, 위치 간의 숨겨진 연결을 발견합니다.

PANO는 그래프 시각화, 타임라인 분석 및 AI 기반 도구를 결합하여 데이터에서 숨겨진 연결과 패턴을 발견할 수 있도록 도와주는 강력한 OSINT 조사 플랫폼입니다.
https://github.com/user-attachments/assets/6b95e97a-ffdd-4056-b12b-f268d8e5d565
https://github.com/user-attachments/assets/af0c0f65-7b79-417c-a678-a789d42a6003
https://github.com/user-attachments/assets/568b4c28-be78-4559-a607-899fca2f9613
https://github.com/user-attachments/assets/6aa191eb-09de-41d5-b96f-4a2e32d6a0c2
https://github.com/user-attachments/assets/96377b80-e137-4eb4-9387-a0db4e49c2c1
https://github.com/user-attachments/assets/4228bda0-6c13-4ea9-bc07-d87abe367e10
저장소를 클론합니다:
git clone https://github.com/ALW1EZ/PANO.git
cd PANO
애플리케이션을 실행합니다:
./start_pano.shstart_pano.bat시작 스크립트는 자동으로 다음을 수행합니다:
이메일 조회 변환을 사용하려면 먼저 GHunt로 로그인해야 합니다. 시작 스크립트를 통해 pano를 실행한 후;
source venv/bin/activatecall venv\Scripts\activate대화형 그래프 시각화
타임라인 분석
지도 통합
이메일 분석
사용자 이름 분석
이미지 분석
엔터티는 PANO의 기본 구성 요소입니다. 연결 및 분석할 수 있는 개별 정보 조각을 나타냅니다:
내장 유형
속성 시스템
변환은 엔터티를 처리하여 새로운 정보와 관계를 발견하는 자동화된 작업입니다:
작업 유형
특징
헬퍼는 특정 조사 작업을 위한 전용 UI를 갖춘 특수 도구입니다:
사용 가능한 헬퍼
헬퍼 특징
우리는 기여를 환영합니다! PANO에 기여하려면:
참고: 개발에는 단일
main브랜치를 사용합니다. 모든 풀 리퀘스트는main브랜치로 직접 생성해야 합니다.
엔터티는 PANO의 핵심 데이터 구조입니다. 각 엔터티는 특정 속성과 동작을 가진 정보 조각을 나타냅니다. 사용자 정의 엔터티를 생성하려면:
entities 폴더에 새 파일을 생성합니다 (예: entities/phone_number.py)from dataclasses import dataclass
from typing import ClassVar, Dict, Any
from .base import Entity
@dataclass
class PhoneNumber(Entity):
name: ClassVar[str] = "Phone Number"
description: ClassVar[str] = "A phone number entity with country code and validation"
def init_properties(self):
"""Initialize phone number properties"""
self.setup_properties({
"number": str,
"country_code": str,
"carrier": str,
"type": str, # mobile, landline, etc.
"verified": bool
})
def update_label(self):
"""Update the display label"""
self.label = self.format_label(["country_code", "number"])
이 프로젝트는 Creative Commons Attribution-NonCommercial (CC BY-NC) 라이선스에 따라 라이선스가 부여됩니다.
다음 권한이 있습니다:
다음 조건에 따라:
이 프로젝트를 가능하게 해준 모든 라이브러리 저자와 기여자에게 특별히 감사드립니다.
ALW1EZ가 AI ❤️로 제작
변환은 엔터티를 처리하고 새로운 인사이트나 관계를 생성하는 작업입니다. 사용자 정의 변환을 생성하려면:
transforms 폴더에 새 파일을 생성합니다 (예: transforms/phone_lookup.py)from dataclasses import dataclass
from typing import ClassVar, List
from .base import Transform
from entities.base import Entity
from entities.phone_number import PhoneNumber
from entities.location import Location
from ui.managers.status_manager import StatusManager
@dataclass
class PhoneLookup(Transform):
name: ClassVar[str] = "Phone Number Lookup"
description: ClassVar[str] = "Lookup phone number details and location"
input_types: ClassVar[List[str]] = ["PhoneNumber"]
output_types: ClassVar[List[str]] = ["Location"]
async def run(self, entity: PhoneNumber, graph) -> List[Entity]:
if not isinstance(entity, PhoneNumber):
return []
status = StatusManager.get()
operation_id = status.start_loading("Phone Lookup")
try:
# Your phone number lookup logic here
# Example: query an API for phone number details
location = Location(properties={
"country": "Example Country",
"region": "Example Region",
"carrier": "Example Carrier",
"source": "PhoneLookup transform"
})
return [location]
except Exception as e:
status.set_text(f"Error during phone lookup: {str(e)}")
return []
finally:
status.stop_loading(operation_id)
헬퍼는 전용 UI 인터페이스를 통해 추가 조사 기능을 제공하는 특수 도구입니다. 사용자 정의 헬퍼를 생성하려면:
helpers 폴더에 새 파일을 생성합니다 (예: helpers/data_analyzer.py)from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
QTextEdit, QLabel, QComboBox
)
from .base import BaseHelper
from qasync import asyncSlot
class DummyHelper(BaseHelper):
"""A dummy helper for testing"""
name = "Dummy Helper"
description = "A dummy helper for testing"
def setup_ui(self):
"""Initialize the helper's user interface"""
# Create input text area
self.input_label = QLabel("Input:")
self.input_text = QTextEdit()
self.input_text.setPlaceholderText("Enter text to process...")
self.input_text.setMinimumHeight(100)
# Create operation selector
operation_layout = QHBoxLayout()
self.operation_label = QLabel("Operation:")
self.operation_combo = QComboBox()
self.operation_combo.addItems(["Uppercase", "Lowercase", "Title Case"])
operation_layout.addWidget(self.operation_label)
operation_layout.addWidget(self.operation_combo)
# Create process button
self.process_btn = QPushButton("Process")
self.process_btn.clicked.connect(self.process_text)
# Create output text area
self.output_label = QLabel("Output:")
self.output_text = QTextEdit()
self.output_text.setReadOnly(True)
self.output_text.setMinimumHeight(100)
# Add widgets to main layout
self.main_layout.addWidget(self.input_label)
self.main_layout.addWidget(self.input_text)
self.main_layout.addLayout(operation_layout)
self.main_layout.addWidget(self.process_btn)
self.main_layout.addWidget(self.output_label)
self.main_layout.addWidget(self.output_text)
# Set dialog size
self.resize(400, 500)
@asyncSlot()
async def process_text(self):
"""Process the input text based on selected operation"""
text = self.input_text.toPlainText()
operation = self.operation_combo.currentText()
if operation == "Uppercase":
result = text.upper()
elif operation == "Lowercase":
result = text.lower()
else: # Title Case
result = text.title()
self.output_text.setPlainText(result)