Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
ry4000 2025-07-09 20:09:56 +10:00 committed by GitHub
commit ac6916777f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 4875 additions and 57 deletions

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 `mqtt` - the pm3 client can now send and receive MQTT messages or json files. (@iceman1001)
- Changed `hf iclass wrbl` - replay behavior to use privilege escalation if the macs field is not passed empty(@antiklesys)
- Changed `hf iclass restore` - it now supports privilege escalation to restore card content using replay (@antiklesys)
- Fixed `hf 15 dump` - now reads sysinfo response correct (@iceman1001)

View file

@ -402,6 +402,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdlfvisa2000.c
${PM3_ROOT}/client/src/cmdlfzx8211.c
${PM3_ROOT}/client/src/cmdmain.c
${PM3_ROOT}/client/src/cmdmqtt.c
${PM3_ROOT}/client/src/cmdnfc.c
${PM3_ROOT}/client/src/cmdparser.c
${PM3_ROOT}/client/src/cmdpiv.c
@ -772,6 +773,7 @@ target_link_libraries(proxmark3 PRIVATE
pm3rrg_rdv4_reveng
pm3rrg_rdv4_hardnested
pm3rrg_rdv4_id48
pm3rrg_rdv4_mqtt
${ADDITIONAL_LNK})
if (NOT SKIPPTHREAD EQUAL 1)

View file

@ -131,6 +131,12 @@ WHEREAMILIBINC = -I$(WHEREAMILIBPATH)
WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a
WHEREAMILIBLD =
## MQTT
MQTTLIBPATH = ./deps/mqtt
MQTTLIBINC = -I$(MQTTLIBPATH)
MQTTLIB = $(MQTTLIBPATH)/mqtt.a
MQTTLIBLD =
##########################
# common local libraries #
##########################
@ -239,6 +245,12 @@ STATICLIBS += $(WHEREAMILIB)
LDLIBS += $(WHEREAMILIBLD)
PM3INCLUDES += $(WHEREAMILIBINC)
## MQTT
# not distributed as system library
STATICLIBS += $(MQTTLIB)
LDLIBS += $(MQTTLIBLD)
PM3INCLUDES += $(MQTTLIBINC)
####################
# system libraries #
####################
@ -682,6 +694,7 @@ SRCS = mifare/aiddesfire.c \
cmdlfvisa2000.c \
cmdlfzx8211.c \
cmdmain.c \
cmdmqtt.c \
cmdnfc.c \
cmdparser.c \
cmdpiv.c \
@ -877,6 +890,7 @@ endif
$(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(MQTTLIBPATH) clean
@# Just in case someone compiled within these dirs:
$(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) clean
@ -974,6 +988,10 @@ ifneq ($(WHEREAMI_FOUND),1)
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all
endif
$(MQTTLIB): .FORCE
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(MQTTLIBPATH) all
########
# SWIG #
########

View file

@ -31,3 +31,6 @@ endif()
if (NOT TARGET pm3rrg_rdv4_whereami)
include(whereami.cmake)
endif()
if (NOT TARGET pm3rrg_rdv4_mqtt)
include(mqtt.cmake)
endif()

View file

@ -440,33 +440,32 @@ int json_dumpfd(const json_t *json, int output, size_t flags) {
}
int json_dump_file(const json_t *json, const char *path, size_t flags) {
int result;
FILE *output = fopen(path, "w");
if (!output)
FILE *f = fopen(path, "w");
if (f == NULL) {
return -1;
result = json_dumpf(json, output, flags);
if (fclose(output) != 0)
return -1;
return result;
}
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) {
int res;
hashtable_t parents_set;
if (!(flags & JSON_ENCODE_ANY)) {
if (!json_is_array(json) && !json_is_object(json))
return -1;
}
if (hashtable_init(&parents_set))
int res = json_dumpf(json, f, flags);
if (fclose(f) != 0)
return -1;
res = do_dump(json, flags, 0, &parents_set, callback, data);
hashtable_close(&parents_set);
return res;
}
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) {
if (!(flags & JSON_ENCODE_ANY)) {
if (!json_is_array(json) && !json_is_object(json)) {
return -1;
}
}
hashtable_t parents_set;
if (hashtable_init(&parents_set)) {
return -1;
}
int res = do_dump(json, flags, 0, &parents_set, callback, data);
hashtable_close(&parents_set);
return res;
}

View file

@ -44,7 +44,7 @@ add_library(pm3rrg_rdv4_mbedtls STATIC
../../common/mbedtls/x509.c
../../common/mbedtls/x509_crl.c
../../common/mbedtls/x509_crt.c
../../common/mbedtls/net_sockets.c
../../common/mbedtls/net_sockets.c
)
target_include_directories(pm3rrg_rdv4_mbedtls PRIVATE ../../common)

9
client/deps/mqtt.cmake Normal file
View file

@ -0,0 +1,9 @@
add_library(pm3rrg_rdv4_mqtt STATIC
mqtt/mqtt.c
mqtt/mqtt_pal.c
)
target_compile_definitions(pm3rrg_rdv4_mqtt PRIVATE WAI_PM3_TUNED)
target_include_directories(pm3rrg_rdv4_mqtt INTERFACE mqtt)
target_compile_options(pm3rrg_rdv4_mqtt PRIVATE -Wall -Werror -O3)
set_property(TARGET pm3rrg_rdv4_mqtt PROPERTY POSITION_INDEPENDENT_CODE ON)

21
client/deps/mqtt/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Liam Bindle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
client/deps/mqtt/Makefile Normal file
View file

@ -0,0 +1,14 @@
MYSRCPATHS =
MYINCLUDES =
MYCFLAGS = -Wno-bad-function-cast -Wno-switch-enum
MYDEFS = -DWAI_PM3_TUNED
MYSRCS = \
mqtt.c \
mqtt_pal.c \
LIB_A = mqtt.a
# Transition: remove old directories and objects
MYCLEANOLDPATH = ../../mqtt
include ../../../Makefile.host

View file

