mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
147 lines
5.6 KiB
Python
147 lines
5.6 KiB
Python
import usb.core
|
|
import usb.util
|
|
import struct
|
|
import time
|
|
|
|
# Chipsbank / ITE CBM2199
|
|
# VID: 0x048d, PID: 0x1234
|
|
VID = 0x048d
|
|
PID = 0x1234
|
|
|
|
class ChipsbankBOT:
|
|
def __init__(self, vid, pid):
|
|
self.dev = usb.core.find(idVendor=vid, idProduct=pid)
|
|
if self.dev is None:
|
|
raise ValueError("Device not found")
|
|
|
|
# Detach kernel driver if necessary (Linux)
|
|
if self.dev.is_kernel_driver_active(0):
|
|
try:
|
|
self.dev.detach_kernel_driver(0)
|
|
print("[*] Detached kernel driver")
|
|
except usb.core.USBError as e:
|
|
print(f"[!] Could not detach driver: {e}")
|
|
|
|
# Set configuration
|
|
try:
|
|
self.dev.set_configuration()
|
|
except usb.core.USBError as e:
|
|
print(f"[!] Could not set configuration: {e}")
|
|
|
|
cfg = self.dev.get_active_configuration()
|
|
intf = cfg[(0,0)]
|
|
|
|
# Find Bulk endpoints
|
|
self.ep_out = usb.util.find_descriptor(intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
|
|
self.ep_in = usb.util.find_descriptor(intf, custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
|
|
|
|
if not self.ep_out or not self.ep_in:
|
|
raise ValueError("Endpoints not found")
|
|
|
|
self.tag = 0xDEADBEEF
|
|
|
|
def send_cbw(self, cmd, data_len, direction_in=True):
|
|
"""Constructs and sends a 31-byte Command Block Wrapper."""
|
|
self.tag += 1
|
|
flags = 0x80 if direction_in else 0x00
|
|
# Signature 'USBC', Tag, DataLen, Flags, LUN, CmdLen, CmdBlock(16 bytes)
|
|
cbw = struct.pack("<4sIIBB B 16s", b"USBC", self.tag, data_len, flags, 0, len(cmd), cmd.ljust(16, b'\x00'))
|
|
self.ep_out.write(cbw)
|
|
return self.tag
|
|
|
|
def receive_csw(self, expected_tag):
|
|
"""Reads the 13-byte Command Status Wrapper."""
|
|
try:
|
|
data = self.ep_in.read(13, timeout=2000)
|
|
if len(data) < 13:
|
|
print(f"[!] CSW truncated: {len(data)} bytes")
|
|
return -1
|
|
# Signature 'USBS', Tag, Residue, Status
|
|
sig, tag, residue, status = struct.unpack("<4sIIB", data)
|
|
if sig != b"USBS":
|
|
print(f"[!] CSW Invalid Signature: {sig}")
|
|
if tag != expected_tag:
|
|
print(f"[!] CSW Tag Mismatch: {tag} (Expected {expected_tag})")
|
|
return status
|
|
except usb.core.USBError as e:
|
|
print(f"[!] CSW Read Error: {e}")
|
|
return -1
|
|
|
|
def execute_command(self, cmd, data_len, direction_in=True):
|
|
"""Full BOT transaction: CBW -> Data -> CSW."""
|
|
try:
|
|
tag = self.send_cbw(cmd, data_len, direction_in)
|
|
|
|
payload = None
|
|
if data_len > 0:
|
|
if direction_in:
|
|
payload = self.ep_in.read(data_len, timeout=2000)
|
|
else:
|
|
# For OUT commands, you would send data here
|
|
pass
|
|
|
|
status = self.receive_csw(tag)
|
|
return status, payload
|
|
except usb.core.USBError as e:
|
|
print(f"[!] Command Execution Error: {e}")
|
|
# Try to clear stall
|
|
try:
|
|
self.dev.clear_halt(self.ep_in.bEndpointAddress)
|
|
self.dev.clear_halt(self.ep_out.bEndpointAddress)
|
|
except: pass
|
|
return -1, None
|
|
|
|
def scsi_inquiry(self):
|
|
"""Standard SCSI Inquiry (0x12)."""
|
|
print("[*] Sending SCSI Inquiry...")
|
|
cmd = struct.pack("B B B B B B", 0x12, 0, 0, 0, 36, 0)
|
|
status, data = self.execute_command(cmd, 36)
|
|
if status == 0 and data:
|
|
data_bytes = data.tobytes() if hasattr(data, 'tobytes') else bytes(data)
|
|
vendor = data_bytes[8:16].decode('ascii', 'ignore').strip()
|
|
product = data_bytes[16:32].decode('ascii', 'ignore').strip()
|
|
rev = data_bytes[32:36].decode('ascii', 'ignore').strip()
|
|
print(f" [+] Success! Vendor: {vendor}, Product: {product}, Rev: {rev}")
|
|
return data
|
|
|
|
def probe_vendor_command(self, opcode, sub, desc):
|
|
print(f"[*] Probing Vendor Command: {desc} ({hex(opcode)} {hex(sub)})...")
|
|
# Chipsbank style: [Opcode, Sub, ...]
|
|
cmd = struct.pack("B B 14x", opcode, sub)
|
|
status, data = self.execute_command(cmd, 36) # Try 36 bytes for info
|
|
if status == 0 and data:
|
|
data_bytes = data.tobytes() if hasattr(data, 'tobytes') else bytes(data)
|
|
print(f" [+] Success! Data: {data_bytes.hex().upper()}")
|
|
# Try to decode as ASCII
|
|
try:
|
|
print(f" [+] ASCII: {data_bytes.decode('ascii', 'ignore')}")
|
|
except: pass
|
|
else:
|
|
print(f" [-] Command rejected or failed (Status: {status})")
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
bot = ChipsbankBOT(VID, PID)
|
|
bot.scsi_inquiry()
|
|
|
|
# Test common vendor entrance points
|
|
# Chipsbank: 0xEF, 0xF0, 0xF1, 0x06
|
|
# ITE: 0x8A, 0xBE, 0xFE
|
|
probes = [
|
|
(0xEF, 0xF1, "Chipsbank Get Info"),
|
|
(0xEF, 0x06, "Chipsbank Read FID"),
|
|
(0xF0, 0x01, "Chipsbank Alt Get Info"),
|
|
(0x8A, 0x01, "ITE Get Info"),
|
|
(0xBE, 0x01, "ITE Read FID"),
|
|
(0xFE, 0x00, "Generic Vendor Inquiry")
|
|
]
|
|
|
|
for op, sub, desc in probes:
|
|
bot.probe_vendor_command(op, sub, desc)
|
|
time.sleep(0.5)
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
finally:
|
|
print("[*] Re-attaching kernel driver...")
|
|
# Re-attach logic would go here if needed, but dev.reset() is easier
|