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.
Files changed (29) hide show
  1. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/PKG-INFO +2 -2
  2. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/pyproject.toml +2 -2
  3. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/adb_check/adb_check.py +1 -7
  4. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/async_sleep_attack.py +0 -1
  5. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/flood_attack/flood_attack.py +19 -19
  6. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/greatfet_echo.py +1 -7
  7. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/greatfet_rubber_duck.py +2 -4
  8. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_ssh_attack.py +1 -1
  9. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/ip_scan/ip_scan.py +9 -7
  10. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/nmap_scan/nmap_scan.py +1 -1
  11. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/plugin_ssh.py +63 -18
  12. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/serial/picocom_serial_reader.py +5 -6
  13. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/simple_rubber_duck.py +2 -4
  14. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/wifi_scan/wifi_scan.py +1 -1
  15. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/README.md +0 -0
  16. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/__init__.py +0 -0
  17. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/adb_check/__init__.py +0 -0
  18. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/__init__.py +0 -0
  19. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/demo/stream_data_attack.py +0 -0
  20. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/flood_attack/__init__.py +0 -0
  21. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/flood_attack/syn_flood_attack.py +0 -0
  22. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_cracker/weak_pass.txt +0 -0
  23. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/hydra_cracker/weak_pass_simple.txt +0 -0
  24. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/ip_scan/__init__.py +0 -0
  25. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/nmap_scan/__init__.py +0 -0
  26. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/rubber_duck_scripts/linux_infogather.txt +0 -0
  27. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/rubber_duck_scripts/windows_payload.txt +0 -0
  28. {iotsploit_exploits-0.0.7 → iotsploit_exploits-0.0.8}/src/iotsploit_exploits/serial/__init__.py +0 -0
  29. {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.7
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: pwntools (>=4.12)
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.7"
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
- pwntools = ">=4.12"
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.
@@ -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(f"Root access required for command but device is not rooted")
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,6 +1,5 @@
1
1
  #!/usr/bin/python3
2
2
 
3
- import logging
4
3
  import pluggy
5
4
  from typing import Optional, Any
6
5
  import asyncio
@@ -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 query_tcam_ip, query_dhu_ip, check_ecu_alive
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 name, e.g., tcam/dhu/vgm',
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
- # Accept both target and parameters for compatibility
46
- if target is None:
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
- return ExploitResult(False, "Invalid target. Expected a dictionary with 'attack_type' and 'ecu'.", {})
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
- if not check_ecu_alive(ecu, checktype):
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(f"{ecu} is not alive", code=IotsErrorCode.HOST_UNREACHABLE, ecu=ecu, checktype=checktype)
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
- if ecu == "tcam":
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":
@@ -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)}")
@@ -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, AsyncExploitResult
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(f"USB keyboard device initialized")
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)}", {})
@@ -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(f"Hydra SSH attack completed successfully")
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,
@@ -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.wifi_mgr import WiFi_Mgr
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.wifi_mgr = WiFi_Mgr.Instance()
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 = query_tcam_ip()
135
- if tcamip and self.wifi_mgr.status()['WIFI_MODE'] == "STA":
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,6 +1,6 @@
1
1
  import logging
2
2
  import pluggy
3
- from typing import Any, Dict, List, Optional, Tuple
3
+ from typing import Any, Dict, List, Optional
4
4
 
5
5
  from iotsploit_core.core.base_plugin import BasePlugin
6
6
  from iotsploit_core.core.exploit_spec import ExploitResult
@@ -1,11 +1,16 @@
1
- import os
2
- # Disable pwntools terminal mode before importing to prevent fileno() errors in non-TTY environments
3
- os.environ.setdefault("PWNLIB_NOTERM", "1")
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
- __ssh_connect_timeout_S = 1
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
- ssh_context = ssh(host=ip, user=user, password=passwd, timeout=self.__ssh_connect_timeout_S)
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 ssh_context
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
- logger.exception("SSH close fail!")
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
- # Run the command via remote process and collect output
135
- proc = ssh_context.process(["sh", "-lc", ssh_cmd])
136
- cmd_result = proc.recvall().decode('utf-8', errors='ignore')
137
- logger.info("SSH run CMD success. CMD: %s\nResult:\n%s", ssh_cmd, cmd_result)
138
- return cmd_result
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, Event
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', f"🎯 SIMPLE EARLY EXIT: All done!")
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', f"🔌 Connection parameters: 8N1, timeout=1s, no flow control")
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', f"📤 Data sent and flushed successfully")
578
+ log_both('info', "📤 Data sent and flushed successfully")
580
579
  return True
581
580
  else:
582
- log_both('error', f"📤 Cannot send data - serial connection not available")
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}")
@@ -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, AsyncExploitResult
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(f"USB keyboard device initialized")
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)}", {})
@@ -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, List, Dict
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