@ -0,0 +1,152 @@
#if !defined(__MBEDTLS_SOCKET_TEMPLATE_H__)
#define __MBEDTLS_SOCKET_TEMPLATE_H__
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mbedtls/error.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#if !defined(MBEDTLS_NET_POLL_READ)
/* compat for older mbedtls */
#define MBEDTLS_NET_POLL_READ 1
#define MBEDTLS_NET_POLL_WRITE 1
int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout) {
/* XXX this is not ideal but good enough for an example */
msleep(300);
return 1;
}
#endif
struct mbedtls_context {
mbedtls_net_context net_ctx;
mbedtls_ssl_context ssl_ctx;
mbedtls_ssl_config ssl_conf;
mbedtls_x509_crt ca_crt;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
};
void failed(const char *fn, int rv);
void cert_verify_failed(uint32_t rv);
void open_nb_socket(struct mbedtls_context *ctx,
const char *hostname,
const char *port,
const char *ca_file);
void failed(const char *fn, int rv) {
char buf[100];
mbedtls_strerror(rv, buf, sizeof(buf));
printf("%s failed with %x (%s)\n", fn, -rv, buf);
exit(1);
}
void cert_verify_failed(uint32_t rv) {
char buf[512];
mbedtls_x509_crt_verify_info(buf, sizeof(buf), "\t", rv);
printf("Certificate verification failed (%0" PRIx32 ")\n%s\n", rv, buf);
exit(1);
}
/*
A template for opening a non-blocking mbed TLS connection.
*/
void open_nb_socket(struct mbedtls_context *ctx,
const char *hostname,
const char *port,
const char *ca_file) {
const unsigned char *additional = (const unsigned char *)"Pm3 Client";
size_t additional_len = 6;
int rv;
mbedtls_net_context *net_ctx = &ctx->net_ctx;
mbedtls_ssl_context *ssl_ctx = &ctx->ssl_ctx;
mbedtls_ssl_config *ssl_conf = &ctx->ssl_conf;
mbedtls_x509_crt *ca_crt = &ctx->ca_crt;
mbedtls_entropy_context *entropy = &ctx->entropy;
mbedtls_ctr_drbg_context *ctr_drbg = &ctx->ctr_drbg;
mbedtls_entropy_init(entropy);
mbedtls_ctr_drbg_init(ctr_drbg);
rv = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy,
additional, additional_len);
if (rv != 0) {
failed("mbedtls_ctr_drbg_seed", rv);
}
mbedtls_x509_crt_init(ca_crt);
rv = mbedtls_x509_crt_parse_file(ca_crt, ca_file);
if (rv != 0) {
failed("mbedtls_x509_crt_parse_file", rv);
}
mbedtls_ssl_config_init(ssl_conf);
rv = mbedtls_ssl_config_defaults(ssl_conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (rv != 0) {
failed("mbedtls_ssl_config_defaults", rv);
}
mbedtls_ssl_conf_ca_chain(ssl_conf, ca_crt, NULL);
mbedtls_ssl_conf_authmode(ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
mbedtls_ssl_conf_rng(ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg);
mbedtls_net_init(net_ctx);
rv = mbedtls_net_connect(net_ctx, hostname, port, MBEDTLS_NET_PROTO_TCP);
if (rv != 0) {
failed("mbedtls_net_connect", rv);
}
rv = mbedtls_net_set_nonblock(net_ctx);
if (rv != 0) {
failed("mbedtls_net_set_nonblock", rv);
}
mbedtls_ssl_init(ssl_ctx);
rv = mbedtls_ssl_setup(ssl_ctx, ssl_conf);
if (rv != 0) {
failed("mbedtls_ssl_setup", rv);
}
rv = mbedtls_ssl_set_hostname(ssl_ctx, hostname);
if (rv != 0) {
failed("mbedtls_ssl_set_hostname", rv);
}
mbedtls_ssl_set_bio(ssl_ctx, net_ctx,
mbedtls_net_send, mbedtls_net_recv, NULL);
for (;;) {
rv = mbedtls_ssl_handshake(ssl_ctx);
uint32_t want = 0;
if (rv == MBEDTLS_ERR_SSL_WANT_READ) {
want |= MBEDTLS_NET_POLL_READ;
} else if (rv == MBEDTLS_ERR_SSL_WANT_WRITE) {
want |= MBEDTLS_NET_POLL_WRITE;
} else {
break;
}
rv = mbedtls_net_poll(net_ctx, want, (uint32_t) -1);
if (rv < 0) {
failed("mbedtls_net_poll", rv);
}
}
if (rv != 0) {
failed("mbedtls_ssl_handshake", rv);
}
uint32_t result = mbedtls_ssl_get_verify_result(ssl_ctx);
if (result != 0) {
if (result == (uint32_t) -1) {
failed("mbedtls_ssl_get_verify_result", (int)result);
} else {
cert_verify_failed(result);
}
}
}
#endif

1770
client/deps/mqtt/mqtt.c Normal file

File diff suppressed because it is too large Load diff

1640
client/deps/mqtt/mqtt.h Normal file

File diff suppressed because it is too large Load diff

235
client/deps/mqtt/mqtt_pal.c Normal file
View file

@ -0,0 +1,235 @@
/*
MIT License
Copyright(c) 2018 Liam Bindle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "mqtt.h"
/**
* @file
* @brief Implements @ref mqtt_pal_sendall and @ref mqtt_pal_recvall and
* any platform-specific helpers you'd like.
* @cond Doxygen_Suppress
*/
#if defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
/*
* In case of MQTT_USE_CUSTOM_SOCKET_HANDLE, a pal implemantation is
* provided by the user.
*/
/* Note: Some toolchains complain on an object without symbols */
int _mqtt_pal_dummy;
#else /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */
#if defined(MQTT_USE_MBEDTLS)
#include <mbedtls/ssl.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) {
enum MQTTErrors error = 0;
size_t sent = 0;
while (sent < len) {
int rv = mbedtls_ssl_write(fd, (const unsigned char *)buf + sent, len - sent);
if (rv < 0) {
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
#endif
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
#endif
) {
/* should call mbedtls_ssl_write later again */
break;
}
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
/*
* Note: rv can be 0 here eg. when mbedtls just flushed
* the previous incomplete record.
*
* Note: we never send an empty TLS record.
*/
sent += (size_t) rv;
}
if (sent == 0) {
return error;
}
return (ssize_t)sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) {
const void *const start = buf;
enum MQTTErrors error = 0;
int rv;
do {
rv = mbedtls_ssl_read(fd, (unsigned char *)buf, bufsz);
if (rv == 0) {
/*
* Note: mbedtls_ssl_read returns 0 when the underlying
* transport was closed without CloseNotify.
*
* Raise an error to trigger a reconnect.
*/
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
if (rv < 0) {
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
#endif
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
#endif
) {
/* should call mbedtls_ssl_read later again */
break;
}
/* Note: MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY is handled here. */
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
buf = (char *)buf + rv;
bufsz -= (unsigned long)rv;
} while (bufsz > 0);
if (buf == start) {
return error;
}
return (const char *)buf - (const char *)start;
}
#elif defined(__unix__) || defined(__APPLE__) || defined(__NuttX__)
#include <errno.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) {
enum MQTTErrors error = 0;
size_t sent = 0;
while (sent < len) {
ssize_t rv = send(fd, (const char *)buf + sent, len - sent, flags);
if (rv < 0) {
if (errno == EAGAIN) {
/* should call send later again */
break;
}
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
if (rv == 0) {
/* is this possible? maybe OS bug. */
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
sent += (size_t) rv;
}
if (sent == 0) {
return error;
}
return (ssize_t)sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) {
const void *const start = buf;
enum MQTTErrors error = 0;
ssize_t rv;
do {
rv = recv(fd, buf, bufsz, flags);
if (rv == 0) {
/*
* recv returns 0 when the socket is (half) closed by the peer.
*
* Raise an error to trigger a reconnect.
*/
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
if (rv < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* should call recv later again */
break;
}
/* an error occurred that wasn't "nothing to read". */
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
buf = (char *)buf + rv;
bufsz -= (unsigned long)rv;
} while (bufsz > 0);
if (buf == start) {
return error;
}
return (char *)buf - (const char *)start;
}
#elif defined(_MSC_VER) || defined(WIN32)
#include <errno.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) {
size_t sent = 0;
while (sent < len) {
ssize_t tmp = send(fd, (char *)buf + sent, len - sent, flags);
if (tmp < 1) {
return MQTT_ERROR_SOCKET_ERROR;
}
sent += (size_t) tmp;
}
return sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) {
const char *const start = buf;
ssize_t rv;
do {
rv = recv(fd, buf, bufsz, flags);
if (rv > 0) {
/* successfully read bytes from the socket */
buf = (char *)buf + rv;
bufsz -= rv;
} else if (rv < 0) {
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) {
/* an error occurred that wasn't "nothing to read". */
return MQTT_ERROR_SOCKET_ERROR;
}
}
} while (rv > 0 && bufsz > 0);
return (ssize_t)((char *)buf - start);
}
#else
#error No PAL!
#endif
#endif /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */
/** @endcond */

173
client/deps/mqtt/mqtt_pal.h Normal file
View file

@ -0,0 +1,173 @@
#if !defined(__MQTT_PAL_H__)
#define __MQTT_PAL_H__
/*
MIT License
Copyright(c) 2018 Liam Bindle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @file
* @brief Includes/supports the types/calls required by the MQTT-C client.
*
* @note This is the \em only file included in mqtt.h, and mqtt.c. It is therefore
* responsible for including/supporting all the required types and calls.
*
* @defgroup pal Platform abstraction layer
* @brief Documentation of the types and calls required to port MQTT-C to a new platform.
*
* mqtt_pal.h is the \em only header file included in mqtt.c. Therefore, to port MQTT-C to a
* new platform the following types, functions, constants, and macros must be defined in
* mqtt_pal.h:
* - Types:
* - \c size_t, \c ssize_t
* - \c uint8_t, \c uint16_t, \c uint32_t
* - \c va_list
* - \c mqtt_pal_time_t : return type of \c MQTT_PAL_TIME()
* - \c mqtt_pal_mutex_t : type of the argument that is passed to \c MQTT_PAL_MUTEX_LOCK and
* \c MQTT_PAL_MUTEX_RELEASE
* - Functions:
* - \c memcpy, \c strlen
* - \c va_start, \c va_arg, \c va_end
* - Constants:
* - \c INT_MIN
*
* Additionally, three macro's are required:
* - \c MQTT_PAL_HTONS(s) : host-to-network endian conversion for uint16_t.
* - \c MQTT_PAL_NTOHS(s) : network-to-host endian conversion for uint16_t.
* - \c MQTT_PAL_TIME() : returns [type: \c mqtt_pal_time_t] current time in seconds.
* - \c MQTT_PAL_MUTEX_LOCK(mtx_pointer) : macro that locks the mutex pointed to by \c mtx_pointer.
* - \c MQTT_PAL_MUTEX_RELEASE(mtx_pointer) : macro that unlocks the mutex pointed to by
* \c mtx_pointer.
*
* Lastly, \ref mqtt_pal_sendall and \ref mqtt_pal_recvall, must be implemented in mqtt_pal.c
* for sending and receiving data using the platforms socket calls.
*/
/* UNIX-like platform support */
#if defined(__unix__) || defined(__APPLE__) || defined(__NuttX__)
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <arpa/inet.h>
#include <pthread.h>
#define MQTT_PAL_HTONS(s) htons(s)
#define MQTT_PAL_NTOHS(s) ntohs(s)
#define MQTT_PAL_TIME() time(NULL)
typedef time_t mqtt_pal_time_t;
typedef pthread_mutex_t mqtt_pal_mutex_t;
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) pthread_mutex_init(mtx_ptr, NULL)
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) pthread_mutex_lock(mtx_ptr)
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) pthread_mutex_unlock(mtx_ptr)
#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
#if defined(MQTT_USE_MBEDTLS)
struct mbedtls_ssl_context;
typedef struct mbedtls_ssl_context *mqtt_pal_socket_handle;
#else
typedef int mqtt_pal_socket_handle;
#endif
#endif
#elif defined(_MSC_VER) || defined(WIN32)
#include <limits.h>
#include <winsock2.h>
#include <windows.h>
#include <time.h>
#include <stdint.h>
typedef SSIZE_T ssize_t;
#define MQTT_PAL_HTONS(s) htons(s)
#define MQTT_PAL_NTOHS(s) ntohs(s)
#define MQTT_PAL_TIME() time(NULL)
typedef time_t mqtt_pal_time_t;
typedef CRITICAL_SECTION mqtt_pal_mutex_t;
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) InitializeCriticalSection(mtx_ptr)
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) EnterCriticalSection(mtx_ptr)
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) LeaveCriticalSection(mtx_ptr)
#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
typedef SOCKET mqtt_pal_socket_handle;
#endif
#endif
/**
* @brief Sends all the bytes in a buffer.
* @ingroup pal
*
* @param[in] fd The file-descriptor (or handle) of the socket.
* @param[in] buf A pointer to the first byte in the buffer to send.
* @param[in] len The number of bytes to send (starting at \p buf).
* @param[in] flags Flags which are passed to the underlying socket.
*
* @returns The number of bytes sent if successful, an \ref MQTTErrors otherwise.
*
* Note about the error handling:
* - On an error, if some bytes have been processed already,
* this function should return the number of bytes successfully
* processed. (partial success)
* - Otherwise, if the error is an equivalent of EAGAIN, return 0.
* - Otherwise, return MQTT_ERROR_SOCKET_ERROR.
*/
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags);
/**
* @brief Non-blocking receive all the byte available.
* @ingroup pal
*
* @param[in] fd The file-descriptor (or handle) of the socket.
* @param[in] buf A pointer to the receive buffer.
* @param[in] bufsz The max number of bytes that can be put into \p buf.
* @param[in] flags Flags which are passed to the underlying socket.
*
* @returns The number of bytes received if successful, an \ref MQTTErrors otherwise.
*
* Note about the error handling:
* - On an error, if some bytes have been processed already,
* this function should return the number of bytes successfully
* processed. (partial success)
* - Otherwise, if the error is an equivalent of EAGAIN, return 0.
* - Otherwise, return MQTT_ERROR_SOCKET_ERROR.
*/
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags);
#if defined(__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,73 @@
#if !defined(__POSIX_SOCKET_TEMPLATE_H__)
#define __POSIX_SOCKET_TEMPLATE_H__
#ifndef _WIN32
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
// A template for opening a non-blocking POSIX socket.
void close_nb_socket(int sockfd);
int open_nb_socket(const char *addr, const char *port);
int open_nb_socket(const char *addr, const char *port) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Must be TCP */
struct addrinfo *p, *servinfo;
/* get address information */
int rv = getaddrinfo(addr, port, &hints, &servinfo);
if (rv != 0) {
fprintf(stderr, "Failed to open socket (getaddrinfo): %s\n", gai_strerror(rv));
return -1;
}
/* open the first possible socket */
int sockfd = -1;
for (p = servinfo; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == -1) {
continue;
}
/* connect to server */
rv = connect(sockfd, p->ai_addr, p->ai_addrlen);
if (rv == -1) {
close(sockfd);
sockfd = -1;
continue;
}
break;
}
// free servinfo
freeaddrinfo(servinfo);
// make non-blocking
if (sockfd != -1) {
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
}
return sockfd;
}
void close_nb_socket(int sockfd) {
if (sockfd != -1) {
close(sockfd);
}
}
#endif
#endif

