Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
Davi Mikael 2023-05-24 09:33:20 -03:00 committed by GitHub
commit 440c5ac1fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 333 additions and 72 deletions

View file

@ -3,6 +3,11 @@ 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]
- Changed `hf mf sim` - reduce 6ms threshold to 4ms for reset to idle #1974 (@net147)
- Rebuilt the Spartan-2 `fpga_*.bit` files to include the `hi_iso14443a.v` update (@d18c7db)
- Added minor orphaned change from `hi_iso14443a.v` in `fpga-xc3s100e` to `hi_iso14443a.v` in `fpga-xc2s30` (@d18c7db)
- Added python3 script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3 (@OscarAkaElvis)
- Changed `hf mf restore` - Auth both key A and key B with default password (@wh201906)
- Changed `nfc decode -f` - now can detect and convert MFC dumpfiles to NDEF byte arrays (@iceman1001)
- Changed `nfc decode` - now handles EXTERNAL RECORDS better (@iceman1001)
- Fixed `nfc decode` - now handles NDEF Signature version1 records better (@iceman1001)
@ -61,6 +66,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Update documentation for installation on macOS with MacPorts (@linuxgemini)
- Added possible Paxton id to hitag2 tag info output
- Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147)
- Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)

View file

@ -655,6 +655,7 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
*txlen = 0;
if (bPwd && (bAuthenticating == false) && write) {
SpinDelay(2);
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
return false;
}

View file

