zipmi is a pure-Python IPMI/BMC stack — an ipmitool-style CLI plus a library where every byte is an inspectable and mangleable object. Built for people/AI (are AIs people yet?) who need to understand, test, or research BMCs, not just run commands.
-
Every IPMI field is real, not an opaque blob. Dissect, build, corrupt, fuzz, and replay any packet with full byte-level visibility — the thing
ipmitoolandpyghmidon't give you. Drop into the middle of a session and ask "what does this byte mean?" or "what if I flip field X?" -
Deep OEM coverage: 1725 vendor commands most tools/people don't know exist. Dell iDRAC6/9/10, Supermicro X11/X14, AMI MegaRAC, and 9 OpenBMC vendor flavors — reverse-engineered from firmware and Ghidra, callable by name, not just raw opcodes.
-
Security research batteries included. Full IPMI 2.0 cipher suites 0–14 + 17, cipher-0 and RAKP-hash checks, unauthenticated
bmc-idfingerprinting, plus a built-in virtual BMC and fuzzers to test against with no hardware. -
Readable wire traces. Color-coded
-doutput showing the full request/response back-and-forth with every packet field labeled — "ipmi-hex friendly," about as friendly as hex gets. -
friendly (hahhahahh... ipmi hex bytes friendly....) color coded output (with -d) showing the full request/response back-and-forth with every packet field labeled.
ONLY seriously tested on: my client system macOS 26.5 with Python 3.11-3.14. Ran on a few linux systems w no problems, but YMMV.
Big thanks to Claude Code, which worked with me over the last half-year on this project — in all aspects of the package.
📊 IPMI command coverage — 132/188 of the standard IPMI command set implemented (all can use the "raw" keyword to send/receive hex bytes as per other IPMI tools) · 44 with Scapy packet classes. 1725 OEM commands that aren't generally documented gleaned from ghidra, firmware, and legwork.
An ipmitool-like thing that is also a pure-Python IPMI stack built as Scapy layers. Lets you dissect, build, fuzz, and replay IPMI traffic with full byte-level visibility — every field of every packet is a real Scapy field, not an opaque blob.
It's somewhat compatible with the basics of ipmitool (most definitely not all),
so things like this should work -
# print out the details of the default channel
zipmi -H 10.0.0.1 -U root -P calvin lan print
# prints out the basics of the various oem vendors
zipmi oem
# supply the vendor to see more on what they have to (potentially) offer
zipmi oem idrac10
Type "zipmi" or "zipmi --help" for other things it can do.
Note — zipmi defaults to the IPMI 2.0 protocol. The -I flag may be used to
specify "lan" to use IPMI 1.5 or "lanplus" for explicitly using 2.0.
zipmi.scapy_ipmi— ScapyPacketclasses for RMCP, ASF (DSP0136), IPMI 1.5 session/message, IPMI 2.0 RMCP+, RAKP 1–4, and per-NetFn command payloads. Driving zipmi programmatically (build/send/dissect/fuzz packets): see docs/scapy-usage.md. The✓column in docs/command-table.md is the authoritative list of which commands have packet classes (vs⚡= CLI verb only).zipmi.scapy_ipmi.oem.{dell, supermicro, idrac9_generated, dell_generated}— vendor OEM dispatch tables ingested from prior firmware RE: 192 Dell iDRAC6 entries (full dispatch) + 277 named iDRAC9 handlers (349 known dispatch slots) + Supermicro X11 OEM cmd/sub-cmd map + shell-injection attack primitives.zipmi.attacks.dell— named, callable Dell attack primitives (PROCHOT throttle, power cap, sensor threshold tamper, racadm extended config) with destructive=True gating.zipmi.core— high-levelSession/TransportAPI.zipmi.cli—zipmicommand-line tool covering the common ipmitool verbs plus extras (scan,dump,replay,diff,oem,vbmc,fuzz).zipmi.vbmc— minimal virtual BMC server that answers IPMI commands.zipmi.fuzz— simple fuzzers built on top of the layer hierarchy and the vbmc.zipmi.parsers.{md_table, idrac9_md}— codegen scripts that ingest the BMC research markdown into Python data + markdown docs.
freeipmi/ipmitool/ipmiutil/etc. are great oracles and much more
expansive in their scope but are a bit opaque/unweildy/difficult to change
for my research. pyghmi is a a wonderful library but its packet format
lives in hand-rolled bytes. Neither makes it easy to drop into the middle
of a session and ask "what does this byte mean?" or "what happens if I
corrupt field X?". Leveraging scapy helps give various interesting
capabilities once all the work is done.
(From my virtual museum :))
- Dell PowerEdge T710 / iDRAC6 — IPMI 1.5, NetFn 0x30 OEM (Dell IANA 674)
- Supermicro X11SSZ-QF — IPMI 2.0 RMCP+, NetFn 0x30 OEM (SM IANA 10876)
- OpenBMC (Phosphor) romulus / AST2500 — IPMI 2.0 RMCP+ cipher-17 only (HMAC-SHA256 / AES-CBC-128). The open BMC stack behind Meta/Google/Intel/ IBM/Ampere/Nvidia fleets. Nine vendor OEM tables (see OEMs section).
Recommended — clone, then:
git clone https://github.com/zenfish/zipmi.git && cd zipmi
make install # make dev for editable + dev extrasONLY seriously tested on: my client system macOS 26.5 with Python 3.11-3.14. Ran on a few linux systems w no problems, but YMMV.
You get both the zipmi / bmc-id commands and a working
import zipmi in your own scripts (python myscript.py, no venv to
activate). The two commands install into the scripts directory of
whichever Python you use — a venv's bin/, Homebrew's bin/ (e.g.
/opt/homebrew/bin), or ~/.local/bin for the per-user fallback. That
directory is already on $PATH for a venv or Homebrew's python3; for
a --user install you may need to add ~/.local/bin to $PATH
yourself. make install prints exactly where each command landed and
warns if it isn't on $PATH. It runs a normal pip install .; if your
Python is "externally-managed" (Homebrew, Debian — PEP 668) and refuses
the global write, it automatically falls back to a per-user install
instead of erroring. Override the interpreter with
make install PY=python3.12.
make # (default) build wheel into dist/, NO install
git pull && make install # update after pulling
make uninstall # drains every layer (global/--user/pipx)
make clean # nuke build cruft AND .venv (keeps .git)Bare make only builds (sdist + wheel into dist/) — it installs
nothing. Use make install to actually install.
make uninstall reuses the same interpreter, so you never have to
guess which Python the install used.
make clean blows away everything regeneratable — build/,
dist/, *.egg-info, __pycache__, *.pyc, tool caches, and
.venv/venv. Only .git survives. Rebuild a dev env with
make dev afterward. (No venv? Skip make dev entirely — make install is venv-free.)
No
make? The fallback is just the two lines it wraps:python3 -m pip install .(add--user --break-system-packagesif the global write is refused) andpython3 -m pip uninstall zipmi.
Alternative: pipx (CLI only — import zipmi will NOT work)
pipx install /path/to/zipmi # zipmi + bmc-id on PATH, isolatedpipx sandboxes the package in its own venv, so the zipmi/bmc-id
commands work but your own scripts cannot import zipmi from a
system interpreter. Fine if you only use the CLI; use make install
if you write Python against the library.
For contributing — runs tests, regenerates docs, exercises hooks:
python3.11 -m venv .venv && . .venv/bin/activate
pip install -e '.[dev]'
./scripts/install-hooks.sh # wire pre-commit doc/code symmetry guardHeads-up: if you previously ran
pip install -e .against a system Python (e.g. Homebrew's/opt/homebrew/bin/python3), it may have left orphan.pth+dist-infofiles in that interpreter'ssite-packages/plus a stalezipmiscript in itsbin/. Clean with:pip uninstall zipmi # using the same python that installed it # then verify nothing remains: find /opt/homebrew/lib/python3.11/site-packages -name 'zipmi*' -o -name '__editable__.zipmi*'
# for examples below... or use -H/-U/-P/-C flags. Env fallbacks:
# ZIPMI_TARGET (-H), ZIPMI_USER (-U), ZIPMI_PASS (-P), ZIPMI_CIPHER (-C).
# An explicit flag always overrides its env var.
export ZIPMI_TARGET=192.168.0.23 ZIPMI_USER=root ZIPMI_PASS=calvin
# Spec-parity verbs
zipmi mc info
zipmi -I lanplus -C 3 mc info # IPMI 2.0 RMCP+
zipmi chassis status
zipmi sel list
zipmi sensor list
zipmi user list # access for present channel (0xE)
zipmi user list 1 # access as seen on channel 1 (like ipmitool 'user list [channel]')
zipmi raw 0x06 0x01
# Security probes
zipmi scan asf-ping
zipmi scan auth-caps
zipmi scan ciphers # advertised RMCP+ ciphers (0x54)
zipmi scan ciphers --verify # + which the BMC actually NEGOTIATES (unauth Open Session probe)
zipmi scan cipher-zero
zipmi scan rakp -U root # grab crackable RAKP2 HMAC, no auth (CVE-2013-4786)
# negotiates MD5>SHA1>SHA256 (fastest crack); prints hashcat line
zipmi scan rakp # no -U: sweep 6 famous default accounts (also user-enum)
zipmi scan rakp --extended-user-list # sweep bundled 44 default BMC accounts (credit: oobscan)
zipmi user-matrix list # full user × channel privilege grid (audit)
zipmi user-matrix list --json | jq '.channels' # machine-readable
zipmi scan all --json # one {steps:[...]} envelope, findings on
zipmi fuzz sweep --netfn 0x30 -v # Dell OEM cmd surface, named
# Channels + bridging
zipmi channel info all # walk channels 0x00..0x0B (medium/protocol)
zipmi bridging info --json | jq '.edges' # Send Message reach map
zipmi --max-priv operator bridging privesc all # does bridging escalate priv?
# --json is global — any command, straight into jq
zipmi lan print --json | jq -r '.parameters[] | select(.label=="MAC Address").value'
# Sessionless mode — omit -U/-P (and unset ZIPMI_USER/ZIPMI_PASS) and
# every send goes out auth_type=0, session_id=0. The BMC decides what
# to answer. zipmi makes no assumption. (ZIPMI_TARGET is still set, so no -H.)
unset ZIPMI_USER ZIPMI_PASS
zipmi raw 0x06 0x38 0x01 0x04 # Get Chan Auth Caps
zipmi sessionless # list pre-session cmds
# In-process target for tests / fuzzing / CI
zipmi vbmc serve --vpersona dell_idrac6 --vport 6231 &
zipmi -H 127.0.0.1 -p 6231 mc infoFull list of things zipmi understands
Global flags (position-independent, work with any verb):
-H/-U/-P host/user/pass, -K raw RAKP key, -C cipher, -A auth, -I lan|lanplus,
-t timeout, -v/-d wire trace, --palette, --json (emit any command's
result as JSON to stdout — text stays the default), --max-priv
{callback,user,operator,admin} (cap the session's requested privilege).
mc {info, reset cold|warm, selftest, guid, watchdog {get,reset,off},
global-enables, acpi, sysinfo}
chassis {status, caps, poh, power on|off|cycle|reset|soft --yes,
identify [secs], bootdev <dev> --yes, bootflags, restart_cause, policy}
sel {info, list, elist, clear --yes, time {get,set}, alloc, utc-offset}
sdr {list, alloc, time, device-info, device-reserve, device-get}
sensor {list, get <name>, threshold <n>, hysteresis <n>, factors <n>,
type <n>, event-enable <n>, event-status <n>} # threshold cooked via SDR
pef {caps, config, last-event}
lan {print [channel], stats [channel]}
fru print [id]
session info [selector]
user {list [channel], set-name, enable, disable, set-password,
test-password, priv} # writes gated by --yes
user-matrix list [--all] [--per-priv] [--findings]
# full user × channel privilege/auth/cipher grid (read-only)
channel {info [chan|all], getaccess <chan> <uid>,
payload-support [chan], payload-version [chan]}
bridging {info [chan|all], privesc [chan|all]}
# info = Send Message reach map (medium, bridgeable, IPMB
# satellite sweep); privesc = does bridging escalate a
# --max-priv operator session? (confused-deputy probe)
serial {config [chan], set <chan> <param> ...} # SOL/modem config
sol {info, baud, payload, payload-instance, set, activate, deactivate,
looptest, autobaud}
firewall [--channel N] [--probe] [--unsafe] [--subfn] # IPMI firmware firewall (§21)
raw <netfn> <cmd> [byte ...]
ipmi [cmd-name [byte ...]] # standard IPMI cmd by name; no args = list Table G-1
oem [vendor [cmd-name [byte ...]]] # OEM cmd dispatcher; no args = list vendors
idrac6/idrac9/supermicro [cmd-name [byte ...]] # shortcuts for `oem <vendor> ...`
groups [body [cmd-name [byte ...]]] # IPMI Group Extension dispatcher (NetFn 0x2C)
dcmi [cmd-name [byte ...]] # shortcut for `groups dcmi ...`
i2c/i2cscan/i2c-id # Master Write-Read bus ops; spd <addr> # decode a DIMM SPD
fingerprint (fp) # identify BMC stack + vendor flavor
scan {asf-ping, auth-caps, cipher-suites, cipher-zero, rakp, unauth, all}
sessionless # list spec-permitted pre-session cmds
fuzz {sweep --netfn 0xNN, rakp, length, cipher, list}
vbmc serve [--vpersona dell_idrac6|generic] [--vport N]
# see VIRTUAL-BMC.md
Nearly every verb honors --json (arrays of records, integer codes + names).
The exceptions are the interactive/streaming ones — sol activate (hands you a
live console) and the streaming fuzzers — where a single JSON blob would defeat
the live output.
bmc-id is a standalone, unauthenticated BMC identification +
vulnerability probe shipped alongside zipmi (installed as its own
bmc-id console script). It chains a handful of sessionless IPMI
probes — plus an optional HTTPS/Redfish grab — to fingerprint a BMC's
real vendor, generation, firmware revision, and security posture in
roughly four UDP packets. Cheap enough to fan out at scan velocity;
reads targets from argv or stdin and can emit a full report, JSON, or
one TSV line per host.
See BMC-ID.md for the full writeup — every probe, the IPMI "tuple" fingerprint, the fleet knowledge-base, confidence scoring, output modes, and worked examples.
The IPMI specification allows vendors to extend the protocol with a set of reserved codes. All the vendors - Dell, HP, Supermicro, etc. - use these, but rarely document them. What follows are some guesses, information gathering, and following the bytes for a couple of them (from my own Dell and Supermicro servers.)
OEM by name — instead of zipmi raw 0x00 0x01, use the vendor's
own catalogue:
zipmi oem # list vendors
zipmi idrac6 # list iDRAC6's 192 cmds (RE'd from fullfw)
zipmi -H <bmc> dell GetChassisStatus # run by name (substring match)
zipmi -H <bmc> oem supermicro UtilRestoreConfig # `oem <vendor>` form
zipmi -H <bmc> oem idrac9 maser get # structured OEM sub-verb (get/set)
zipmi -H <bmc> oem supermicro fwdump flash.bin # dump X10-X13 firmware over IPMI
# Firmware/bus access: IPMI reaches I2C/SMBus (Master Write-Read: i2c/i2cscan/
# spd) but NOT SPI/eSPI. SPI flash is only reachable via vendor OEM dump cmds
# (the BMC dd's its own flash) — see docs/firmware-and-bus-access.md.
# Multi-word command names MUST be quoted (the shell would otherwise pass
# each word as a separate arg, and the trailing words become data bytes):
export ZIPMI_CIPHER=17 # OpenBMC = cipher 17 only; set once (implies -I lanplus)
zipmi -H <bmc> oem intel "Get BMC Version String"
zipmi -H <bmc> oem intel "Get FW Version Info"
# OpenBMC vendors also answer to ob-<v> / openbmc-<v> to make the namespace
# explicit (the bare short name still works):
zipmi -H <bmc> openbmc-ampere "Get Fan Control Status"
zipmi -H <bmc> ob-google "Sys OEM Command"Data bytes. Everything after the command name is the request payload,
sent verbatim — hex (0x01), decimal (1), space-separated. Whether bytes
are required depends on the command: many reads take none
(Get BMC Version String), some need a one-byte sub-command or selector,
and writes need structured args. zipmi does NOT synthesize them for you —
it's a raw-data model (same as zipmi raw). To know what a given OEM
command expects, read its handler / the per-command notes; the OpenBMC
OEM IPMI survey (upstream source review) documents the byte
layouts that were recovered from source. A wrong-length payload comes back
as a completion code (e.g. 0xC7 Request Data Length Invalid), not a crash.
zipmi defaults to IPMI 2.0 RMCP+ (
-I lanplus), cipher auto-discovered. The right default: nearly every BMC from the last ~15 years speaks 2.0, OpenBMC is 2.0-only, and 2.0 encrypts the session. Pass-I lanonly for a legacy 1.5-only BMC. (Older zipmi defaulted to 1.5-I lan; changed 2026-08.)OpenBMC speaks only IPMI 2.0 (RMCP+). It does NOT answer IPMI 1.5 at all — a 1.5 request (
-I lan) is silently dropped and you get a timeout, not an error. With the 2.0 default you no longer need-C 17; the cipher is auto-discovered (OpenBMC offers only suite 17 = HMAC-SHA256 / AES-CBC-128). Once you have a valid session, an unimplemented command returns a real completion code (0xC1Invalid Command) — the timeout-vs-0xC1 distinction tells you "wrong protocol/session" vs "command not supported".
The standard IPMI 2.0 set has the same by-name UX — zipmi ipmi
lists Table G-1, zipmi -H <bmc> ipmi "Get Channel Authentication Capabilities" 0x01 0x04 resolves the name and sends the bytes you
supply (same raw-data model as raw/oem).
Names are case-insensitive and tolerate hyphens/underscores; the
Cmd/OEM/Dell prefixes are stripped before matching. Multiple
matches print the candidate list and exit non-zero; no host is needed
for the listing forms.
The catalogue header reports two numbers:
idrac6 IANA 674 192 cmds
idrac9 IANA 674 46 named / 271 known
supermicro IANA 10876 65 cmds
N named / M known means M (NetFn, cmd) dispatch slots have been
recovered (from binary RE / vendor docs) but only N cross-reference to
a human-readable handler name — the rest are runtime-bound stubs that
appear in the listing as (unnamed: ...) with their originating
dispatch-table name in the description so you can still send raw
bytes via zipmi raw.
Source-of-truth (hahah... well, for some value of truth) per vendor:
-
idrac6: handler symbols recovered from
T710-bmc/bin/fullfwwith radare2 auto-analysis (ARM debug-string residue carried function names through the strip). 195 of 213 dispatch slots are now named. Seezipmi/scapy_ipmi/oem/dell_binary_names.py. The MD-derived fallback atdell_generated.pyis kept for privilege/description metadata. Resolution order inDELL_CMD_NAMES: hand-curatedDELL_NAME_OVERRIDES→ binary-RE'dDELL_BINARY_NAMES→ MD-derivedDELL_NAMES. -
idrac9: 277 named (46 from upstream RE doc + 99 from dynsym addr resolution + 132 from R_ARM_GLOB_DAT runtime-dispatch extraction). The catalogue surfaces 349 known dispatch slots: 271 static (from binary RE of the lib dispatch tables) plus 78 runtime-only (handler-pointer relocations in lib data sections that aren't in any static dispatch but get registered at boot). Resolution layers:
- Static dispatch + addr resolution: the 271 static entries
with
handler_addr≠ 0 — the address points into a lib's.textand the dynsymDF .textexports name it. 145 hits. - R_ARM_GLOB_DAT runtime dispatch: every
*.so.9.9.9lib has dispatch slots in.datawhose handler-pointer slot is a relocation. Pair the descriptor (4B before each reloc) with the symbol from the reloc to recover (NetFn, cmd) → handler. 132 hits (54 of which fill in static-dispatch slots that hadhandler_addr=0x00000000; the remaining 78 are runtime-only additions not present in any static table). - Remaining 72 slots have neither a static address nor a relocation; the init agent must register them at boot via paths not visible to static analysis. They keep their dispatch-table tag (DCMI / OEMIPMI / OSAOEM) so they remain fuzzing targets.
Reference dumps (iDRAC9 firmware reverse-engineering notes):
idrac9_addr_map.json(3235 dynsym entries),idrac9_resolution_report.md(per-entry addr-resolution breakdown),idrac9_runtime_dispatch.json(211 R_ARM_GLOB_DAT pairs across libs),idrac9_runtime_dispatch_report.md. Regenerate viabuild_idrac9_addr_map.pyandextract_runtime_dispatch.py. - Static dispatch + addr resolution: the 271 static entries
with
-
supermicro: 422 cmds total. Two layers:
- smcipmi RE work (4 top + 61 sub-cmds) — original handler
names with HIGH RISK / CRITICAL annotations on the path-traversal
and shell-injection sites (
UtilRestoreConfig,OEMFlashFWCmd, etc.) plus the ATEN AlUpdate firmware-exfil sequence at NetFn 0x3e cmds 0x1d/0x1e/0x1f. - SMCIPMITool 2.30.0 decompile overlay
(
supermicro_smcipmi_names.py) — 153 OEM (NetFn, cmd) + 226 sub-cmds harvested by walking everysetCommandAndData((byte)NetFn<<2, (byte)Cmd, ...)call site in the decompiledcom/supermicro/ipmi/*.classJava sources. Adds full coverage of NetFn 0x32 flash ops (read / write / erase / activate flash mode), NetFn 0x2e Intel Node Manager (40+ cmds), NetFn 0x30 0x32 InfiniBand control, and a long tail of manufacturing/diagnostic cmds. Sub-cmds dispatched via 1st data byte; zipmi prepends it on<verb-name>resolution.
- smcipmi RE work (4 top + 61 sub-cmds) — original handler
names with HIGH RISK / CRITICAL annotations on the path-traversal
and shell-injection sites (
-
OpenBMC (open source — no firmware RE needed): nine vendor flavors catalogued straight from the upstream provider repos. Unlike a single proprietary BMC, OpenBMC spans many vendor IANAs and reuses the raw vendor NetFns 0x30..0x3E, so the same
(NetFn, cmd)means different things per vendor — load exactly the vendor you target.vendor IANA NetFns provider repo intel343 0x30/0x32/0x3E + fw 0x08 intel-ipmi-oem facebook(meta)4337¹ 0x30/0x36/0x38 + BIC fb-ipmi-oem google11129 0x2E + IANA, sub-cmds google-ipmi-sys ampere40981 0x3C (ARM) ampere-ipmi-oem openpower(ibm)2 0x32/0x3A openpower-host-ipmi-oem inspur37945¹ 0x3C inspur-ipmi-oem foxconn— 0x34 foxconn-ipmi-oem wistron— 0x30 wistron-ipmi-oem nvidia— group 0x3C / NetFn 0x2C phosphor-host-ipmid oem/nvidia ¹ informational; NOT on the wire (raw vendor NetFns carry no IANA — only Google uses the real NetFn 0x2E + IANA group form).
zipmi.load_vendor("openbmc")loads all nine at once (for pcap dissection); the manifest lives atzipmi/scapy_ipmi/oem/openbmc.pyand adding a vendor is oneoem/<v>.pymodule + one manifest row. Full source catalogue + per-cmd security notes: OpenBMC OEM IPMI survey (upstream source review).Note on OpenBMC RMCP+: OpenBMC commonly offers only cipher suite 17 (HMAC-SHA256 / SHA256-128 / AES-CBC-128) — use
-C 17. Its Get Device ID advertises manufacturer-id 0 ("Unknown"), so IPMI alone won't tell you the vendor; fingerprint over Redfish (GET /redfish/v1/Managers/bmc→ a manager namedbmcwithOem.OpenBmc). See the OpenBMC OEM IPMI survey (upstream source review) for the live romulus walkthrough and the internet-survey prevalence study.
OEM NetFns (0x2E, 0x30..0x3E) are a private namespace per vendor.
The same (NetFn 0x30, cmd 0xC0) means PROCHOT throttle on Dell, an
unrelated cmd on Supermicro, and something else again on HP. Without
knowing whose namespace you're in, OEM cmds are ambiguous garbage.
The disambiguator is the IANA Private Enterprise Number — a unique integer the IANA registry hands out to organisations (https://www.iana.org/assignments/enterprise-numbers/). Dell = 674, Supermicro = 10876, HPE = 11, Intel = 343, IBM = 2.
Standardised cmds that ride NetFn 0x2C/0x2D with a group code as the first data byte (0xDC=DCMI, 0x00=PICMG, 0x03=VITA, 0x04=HPM). Different namespace from OEM — same UX:
zipmi groups # list group bodies
zipmi dcmi # list DCMI's 15 cmds
zipmi -H <bmc> dcmi GetPowerReading 0x01 0x00 0x00
zipmi -H <bmc> groups dcmi GetCapabilitieszipmi prepends the group-code byte automatically; supply only the
cmd-specific bytes after. The wire-trace label shows the body-aware
name (e.g. DCMI Get Power Reading instead of generic NetFn 0x2c cmd 0x02).
Currently implemented: DCMI 1.5 (15 cmds, source: Intel/DMTF spec
Table 6-1). PICMG / HPM / VITA wired as future entries in
zipmi/scapy_ipmi/groups/.
A target advertises its IANA in three places on the wire, all parseable without authentication:
Get Device IDresponse (App 0x06 cmd 0x01) — bytes 6-8 are the 3-byte little-endian Manufacturer ID. First thing to check on any BMC. (zipmi mc infoprints it.)- ASF Pong (RMCP class 0x06) —
OEM IANAfield in the reply. Sessionless, runs on a closed network. (zipmi scan asf-pingprints it.) - IPMI 2.0 OEM payload type / OEM Group cmds — IANA carried in the payload itself.
Workflow: probe the target → read IANA → pick the matching
zipmi <vendor> to get cmd names. The IANA column in zipmi oem is
documentation — it tells you which probed value should pick that
vendor's table. (Note iDRAC9 reuses Dell's 674; load_vendor("idrac9")
overlays iDRAC9-specific names onto the iDRAC6 base.)
Common flags: -H -p -U -P -A {none,password,md5} -I {lan,lanplus} -C N -t T,
or set ZIPMI_TARGET / ZIPMI_USER / ZIPMI_PASS env vars.
Credentials are not assumed. Pass -U and -P (or set both env
vars) to authenticate. Pass neither and zipmi sends every request
sessionless — auth_type=0, session_id=0, no handshake. The BMC
decides whether to answer. Mixed (one flag without the other) is an
error. zipmi sessionless lists the commands the IPMI 2.0 spec
permits outside a session.
Wire trace — every verb that talks to a BMC accepts:
-v/--verbose— timestamped human-readable event log:→ send NNN B Get Device ID 192.168.0.23:623,← recv …,!! timeout after 3.0s. Session-setup events are tagged[setup].-d/--debug— everything-vshows PLUS a hex dump of every packet (work + setup).
Each event line carries the IPMI Table G-1 command name (or the
RAKP/OpenSession payload type, or the ASF message type). OEM commands
(NetFn 0x2E and 0x30..0x3E) are prefixed [OEM]. The ← recv line
omits the name — it is always the immediate reply to the → send
above.
The hex column is colour-coded by ColorBrewer palette: RMCP header, session header, AuthCode, IPMB framing, NetFn, cmd / payload-type, data, and the completion-code byte of every response each get their own colour. Colour is on by default when stdout is a TTY.
Three palettes ship; pick one with --palette:
auto(default) — detects terminal background, picks pastel for dark, set for light. Detection usesCOLORFGBGif set, otherwise an OSC 11 query (100 ms timeout); falls back to pastel if neither responds.pastel— ColorBrewer Pastel1, soft pastels, dark terminalsset— ColorBrewer Set1, saturated, light terminalsdark— ColorBrewer Dark2, muted dark, dark terminals
Single-letter forms accepted: -p a / -p p / -p s / -p d.
Disable colour entirely with -n / --no-color or NO_COLOR=1
(https://no-color.org). Force it on off a TTY (e.g. capturing the
trace into a pipe) with FORCE_COLOR=1 or CLICOLOR_FORCE=1.
Palette + role mapping live in a single COLOR CONFIG block at the
top of zipmi/scapy_ipmi/colorize.py. Add a new palette by appending
to the PALETTES dict; remap which field gets which colour by editing
the per-palette role dict.
In fuzz verbs the same flags additionally enable streaming output (rows print as each probe lands).
zipmi/scapy_ipmi/ — Scapy layers (rmcp, asf, ipmi15, ipmi20, rakp, oem/, ...)
zipmi/core.py — Session / Transport
zipmi/cli/ — argparse CLI
zipmi/vbmc/ — virtual BMC server
zipmi/fuzz/ — fuzzers (Phase 6)
examples/ — runnable demos
tests/ — unit + integration + golden pcap diffs
docs/ — architecture, ipmi notes, fuzzing, vbmc
Did you know that cipher suites 4, 5, 9, 10, 18, and 19 (as per IPMI spec 2.0) aren't supported by ipmitool or freeipmi?
It's because of the weird xRC4-40/128 confidentiality algorithms... no one supports it.
I think I do here. But it's hard to even find a BMC that supports it either.
I guess you just enable that - and only that - cipher and you're invulnerable! Well. Maybe not. But no one can run rakp-authenticated commands against your system.
MIT. No third-party code is included or vendored. zipmi's wire code is its own, built from the IPMI/DCMI/ASF specifications and cross-checked against reference tools. See docs/Bibliography.md for the specs, tools, libraries, and research it leaned on (IPMI 2.0/1.5, DCMI, ipmitool, FreeIPMI, Scapy, pyghmi, OpenBMC, and more), each with a URL.
Please use zipmi responsibly and ensure you have permission prior to scanning any systems that aren't owned by you.