View file

@ -0,0 +1,15 @@
# Information
Source: https://github.com/LiamBindle/MQTT-C
License: MIT
Authors:
MQTT-C was initially developed as a CMPT 434 (Winter Term, 2018) final project at the University of Saskatchewan by:
- Liam Bindle
- Demilade Adeoye
# about
MQTT-C is an MQTT v3.1.1 client written in C. MQTT is a lightweight publisher-subscriber-based messaging protocol that is commonly used in IoT and networking applications where high-latency and low data-rate links are expected. The purpose of MQTT-C is to provide a portable MQTT client, written in C, for embedded systems and PC's alike. MQTT-C does this by providing a transparent Platform Abstraction Layer (PAL) which makes porting to new platforms easy. MQTT-C is completely thread-safe but can also run perfectly fine on single-threaded systems making MQTT-C well-suited for embedded systems and microcontrollers. Finally, MQTT-C is small; there are only two source files totalling less than 2000 lines.

View file

@ -0,0 +1,91 @@
#if !defined(__WIN32_SOCKET_TEMPLATE_H__)
#include <stdio.h>
#include <unistd.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
void close_nb_socket(int sockfd);
int open_nb_socket(const char *addr, const char *port);
int open_nb_socket(const char *addr, const char *port) {
WSADATA wsaData;
int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (res != 0) {
fprintf(stderr, "error: WSAStartup failed with error: %i", res);
return -1;
}
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // Must be TCP
hints.ai_protocol = IPPROTO_TCP; //
struct addrinfo *p, *servinfo;
// get address information
int rv = getaddrinfo(addr, port, &hints, &servinfo);
if (rv != 0) {
fprintf(stderr, "error: getaddrinfo: %s", gai_strerror(rv));
WSACleanup();
return -1;
}
/* open the first possible socket */
SOCKET hSocket = INVALID_SOCKET;
for (p = servinfo; p != NULL; p = p->ai_next) {
hSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (hSocket == INVALID_SOCKET) {
continue;
}
// connect to server
if (connect(hSocket, p->ai_addr, (int)p->ai_addrlen) != INVALID_SOCKET) {
break;
}
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
// free servinfo
freeaddrinfo(servinfo);
if (p == NULL) { // No address succeeded
fprintf(stderr, "error: Could not connect");
WSACleanup();
return -1;
}
// make non-blocking
if (hSocket != INVALID_SOCKET) {
uint32_t mode = 1; // FIONBIO returns size on 32b
ioctlsocket(hSocket, FIONBIO, (u_long *)&mode);
}
int flag = 1;
res = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
if (res != 0) {
closesocket(hSocket);
WSACleanup();
return -1;
}
return hSocket;
}
void close_nb_socket(int sockfd) {
if (sockfd != -1) {
close(sockfd);
}
}
#endif
#endif

View file

@ -1135,7 +1135,7 @@ int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) {
res = PM3_EMALLOC;
}
}
} while (loop && kbd_enter_pressed() == false);
} while (loop && (kbd_enter_pressed() == false));
DropField();
return res;