@ -2097,8 +2097,8 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
if (timer == 0) {
timer = GetTickCount();
} else {
// 6ms no field --> card to idle state
if (GetTickCountDelta(timer) > 6) {
// 4ms no field --> card to idle state
if (GetTickCountDelta(timer) > 4) {
return 2;
}
}

View file

@ -2150,3 +2150,7 @@ D201DBB6AB6E
# Data from Discord, French pool
9B7C25052FC3
494446555455
#
# Data from Discord, seems to be related to ASSA
427553754D47

View file

@ -55,6 +55,9 @@ amiibo_tools.db =
["0x00000003039bff02"] = {
name = "Mario - Power Up Band"
},
["0x000000030430ff02"] = {
name = "Golden - Power Up Band"
},
["0x0000010000190002"] = {
name = "Dr. Mario"
},
@ -214,6 +217,9 @@ amiibo_tools.db =
["0x0100000003990902"] = {
name = "Link - Link's Awakening"
},
["0x0100000004180902"] = {
name = "Link - Tears of the Kingdom"
},
["0x0100010000160002"] = {
name = "Toon Link"
},
@ -1834,6 +1840,9 @@ amiibo_tools.db =
["0x0800010003820002"] = {
name = "Inkling"
},
["0x0800010004150402"] = {
name = "Inkling - Yellow"
},
["0x08000200003f0402"] = {
name = "Inkling Boy"
},
@ -1870,9 +1879,15 @@ amiibo_tools.db =
["0x08050200038f0402"] = {
name = "Octoling Boy"
},
["0x08050200041b0402"] = {
name = "Octoling - Blue"
},
["0x0805030003900402"] = {
name = "Octoling Octopus"
},
["0x08060100041c0402"] = {
name = "Smallfry"
},
["0x09c0010102690e02"] = {
name = "Mario - Soccer"
},
@ -2374,6 +2389,9 @@ amiibo_tools.db =
["0x3380000003781402"] = {
name = "Solaire of Astora"
},
["0x33c0000004200002"] = {
name = "Kazuya"
},
["0x3480000000310002"] = {
name = "Mega Man"
},
@ -2455,6 +2473,9 @@ amiibo_tools.db =
["0x3600010003620002"] = {
name = "Cloud - Player 2"
},
["0x3601000004210002"] = {
name = "Sephiroth"
},
["0x3640000003a20002"] = {
name = "Hero"
},
@ -2520,6 +2541,12 @@ amiibo_tools.db =
},
["0x3c80000003a40002"] = {
name = "Terry"
},
["0x3dc0000004220002"] = {
name = "Steve"
},
["0x3dc1000004230002"] = {
name = "Alex"
}
},
game_series = {
@ -2621,6 +2648,7 @@ amiibo_tools.db =
["0x324"] = "Bayonetta",
["0x334"] = "Pac-man",
["0x338"] = "Dark Souls",
["0x33c"] = "Tekken",
["0x348"] = "Megaman",
["0x34c"] = "Street fighter",
["0x350"] = "Monster Hunter",
@ -2635,7 +2663,8 @@ amiibo_tools.db =
["0x38c"] = "Diablo",
["0x3a0"] = "Persona",
["0x3b4"] = "Banjo Kazooie",
["0x3c8"] = "Fatal Fury"
["0x3c8"] = "Fatal Fury",
["0x3dc"] = "Minecraft"
},
types = {
["0x00"] = "Figure",

112
client/pyscripts/pm3_nfc2eml.py Executable file
View file

@ -0,0 +1,112 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3
Date: 18/05/2023
Script Author: OscarAkaElvis
Tested on: Linux and Windows
OscarAkaElvis - https://twitter.com/OscarAkaElvis
"""
import re
import argparse
import os
from os import path
from sys import argv
# Vars
script_name = path.basename(argv[0])
script_version = "1.0"
# Function to print script's version
def print_version():
print()
return 'v{}'.format(script_version)
# Check if the input file is a text file based on its content
def is_text_file(file_path):
with open(file_path, 'rb') as file:
try:
file_content = file.read().decode('utf-8')
return all(ord(char) < 128 for char in file_content)
except UnicodeDecodeError:
return False
# Main script code
def main():
# Text help data
description_text = "Script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3."
epilog_text = 'Example:\n python3 ' + script_name + ' -i file.nfc -o output.eml'
# Create an argument parser
parser = argparse.ArgumentParser(exit_on_error=False, description=description_text, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=epilog_text)
# Add the input file argument
parser.add_argument("-i", "--input", required=True, help="Path to the input nfc file.")
# Add the output file argument
parser.add_argument("-o", "--output", required=True, help="Name of the output eml file.")
# Add the version argument
parser.add_argument('-v', '--version', action='version', version=print_version(), help="Show script's version number and exit")
# Parse the command-line arguments
args = parser.parse_args()
# Extract the file paths from the command-line arguments
file_path = args.input
output_file = args.output
# Check if the target file exists
if not os.path.isfile(file_path):
print(f"[!] The input file '{file_path}' does not exist.")
exit(0)
# Validation to check if the input file is a text file based on its content
if not is_text_file(file_path):
print("[!] The input file does not appear to be a nfc text file.")
# Check if the input file name has the .nfc extension
if not file_path.lower().endswith('.nfc'):
print("[+] Warning. The input file should have the '.nfc' extension.")
# Get the absolute path of the output file
output_file_path = os.path.abspath(output_file)
# Check if the directory of the output file is writable
output_dir = os.path.dirname(output_file_path)
if not os.access(output_dir, os.W_OK):
print(f"[!] The output directory '{output_dir}' is not writable or doesn't exist.")
# Check if the output file name has the .eml extension
if not output_file.lower().endswith('.eml'):
print("[+] Warning. The output file should have the '.eml' extension.")
# Read the target file
with open(file_path, 'r') as file:
file_content = file.read()
# Extract the data from each "Page X" line
matches = re.findall(r'Page \d+:(.*?)$', file_content, re.MULTILINE | re.DOTALL)
if matches:
# Remove spaces and convert to lowercase for each match
extracted_data = [re.sub(r'\s', '', match).lower() for match in matches]
# Join the extracted data with line feeds
result = '\n'.join(extracted_data)
# Write the extracted data to the output file
with open(output_file_path, 'w', newline='\n') as output_file:
output_file.write(result)
print(f"[*] File converted successfully. Output eml file written as '{os.path.basename(output_file.name)}'.")
else:
# If the needed data is not there
print("[!] Provided input file seems to not be a valid nfc file to work with.")
# Application entrypoint
if __name__ == '__main__':
try:
main()
except:
pass

View file

@ -137,15 +137,14 @@ static char *GenerateFilename(const char *prefix, const char *suffix) {
static int initSectorTable(sector_t **src, size_t items) {
(*src) = calloc(items, sizeof(sector_t));
if (*src == NULL)
return PM3_EMALLOC;
// empty e_sector
for (int i = 0; i < items; ++i) {
for (int j = 0; j < 2; ++j) {
for (int i = 0; i < items; i++) {
for (int j = 0; j < 2; j++) {
(*src)[i].Key[j] = 0xffffffffffff;
(*src)[i].foundKey[j] = false;
(*src)[i].foundKey[j] = 0;
}
}
return PM3_SUCCESS;
@ -1109,7 +1108,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
"Restore MIFARE Classic dump file to tag.\n"
"\n"
"The key file and dump file will program the card sector trailers.\n"
"By default we authenticate to card with key B 0xFFFFFFFFFFFF.\n"
"By default we authenticate to card with key 0xFFFFFFFFFFFF.\n"
"If access rights in dump file is all zeros, it will be replaced with default values\n"
"\n"
"`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
@ -1321,56 +1320,37 @@ static int CmdHF14AMfRestore(const char *Cmd) {
uint8_t wdata[26];
memcpy(wdata + 10, bldata, sizeof(bldata));
if (use_keyfile_for_auth) {
for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
if (use_keyfile_for_auth) {
if (kt == MF_KEY_A)
memcpy(wdata, keyA[s], 6);
else
memcpy(wdata, keyB[s], 6);
PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK == 0) {
if (b == 0) {
PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B');
} else {
PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B');
}
} else {
// if success, skip to next block
break;
}
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
}
} else {
// use default key to authenticate for the write command
memcpy(wdata, default_key, 6);
}
} else {
// use default key to authenticate for the write command
memcpy(wdata, default_key, 6);
PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, MF_KEY_B, 0, wdata, sizeof(wdata));
SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK == 0) {
if (b == 0) {
PrintAndLogEx(INFO, "Writing to manufacture block w key B ( " _RED_("fail") " )");
PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B');
} else {
PrintAndLogEx(FAILED, "Write to block %u w key B ( " _RED_("fail") " )", b);
PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B');
}
} else {
// if success, skip to next block
break;
}
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
}
} // end use_keyfile_for_auth
}
} // end loop B
} // end loop S

View file

@ -2690,7 +2690,7 @@ static void wait4response(uint8_t b) {
int CmdHF14MfUTamper(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu tamper",
"Set the congiguration of the NTAG 213TT tamper feature\n"
"Set the configuration of the NTAG 213TT tamper feature\n"
"Supports:\n"
"NTAG 213TT\n",
"hf mfu tamper -e -> enable tamper feature\n"
@ -4697,7 +4697,7 @@ static command_t CommandTable[] = {
{"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"},
{"view", CmdHF14AMfuView, AlwaysAvailable, "Display content from tag dump file"},
{"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"},
{"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Cofigure the tamper feature on an NTAG 213TT"},
{"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Configure the tamper feature on an NTAG 213TT"},
{"---------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"},
{"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Load Ultralight dump file into emulator memory"},
{"esave", CmdHF14AMfuESave, IfPm3Iso14443a, "Save Ultralight dump file from emulator memory"},

View file

@ -43,10 +43,36 @@
static const uint64_t g_mifare_default_keys[] = {
0xffffffffffff, // Default key (first key used by program if no user defined key)
0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key
0xd3f7d3f7d3f7, // NDEF public key
0x4b791bea7bcc, // MFC EV1 Signature B
0xfc00018778f7, // Public Transport
0x6471a5ef2d1a, // SimonsVoss
0x4E3552426B32, // ID06
0x6A1987C40A21, // Salto
0xef1232ab18a0, // Schlage
0x3B7E4FD575AD, //
0xb7bf0c13066e, // Gallagher
0x135b88a94b8b, // Saflok
0x2A2C13CC242A, // Dorma Kaba
0x5a7a52d5e20d, // Bosch
0x314B49474956, // VIGIK1 A
0x564c505f4d41, // VIGIK1 B
0x021209197591, // BTCINO
0x484558414354, // Intratone
0xEC0A9B1A9E06, // Vingcard
0x66b31e64ca4b, // Vingcard
0x97F5DA640B18, // Bangkok metro key
0xA8844B0BCA06, // Metro Valencia key
0xE4410EF8ED2D, // Armenian metro
0x857464D3AAD1, // HTC Eindhoven key
0x08B386463229, // troika
0xe00000000000, // icopy
0x199404281970, // NSP A
0x199404281998, // NSP B
0x6A1987C40A21, // SALTO
0x7F33625BC129, // SALTO
0x000000000000, // Blank key
0xb0b1b2b3b4b5,
0xaabbccddeeff,
0x1a2b3c4d5e6f,
@ -64,29 +90,6 @@ static const uint64_t g_mifare_default_keys[] = {
0x0000014b5c31,
0xb578f38a5c61,
0x96a301bce267,
0xfc00018778f7, // Public Transport
0x6471a5ef2d1a, // SimonsVoss
0x4E3552426B32, // ID06
0x6A1987C40A21, // Salto
0xef1232ab18a0, // Schlage
0x3B7E4FD575AD, //
0xb7bf0c13066e, // Gallagher
0x135b88a94b8b, // Saflock
0x5a7a52d5e20d, // Bosch
0x314B49474956, // VIGIK1 A
0x564c505f4d41, // VIGIK1 B
0x021209197591, // BTCINO
0x484558414354, // Intratone
0xEC0A9B1A9E06, // Vingcard
0x66b31e64ca4b, // Vingcard
0x97F5DA640B18, // Bangkok metro key
0xA8844B0BCA06, // Metro Valencia key
0xE4410EF8ED2D, // Armenian metro
0x857464D3AAD1, // HTC Eindhoven key
0x08B386463229, // troika
0xe00000000000, // icopy
0x199404281970, // NSP A
0x199404281998, // NSP B
};
static const uint8_t g_mifare_default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

View file

@ -923,7 +923,7 @@ static int ndefDecodeExternal_record(NDEFHeader_t *ndef) {
);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Payload [%u]...", ndef->PayloadLen);
PrintAndLogEx(INFO, "Payload [%zu]...", ndef->PayloadLen);
print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32);
// do a character check?

View file

@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""
-----------------------------------------------------------------------------
Name: update_amiibo_tools_lua.py
Author: Cory Solovewicz
Description:
This is a python script to automate what the updating of the amiibo_tools.lua
file which holds a lua table of all known amiibos. Previously updating the
amiibo_tools.lua was a very manual process.
This script automates the following original command:
curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json | jq 'del(.amiibos[].release)' | jq 'del(.characters)' | pbcopy --> transform to table
And outputs the formatted file as amiibo_tools.lua
If everything goes well, this should be an updated copy of amiibo_tools.lua
which can then be placed in the /lualibs/ directory.
The temporary amiibo.json file is then deleted
Dependencies:
python3 -m pip install jq
How to run:
python update_amiibo_tools_lua.py
The script will create the file amiibo_tools.lua
After running, manually backup the original /lualibs/amiibo_tools.lua and move the
updated amiibo_tools.lua to the /lualibs/ directory.
-----------------------------------------------------------------------------
"""
import os
import re
import subprocess
import json
from jq import jq
def fetch_data():
print("Fetching amiibo.json")
# Perform the curl command
curl_command = "curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json"
curl_process = subprocess.Popen(curl_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = curl_process.communicate()
if curl_process.returncode != 0:
print("Error fetching data: ", error.decode())
return None
return output
def filter_data(data):
print("Filtering downloaded data")
# Convert the output to JSON and use jq to filter data
data_json = json.loads(data)
filtered_data_json = jq('del(.amiibos[].release) | del(.characters)').transform(data_json)
# Convert the filtered JSON data back to a string, preserving Unicode characters
filtered_data = json.dumps(filtered_data_json, indent=2, ensure_ascii=False)
return filtered_data
def save_data(filtered_data, filename):
# Save filtered data to file
with open(filename, 'w', encoding='utf-8') as file:
file.write(filtered_data)
print(f"Data saved to {filename}")
def process_file(filename):
# Open the file
with open(filename, 'r', encoding='utf-8') as file:
data = file.read()
# Perform the replacements
data = data.replace('"name"', 'name')
data = data.replace('"amiibo_series"', 'amiibo_series')
data = data.replace('"amiibos"', 'amiibos')
data = data.replace('"game_series"', 'game_series')
data = data.replace('"types"', 'types')
data = data.replace(':', ' =')
data = re.sub('"0x', '["0x', data)
data = re.sub('" =', '"] =', data)
# Prepend the text
prepend_text = 'local amiibo_tools = {}\n\n-- curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json | jq \'del(.amiibos[].release)\' | jq \'del(.characters)\' | pbcopy --> transform to table\namiibo_tools.db =\n'
data = prepend_text + data
# Append the text
append_text = '\n\nreturn amiibo_tools\n'
data = data + append_text
return data
def write_to_file(data, filename):
# Write the output
with open(filename, 'w', encoding='utf-8') as file:
file.write(data)
print(f"Output written to {filename}")
def delete_file(filename):
try:
os.remove(filename)
print(f"Temporary file {filename} deleted")
except OSError as e:
print(f"Error deleting file {filename}: ", e)
def main():
data = fetch_data()
if data:
filtered_data = filter_data(data)
save_data(filtered_data, 'amiibo.json')
processed_data = process_file('amiibo.json')
write_to_file(processed_data, 'amiibo_tools.lua')
delete_file('amiibo.json')
if __name__ == "__main__":
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -222,17 +222,29 @@ reg signed [10:0] rx_mod_falling_edge_max;
reg signed [10:0] rx_mod_rising_edge_max;
reg curbit;
`define EDGE_DETECT_THRESHOLD 5
`define EDGE_DETECT_THRESHOLD 3
`define EDGE_DETECT_THRESHOLDHIGH 20
always @(negedge adc_clk)
begin
if(negedge_cnt[3:0] == mod_detect_reset_time)
begin
// detect modulation signal: if modulating, there must have been a falling AND a rising edge
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLD) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLD))
curbit <= 1'b1; // modulation
else
curbit <= 1'b0; // no modulation
if (mod_type == `FPGA_HF_ISO14443A_SNIFFER)
begin
// detect modulation signal: if modulating, there must have been a falling AND a rising edge
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLDHIGH) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLDHIGH))
curbit <= 1'b1; // modulation
else
curbit <= 1'b0; // no modulation
end
else
begin
// detect modulation signal: if modulating, there must have been a falling AND a rising edge
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLD) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLD))
curbit <= 1'b1; // modulation
else
curbit <= 1'b0; // no modulation
end
// reset modulation detector
rx_mod_rising_edge_max <= 0;
rx_mod_falling_edge_max <= 0;