iotsploit-exploits 0.0.7__tar.gz → 0.0.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/PKG-INFO +2 -2
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/pyproject.toml +2 -2
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/adb_check/adb_check.py +1 -7
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/async_sleep_attack.py +0 -1
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/flood_attack/flood_attack.py +19 -19
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/greatfet_echo.py +1 -7
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/greatfet_rubber_duck.py +2 -4
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_ssh_attack.py +1 -1
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/ip_scan/ip_scan.py +9 -7
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/nmap_scan/nmap_scan.py +1 -1
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/plugin_ssh.py +63 -18
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/serial/picocom_serial_reader.py +5 -6
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/simple_rubber_duck.py +2 -4
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/wifi_scan/wifi_scan.py +1 -1
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/README.md +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/adb_check/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/stream_data_attack.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/flood_attack/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/flood_attack/syn_flood_attack.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_cracker/weak_pass.txt +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_cracker/weak_pass_simple.txt +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/ip_scan/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/nmap_scan/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/rubber_duck_scripts/linux_infogather.txt +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/rubber_duck_scripts/windows_payload.txt +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/serial/__init__.py +0 -0
- {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/wifi_scan/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iotsploit-exploits
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.8
|
|
4
4
|
Summary: Official IoTSploit exploit plugin package
|
|
5
5
|
License: GPL-3.0-or-later
|
|
6
6
|
Author: IoTSploit Team
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
16
16
|
Requires-Dist: facedancer (>=3.0.6,<4.0)
|
|
17
17
|
Requires-Dist: iotsploit-core
|
|
18
18
|
Requires-Dist: iotsploit-django
|
|
19
|
-
Requires-Dist:
|
|
19
|
+
Requires-Dist: paramiko (>=3.0)
|
|
20
20
|
Requires-Dist: pyserial (>=3.5)
|
|
21
21
|
Requires-Dist: scapy (>=2.5)
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "iotsploit-exploits"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.8"
|
|
4
4
|
description = "Official IoTSploit exploit plugin package"
|
|
5
5
|
authors = ["IoTSploit Team <support@iotsploit.org>"]
|
|
6
6
|
license = "GPL-3.0-or-later"
|
|
@@ -16,7 +16,7 @@ python = ">=3.10,<4.0"
|
|
|
16
16
|
iotsploit-core = "*"
|
|
17
17
|
iotsploit-django = "*"
|
|
18
18
|
scapy = ">=2.5"
|
|
19
|
-
|
|
19
|
+
paramiko = ">=3.0"
|
|
20
20
|
pyserial = ">=3.5"
|
|
21
21
|
# Bare ">=3.0" also matches legacy FaceDancer 2019.x releases under PEP 440.
|
|
22
22
|
# Keep this on the 3.x line so the exploit imports resolve to the expected API.
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/adb_check/adb_check.py
RENAMED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
|
-
# Disable pwntools terminal mode before importing to prevent fileno() errors in non-TTY environments
|
|
5
|
-
os.environ.setdefault("PWNLIB_NOTERM", "1")
|
|
6
|
-
|
|
7
|
-
import logging
|
|
8
3
|
import traceback
|
|
9
4
|
import pluggy
|
|
10
5
|
from iotsploit_django.tools.adb_mgr import ADB_Mgr
|
|
@@ -88,7 +83,6 @@ class AdbSecurityCheckPlugin(BasePlugin):
|
|
|
88
83
|
try_root = params.get('try_root', False)
|
|
89
84
|
check_suid = params.get('check_suid', True)
|
|
90
85
|
check_writable = params.get('check_writable', True)
|
|
91
|
-
skip_interactive = params.get('skip_interactive', True)
|
|
92
86
|
|
|
93
87
|
# If target is provided, try to get the device from it
|
|
94
88
|
if target:
|
|
@@ -295,7 +289,7 @@ class AdbSecurityCheckPlugin(BasePlugin):
|
|
|
295
289
|
|
|
296
290
|
# If root is required but we know we don't have it, don't even try
|
|
297
291
|
if require_root and self._has_root is False:
|
|
298
|
-
logger.debug(
|
|
292
|
+
logger.debug("Root access required for command but device is not rooted")
|
|
299
293
|
return None
|
|
300
294
|
|
|
301
295
|
# Execute the command
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import pluggy
|
|
3
3
|
from typing import Optional, Any
|
|
4
|
-
from iotsploit_django.tools.vehicle_utils import
|
|
4
|
+
from iotsploit_django.tools.vehicle_utils import get_ecu_ip, check_ecu_alive
|
|
5
5
|
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
6
6
|
from iotsploit_django.tools.net_audit_mgr import NetAudit_Mgr
|
|
7
7
|
from iotsploit_core.utils import abort, sleep, IotsErrorCode
|
|
@@ -22,13 +22,15 @@ class FloodAttackPlugin(BasePlugin):
|
|
|
22
22
|
'type': 'str',
|
|
23
23
|
'required': True,
|
|
24
24
|
'description': 'Flood attack type',
|
|
25
|
-
'default': 'icmp'
|
|
25
|
+
'default': 'icmp',
|
|
26
|
+
'validation': {'choices': ['icmp', 'udp', 'tcp', 'mac']}
|
|
26
27
|
},
|
|
27
28
|
'ecu': {
|
|
28
29
|
'type': 'str',
|
|
29
30
|
'required': True,
|
|
30
|
-
'description': 'ECU
|
|
31
|
-
'default': 'tcam'
|
|
31
|
+
'description': 'Target ECU',
|
|
32
|
+
'default': 'tcam',
|
|
33
|
+
'validation': {'choices': ['tcam', 'dhu', 'vgm']}
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
})
|
|
@@ -42,14 +44,13 @@ class FloodAttackPlugin(BasePlugin):
|
|
|
42
44
|
|
|
43
45
|
@hookimpl
|
|
44
46
|
def execute(self, target: Optional[Any] = None, parameters: Optional[dict] = None) -> ExploitResult:
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
target = {}
|
|
47
|
+
# Params come via `parameters` (CLI/GUI/HTTP); fall back to `target` for compatibility.
|
|
48
|
+
params = parameters or {}
|
|
48
49
|
if not isinstance(target, dict):
|
|
49
|
-
|
|
50
|
+
target = {}
|
|
50
51
|
|
|
51
|
-
attack_type = target.get('attack_type', self.info['Parameters']['attack_type']['default'])
|
|
52
|
-
ecu = target.get('ecu', self.info['Parameters']['ecu']['default'])
|
|
52
|
+
attack_type = params.get('attack_type', target.get('attack_type', self.info['Parameters']['attack_type']['default']))
|
|
53
|
+
ecu = params.get('ecu', target.get('ecu', self.info['Parameters']['ecu']['default']))
|
|
53
54
|
|
|
54
55
|
logger.info(f"Executing {attack_type} flood attack on {ecu}")
|
|
55
56
|
|
|
@@ -83,18 +84,17 @@ class FloodAttackPlugin(BasePlugin):
|
|
|
83
84
|
self.net_audit_mgr.stop_mac_flood_attack()
|
|
84
85
|
|
|
85
86
|
def _check_ecu_alive(self, ecu, checktype, attack_type):
|
|
86
|
-
|
|
87
|
+
# allow_live=False: never trigger WiFi resolution; the ECU IP must be configured
|
|
88
|
+
# on the current target (component properties.ip_address).
|
|
89
|
+
if not check_ecu_alive(ecu, checktype, allow_live=False):
|
|
87
90
|
self._stop_flood_attack(attack_type)
|
|
88
|
-
abort(
|
|
91
|
+
abort(
|
|
92
|
+
f"{ecu} is not reachable. Configure the {ecu} component's ip_address on the "
|
|
93
|
+
f"current target (WiFi auto-connect is disabled for this plugin).",
|
|
94
|
+
code=IotsErrorCode.HOST_UNREACHABLE, ecu=ecu, checktype=checktype)
|
|
89
95
|
|
|
90
96
|
def _get_ecu_ip(self, ecu):
|
|
91
|
-
|
|
92
|
-
return query_tcam_ip()
|
|
93
|
-
elif ecu == "dhu":
|
|
94
|
-
return query_dhu_ip()
|
|
95
|
-
elif ecu == "vgm":
|
|
96
|
-
return "169.254.19.1"
|
|
97
|
-
return None
|
|
97
|
+
return get_ecu_ip(ecu, allow_live=False)
|
|
98
98
|
|
|
99
99
|
def _start_flood_attack(self, attack_type, ecu, ecu_ip):
|
|
100
100
|
if attack_type == "icmp":
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/greatfet_echo.py
RENAMED
|
@@ -7,7 +7,6 @@ from iotsploit_core.core.exploit_spec import AsyncExploitResult
|
|
|
7
7
|
from iotsploit_core.core.base_plugin import BasePlugin
|
|
8
8
|
from facedancer.devices.ftdi import FTDIDevice
|
|
9
9
|
from iotsploit_core.utils import iots_logger
|
|
10
|
-
import asyncio
|
|
11
10
|
|
|
12
11
|
hookimpl = pluggy.HookimplMarker("exploit_mgr")
|
|
13
12
|
|
|
@@ -56,11 +55,6 @@ class FTDIEchoPlugin(BasePlugin):
|
|
|
56
55
|
if not self.device:
|
|
57
56
|
return AsyncExploitResult(False, "FTDI device not initialized", {})
|
|
58
57
|
|
|
59
|
-
# Get welcome message
|
|
60
|
-
welcome_msg = (parameters.get('message')
|
|
61
|
-
if parameters
|
|
62
|
-
else self.info['Parameters']['message']['default'])
|
|
63
|
-
|
|
64
58
|
# Define the coroutine that waits for host and sends welcome message.
|
|
65
59
|
async def send_hello():
|
|
66
60
|
self.logger.info("Waiting for the host to connect.")
|
|
@@ -100,4 +94,4 @@ class FTDIEchoPlugin(BasePlugin):
|
|
|
100
94
|
self.logger.info("FTDI Device disconnected")
|
|
101
95
|
self.device = None
|
|
102
96
|
except Exception as e:
|
|
103
|
-
self.logger.error(f"Error during cleanup: {str(e)}")
|
|
97
|
+
self.logger.error(f"Error during cleanup: {str(e)}")
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/greatfet_rubber_duck.py
RENAMED
|
@@ -4,10 +4,9 @@ import pluggy
|
|
|
4
4
|
from typing import Optional, Any
|
|
5
5
|
import asyncio
|
|
6
6
|
import os
|
|
7
|
-
import re
|
|
8
7
|
from importlib.resources import files
|
|
9
8
|
from facedancer.errors import EndEmulation
|
|
10
|
-
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
9
|
+
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
11
10
|
from iotsploit_core.core.base_plugin import BasePlugin
|
|
12
11
|
from facedancer.devices.keyboard import USBKeyboardDevice
|
|
13
12
|
from facedancer.classes.hid.keyboard import KeyboardModifiers
|
|
@@ -144,7 +143,6 @@ class RubberDuckPlugin(BasePlugin):
|
|
|
144
143
|
async def _parse_ducky_script(self, script):
|
|
145
144
|
"""Parse a DuckyScript formatted script into executable commands"""
|
|
146
145
|
commands = []
|
|
147
|
-
delay = 0.5 # Default delay in seconds
|
|
148
146
|
|
|
149
147
|
for line in script.splitlines():
|
|
150
148
|
line = line.strip()
|
|
@@ -267,7 +265,7 @@ class RubberDuckPlugin(BasePlugin):
|
|
|
267
265
|
self.logger.info("Initializing USB keyboard device...")
|
|
268
266
|
try:
|
|
269
267
|
self.device = USBKeyboardDevice()
|
|
270
|
-
self.logger.info(
|
|
268
|
+
self.logger.info("USB keyboard device initialized")
|
|
271
269
|
except Exception as e:
|
|
272
270
|
self.logger.error(f"Failed to initialize USB keyboard device: {str(e)}")
|
|
273
271
|
return ExploitResult(False, f"Failed to initialize USB keyboard device: {str(e)}", {})
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_ssh_attack.py
RENAMED
|
@@ -131,7 +131,7 @@ class HydraSSHAttackPlugin(BasePlugin):
|
|
|
131
131
|
result = self.network_service.execute_tool('hydra', args, timeout=600)
|
|
132
132
|
|
|
133
133
|
if result.success:
|
|
134
|
-
logger.info(
|
|
134
|
+
logger.info("Hydra SSH attack completed successfully")
|
|
135
135
|
return ExploitResult(True, "Hydra SSH attack executed successfully", {
|
|
136
136
|
"output": result.stdout,
|
|
137
137
|
"execution_time": result.execution_time,
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/ip_scan/ip_scan.py
RENAMED
|
@@ -4,8 +4,7 @@ from typing import Optional
|
|
|
4
4
|
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
5
5
|
from iotsploit_django.tools.net_audit_mgr import NetAudit_Mgr
|
|
6
6
|
from iotsploit_django.tools.env_mgr import Env_Mgr
|
|
7
|
-
from iotsploit_django.tools.
|
|
8
|
-
from iotsploit_django.tools.vehicle_utils import query_tcam_ip
|
|
7
|
+
from iotsploit_django.tools.vehicle_utils import get_ecu_ip
|
|
9
8
|
from iotsploit_django.tools.bash_script_engine import Bash_Script_Mgr
|
|
10
9
|
from iotsploit_core.core.base_plugin import BasePlugin
|
|
11
10
|
|
|
@@ -43,7 +42,7 @@ class IPScanPlugin(BasePlugin):
|
|
|
43
42
|
|
|
44
43
|
self.net_audit_mgr = NetAudit_Mgr.Instance()
|
|
45
44
|
self.env_mgr = Env_Mgr.Instance()
|
|
46
|
-
self.
|
|
45
|
+
self.wifi_backend = None
|
|
47
46
|
self.bash_mgr = Bash_Script_Mgr.Instance()
|
|
48
47
|
|
|
49
48
|
# Constants
|
|
@@ -52,7 +51,6 @@ class IPScanPlugin(BasePlugin):
|
|
|
52
51
|
|
|
53
52
|
# IP Lists
|
|
54
53
|
self.scan_iplist_fast = [
|
|
55
|
-
"10.0.0.0/8", #扫这个段会很慢
|
|
56
54
|
"198.18.0.0/16",
|
|
57
55
|
"198.99.0.0/16",
|
|
58
56
|
"192.168.0.0/16",
|
|
@@ -110,8 +108,9 @@ class IPScanPlugin(BasePlugin):
|
|
|
110
108
|
self.fast_ports = "21,22,23,5555,50000,8000,11111,12345,10086,53,1883,13400"
|
|
111
109
|
|
|
112
110
|
@hookimpl
|
|
113
|
-
def initialize(self, device_plugin=None):
|
|
111
|
+
def initialize(self, ctx=None, device_plugin=None):
|
|
114
112
|
logger.debug("Initializing IPScanPlugin")
|
|
113
|
+
self.wifi_backend = getattr(ctx, "wifi", None) if ctx is not None else None
|
|
115
114
|
self.scan_iplist = []
|
|
116
115
|
self.scan_portlist = ""
|
|
117
116
|
|
|
@@ -131,8 +130,11 @@ class IPScanPlugin(BasePlugin):
|
|
|
131
130
|
def tcam_ap_ip_scan(self):
|
|
132
131
|
iplist = self.env_mgr.query(self.TCAM_AP_SCAN_IP_LIST)
|
|
133
132
|
if iplist is None:
|
|
134
|
-
tcamip =
|
|
135
|
-
if
|
|
133
|
+
tcamip = get_ecu_ip("tcam")
|
|
134
|
+
if self.wifi_backend is None:
|
|
135
|
+
from iotsploit_platforms import get_shared_wifi_backend
|
|
136
|
+
self.wifi_backend = get_shared_wifi_backend()
|
|
137
|
+
if tcamip and self.wifi_backend.status()['wifi_mode'] == "STA":
|
|
136
138
|
self._add_routes(tcamip, self.scan_iplist)
|
|
137
139
|
iplist = self.net_audit_mgr.ip_detect(self.scan_iplist)
|
|
138
140
|
self._del_routes()
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"""SSH exploit plugin using Paramiko.
|
|
2
|
+
|
|
3
|
+
Replaces the former pwntools-based SSH manager and plugin. The SSH_Mgr
|
|
4
|
+
here mirrors the behavioural contract of ``iotsploit_django.tools.ssh_mgr``
|
|
5
|
+
but lives in the separately-packaged exploits component.
|
|
6
|
+
"""
|
|
4
7
|
|
|
5
|
-
import pluggy
|
|
6
8
|
import logging
|
|
7
|
-
from pwn import ssh
|
|
8
9
|
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
import paramiko
|
|
12
|
+
import pluggy
|
|
13
|
+
|
|
9
14
|
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
10
15
|
from iotsploit_core.core.base_plugin import BasePlugin
|
|
11
16
|
|
|
@@ -28,6 +33,7 @@ def _extract_ip_from_target(target: Optional[dict]) -> Optional[str]:
|
|
|
28
33
|
return ip.strip()
|
|
29
34
|
return None
|
|
30
35
|
|
|
36
|
+
|
|
31
37
|
class SSHPlugin(BasePlugin):
|
|
32
38
|
def __init__(self):
|
|
33
39
|
super().__init__({
|
|
@@ -96,51 +102,90 @@ class SSHPlugin(BasePlugin):
|
|
|
96
102
|
pass
|
|
97
103
|
return ExploitResult(False, f"SSH execution failed: {str(e)}", {})
|
|
98
104
|
|
|
105
|
+
|
|
99
106
|
class SSH_Mgr:
|
|
100
|
-
|
|
107
|
+
"""SSH connection manager backed by Paramiko.
|
|
108
|
+
|
|
109
|
+
Security note: ``AutoAddPolicy`` matches the old
|
|
110
|
+
``StrictHostKeyChecking=no`` behaviour and does not authenticate the
|
|
111
|
+
server. A known-hosts policy should be configured separately when a
|
|
112
|
+
credential design is available.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
__ssh_connect_timeout_S = 10
|
|
116
|
+
__ssh_cmd_timeout_S = 30
|
|
101
117
|
|
|
102
118
|
@staticmethod
|
|
103
119
|
def Instance():
|
|
104
120
|
return _instance
|
|
105
|
-
|
|
121
|
+
|
|
106
122
|
def __init__(self):
|
|
107
123
|
self.__ssh_dict = {}
|
|
108
124
|
|
|
109
125
|
def open_ssh(self, ip: str, user: str, passwd: str):
|
|
126
|
+
"""Open an SSH connection.
|
|
127
|
+
|
|
128
|
+
Returns ``paramiko.SSHClient`` on success, ``None`` on failure.
|
|
129
|
+
Closes the client if connection fails.
|
|
130
|
+
"""
|
|
131
|
+
client = paramiko.SSHClient()
|
|
132
|
+
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
110
133
|
try:
|
|
111
|
-
|
|
134
|
+
client.connect(
|
|
135
|
+
hostname=ip,
|
|
136
|
+
username=user,
|
|
137
|
+
password=passwd,
|
|
138
|
+
timeout=self.__ssh_connect_timeout_S,
|
|
139
|
+
banner_timeout=self.__ssh_connect_timeout_S,
|
|
140
|
+
auth_timeout=self.__ssh_connect_timeout_S,
|
|
141
|
+
)
|
|
112
142
|
logger.info("SSH connect %s success.", ip)
|
|
113
|
-
return
|
|
143
|
+
return client
|
|
114
144
|
except Exception:
|
|
115
145
|
logger.exception("SSH connect %s fail!", ip)
|
|
146
|
+
try:
|
|
147
|
+
client.close()
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
116
150
|
return None
|
|
117
151
|
|
|
118
152
|
def close_ssh(self, ssh_context: Any):
|
|
153
|
+
"""Close an SSH connection. Safe for ``None`` and idempotent."""
|
|
119
154
|
if ssh_context is None:
|
|
120
|
-
logger.error("SSH context invalid!")
|
|
121
155
|
return
|
|
122
156
|
try:
|
|
123
157
|
ssh_context.close()
|
|
124
|
-
logger.info("SSH close success.")
|
|
125
158
|
except Exception:
|
|
126
|
-
|
|
159
|
+
pass
|
|
127
160
|
return
|
|
128
161
|
|
|
129
162
|
def ssh_cmd(self, ssh_context: Any, ssh_cmd: str):
|
|
163
|
+
"""Execute a command over SSH.
|
|
164
|
+
|
|
165
|
+
Returns decoded stdout on success (exit status 0), ``None`` on failure.
|
|
166
|
+
"""
|
|
130
167
|
if ssh_context is None:
|
|
131
168
|
logger.error("SSH context invalid!")
|
|
132
169
|
return None
|
|
133
170
|
try:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
171
|
+
stdin, stdout, stderr = ssh_context.exec_command(ssh_cmd, timeout=self.__ssh_cmd_timeout_S)
|
|
172
|
+
exit_status = stdout.channel.recv_exit_status()
|
|
173
|
+
out = stdout.read().decode("utf-8", errors="replace")
|
|
174
|
+
err = stderr.read().decode("utf-8", errors="replace")
|
|
175
|
+
|
|
176
|
+
if exit_status != 0:
|
|
177
|
+
logger.error("SSH command failed (exit=%s). CMD: %s\nstderr: %s", exit_status, ssh_cmd, err)
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
logger.info("SSH run CMD success. CMD: %s\nResult:\n%s", ssh_cmd, out)
|
|
181
|
+
return out
|
|
139
182
|
except Exception:
|
|
140
183
|
logger.exception("SSH run CMD fail! CMD: %s", ssh_cmd)
|
|
141
184
|
return None
|
|
142
185
|
|
|
186
|
+
|
|
143
187
|
_instance = SSH_Mgr()
|
|
144
188
|
|
|
189
|
+
|
|
145
190
|
def register_plugin(pm):
|
|
146
|
-
pm.register(SSHPlugin())
|
|
191
|
+
pm.register(SSHPlugin())
|
|
@@ -8,7 +8,7 @@ import serial.tools.list_ports
|
|
|
8
8
|
import re
|
|
9
9
|
import time
|
|
10
10
|
from typing import Optional, Any, List, Dict
|
|
11
|
-
from threading import Thread
|
|
11
|
+
from threading import Thread
|
|
12
12
|
from queue import Queue, Empty
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
from iotsploit_core.core.exploit_spec import AsyncExploitResult
|
|
@@ -19,7 +19,6 @@ logger = iots_logger.get_logger("picocom_serial_reader")
|
|
|
19
19
|
hookimpl = pluggy.HookimplMarker("exploit_mgr")
|
|
20
20
|
|
|
21
21
|
# Add file logging for debugging
|
|
22
|
-
import logging
|
|
23
22
|
import os
|
|
24
23
|
file_logger = logging.getLogger('picocom_serial_reader_file')
|
|
25
24
|
file_logger.setLevel(logging.DEBUG)
|
|
@@ -278,7 +277,7 @@ class PicocomSerialReaderPlugin(BasePlugin):
|
|
|
278
277
|
sufficient_data = len(self._analysis.raw_output) >= min_data_threshold
|
|
279
278
|
|
|
280
279
|
if interactions_complete and sufficient_data:
|
|
281
|
-
log_both('info',
|
|
280
|
+
log_both('info', "🎯 SIMPLE EARLY EXIT: All done!")
|
|
282
281
|
log_both('info', f"🎯 - All interactions sent: {interaction_step}/{len(self._interaction_sequences)} ✅")
|
|
283
282
|
log_both('info', f"🎯 - Sufficient data captured: {len(self._analysis.raw_output)} lines ✅")
|
|
284
283
|
# Stop reader thread early to speed up cleanup
|
|
@@ -451,7 +450,7 @@ class PicocomSerialReaderPlugin(BasePlugin):
|
|
|
451
450
|
"""Connect to serial port"""
|
|
452
451
|
try:
|
|
453
452
|
log_both('info', f"🔌 Attempting to connect to serial port {port} at {baudrate} baud...")
|
|
454
|
-
log_both('info',
|
|
453
|
+
log_both('info', "🔌 Connection parameters: 8N1, timeout=1s, no flow control")
|
|
455
454
|
|
|
456
455
|
self._serial_conn = serial.Serial(
|
|
457
456
|
port=port,
|
|
@@ -576,10 +575,10 @@ class PicocomSerialReaderPlugin(BasePlugin):
|
|
|
576
575
|
log_both('info', f"📤 Sending {len(encoded_data)} bytes: {repr(data)}")
|
|
577
576
|
self._serial_conn.write(encoded_data)
|
|
578
577
|
self._serial_conn.flush()
|
|
579
|
-
log_both('info',
|
|
578
|
+
log_both('info', "📤 Data sent and flushed successfully")
|
|
580
579
|
return True
|
|
581
580
|
else:
|
|
582
|
-
log_both('error',
|
|
581
|
+
log_both('error', "📤 Cannot send data - serial connection not available")
|
|
583
582
|
return False
|
|
584
583
|
except Exception as e:
|
|
585
584
|
log_both('error', f"📤 Error sending data: {e}")
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/simple_rubber_duck.py
RENAMED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import pluggy
|
|
4
4
|
import asyncio
|
|
5
|
-
import os
|
|
6
|
-
import sys
|
|
7
5
|
from typing import Optional, Any
|
|
8
6
|
|
|
9
|
-
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
7
|
+
from iotsploit_core.core.exploit_spec import ExploitResult
|
|
10
8
|
from iotsploit_core.core.base_plugin import BasePlugin
|
|
11
9
|
from facedancer.devices.keyboard import USBKeyboardDevice
|
|
12
10
|
from facedancer.errors import EndEmulation
|
|
@@ -98,7 +96,7 @@ class SimpleRubberDuckPlugin(BasePlugin):
|
|
|
98
96
|
self.logger.info("Initializing USB keyboard device...")
|
|
99
97
|
try:
|
|
100
98
|
self.device = USBKeyboardDevice()
|
|
101
|
-
self.logger.info(
|
|
99
|
+
self.logger.info("USB keyboard device initialized")
|
|
102
100
|
except Exception as e:
|
|
103
101
|
self.logger.error(f"Failed to initialize USB keyboard device: {str(e)}")
|
|
104
102
|
return ExploitResult(False, f"Failed to initialize USB keyboard device: {str(e)}", {})
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/wifi_scan/wifi_scan.py
RENAMED
|
@@ -9,7 +9,7 @@ and provides a simple way to discover available WiFi networks.
|
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
11
|
import pluggy
|
|
12
|
-
from typing import Optional, Any
|
|
12
|
+
from typing import Optional, Any
|
|
13
13
|
|
|
14
14
|
from iotsploit_core.core.exploit_spec import ExploitResult, AsyncExploitResult
|
|
15
15
|
from iotsploit_core.core.base_plugin import BasePlugin
|
|
File without changes
|
|
File without changes
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/adb_check/__init__.py
RENAMED
|
File without changes
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/ip_scan/__init__.py
RENAMED
|
File without changes
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/nmap_scan/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/serial/__init__.py
RENAMED
|
File without changes
|
{iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/wifi_scan/__init__.py
RENAMED
|
File without changes
|