View file

@ -781,17 +781,20 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces) {
}
int legic_get_type(legic_card_select_t *card) {
if (card == NULL)
if (card == NULL) {
return PM3_EINVARG;
}
clearCommandBuffer();
SendCommandNG(CMD_HF_LEGIC_INFO, NULL, 0);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false)
if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false) {
return PM3_ETIMEOUT;
}
if (resp.status != PM3_SUCCESS)
if (resp.status != PM3_SUCCESS) {
return PM3_ESOFT;
}
memcpy(card, resp.data.asBytes, sizeof(legic_card_select_t));
return PM3_SUCCESS;
@ -1527,7 +1530,7 @@ int readLegicUid(bool loop, bool verbose) {
PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1));
legic_print_type(card.cardsize, 0);
} while (loop && kbd_enter_pressed() == false);
} while (loop && (kbd_enter_pressed() == false));
return PM3_SUCCESS;
}

View file

@ -462,7 +462,7 @@ int CmdLFCommandRead(const char *Cmd) {
return PM3_ETIMEOUT;
}
} while (cm && kbd_enter_pressed() == false);
} while (cm && (kbd_enter_pressed() == false));
return ret;
}
@ -859,7 +859,7 @@ int CmdLFRead(const char *Cmd) {
int ret = PM3_SUCCESS;
do {
ret = lf_read_internal(realtime, verbose, samples);
} while (cm && kbd_enter_pressed() == false);
} while (cm && (kbd_enter_pressed() == false));
if (ret == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Got " _YELLOW_("%zu") " samples", g_GraphTraceLen);
@ -985,7 +985,7 @@ int CmdLFSniff(const char *Cmd) {
int ret = PM3_SUCCESS;
do {
ret = lf_sniff(realtime, verbose, samples);
} while (cm && kbd_enter_pressed() == false);
} while (cm && (kbd_enter_pressed() == false));
return ret;
}

