lf t55xx detect: do not send a password the PWD bit has not confirmed

`lf t55xx detect -p <pwd>` reached for the password whenever detection
failed without one, and sent it across every downlink mode and again
after a wake. On a tag that is not password protected those frames can
be taken for a write: the PWD bit gets set and the tag's data is
destroyed, leaving it locked behind whatever block 7 already held.

`lf t55xx read` and `lf t55xx dump` already guard against this. They
verify the PWD bit in the configuration block before using a password,
and expose -o/--override to bypass the check deliberately. detect had
neither, and T55xxReadBlockEx() treats a live `detect -p` as proof the
bit is set.

detect cannot run the same check -- reading the configuration is what it
is for, and the password is only reached for once that has failed -- so
the risk has to be the user's to accept. Gate it behind -o/--override to
match read and dump, and carry read's warning banner into the help.

No change in behaviour for anyone not passing -p.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Matthew CarrollandClaude Opus 5 committed 2026-10-01 16:13:49 -07:00
1 parent 256f30f0fa
commit 8917c48cde
3 files changed
+30 -13

No files matched your search

+1
View File
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Fixed `lf t55xx detect -p` - the password is no longer sent to a tag whose PWD bit could not be confirmed, which could set it and destroy the tag's data; pass `-o` to override (@mfcarroll)
- Added `A1856618` (an EM4305 anti-clone card password) to the `t55xx_default_pwds` dictionary used by `lf em 4x05 chk` (@nemanjan00)
- Added `hw bwm ble` - the BWM's BLE settings: `on`/`off` (persisted radio switch), `pairing` (require a 6-digit passkey, LE Secure Connections; the module ships open), `forget` bonded devices, `txpower`, `status` (@Msprg)
- Changed `hw bwm autooff` - `--idle <sec>` adds an opt-in power-off after that long idle on battery (no command, button press or BLE/WiFi client), off by default; `--unplug off` makes an unplug only restart that idle clock instead of powering off at once; all stored on the BWM, `hw status` shows it (@Msprg)
+25 -10
View File
@@ -1090,19 +1090,24 @@ static int CmdT55xxWakeUp(const char *Cmd) {
static int CmdT55xxDetect(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf t55xx detect",
"Try detecting the tag modulation from reading the configuration block",
"Try detecting the tag modulation from reading the configuration block.\n\n"
_RED_(" * * * WARNING * * *") "\n"
_CYAN_("Use of detect with password on a tag not configured") "\n"
_CYAN_("for a password can damage the tag") "\n"
_RED_(" * * * * * * * * * *"),
"lf t55xx detect\n"
"lf t55xx detect -1\n"
"lf t55xx detect -p 11223344\n"
"lf t55xx detect -p 11223344 -o\n"
);
// 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL)
void *argtable[3 + 6] = {
// 1 (help) + 3 (three user specified params) + (6 T55XX_DLMODE_ALL)
void *argtable[4 + 6] = {
arg_param_begin,
arg_lit0("1", NULL, "extract using data from graphbuffer"),
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
arg_lit0("o", "override", "override safety check"),
};
uint8_t idx = 3;
uint8_t idx = 4;
arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, config.downlink_mode);
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -1122,11 +1127,13 @@ static int CmdT55xxDetect(const char *Cmd) {
password = tmp_pwd;
}
bool r0 = arg_get_lit(ctx, 3);
bool r1 = arg_get_lit(ctx, 4);
bool r2 = arg_get_lit(ctx, 5);
bool r3 = arg_get_lit(ctx, 6);
bool ra = arg_get_lit(ctx, 7);
bool override = arg_get_lit(ctx, 3);
bool r0 = arg_get_lit(ctx, 4);
bool r1 = arg_get_lit(ctx, 5);
bool r2 = arg_get_lit(ctx, 6);
bool r3 = arg_get_lit(ctx, 7);
bool ra = arg_get_lit(ctx, 8);
CLIParserFree(ctx);
if ((r0 + r1 + r2 + r3 + ra) > 1) {
@@ -1134,6 +1141,14 @@ static int CmdT55xxDetect(const char *Cmd) {
return PM3_EINVARG;
}
// A password frame on an unprotected tag can land as a write, and detect cannot
// check the PWD bit first the way read does -- finding the config is its job.
if (usepwd && (override == false)) {
PrintAndLogEx(WARNING, "Safety check: Could not confirm PWD bit is set. Detecting without password...");
PrintAndLogEx(HINT, "Hint: Consider using the override parameter to force detect with password.");
usepwd = false;
}
bool try_all_dl_modes = false;
uint8_t downlink_mode = config.downlink_mode;
if (r0)
+4 -3
View File
@@ -14594,24 +14594,25 @@
},
"lf t55xx detect": {
"command": "lf t55xx detect",
"description": "Try detecting the tag modulation from reading the configuration block",
"description": "Try detecting the tag modulation from reading the configuration block. * * * WARNING * * * Use of detect with password on a tag not configured for a password can damage the tag * * * * * * * * * *",
"notes": [
"lf t55xx detect",
"lf t55xx detect -1",
"lf t55xx detect -p 11223344"
"lf t55xx detect -p 11223344 -o"
],
"offline": true,
"options": [
"-h, --help This help",
"-1 extract using data from graphbuffer",
"-p, --pwd <hex> password (4 hex bytes)",
"-o, --override override safety check",
"--r0 downlink - fixed bit length (detected def)",
"--r1 downlink - long leading reference",
"--r2 downlink - leading zero",
"--r3 downlink - 1 of 4 coding reference",
"--all try all downlink modes"
],
"usage": "lf t55xx detect [-h1] [-p <hex>] [--r0] [--r1] [--r2] [--r3] [--all]"
"usage": "lf t55xx detect [-h1o] [-p <hex>] [--r0] [--r1] [--r2] [--r3] [--all]"
},
"lf t55xx deviceconfig": {
"command": "lf t55xx deviceconfig",