Closed NathanielJS1541 closed 2 years ago
I managed to get gdb to work properly and display line numbers etc:
Thread 1 "proxmark3" received signal SIGSEGV, Segmentation fault.
0x00000055556de4f8 in count_bitarray_AND_NOSIMD (A=0xb400007ca5371040, B=0x0)
at hardnested_bitarray_core.c:212
212 A[i] &= B[i];
(gdb) bt
#0 0x00000055556de4f8 in count_bitarray_AND_NOSIMD (A=0xb400007ca5371040, B=0x0)
at hardnested_bitarray_core.c:212
#1 0x000000555560a708 in apply_sum_a0 () at src/cmdhfmfhard.c:1287
#2 acquire_nonces (blockNo=<optimized out>, keyType=<optimized out>, key=<optimized out>,
trgBlockNo=<optimized out>, trgKeyType=<optimized out>, nonce_file_write=false, slow=<optimized out>,
filename=0x7fffffe39c "") at src/cmdhfmfhard.c:1491
#3 mfnestedhard (blockNo=<optimized out>, blockNo@entry=0 '\000', keyType=<optimized out>,
keyType@entry=0 '\000', key=key@entry=0x7fffffe7ac "\377\377\377\377\377\377\377\377\006",
trgBlockNo=<optimized out>, trgBlockNo@entry=60 '<', trgKeyType=<optimized out>,
trgKeyType@entry=0 '\000', trgkey=<optimized out>, nonce_file_read=<optimized out>,
nonce_file_write=false, slow=<optimized out>, tests=0, foundkey=0x7fffffe390, filename=0x7fffffe39c "")
at src/cmdhfmfhard.c:2380
#4 0x00000055555ea2bc in CmdHF14AMfNestedHard (Cmd=<optimized out>) at src/cmdhfmf.c:1788
#5 0x000000555565f3e0 in CmdsParse (Commands=0x555581f688 <CommandTable>,
Cmd=0xb400007d8daa31a6 "hardnested --blk 0 -a -k ", 'f' <repeats 12 times>, " --tblk 60 --ta")
at src/cmdparser.c:297
#6 0x000000555565f3e0 in CmdsParse (Commands=0x555581cac0 <CommandTable>,
Cmd=0xb400007d8daa31a3 "mf hardnested --blk 0 -a -k ", 'f' <repeats 12 times>, " --tblk 60 --ta")
at src/cmdparser.c:297
#7 0x000000555565f3e0 in CmdsParse (Commands=0x5555823240 <CommandTable>,
Cmd=Cmd@entry=0xb400007d8daa31a0 "hf mf hardnested --blk 0 -a -k ", 'f' <repeats 12 times>, " --tblk 60 --ta") at src/cmdparser.c:297
#8 0x000000555565dad8 in CommandReceived (Cmd=0x0,
Cmd@entry=0xb400007d8daa31a0 "hf mf hardnested --blk 0 -a -k ", 'f' <repeats 12 times>, " --tblk 60 --ta") at src/cmdmain.c:348
#9 0x00000055556ac83c in main_loop (script_cmds_file=<optimized out>, script_cmds_file@entry=0x0,
script_cmd=0xb400007d8daa359b "ated", script_cmd@entry=0x0, stayInCommandLoop=<optimized out>)
at src/proxmark3.c:462
#10 0x00000055556ada48 in main (argc=<optimized out>, argv=<optimized out>) at src/proxmark3.c:1110
Following this back, it appears that the variable first_byte_sum
is set to 132 in cmdhfmfhard.c
, but the array which it is used as an index for is 2x19. This results in a value for B at addres 0x00 being passed to count_bitarray_AND_NOSIMD and causing the SIGSEGV it looks like. I'll keep digging.
first_byte_sum == 132...
used as index in a arr with size of 1<<19 elements. Index 132 shouldn't be any issue, its almost like the arr wasn't initialized properly.
or termux doesn't align the memory when initialized. __builtin_assume_aligned is heavily used in hardnested_bitarray_core.c
Its a interesting bug though.
Ok a little more progress on the issue. It looks like it's something to do with first_byte_Sum
since without compiler optimisations it has a value of < 19 at the point where it is used as an index for sum_a0_bitarrays
, and with them it has a value of over 100. The array sum_a0_bitarrays
appears to be the same size in both cases so I don't think it's a problem with the initialisation there.
Here is a gdb output without compiler optimisations:
Thread 1 "proxmark3" hit Breakpoint 1, acquire_nonces (blockNo=0 '\000', keyType=0 '\000', key=0x7fffffe324 "\377\377\377\377\377\377\020@\006", trgBlockNo=60 '<', trgKeyType=0 '\000', nonce_file_write=false, slow=false,
filename=0x7fffffdf14 "") at src/cmdhfmfhard.c:1490
1490 hardnested_stage |= CHECK_2ND_BYTES;
(gdb) s
1491 apply_sum_a0();
(gdb) s
apply_sum_a0 () at src/cmdhfmfhard.c:1286
1286 uint32_t old_count = num_all_bitflips_bitarray[EVEN_STATE];
(gdb) p old_count
$1 = 1
(gdb) p first_byte_Sum
$2 = 7
(gdb) p all_bitflips_bitarray[EVEN_STATE]
$4 = (uint32_t *) 0xb400007ca5391040
(gdb) p *all_bitflips_bitarray[EVEN_STATE]
$5 = 4294967295
(gdb) p sum_a0_bitarrays[EVEN_STATE][first_byte_Sum]
$6 = (uint32_t *) 0xb400007ca83d9040
(gdb) p *sum_a0_bitarrays[EVEN_STATE][first_byte_Sum]
$7 = 4294967295
(gdb) p sum_a0_bitarrays[EVEN_STATE]
$9 = {0xb400007caa003040, 0xb400007ca9bfd040, 0xb400007ca97f7040, 0xb400007ca93f1040, 0xb400007ca8feb040, 0xb400007ca8be5040, 0xb400007ca87df040, 0xb400007ca83d9040, 0xb400007ca7fd3040, 0xb400007ca7bcd040, 0xb400007ca77c7040,
0xb400007ca73c1040, 0xb400007ca6fbb040, 0xb400007ca6bb5040, 0xb400007ca67af040, 0xb400007ca63a9040, 0xb400007ca5fa3040, 0xb400007ca5b9d040, 0xb400007ca5797040}
(gdb)
And here's one at the same point with compiler optimisations enabled:
Thread 1 "proxmark3" hit Breakpoint 1, acquire_nonces (blockNo=<optimized out>, keyType=<optimized out>, key=<optimized out>, trgBlockNo=<optimized out>, trgKeyType=<optimized out>, nonce_file_write=false, slow=<optimized out>,
filename=0x7fffffe2cc "") at src/cmdhfmfhard.c:1490
1490 hardnested_stage |= CHECK_2ND_BYTES;
(gdb) s
1491 apply_sum_a0();
(gdb) s
apply_sum_a0 () at src/cmdhfmfhard.c:1287
1287 num_all_bitflips_bitarray[EVEN_STATE] = count_bitarray_AND(all_bitflips_bitarray[EVEN_STATE], sum_a0_bitarrays[EVEN_STATE][first_byte_Sum]);
(gdb) p all_bitflips_bitarray[EVEN_STATE]
$4 = (uint32_t *) 0xb400007ca537c040
(gdb) p *all_bitflips_bitarray[EVEN_STATE]
$5 = 4294967295
(gdb) p sum_a0_bitarrays[EVEN_STATE][first_byte_Sum]
$6 = (uint32_t *) 0x0
(gdb) p first_byte_Sum
$7 = 125
(gdb) p sum_a0_bitarrays[EVEN_STATE]
$8 = {0xb400007ca9fee040, 0xb400007ca9be8040, 0xb400007ca97e2040, 0xb400007ca93dc040, 0xb400007ca8fd6040, 0xb400007ca8bd0040, 0xb400007ca87ca040, 0xb400007ca83c4040, 0xb400007ca7fbe040, 0xb400007ca7bb8040, 0xb400007ca77b2040,
0xb400007ca73ac040, 0xb400007ca6fa6040, 0xb400007ca6ba0040, 0xb400007ca679a040, 0xb400007ca6394040, 0xb400007ca5f8e040, 0xb400007ca5b88040, 0xb400007ca5782040}
(gdb)
As you can see there's also a lot of stuff optimised out, including old_count
etc. I'm not too familiar with this codebase so I'll try and keep digging but please let me know if you see anything that stands out as weird here.
Ok I'm not sure whether I'm interpreting this right, but I've found something weird going on with lines 1483 to 1492 of cmdhfmfhard.c (I think anyway). Here are the lines of code in question:
if (hardnested_stage == CHECK_1ST_BYTES) {
for (uint8_t i = 0; i < NUM_SUMS; i++) {
if (first_byte_Sum == sums[i]) {
first_byte_Sum = i;
break;
}
}
hardnested_stage |= CHECK_2ND_BYTES;
apply_sum_a0();
}
With the compiler optimisations, here is the gdb info I've gathered:
Thread 1 "proxmark3" hit Breakpoint 11, acquire_nonces (blockNo=<optimized out>, keyType=<optimized out>, key=<optimized out>, trgBlockNo=<optimized out>, trgKeyType=<optimized out>, nonce_file_write=false, slow=<optimized out>,
filename=0x7fffffe2cc "") at src/cmdhfmfhard.c:1485
1485 if (first_byte_Sum == sums[i]) {
(gdb) p first_byte_Sum
$49 = 124
(gdb) p sums
$50 = {0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256}
(gdb) p sums[i]
$51 = 0
(gdb) s
0x000000555560a6e0 in apply_sum_a0 () at src/cmdhfmfhard.c:1287
1287 num_all_bitflips_bitarray[EVEN_STATE] = count_bitarray_AND(all_bitflips_bitarray[EVEN_STATE], sum_a0_bitarrays[EVEN_STATE][first_byte_Sum]);
(gdb) p first_byte_Sum
$52 = 124
(gdb) s
1286 uint32_t old_count = num_all_bitflips_bitarray[EVEN_STATE];
(gdb) s
Thread 1 "proxmark3" hit Breakpoint 13, acquire_nonces (blockNo=<optimized out>, keyType=<optimized out>, key=<optimized out>, trgBlockNo=<optimized out>, trgKeyType=<optimized out>, nonce_file_write=false, slow=<optimized out>,
filename=0x7fffffe2cc "") at src/cmdhfmfhard.c:1490
1490 hardnested_stage |= CHECK_2ND_BYTES;
(gdb) s
1491 apply_sum_a0();
(gdb) s
apply_sum_a0 () at src/cmdhfmfhard.c:1287
1287 num_all_bitflips_bitarray[EVEN_STATE] = count_bitarray_AND(all_bitflips_bitarray[EVEN_STATE], sum_a0_bitarrays[EVEN_STATE][first_byte_Sum]);
(gdb)
First off, if first_byte_sum
is not in sums[]
(as it isn't here), this loop won't do anything. It seems like it's intended to convert a number to a valid index for sum_a0_bitarrays
, but if the number in first_byte_sum
is not contained within sums[]
, the number will simply remain the same and provide an invalid index for sum_a0_bitarrays
, which is what I believe is causing the SIGSEGV fault.
The thing that's confusing me is that by stepping through after if (first_byte_Sum == sums[i]) {
, instead of being able to step through the loop, the apply_sum_a0
function, I can then step through lines 1287 and 1286 (I'm presuming they're in reverse order due to compiler optimisations), but then the next step takes me back to line 1490, and then 1491 which is the call to the apply_sum_a0
function?? Is this some inlining optimisation or something?
I'll be honest I'm way out of my depth with this one, so please tell me if any conclusions I come to are completely stupid. But from what I can tell this might be at least part of the problem?
you are right, there are no logic for when the first byte sum
doesn't exists in sums
still doing second byte check regardless..
I wonder what happens if you break if not found, not doing the apply_sum_a0
call..
interesting, the 132 is not one of the possible sums. And the attack should reset or something else, but it continues and messes up
ok, since we don't know anymore but there is a check added in order to make the segfault to trigger. It doesn't solve the underlaying issue on that hardware but when someone finds more details about it they can make a new issue / PR or comment in this one and we can reopen it.
Describe the bug When building the client from source on Termux,
hf mf hardnested
causes a SIGSEGV, but when it is compiled withmake client DEBUG=1
, it does not cause the same issue. I think it's because whenDEBUG=1
is specified, the-O0
flag is included. I'd guess that the compiler optimises something out that causes the segmentation fault. I presume this is what's causing the issues withhf mf autopwn
for some Termux users tooTo Reproduce
cd proxmark3
git pull
make clean && make client
client/proxmark3 tcp:loaclhost:1234
hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 60 --ta
Expected behavior The attack should complete the same as it does on a PC.
Screenshots Running the compiled proxmark3 client with gdb to show more about the error: After compiling with
DEBUG=1
, the attack runs correctly:Desktop (please complete the following information):
hw version