View file

@ -349,7 +349,7 @@ static int CmdAWIDReader(const char *Cmd) {
do {
lf_read(false, 12000);
demodAWID(!cm);
} while (cm && !kbd_enter_pressed());
} while (cm && (kbd_enter_pressed() == false));
return PM3_SUCCESS;
}

View file

@ -445,7 +445,7 @@ static int CmdEM410xReader(const char *Cmd) {
if (break_first && gs_em410xid != 0) {
break;
}
} while (cm && !kbd_enter_pressed());
} while (cm && (kbd_enter_pressed() == false));
return PM3_SUCCESS;
}

View file

@ -243,7 +243,7 @@ static int CmdGuardReader(const char *Cmd) {
do {
lf_read(false, 10000);
demodGuard(!cm);
} while (cm && !kbd_enter_pressed());
} while (cm && (kbd_enter_pressed() == false));
return PM3_SUCCESS;
}

View file

@ -215,7 +215,7 @@ static int CmdHIDReader(const char *Cmd) {
do {
lf_read(false, 16000);
demodHID(!cm);
} while (cm && !kbd_enter_pressed());
} while (cm && (kbd_enter_pressed() == false));
return PM3_SUCCESS;
}

View file

@ -912,7 +912,7 @@ static int CmdLFHitagReader(const char *Cmd) {
if (ht2_get_uid(&uid)) {
PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid);
}
} while (cm && kbd_enter_pressed() == false);
} while (cm && (kbd_enter_pressed() == false));
return PM3_SUCCESS;
}

View file

