Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions client/hardnested/hardnested_bruteforce.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ static uint8_t bf_test_nonce_par[256];
static uint32_t bucket_count = 0;
static statelist_t* buckets[128];
static uint32_t keys_found = 0;
uint64_t cracked_key;
static uint64_t num_keys_tested;


Expand Down Expand Up @@ -169,6 +170,7 @@ crack_states_thread(void* x){
const uint64_t key = crack_states_bitsliced(thread_arg->cuid, thread_arg->best_first_bytes, bucket, &keys_found, &num_keys_tested, nonces_to_bruteforce, bf_test_nonce_2nd_byte, thread_arg->nonces);
if(key != -1){
__sync_fetch_and_add(&keys_found, 1);
cracked_key = key;
char progress_text[80];
sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key);
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
Expand Down
1 change: 1 addition & 0 deletions client/hardnested/hardnested_bruteforce.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct {
extern void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte);
extern bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes);
extern float brute_force_benchmark();
extern uint64_t cracked_key;
extern uint8_t trailing_zeros(uint8_t byte);
extern bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even);

Expand Down
20 changes: 20 additions & 0 deletions client/scripting.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "cmdmain.h"
#include "util.h"
#include "mifarehost.h"
#include "hardnested/hardnested_bruteforce.h"
#include "../common/iso15693tools.h"
#include "iso14443crc.h"
#include "../common/crc16.h"
Expand Down Expand Up @@ -65,6 +66,24 @@ static int l_SendCommand(lua_State *L){
SendCommand((UsbCommand* )data);
return 0; // no return values
}

static int l_HardNested(lua_State *L){
size_t size;
const char *data = luaL_checklstring(L, 1, &size);
bool isOK = CmdHF14AMfNestedHard(data);
if (isOK == 0){
char destination[17];
snprintf(destination, 16, "%012" PRIx64, cracked_key);
destination[16] = 0;
lua_pushnil(L);
lua_pushstring(L, destination);
} else {
lua_pushstring(L, "key not found");
lua_pushstring(L, "FFFFFFFFFFFF");
}
return 2;
}

