2022-07-26 11:01:36 +00:00
|
|
|
import pyshark
|
|
|
|
import requests
|
2024-10-21 19:04:06 +00:00
|
|
|
import json
|
2022-07-26 11:01:36 +00:00
|
|
|
import csv
|
2024-10-21 19:22:03 +00:00
|
|
|
import argparse
|
2024-10-21 20:29:01 +00:00
|
|
|
from colorama import Fore, Style
|
2022-07-26 11:01:36 +00:00
|
|
|
from datetime import date
|
2022-07-26 23:44:46 +00:00
|
|
|
import ipaddress
|
2024-10-21 20:11:39 +00:00
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
2024-10-21 20:29:01 +00:00
|
|
|
def display_banner():
|
|
|
|
"""Display a welcome banner."""
|
|
|
|
banner = f"""
|
2024-10-21 20:44:08 +00:00
|
|
|
{Fore.RED + Style.BRIGHT}
|
2024-10-21 20:29:01 +00:00
|
|
|
|
|
|
|
$$$$$$$\\ $$$$$$$\\ $$$$$$$$\\ $$$$$$\\ $$$$$$$\\ $$$$$$$$\\ $$\\ $$\\ $$\\
|
|
|
|
$$ __$$\\ $$ __$$\\ $$ _____|$$ __$$\\ $$ __$$\\ $$ _____|$$ | $$ |$$ |
|
|
|
|
$$ | $$ |$$ | $$ |$$ | $$ / $$ |$$ | $$ |$$ | $$ | $$ |$$ |
|
|
|
|
$$ | $$ |$$$$$$$ |$$$$$\\ $$$$$$$$ |$$ | $$ |$$$$$\\ $$ | $$ |$$ |
|
|
|
|
$$ | $$ |$$ __$$< $$ __| $$ __$$ |$$ | $$ |$$ __| $$ | $$ |$$ |
|
|
|
|
$$ | $$ |$$ | $$ |$$ | $$ | $$ |$$ | $$ |$$ | $$ | $$ |$$ |
|
|
|
|
$$$$$$$ |$$ | $$ |$$$$$$$$\\ $$ | $$ |$$$$$$$ |$$ | \\$$$$$$ |$$$$$$$$\\
|
|
|
|
\\_______/ \\__| \\__|\\________|\\__| \\__|\\_______/ \\__| \\______/ \\________|
|
|
|
|
|
|
|
|
{Style.RESET_ALL}Welcome to the PCAP IP Extractor and Geolocator!
|
|
|
|
"""
|
|
|
|
print(banner)
|
|
|
|
|
|
|
|
|
2024-10-21 20:11:39 +00:00
|
|
|
def get_local_ips():
|
|
|
|
"""Retrieve a list of local IPs and their subnets."""
|
|
|
|
local_ips = set()
|
|
|
|
local_subnets = set()
|
|
|
|
|
|
|
|
# Using 'ifconfig' to get all local IPs
|
|
|
|
try:
|
|
|
|
output = subprocess.check_output("ifconfig", universal_newlines=True)
|
|
|
|
for line in output.splitlines():
|
|
|
|
if "inet " in line and not line.strip().startswith("inet6"):
|
|
|
|
parts = line.split()
|
|
|
|
if len(parts) >= 2:
|
|
|
|
ip = parts[1]
|
|
|
|
local_ips.add(ip)
|
|
|
|
# Get the subnet mask
|
|
|
|
netmask_index = line.index("netmask") + len("netmask")
|
|
|
|
netmask = line[netmask_index:line.index(" ", netmask_index)].strip()
|
|
|
|
|
|
|
|
# Ensure that netmask is a valid value
|
|
|
|
if ip and netmask:
|
|
|
|
# Calculate the subnet and add it to the set
|
|
|
|
try:
|
|
|
|
subnet = ipaddress.ip_network(f"{ip}/{netmask}", strict=False)
|
|
|
|
local_subnets.add(subnet)
|
|
|
|
except ValueError as e:
|
|
|
|
print(Fore.RED + f"[!] Error creating subnet for IP {ip} with netmask {netmask}: {str(e)}")
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
print(Fore.RED + f"[!] Error fetching local IPs: {str(e)}")
|
|
|
|
|
|
|
|
return local_ips, local_subnets
|
|
|
|
|
2022-07-26 11:01:36 +00:00
|
|
|
|
2024-10-21 19:22:03 +00:00
|
|
|
def read_pcap(pcap_file, output_format):
|
2024-10-21 20:11:39 +00:00
|
|
|
ips = set() # Use a set to avoid duplicates
|
2024-10-21 19:04:06 +00:00
|
|
|
try:
|
|
|
|
pcap = pyshark.FileCapture(pcap_file)
|
|
|
|
print(Fore.GREEN + "[+] Pcap File is valid")
|
|
|
|
for packet in pcap:
|
2024-10-21 20:11:39 +00:00
|
|
|
if "IP" in packet:
|
|
|
|
ips.add(packet.ip.src) # Add source IP
|
|
|
|
ips.add(packet["ip"].dst) # Add destination IP
|
|
|
|
|
2024-10-21 19:22:03 +00:00
|
|
|
ips_list(ips, output_format)
|
2022-07-26 11:01:36 +00:00
|
|
|
|
2024-10-21 19:04:06 +00:00
|
|
|
except FileNotFoundError:
|
|
|
|
exit(Fore.RED + '[!] Pcap path is incorrect')
|
2022-07-26 11:01:36 +00:00
|
|
|
|
2024-10-21 19:22:03 +00:00
|
|
|
|
|
|
|
def ips_list(ips, output_format):
|
2024-10-21 20:11:39 +00:00
|
|
|
local_ips, local_subnets = get_local_ips()
|
2024-10-21 19:04:06 +00:00
|
|
|
ips_lists = []
|
|
|
|
aborted_ips = []
|
|
|
|
for ip in ips:
|
2024-10-21 20:11:39 +00:00
|
|
|
# Check if IP is private or matches local IPs or subnets
|
|
|
|
if ipaddress.ip_address(ip).is_private or ip in local_ips or any(ipaddress.ip_address(ip) in subnet for subnet in local_subnets):
|
2024-10-21 19:04:06 +00:00
|
|
|
aborted_ips.append(ip)
|
2024-10-21 20:11:39 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
# Check if IP is global
|
|
|
|
if ipaddress.ip_address(ip).is_global:
|
|
|
|
ips_lists.append(ip)
|
|
|
|
|
|
|
|
# Inform about removed IPs
|
2024-10-21 19:04:06 +00:00
|
|
|
for ip in aborted_ips:
|
|
|
|
print(Fore.YELLOW + "[!] Remove " + Fore.RED + ip + Fore.YELLOW + ' From Scanning')
|
2024-10-21 20:11:39 +00:00
|
|
|
|
2024-10-21 19:04:06 +00:00
|
|
|
if len(ips_lists) < 1:
|
2024-10-21 20:11:39 +00:00
|
|
|
exit(Fore.RED + "[-] No global IPs to scan.")
|
2022-07-26 11:01:36 +00:00
|
|
|
|
2024-10-21 19:22:03 +00:00
|
|
|
get_ip_info(ips_lists, output_format)
|
|
|
|
|
|
|
|
|
|
|
|
def get_ip_info(list_ip, output_format):
|
2024-10-21 19:04:06 +00:00
|
|
|
data = []
|
|
|
|
for ip in list_ip:
|
2024-10-21 19:22:03 +00:00
|
|
|
print(Fore.YELLOW + "[+] Start analyzing IP : " + ip)
|
2024-10-21 19:04:06 +00:00
|
|
|
try:
|
2024-10-21 20:11:39 +00:00
|
|
|
req = requests.get("http://ip-api.com/json/" + ip + "?fields=status,message,country,countryCode,region,regionName,city,district,zip,lat,lon,timezone,isp,org,as,asname,reverse,mobile,proxy,hosting,query")
|
|
|
|
req_content = req.content.decode()
|
|
|
|
|
|
|
|
# Check if the response is valid JSON
|
|
|
|
if req.status_code == 200 and req_content:
|
|
|
|
try:
|
|
|
|
json_data = json.loads(req_content)
|
|
|
|
if json_data.get("status") == "success":
|
|
|
|
# Skip IPs from hosting providers
|
|
|
|
if json_data.get("isp") and "Hosting" in json_data.get("isp"):
|
|
|
|
print(Fore.YELLOW + f"[!] Skipping hosting IP: {ip} - ISP: {json_data['isp']}")
|
|
|
|
continue
|
|
|
|
|
|
|
|
data.append(json_data)
|
|
|
|
else:
|
|
|
|
print(Fore.RED + f"[!] Error for IP {ip}: {json_data.get('message', 'Unknown error')}")
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
print(Fore.RED + f"[!] Error decoding JSON for IP {ip}. Response content: {req_content}")
|
|
|
|
else:
|
|
|
|
print(Fore.RED + f"[!] Request failed for IP {ip}: {req_content}")
|
|
|
|
|
2024-10-21 19:04:06 +00:00
|
|
|
except requests.exceptions.ConnectionError:
|
2024-10-21 19:22:03 +00:00
|
|
|
exit(Fore.RED + "Check your internet connection and try again ....")
|
2024-10-21 19:04:06 +00:00
|
|
|
|
2024-10-21 20:11:39 +00:00
|
|
|
if data: # Proceed to export only if data is collected
|
|
|
|
export_result(data, output_format)
|
|
|
|
else:
|
|
|
|
print(Fore.YELLOW + "[-] No valid IP data to export.")
|
2024-10-21 19:22:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
def export_result(data, output_format):
|
2024-10-21 19:04:06 +00:00
|
|
|
if output_format == 'json':
|
2024-10-21 19:22:03 +00:00
|
|
|
with open('scan_result-' + str(date.today()) + '.json', 'w', encoding='UTF8') as f:
|
2024-10-21 19:04:06 +00:00
|
|
|
json.dump(data, f, indent=4)
|
|
|
|
elif output_format == 'csv':
|
2024-10-21 19:22:03 +00:00
|
|
|
fieldnames = data[0].keys()
|
|
|
|
with open('scan_result-' + str(date.today()) + '.csv', 'w', encoding='UTF8', newline='') as f:
|
|
|
|
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
2024-10-21 19:04:06 +00:00
|
|
|
writer.writeheader()
|
|
|
|
writer.writerows(data)
|
|
|
|
elif output_format == 'txt':
|
2024-10-21 19:22:03 +00:00
|
|
|
with open('scan_result-' + str(date.today()) + '.txt', 'w', encoding='UTF8') as f:
|
|
|
|
for item in data:
|
|
|
|
f.write(f"{item}\n")
|
2024-10-21 19:04:06 +00:00
|
|
|
elif output_format == 'md':
|
2024-10-21 19:22:03 +00:00
|
|
|
with open('scan_result-' + str(date.today()) + '.md', 'w', encoding='UTF8') as f:
|
|
|
|
for item in data:
|
|
|
|
f.write(f"| {' | '.join(f'{key}: {value}' for key, value in item.items())} |\n")
|
|
|
|
|
|
|
|
print(Fore.GREEN + "\n **Report Exported Successfully!**")
|
2024-10-21 19:04:06 +00:00
|
|
|
|
2022-07-26 11:01:36 +00:00
|
|
|
|
2024-10-21 20:29:01 +00:00
|
|
|
def interactive_mode():
|
|
|
|
"""Run the script in interactive mode."""
|
|
|
|
print(Fore.YELLOW + "Interactive Mode: Please enter the path to the pcap file:")
|
|
|
|
pcap_file = input("Pcap File Path: ").strip()
|
|
|
|
print(Fore.YELLOW + "Choose output format (json, csv, txt, md):")
|
|
|
|
output_format = input("Output Format: ").strip().lower()
|
|
|
|
|
|
|
|
if output_format not in ['json', 'csv', 'txt', 'md']:
|
|
|
|
print(Fore.RED + "[!] Invalid output format. Defaulting to json.")
|
|
|
|
output_format = 'json'
|
|
|
|
|
|
|
|
read_pcap(pcap_file, output_format)
|
|
|
|
|
|
|
|
|
2024-10-21 19:04:06 +00:00
|
|
|
def main():
|
2024-10-21 20:29:01 +00:00
|
|
|
display_banner() # Call the display banner function
|
2024-10-21 19:22:03 +00:00
|
|
|
parser = argparse.ArgumentParser(description='Extract IP addresses from pcap files and geolocate them.')
|
2024-10-21 20:29:01 +00:00
|
|
|
parser.add_argument('pcap', nargs='?', help='Path to the pcap file.')
|
2024-10-21 19:22:03 +00:00
|
|
|
parser.add_argument('--format', choices=['json', 'csv', 'txt', 'md'], default='json', help='Output format (default: json).')
|
2024-10-21 20:11:39 +00:00
|
|
|
|
2024-10-21 19:04:06 +00:00
|
|
|
args = parser.parse_args()
|
2024-10-21 20:11:39 +00:00
|
|
|
|
2024-10-21 20:29:01 +00:00
|
|
|
if args.pcap:
|
|
|
|
read_pcap(args.pcap, args.format)
|
|
|
|
else:
|
|
|
|
interactive_mode() # Enter interactive mode if no arguments are provided
|
2022-07-26 11:01:36 +00:00
|
|
|
|
2024-10-21 20:11:39 +00:00
|
|
|
|
2024-10-21 19:04:06 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|