@ -48,6 +48,7 @@
#include "commonutil.h" // ARRAYLEN
#include "preferences.h"
#include "cliparser.h"
#include "cmdmqtt.h"
static int CmdHelp(const char *Cmd);
@ -338,6 +339,7 @@ static command_t CommandTable[] = {
{"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"},
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
{"mqtt", CmdMqtt, AlwaysAvailable, "{ MQTT commmands... }"},
{"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
{"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},

390
client/src/cmdmqtt.c Normal file
View file

@ -0,0 +1,390 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// 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, either version 3 of the License, or
// (at your option) any later version.
//
// 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.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// MQTT commands
//-----------------------------------------------------------------------------
#include "cmdmqtt.h"
#include "cmdparser.h"
#include "cliparser.h"
#include "mqtt.h" // MQTT support
//#include "mbedtls_sockets.h" // MQTT networkings examples
#ifndef _WIN32
#include "posix_sockets.h" // MQTT networkings examples
#else
#include "win32_sockets.h" // MQTT networkings examples
#endif
#include "util_posix.h" // time
#include "fileutils.h"
#define MQTT_BUFFER_SIZE ( 1 << 16 )
static int CmdHelp(const char *Cmd);
static void mqtt_publish_callback(void **unused, struct mqtt_response_publish *published) {
// note that published->topic_name is NOT null-terminated (here we'll change it to a c-string)
char *topic_name = (char *) calloc(published->topic_name_size + 1, 1);
memcpy(topic_name, published->topic_name, published->topic_name_size);
const char *msg = published->application_message;
char *ps = strstr(msg, "Created\": \"proxmark3");
if (ps) {
int res = saveFileTXT("ice_mqtt", ".json", msg, published->application_message_size, spDefault);
if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, "Got a json file ( %s )", _GREEN_("ok"));
}
} else {
PrintAndLogEx(SUCCESS, _GREEN_("%s") " - ( %zu ) " _YELLOW_("%s"), topic_name, published->application_message_size, msg);
}
free(topic_name);
}
static void *mqtt_client_refresher(void *client) {
while (1) {
mqtt_sync((struct mqtt_client *) client);
msleep(100);
}
return NULL;
}
static int mqtt_exit(int status, int sockfd, pthread_t *client_daemon) {
close_nb_socket(sockfd);
if (client_daemon != NULL) {
pthread_cancel(*client_daemon);
#ifndef _WIN32
pthread_join(*client_daemon, NULL); // Wait for the thread to finish
#endif
}
return status;
}
/*
static void mqtt_reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr) {
struct reconnect_state_t *rs = *((struct reconnect_state_t**) reconnect_state_vptr);
// Close the clients socket if this isn't the initial reconnect call
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
close_nb_socket(client->socketfd);
}
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
PrintAndLogEx(INFO, "reconnect_client: called while client was in error state `%s`", mqtt_error_str(client->error));
}
int sockfd = open_nb_socket(rs->hostname, rs->port);
if (sockfd == -1) {
PrintAndLogEx(FAILED, "Failed to open socket");
mqtt_exit(PM3_EFAILED, sockfd, NULL);
}
// Reinitialize the client.
mqtt_reinit(client, sockfd, rs->sendbuf, rs->sendbufsz, rs->recvbuf, rs->recvbufsz);
const char* client_id = NULL;
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
mqtt_connect(client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
mqtt_subscribe(client, rs->topic, 0);
}
*/
static int mqtt_receive(const char *addr, const char *port, const char *topic, const char *fn) {
// open the non-blocking TCP socket (connecting to the broker)
int sockfd = open_nb_socket(addr, port);
if (sockfd == -1) {
PrintAndLogEx(FAILED, "Failed to open socket");
return mqtt_exit(PM3_EFAILED, sockfd, NULL);
}
uint8_t sendbuf[MQTT_BUFFER_SIZE]; // 64kb sendbuf should be large enough to hold multiple whole mqtt messages
uint8_t recvbuf[MQTT_BUFFER_SIZE]; // 64kb recvbuf should be large enough any whole mqtt message expected to be received
struct mqtt_client client;
/*
struct reconnect_state_t rs;
rs.hostname = addr;
rs.port = port;
rs.topic = topic;
rs.sendbuf = sendbuf;
rs.sendbufsz = sizeof(sendbuf);
rs.recvbuf = recvbuf;
rs.recvbufsz = sizeof(recvbuf);
mqtt_init_reconnect(&client, mqtt_reconnect_client, &rs, mqtt_publish_callback);
*/
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), mqtt_publish_callback);
char cid[20] = "pm3_";
sprintf(cid + strlen(cid), "%02x%02x%02x%02x"
, rand() % 0xFF
, rand() % 0xFF
, rand() % 0xFF
, rand() % 0xFF
);
// Ensure we have a clean session
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
// Send connection request to the broker
mqtt_connect(&client, cid, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
// check that we don't have any errors
if (client.error != MQTT_OK) {
PrintAndLogEx(FAILED, "error: %s", mqtt_error_str(client.error));
return mqtt_exit(PM3_ESOFT, sockfd, NULL);
}
// start a thread to refresh the client (handle egress and ingree client traffic)
pthread_t client_daemon;
if (pthread_create(&client_daemon, NULL, mqtt_client_refresher, &client)) {
PrintAndLogEx(FAILED, "Failed to start client daemon");
return mqtt_exit(PM3_ESOFT, sockfd, NULL);
}
// subscribe to a topic with a max QoS level of 0
mqtt_subscribe(&client, topic, 0);
PrintAndLogEx(INFO, _CYAN_("%s") " listening at " _CYAN_("%s:%s") " for " _YELLOW_("%s") " messages", cid, addr, port, topic);
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
while (kbd_enter_pressed() == false) {
msleep(2000);
};
PrintAndLogEx(INFO, _CYAN_("%s") " disconnecting from " _CYAN_("%s"), cid, addr);
return mqtt_exit(PM3_SUCCESS, sockfd, &client_daemon);
}
static int mqtt_send(const char *addr, const char *port, const char *topic, char *msg, const char *fn) {
uint8_t *data;
size_t bytes_read = 0;
if (fn != NULL) {
int res = loadFile_TXTsafe(fn, "", (void **)&data, &bytes_read, true);
if (res != PM3_SUCCESS) {
return res;
}
}
// open the non-blocking TCP socket (connecting to the broker)
int sockfd = open_nb_socket(addr, port);
if (sockfd == -1) {
PrintAndLogEx(FAILED, "Failed to open socket");
return mqtt_exit(PM3_EFAILED, sockfd, NULL);
}
struct mqtt_client client;
uint8_t sendbuf[MQTT_BUFFER_SIZE];
uint8_t recvbuf[MQTT_BUFFER_SIZE];
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), mqtt_publish_callback);
char cid[20] = "pm3_";
sprintf(cid + strlen(cid), "%02x%02x%02x%02x"
, rand() % 0xFF
, rand() % 0xFF
, rand() % 0xFF
, rand() % 0xFF
);
// Ensure we have a clean session
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
// Send connection request to the broker
mqtt_connect(&client, cid, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
// check that we don't have any errors
if (client.error != MQTT_OK) {
PrintAndLogEx(FAILED, "error: %s", mqtt_error_str(client.error));
mqtt_exit(PM3_EFAILED, sockfd, NULL);
}
// start a thread to refresh the client (handle egress and ingree client traffic)
pthread_t client_daemon;
if (pthread_create(&client_daemon, NULL, mqtt_client_refresher, &client)) {
PrintAndLogEx(FAILED, "Failed to start client daemon");
mqtt_exit(PM3_EFAILED, sockfd, NULL);
}
PrintAndLogEx(INFO, _CYAN_("%s") " is ready", cid);
if (fn != NULL) {
PrintAndLogEx(INFO, "Publishing file...");
mqtt_publish(&client, topic, data, bytes_read, MQTT_PUBLISH_QOS_0);
} else {
PrintAndLogEx(INFO, "Publishing message...");
mqtt_publish(&client, topic, msg, strlen(msg) + 1, MQTT_PUBLISH_QOS_0);
}
if (client.error != MQTT_OK) {
PrintAndLogEx(INFO, "error: %s", mqtt_error_str(client.error));
mqtt_exit(PM3_ESOFT, sockfd, &client_daemon);
}
msleep(4000);
PrintAndLogEx(INFO, _CYAN_("%s") " disconnecting from " _CYAN_("%s"), cid, addr);
return mqtt_exit(PM3_SUCCESS, sockfd, &client_daemon);
}
static int CmdMqttSend(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mqtt send",
"This command send MQTT messages. You can send JSON file\n"
"Default server: proxdump.com:1883 topic: proxdump\n",
"mqtt send --msg \"Hello from Pm3\" --> sending msg to default server/port/topic\n"
"mqtt send -f myfile.json --> sending file to default server/port/topic\n"
"mqtt send --addr test.mosquitto.org -p 1883 --topic pm3 --msg \"custom mqtt server \"\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0(NULL, "addr", "<str>", "MQTT server address"),
arg_str0("p", "port", "<str>", "MQTT server port"),
arg_str0(NULL, "topic", "<str>", "MQTT topic"),
arg_str0(NULL, "msg", "<str>", "Message to send over MQTT"),
arg_str0("f", "file", "<fn>", "file to send"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int alen = 0;
char addr[256] = {0x00};
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)addr, sizeof(addr), &alen);
int plen = 0;
char port[10 + 1] = {0x00};
res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)port, sizeof(port), &plen);
int tlen = 0;
char topic[128] = {0x00};
res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)topic, sizeof(topic), &tlen);
int mlen = 0;
char msg[128] = {0x00};
res = CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)msg, sizeof(msg), &mlen);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
// Error message if... an error occured.
if (res) {
PrintAndLogEx(FAILED, "Error parsing input strings");
return PM3_EINVARG;
}
if (alen == 0) {
strcpy(addr, "proxdump.com");
}
if (plen == 0) {
strcpy(port, "1883");
}
if (tlen == 0) {
strcpy(topic, "proxdump");
}
if (fnlen) {
return mqtt_send(addr, port, topic, NULL, filename);
}
if (mlen) {
return mqtt_send(addr, port, topic, msg, NULL);
}
return PM3_SUCCESS;
}
static int CmdMqttReceive(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mqtt receive",
"This command receives MQTT messages. JSON text will be saved to file if detected\n"
"Default server: proxdump.com:1883 topic: proxdump\n",
"mqtt receive --> listening to default server/port/topic\n"
"mqtt receive --addr test.mosquitto.org -p 1883 --topic pm3\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0(NULL, "addr", "<str>", "MQTT server address"),
arg_str0("p", "port", "<str>", "MQTT server port"),
arg_str0(NULL, "topic", "<str>", "MQTT topic"),
arg_str0("f", "file", "<fn>", "file name to use for received files"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int alen = 0;
char addr[256] = {0x00};
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)addr, sizeof(addr), &alen);
int plen = 0;
char port[10 + 1] = {0x00};
res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)port, sizeof(port), &plen);
int tlen = 0;
char topic[128] = {0x00};
res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)topic, sizeof(topic), &tlen);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
// Error message if... an error occured.
if (res) {
PrintAndLogEx(FAILED, "Error parsing input strings");
return PM3_EINVARG;
}
if (alen == 0) {
strcpy(addr, "proxdump.com");
}
if (plen == 0) {
strcpy(port, "1883");
}
if (tlen == 0) {
strcpy(topic, "proxdump");
}
return mqtt_receive(addr, port, topic, filename);
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"send", CmdMqttSend, AlwaysAvailable, "Send messages or json file over MQTT"},
{"receive", CmdMqttReceive, AlwaysAvailable, "Receive message or json file over MQTT"},
{NULL, NULL, NULL, NULL}
};
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable);
return 0;
}
int CmdMqtt(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}