/**
* @brief The following params expected:
* uint32_t cmd
Expand Down Expand Up @@ -424,6 +443,7 @@ int set_pm3_libraries(lua_State *L)
{"SendCommand", l_SendCommand},
{"WaitForResponseTimeout", l_WaitForResponseTimeout},
{"mfDarkside", l_mfDarkside},
{"hardnested", l_HardNested},
//{"PrintAndLog", l_PrintAndLog},
{"foobar", l_foobar},
{"ukbhit", l_ukbhit},
Expand Down
208 changes: 208 additions & 0 deletions client/scripts/hard_autopwn.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
local cmds = require('commands')
local getopt = require('getopt')
local utils = require('utils')
local lib14a = require('read14a')

example = "script iterates over all possible sectors for a tag and runs hardnested attack against them to collect the keys."
author = "Iceman"
desc =
[[
This script iterates over all possible sectors for a tag and runs hardnested attack against them to collect the keys.

Arguments:
-k Known key, 6 bytes (12 hex digits)
-a key A
-b key B
-s Blocknumber for known key
Examples :
script hard -k 112233445566
]]

local numBlocks = 64
local numSectors = 16
local DEBUG = TRUE
---
-- A debug printout-function
function dbg(args)
if not DEBUG then return end

if type(args) == "table" then
local i = 1
while result[i] do
dbg(result[i])
i = i+1
end
else
print("###", args)
end
end
---
-- This is only meant to be used when errors occur
function oops(err)
print("ERROR: ",err)
return nil,err
end
---
-- Usage help
function help()
print(desc)
print("Example usage")
print(example)
end
--
-- Exit message
function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
-- A little helper to place an item first in the list
local function placeFirst(akey, list)
akey = akey:lower()
if list[1] == akey then
-- Already at pole position
return list
end
local result = {akey}
--print(("Putting '%s' first"):format(akey))
for i,v in ipairs(list) do
if v ~= akey then
result[#result+1] = v
end
end
return result
end
-- A function to display the results
-- TODO: iceman 2016, still screws up output when a key is not found.
local function displayresults(results)
local sector, blockNo, keyA, keyB, succA, succB, _

print("|---|----------------|---|----------------|---|")
print("|sec|key A |res|key B |res|")
print("|---|----------------|---|----------------|---|")

for sector,_ in pairs(results) do
succA, succB, keyA, keyB = unpack(_)
print(("|%03d| %s | %s | %s | %s |"):format(sector, keyA, succA, keyB, succB))
end
print("|---|----------------|---|----------------|---|")

end

--[[
The mifare Classic 1k card has 16 sectors of 4 data blocks each.
The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
8 sectors consist of 16 data blocks.
--]]
local function GetTargetBlockNo(sector)
local trgblockno = sector * 4 - 1
if sector > 32 then
trgblockno = 32 * 4 + (sector-32) * 16 -1
end
return ("%d"):format(trgblockno)
end

---
-- The main entry point
function main(args)

local blockno = '00'
local keytype
local key = 'fc00018778f7'
local trgkey = ''
local numSectors = 16

-- Read the parameters
for o, a in getopt.getopt(args, 'hk:abs:') do
if o == "h" then return help() end
if o == "k" then key = a end
if o == "a" then keytype = '0' end
if o == "b" then keytype = '1' end
if o == "s" then blockno = a end
end

keytype = keytype or '0'

-- Turn off Debug
local cmdSetDbgOff = "hf mf dbg 0"
core.console( cmdSetDbgOff)
core.clearCommandBuffer()
-- identify tag
result, err = lib14a.read14443a(false, true)
if not result then return oops(err) end

-- Show tag info
print((' Found tag %s'):format(result.name))

if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
-- IFARE Classic 4K offers 4096 bytes split into forty sectors,
-- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
numSectors = 40
elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
-- 1K offers 1024 bytes of data storage, split into 16 sector
numSectors = 16
elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
-- MIFARE Classic mini offers 320 bytes split into five sectors.
numSectors = 5
elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
numSectors = 32
else
print("I don't know how many sectors there are on this type of card, defaulting to 16")
end

result = {}
for sector=1,numSectors do

local trgblockno = GetTargetBlockNo(sector)
local succA = 1
local succB = 1
local keyA = ''
local keyB = ''

for targetkeytype=0,1 do

-- skip first sector, KeyA...
-- or actually blockNo and keytype
-- just try default for now
if sector == 1 and targetkeytype == 0 then
keyA = key
else
local cmd = ''
if keytype == '0' and targetkeytype == 0 then
cmd = ("%s %s %s %s %s"):format(blockno, "A", key, trgblockno, "A")
elseif keytype == '0' and targetkeytype == 1 then
cmd = ("%s %s %s %s %s"):format(blockno, "A", key, trgblockno, "B")
elseif keytype == '1' and targetkeytype == 0 then
cmd = ("%s %s %s %s %s"):format(blockno, "B", key, trgblockno, "A")
elseif keytype == '1' and targetkeytype == 1 then
cmd = ("%s %s %s %s %s"):format(blockno, "B", key, trgblockno, "B")
end
print(("run cmd %s"):format(cmd))
local err, foundkey = core.hardnested(cmd)
--local err, foundkey = core.hardnested(blockno, keytype, key, trgblockno, tostring(targetkeytype), trgkey, 0,0,0,0)
--foundkey = foundkey or ""
print(("cmd result %s %s"):format(err, foundkey))
if targetkeytype == 0 then
if err ~= nil then succA = 0 else keyA = foundkey end
else
if err ~= nil then succB = 0 else keyB = foundkey end
end
end

-- clearing BigBuff between hardnested executions seems to make it more stable.
core.clearCommandBuffer()
core.console('data buffclear')
end
-- Check if user aborted
if core.ukbhit() then
print("Aborted by user")
break
end
-- log
result[sector] = { succA, succB, keyA, keyB }
end
displayresults(result)
end

main(args)