Skip to content

Commit

Permalink
Add NFC write support for ultralight/NTAG and FlipperZero file format
Browse files Browse the repository at this point in the history
  • Loading branch information
andreock committed Nov 28, 2024
1 parent c2ef55c commit f51cb7e
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 3 deletions.
92 changes: 92 additions & 0 deletions lib/nfc_attacks/flipper_zero_nfc_file_parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* This file is part of the Capibara zero (https://github.com/CapibaraZero/fw or
* https://capibarazero.github.io/). Copyright (c) 2024 Andrea Canale.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <string>
#include <vector>

#include "../UI/navigation/NFC/NFCNavigation.hpp"
#include "nfc_attacks.hpp"

static int count_chars_in_line(const char *str, int pos) {
int end_pos = pos;
while (str[end_pos] != '\n') {
end_pos++;
}
return end_pos;
}

static std::vector<std::string> split(std::string &s,
const std::string &delimiter) {
std::vector<std::string> tokens;
size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
tokens.push_back(token);
s.erase(0, pos + delimiter.length());
}
tokens.push_back(s);

return tokens;
}

void flipper_zero_nfc_parser(std::string file, NFCAttacks *attacks) {
int start_position = file.find("Device type:");
start_position += std::string("Device type: ").size();
int end_position = count_chars_in_line(file.c_str(), start_position);
int type = 0;
std::string nfc_type =
file.substr(start_position, end_position - start_position);
if (nfc_type == "Mifare Classic") {
type = 0;
} else if (nfc_type.find("NTAG") != std::string::npos) {
type = 1;
}
start_position = type == 0 ? file.find("Block 0:") : file.find("Page 0:");
std::string blocks_str = file.substr(start_position);
size_t i = 0;
std::vector<std::string> blocks = split(blocks_str, "\n");
uint8_t key[6] = {0xFF, 0xFF, 0XFF, 0XFF, 0XFF, 0XFF};
size_t wrote_sectors = 0;
size_t unwritable_sectors = 0;
for (std::string block : blocks) {
if (block.find("Failed") == std::string::npos && block != "") {
uint8_t data[type == 0 ? 16 : 4];
size_t substr_space = i < 10 ? 9 : 10;
if(type != 0) {
substr_space--;
}
std::string parsed_blocks = block.substr(substr_space);
std::vector<std::string> values = split(parsed_blocks, " ");
size_t j = 0;
for (std::string val : values) {
data[j++] = val != "??" ? strtol(val.c_str(), NULL, 16) : 0xFF;
}
bool success = false;
if (type == 0) {
success = attacks->write_sector(i++, data, 0, key);
} else {
success = attacks->write_ntag(i++, data);
}
if (success) {
set_wrote_sectors(++wrote_sectors);
} else {
set_unwritable_sectors(++unwritable_sectors);
}
}
}
}
21 changes: 21 additions & 0 deletions lib/nfc_attacks/flipper_zero_nfc_file_parser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* This file is part of the Capibara zero (https://github.com/CapibaraZero/fw or
* https://capibarazero.github.io/). Copyright (c) 2024 Andrea Canale.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "nfc_attacks.hpp"
#include <string>

void flipper_zero_nfc_parser(std::string file, NFCAttacks *attacks);
12 changes: 12 additions & 0 deletions lib/nfc_attacks/nfc_attacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,18 @@ uint8_t NFCAttacks::write_ntag(NFCTag *tag) {
return unwritable;
}

bool NFCAttacks::write_ntag(uint8_t page, uint8_t *data) {
uint8_t uid[7];
uint8_t uid_length;
bool success = false;

if (nfc_framework.get_tag_uid(uid, uid_length)) {
success = nfc_framework.write_ntag2xx_page(page, data);
}

return success;
}

uint8_t NFCAttacks::format_ntag(int pages) {
LOG_INFO("Formatting ntag...");
uint8_t empty_tag_data[pages * NTAG_PAGE_SIZE] = {0};
Expand Down
1 change: 1 addition & 0 deletions lib/nfc_attacks/nfc_attacks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class NFCAttacks {
bool write_sector(uint8_t block_number, uint8_t *data, uint8_t key_type,
uint8_t *key);
uint8_t write_ntag(NFCTag *tag);
bool write_ntag(uint8_t page, uint8_t *data);
uint8_t format_ntag(int pages);
void format_tag();
bool detect_felica(uint8_t *idm, uint8_t *pmm, uint16_t *sys_code);
Expand Down
12 changes: 9 additions & 3 deletions lib/nfc_attacks/nfc_tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,19 @@ void write_nfc_sectors(void *pv) {
key[i++] = key_byte;
}

uint8_t data[16];
uint8_t data[type == "0" ? 16 : 4];
i = 0;
for (uint8_t data_byte : block.value()["data"].as<JsonArray>()) {
data[i++] = data_byte;
}

if (params->attacks->write_sector(block_key, data, block_value_key_type,
key)) {
bool success = false;
if (type == "0") {
success = params->attacks->write_sector(i++, data, 0, key);
} else {
success = params->attacks->write_ntag(i++, data);
}
if (success) {
set_wrote_sectors(++wrote_sectors);
} else {
set_unwritable_sectors(++unwritable_sectors);
Expand All @@ -233,6 +238,7 @@ void write_nfc_sectors(void *pv) {
} else {
flipper_zero_nfc_parser(std::string(nfc_dump.readString().c_str()), params->attacks);
}
delay(6000);
goto_home_nfc(params);
free(pv);
vTaskDelete(NULL);
Expand Down

0 comments on commit f51cb7e

Please sign in to comment.