26
client/src/cmdmqtt.h Normal file
View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// 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, either version 3 of the License, or
// (at your option) any later version.
//
// 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.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// MQTT commands
//-----------------------------------------------------------------------------
#ifndef CMDMQTT_H__
#define CMDMQTT_H__
#include "common.h"
int CmdMqtt(const char *Cmd);
#endif

View file

@ -278,7 +278,7 @@ int saveFileEx(const char *preferredName, const char *suffix, const void *data,
// Opening file for writing in binary mode
FILE *f = fopen(fileName, "wb");
if (!f) {
if (f == NULL) {
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
free(fileName);
return PM3_EFILE;
@ -291,6 +291,33 @@ int saveFileEx(const char *preferredName, const char *suffix, const void *data,
return PM3_SUCCESS;
}
int saveFileTXT(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path) {
if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopyEx(preferredName, suffix, e_save_path);
if (fileName == NULL) {
return PM3_EMALLOC;
}
// We should have a valid filename now, e.g. dumpdata-3.txt
// Opening file for writing in text mode
FILE *f = fopen(fileName, "w");
if (f == NULL) {
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
free(fileName);
return PM3_EFILE;
}
fwrite(data, 1, datalen, f);
fflush(f);
fclose(f);
PrintAndLogEx(SUCCESS, "Saved " _YELLOW_("%zu") " bytes to text file `" _YELLOW_("%s") "`", datalen, fileName);
free(fileName);
return PM3_SUCCESS;
}
int prepareJSON(json_t *root, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
if (ftype != jsfCustom) {
if (data == NULL || datalen == 0) {
@ -794,8 +821,9 @@ int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool v
}
int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite, savePaths_t e_save_path) {
if (root == NULL)
if (root == NULL) {
return PM3_EINVARG;
}
char *filename = NULL;
if (overwrite)
@ -975,7 +1003,7 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
}
FILE *f = fopen(path, "rb");
if (!f) {
if (f == NULL) {
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
free(path);
return PM3_EFILE;
@ -1018,6 +1046,58 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
return PM3_SUCCESS;
}
int loadFile_TXTsafe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose) {
char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false);
if (res != PM3_SUCCESS) {
return PM3_EFILE;
}
FILE *f = fopen(path, "r");
if (f == NULL) {
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
free(path);
return PM3_EFILE;
}
free(path);
// get filesize in order to malloc memory
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize <= 0) {
PrintAndLogEx(FAILED, "error, when getting filesize");
fclose(f);
return PM3_EFILE;
}
*pdata = calloc(fsize, sizeof(uint8_t));
if (*pdata == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
fclose(f);
return PM3_EMALLOC;
}
size_t bytes_read = fread(*pdata, 1, fsize, f);
fclose(f);
if (bytes_read != fsize) {
PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
free(*pdata);
return PM3_EFILE;
}
*datalen = bytes_read;
if (verbose) {
PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from text file `" _YELLOW_("%s") "`", bytes_read, preferredName);
}
return PM3_SUCCESS;
}
int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
@ -1121,7 +1201,7 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s
}
FILE *f = fopen(path, "r");
if (!f) {
if (f == NULL) {
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
free(path);
return PM3_EFILE;
@ -1446,7 +1526,9 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_
}
int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, bool verbose, void (*callback)(json_t *)) {
if (data == NULL) return PM3_EINVARG;
if (data == NULL) {
return PM3_EINVARG;
}
*datalen = 0;
int retval = PM3_SUCCESS;
@ -2629,6 +2711,10 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool
*dump_type = NFC_DF_14_4A;
break;
}
if (str_startswith(line, "device type: iso15693")) {
*dump_type = NFC_DF_15;
break;
}
if (str_startswith(line, "filetype: flipper picopass device")) {
*dump_type = NFC_DF_PICOPASS;
break;
@ -2661,6 +2747,8 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool
case NFC_DF_PICOPASS:
PrintAndLogEx(INFO, "Detected PICOPASS based dump format");
break;
case NFC_DF_15:
PrintAndLogEx(INFO, "Detected ISO15693 based dump format");
case NFC_DF_UNKNOWN:
PrintAndLogEx(WARNING, "Failed to detected dump format");
break;
@ -3210,7 +3298,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
break;
}
if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS) {
if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS || dumptype == NFC_DF_15) {
*pdump = calloc(maxdumplen, sizeof(uint8_t));
if (*pdump == NULL) {
@ -3247,6 +3335,7 @@ int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
PrintAndLogEx(INFO, "No data to save, skipping...");
return PM3_EINVARG;
}
saveFile(fn, ".bin", d, n);
saveFileJSON(fn, jsft, d, n, NULL);
return PM3_SUCCESS;

View file

@ -100,9 +100,16 @@ typedef enum {
NFC_DF_14_3A,
NFC_DF_14_3B,
NFC_DF_14_4A,
NFC_DF_15,
NFC_DF_PICOPASS,
} nfc_df_e;
typedef enum {
ISO15_DF_UNKNOWN,
ISO15_DF_V4_BIN,
ISO15_DF_V5_BIN
} iso15_df_e;
int fileExists(const char *filename);
// set a path in the path list g_session.defaultPaths
@ -116,7 +123,7 @@ void truncate_filename(char *fn, uint16_t maxlen);
/**
* @brief Utility function to save data to a binary file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
* E.g. dumpdata-15.bin
*
* @param preferredName
* @param suffix the file suffix. Including the ".".
@ -127,6 +134,19 @@ void truncate_filename(char *fn, uint16_t maxlen);
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen);
int saveFileEx(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path);
/**
* @brief Utility function to save data to a text file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
*
* @param preferredName
* @param suffix the file suffix. Including the ".".
* @param data The binary data to write to the file
* @param datalen the length of the data
* @return 0 for ok, 1 for failz
*/
int saveFileTXT(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path);
/** STUB
* @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
@ -190,6 +210,19 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector
*/
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen);
int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose);
/**
* @brief Utility function to load a text file. This method takes a preferred name.
* E.g. dumpdata-15.json, tries to search for it, and allocated memory.
*
* @param preferredName
* @param suffix the file suffix. Including the ".".
* @param data The data array to store the loaded bytes from file
* @param datalen the number of bytes loaded from file
* @return PM3_SUCCESS for ok, PM3_E* for failz
*/
int loadFile_TXTsafe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose);
/**
* @brief Utility function to load data from a textfile (EML). This method takes a preferred name.
* E.g. dumpdata-15.txt

View file

@ -575,10 +575,11 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin
size_t sentdatalen = 0;
while (cdatalen >= sentdatalen) {
if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN)
if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN) {
len = DESFIRE_TX_FRAME_MAX_LEN;
else
} else {
len = cdatalen - sentdatalen;
}
size_t sendindx = sentdatalen;
size_t sendlen = len;
@ -657,8 +658,9 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin
}
pos += buflen;
if (rcode != MFDES_ADDITIONAL_FRAME)
if (rcode != MFDES_ADDITIONAL_FRAME) {
break;
}
}
if (resplen) {
@ -969,12 +971,14 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext_t *ctx, uint32_t aid) {
ctx->secureChannel = DACNone;
int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0);
if (res == PM3_SUCCESS) {
if (resplen != 0)
if (resplen != 0) {
return PM3_ECARDEXCHANGE;
}
// select operation fail
if (respcode != MFDES_S_OPERATION_OK)
if (respcode != MFDES_S_OPERATION_OK) {
return PM3_EAPDU_FAIL;
}
DesfireClearSession(ctx);
ctx->appSelected = (aid != 0x000000);

View file

@ -832,6 +832,9 @@ const static vocabulary_t vocabulary[] = {
{ 0, "mem spiffs upload" },
{ 0, "mem spiffs view" },
{ 0, "mem spiffs wipe" },
{ 1, "mqtt help" },
{ 1, "mqtt send" },
{ 1, "mqtt receive" },
{ 1, "nfc help" },
{ 1, "nfc decode" },
{ 0, "nfc type1 read" },

View file

@ -17,14 +17,12 @@
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <ctype.h>
#include <libgen.h> // basename
#include <time.h>
#include "pm3line.h"
#include "usart_defs.h"
#include "util_posix.h"
@ -43,7 +41,6 @@
#include <locale.h>
#endif
static int mainret = PM3_SUCCESS;
#ifndef LIBPM3
@ -209,7 +206,6 @@ static void showBanner(void) {
PrintAndLogEx(NORMAL, " [ " _YELLOW_("%s!")" :coffee: ]", get_quote());
// PrintAndLogEx(NORMAL, " [ https://patreon.com/iceman1001/ ]");
// PrintAndLogEx(NORMAL, "");
// PrintAndLogEx(NORMAL, " Monero");
// PrintAndLogEx(NORMAL, " 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
PrintAndLogEx(NORMAL, "");

View file

@ -75,6 +75,7 @@ typedef struct {
int calculate_hours_between_dates(const Date_t s, Date_t *e);
void add_minutes(Date_t *d, int minutes_to_add);
void add_hours(Date_t *d, int hours_to_add);
void add_days(Date_t *d, int days_to_add);
uint8_t days_in_month(int year, int month);

View file

@ -29,7 +29,7 @@ typedef struct {
enum {
TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr
TAG_STATE_ACTIVATING = 0x02, // In activation phase (password mode), sent UID, awaiting reader password
TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands
// TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands
TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written
} state;
uint16_t active_sector;

View file

@ -1136,7 +1136,7 @@
},
"help": {
"command": "help",
"description": "help Use `<command> help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
"description": "help Use `<command> help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } mqtt { MQTT commmands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
"notes": [
"auto"
],
@ -12331,6 +12331,42 @@
],
"usage": "mem wipe [-h] [-p <dec>]"
},
"mqtt help": {
"command": "mqtt help",
"description": "help This help send Send messages or json file over MQTT receive Receive message or json file over MQTT --------------------------------------------------------------------------------------- mqtt send available offline: yes This command send MQTT messages. You can send JSON file Default server: proxdump.com:1883 topic: proxdump",
"notes": [
"mqtt send --msg \"Hello from Pm3\" -> sending msg to default server/port/topic",
"mqtt send -f myfile.json -> sending file to default server/port/topic",
"mqtt send --addr test.mosquitto.org -p 1883 --topic pm3 --msg \"custom mqtt server \""
],
"offline": true,
"options": [
"-h, --help This help",
"--addr <str> MQTT server address",
"-p, --port <str> MQTT server port",
"--topic <str> MQTT topic",
"--msg <str> Message to send over MQTT",
"-f, --file <fn> file to send"
],
"usage": "mqtt send [-h] [--addr <str>] [-p <str>] [--topic <str>] [--msg <str>] [-f <fn>]"
},
"mqtt receive": {
"command": "mqtt receive",
"description": "This command receives MQTT messages. JSON text will be saved to file if detected Default server: proxdump.com:1883 topic: proxdump",
"notes": [
"mqtt receive -> listening to default server/port/topic",
"mqtt receive --addr test.mosquitto.org -p 1883 --topic pm3"
],
"offline": true,
"options": [
"-h, --help This help",
"--addr <str> MQTT server address",
"-p, --port <str> MQTT server port",
"--topic <str> MQTT topic",
"-f, --file <fn> file to send"
],
"usage": "mqtt receive [-h] [--addr <str>] [-p <str>] [--topic <str>] [-f <fn>]"
},
"msleep": {
"command": "msleep",
"description": "Sleep for given amount of milliseconds",
@ -13375,8 +13411,8 @@
}
},
"metadata": {
"commands_extracted": 768,
"commands_extracted": 770,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2025-07-06T18:10:18"
"extracted_on": "2025-07-08T19:08:23"
}
}

View file

@ -1414,6 +1414,17 @@ Check column "offline" for their availability.
|`mem spiffs wipe `|N |`Wipe all files from SPIFFS file system * dangerous *`
### mqtt
{ MQTT commmands... }
|command |offline |description
|------- |------- |-----------
|`mqtt help `|Y |`This help`
|`mqtt send `|Y |`Send messages or json file over MQTT`
|`mqtt receive `|Y |`Receive message or json file over MQTT`
### nfc
{ NFC commands... }

View file

@ -24,7 +24,8 @@
//-----------------------------------------------------------------------------
// iCLASS / PICOPASS
//-----------------------------------------------------------------------------
#define PICOPASS_BLOCK_SIZE 8
#define PICOPASS_BLOCK_SIZE ( 8 )
#define PICOPASS_MAX_BYTES ( 4096 ) // # 32k bits = 4096 bytes
// iCLASS reader flags
#define FLAG_ICLASS_READER_INIT 0x01
@ -197,5 +198,12 @@ typedef struct {
} header;
} PACKED iclass_card_select_resp_t;
typedef struct {
union {
picopass_hdr_t hdr;
picopass_ns_hdr_t ns_hdr;
} header;
uint8_t data[PICOPASS_MAX_BYTES];
} PACKED iclass_tag_t;
#endif // _ICLASS_H_