Add '--aid' param to 'hf seos' commands

This commit is contained in:
kormax
2026-03-20 20:16:44 +02:00
parent 6ff7df910d
commit 58dcfb1dbc
2 changed files with 119 additions and 79 deletions
+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]
- Added `--aid` parameter to `hf seos` commands (@kormax)
- Added `hf iclass blacktears` command to perform an automated tearoff of block 1 to set non-secure page mode(@antiklesys)
- Changed wiegand encoding to use shared helpers and have unified parameters (--raw, --bin, --new, --wiegand, etc.) (@cindersocket)
- Added `hf gst read` command (@kormax)
+118 -79
View File
@@ -44,6 +44,7 @@ static uint8_t zeros[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
#define MAX_DIVERSIFIER_LEN 16
#define MAX_OID_LEN 32
#define MAX_SEOS_AID_LEN 16
static int CmdHelp(const char *Cmd);
@@ -99,6 +100,19 @@ static const known_algo_t known_algorithm_map[] = {
{9, "AES-128_CBC_MODE"},
};
static const char *known_seos_aids[] = {
"A0000004400001010001",
"A000000382002D000101",
};
static int seos_get_custom_aid(CLIParserContext *ctx, int arg_index, uint8_t *aid, int *aid_len) {
int res = CLIParamHexToBuf(arg_get_str(ctx, arg_index), aid, MAX_SEOS_AID_LEN, aid_len);
if (res != PM3_SUCCESS) {
return PM3_ESOFT;
}
return res;
}
static int create_cmac(uint8_t *key, uint8_t *input, uint8_t *out, int input_len, int output_len, int encryption_algorithm) {
uint8_t iv[16] = {0x00};
uint8_t mac[16] = {0x00};
@@ -1088,73 +1102,61 @@ static int seos_mutual_auth(uint8_t *adfOID, size_t adfoid_len, uint8_t *randomI
return PM3_SUCCESS;
};
static int seos_aid_select(void) {
// Working 100%, pulls from live card
bool activate_field = true;
bool keep_field_on = true;
static int seos_try_aid_select(const uint8_t *aid, int aid_len, bool activate_field, bool keep_field_on) {
uint8_t response[PM3_CMD_DATA_SIZE];
int resplen = 0;
// --------------- Select AID for SEOS Card ----------------
typedef struct {
const char *name;
const char *value;
} seos_aid_t;
uint8_t aSELECT_AID[5 + MAX_SEOS_AID_LEN + 1] = {0};
aSELECT_AID[0] = 0x00;
aSELECT_AID[1] = 0xA4;
aSELECT_AID[2] = 0x04;
aSELECT_AID[3] = 0x00;
aSELECT_AID[4] = aid_len;
memcpy(aSELECT_AID + 5, aid, aid_len);
aSELECT_AID[5 + aid_len] = 0x00;
static const seos_aid_t known_AID_map[] = {
{"STANDARD_SEOS", "A00000044000010100010"},
{"MOBILE_SEOS_ADMIN_CARD", "A000000382002D0001010"},
};
int i;
int res = PM3_ESOFT;
//PrintAndLogEx(INFO, "--- " _CYAN_("AID Selection") " ---------------------------");
for (i = 0; i < ARRAYLEN(known_AID_map); i++) {
const char *selectedAID = known_AID_map[i].value;
// Select command prefixed with a 00
const char *prefix = "00A404";
uint16_t aidlen = strlen(selectedAID) >> 1;
char aidlenHex[5];
snprintf(aidlenHex, sizeof(aidlenHex), "%04X", aidlen);
const char *suffix = "0";
char combinedString[100];
snprintf(combinedString, sizeof(combinedString), "%s%s%s%s", prefix, aidlenHex, selectedAID, suffix);
//PrintAndLogEx(SUCCESS, "AID Selected: " _YELLOW_("%s"), known_AID_map[i].name);
//PrintAndLogEx(SUCCESS, "AID Select Command: " _YELLOW_("%s"), combinedString);
// --------------- Select AID for SEOS Card ----------------
uint8_t aSELECT_AID[80];
int aSELECT_AID_n = 0;
param_gethex_to_eol(combinedString, 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
continue;
}
if (resplen < 2) {
DropField();
continue;
}
uint16_t sw = get_sw(response, resplen);
if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting SEOS applet aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
continue;
}
// if we made it here, its a success and we break :)
break;
int res = ExchangeAPDU14a(aSELECT_AID, 6 + aid_len, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res != PM3_SUCCESS) {
DropField();
return res;
}
if (i == ARRAYLEN(known_AID_map)) {
if (resplen < 2) {
PrintAndLogEx(ERR, "Selecting SEOS applet aid %s failed (short response).", sprint_hex_inrow(aid, aid_len));
DropField();
return PM3_EWRONGANSWER;
}
uint16_t sw = get_sw(response, resplen);
if (sw != ISO7816_OK) {
PrintAndLogEx(ERR, "Selecting SEOS applet aid %s failed (%04x - %s).", sprint_hex_inrow(aid, aid_len), sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
return PM3_SUCCESS;
}
static int seos_aid_select(const uint8_t *custom_aid, int custom_aid_len) {
// Working 100%, pulls from live card
bool activate_field = true;
bool keep_field_on = true;
if (custom_aid_len > 0) {
return seos_try_aid_select(custom_aid, custom_aid_len, activate_field, keep_field_on);
}
int res = PM3_ESOFT;
for (size_t i = 0; i < ARRAYLEN(known_seos_aids); i++) {
uint8_t aid[MAX_SEOS_AID_LEN] = {0};
int aid_len = 0;
param_gethex_to_eol(known_seos_aids[i], 0, aid, sizeof(aid), &aid_len);
res = seos_try_aid_select(aid, aid_len, activate_field, keep_field_on);
if (res == PM3_SUCCESS) {
return res;
}
}
return res;
};
@@ -1418,8 +1420,8 @@ static int seos_gdf_select(int key_index) {
return PM3_SUCCESS;
};
static int seos_select(void) {
int res = seos_aid_select();
static int seos_select(const uint8_t *aid, int aid_len) {
int res = seos_aid_select(aid, aid_len);
if (res != PM3_SUCCESS) {
DropField();
return res;
@@ -1432,8 +1434,8 @@ static int seos_select(void) {
return res;
}
static int seos_pacs(char *oid, int oid_len, uint8_t *data_tag, int data_tag_len, int key_index) {
int res = seos_aid_select();
static int seos_pacs(char *oid, int oid_len, uint8_t *data_tag, int data_tag_len, int key_index, const uint8_t *aid, int aid_len) {
int res = seos_aid_select(aid, aid_len);
if (res != PM3_SUCCESS) {
DropField();
return res;
@@ -1444,8 +1446,8 @@ static int seos_pacs(char *oid, int oid_len, uint8_t *data_tag, int data_tag_len
return res;
}
static int seos_write(char *oid, int oid_len, uint8_t *data_tag, int data_tag_len, int key_index, uint8_t *write, int write_len) {
int res = seos_aid_select();
static int seos_write(char *oid, int oid_len, uint8_t *data_tag, int data_tag_len, int key_index, uint8_t *write, int write_len, const uint8_t *aid, int aid_len) {
int res = seos_aid_select(aid, aid_len);
if (res != PM3_SUCCESS) {
DropField();
return res;
@@ -1456,8 +1458,8 @@ static int seos_write(char *oid, int oid_len, uint8_t *data_tag, int data_tag_le
return res;
}
static int seos_global_df(int key_index) {
int res = seos_aid_select();
static int seos_global_df(int key_index, const uint8_t *aid, int aid_len) {
int res = seos_aid_select(aid, aid_len);
if (res == PM3_SUCCESS) {
res = seos_gdf_select(key_index);
}
@@ -1526,7 +1528,7 @@ static int seos_load_keys(char *filename) {
}
int infoSeos(bool verbose) {
return seos_select();
return seos_select(NULL, 0);
}
static int CmdHfSeosInfo(const char *Cmd) {
@@ -1536,15 +1538,24 @@ static int CmdHfSeosInfo(const char *Cmd) {
"- If the card is a SEOS card\n"
"- Are static RND.ICC keys used (can detect SEOS default keyset)\n"
"- What encryption and hashing algorithm is use\n",
"hf seos info"
"hf seos info\n"
"hf seos info --aid A0000004400001010001"
);
void *argtable[] = {
arg_param_begin,
arg_str0(NULL, "aid", "<hex>", "Use a custom SEOS AID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
uint8_t aid[MAX_SEOS_AID_LEN] = {0};
int aid_len = 0;
int res = seos_get_custom_aid(ctx, 1, aid, &aid_len);
CLIParserFree(ctx);
return infoSeos(true);
if (res != PM3_SUCCESS) {
return res;
}
return seos_select(aid, aid_len);
}
static int CmdHfSeosGDF(const char *Cmd) {
@@ -1553,20 +1564,28 @@ static int CmdHfSeosGDF(const char *Cmd) {
"Get Global Data File (GDF) from SEOS card\n\n"
"By default:\n"
" - Key Index: 3\n",
"hf seos gdf"
"hf seos gdf --ki 3"
"hf seos gdf\n"
"hf seos gdf --ki 3\n"
"hf seos gdf --aid A0000004400001010001"
);
void *argtable[] = {
arg_param_begin,
arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
arg_str0(NULL, "aid", "<hex>", "Use a custom SEOS AID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int key_index = arg_get_int_def(ctx, 1, 3);
uint8_t aid[MAX_SEOS_AID_LEN] = {0};
int aid_len = 0;
int res = seos_get_custom_aid(ctx, 2, aid, &aid_len);
CLIParserFree(ctx);
return seos_global_df(key_index);
if (res != PM3_SUCCESS) {
return res;
}
return seos_global_df(key_index, aid, aid_len);
}
static int CmdHfSeosPACS(const char *Cmd) {
@@ -1585,6 +1604,7 @@ static int CmdHfSeosPACS(const char *Cmd) {
arg_param_begin,
arg_str0("o", "oid", "<hex>", "<0-100> hex bytes for OID (Default: 2B0601040181E438010102011801010202)"),
arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
arg_str0(NULL, "aid", "<hex>", "Use a custom SEOS AID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -1597,8 +1617,14 @@ static int CmdHfSeosPACS(const char *Cmd) {
CLIGetHexWithReturn(ctx, 1, oid_hex, &oid_len);
int key_index = arg_get_int_def(ctx, 2, 0);
uint8_t aid[MAX_SEOS_AID_LEN] = {0};
int aid_len = 0;
int res = seos_get_custom_aid(ctx, 3, aid, &aid_len);
CLIParserFree(ctx);
if (res != PM3_SUCCESS) {
return res;
}
// Fall back to default OID
if (oid_len == 0) {
@@ -1617,7 +1643,7 @@ static int CmdHfSeosPACS(const char *Cmd) {
return PM3_ESOFT;
}
return seos_pacs((char *)oid, oid_len, data_tag, data_tag_len, key_index);
return seos_pacs((char *)oid, oid_len, data_tag, data_tag_len, key_index, aid, aid_len);
}
static int CmdHfSeosWrite(const char *Cmd) {
@@ -1636,6 +1662,7 @@ static int CmdHfSeosWrite(const char *Cmd) {
arg_param_begin,
arg_str0("o", "oid", "<hex>", "<0-100> hex bytes for OID (Default: 2B0601040181E438010102011801010202)"),
arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
arg_str0(NULL, "aid", "<hex>", "Use a custom SEOS AID"),
arg_str0("d", "data", "<hex>", "<0-128> hex bytes for data (Must be valid BER-TLV)"),
arg_param_end
};
@@ -1649,12 +1676,18 @@ static int CmdHfSeosWrite(const char *Cmd) {
CLIGetHexWithReturn(ctx, 1, oid_hex, &oid_len);
int key_index = arg_get_int_def(ctx, 2, 2);
uint8_t aid[MAX_SEOS_AID_LEN] = {0};
int aid_len = 0;
int res = seos_get_custom_aid(ctx, 3, aid, &aid_len);
int data_len = 0;
uint8_t data[256] = {};
CLIGetHexWithReturn(ctx, 3, data, &data_len);
CLIGetHexWithReturn(ctx, 4, data, &data_len);
CLIParserFree(ctx);
if (res != PM3_SUCCESS) {
return res;
}
// Fall back to default OID
if (oid_len == 0) {
@@ -1678,7 +1711,7 @@ static int CmdHfSeosWrite(const char *Cmd) {
return PM3_ESOFT;
}
return seos_write((char *)oid, oid_len, data_tag, data_tag_len, key_index, data, data_len);
return seos_write((char *)oid, oid_len, data_tag, data_tag_len, key_index, data, data_len, aid, aid_len);
}
static int CmdHfSeosADF(const char *Cmd) {
@@ -1702,6 +1735,7 @@ static int CmdHfSeosADF(const char *Cmd) {
arg_str0("t", "tag", "<hex>", "<0-100> hex bytes for tag to read (Default: FF00)"),
arg_str0("o", "oid", "<hex>", "<0-100> hex bytes for OID (Default: 2B0601040181E438010102011801010202)"),
arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
arg_str0(NULL, "aid", "<hex>", "Use a custom SEOS AID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -1715,8 +1749,14 @@ static int CmdHfSeosADF(const char *Cmd) {
CLIGetHexWithReturn(ctx, 2, oid_hex, &oid_len);
int key_index = arg_get_int_def(ctx, 3, 0);
uint8_t aid[MAX_SEOS_AID_LEN] = {0};
int aid_len = 0;
int res = seos_get_custom_aid(ctx, 4, aid, &aid_len);
CLIParserFree(ctx);
if (res != PM3_SUCCESS) {
return res;
}
if (data_tag_len == 0) {
data_tag_len = 2;
@@ -1738,7 +1778,7 @@ static int CmdHfSeosADF(const char *Cmd) {
return PM3_ESOFT;
}
return seos_pacs((char *)oid, oid_len, data_tag, data_tag_len, key_index);
return seos_pacs((char *)oid, oid_len, data_tag, data_tag_len, key_index, aid, aid_len);
}
static int CmdHfSeosSim(const char *Cmd) {
@@ -2167,4 +2207,3 @@ int CmdHFSeos(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}