Printing Fake Fiscal Receipts - An Italian Job p.1


Italretail SpiceT fiscal printer allows any installed Android app to talk to the fiscal unit to print receipts, forge data in the Electronic Journal, open the cash drawer, etc.


In this post series I will walk you through the vulnerabilities I’ve found during my research time on a fiscal printer model that is widely used in Italy.

Lets take a step back to better understand what we are talking about.

The fiscal printer is a part of a cash register, a tool introduced by the italian revenue agency back in 1983 in order to prevent tax evasion. The cash register, also called in Italian misuratore fiscale or registratore di cassa, is used to keep track of all the incomes a retailer would get in a day. It was originally equipped with 2 paper rolls, the first used to print a receipt for the customer, the other kept by the retailer as a proof of their sales to show in case of a fiscal control. Since the 2000s technology led to new models where the second paper roll was replaced by a digital memory and nowadays there are telematic cash registers (registratore telematico), devices connected to the internet, able to send the daily sales amount to the revenue agency each day.

The device physical integrity is still granted by a seal with a mark that identifies the vendor or the certified technician who operated on it but being internet-connected and with complex operating systems introduced a full spectrum of new potential threats.

The main driver for this research was the fact that since the 1st of January 2019 the Italian government made mandatory the use of telematic cash registers to prevent frauds and to ease the tax controls.

As Shielder we made a cross-vendor research and we mainly focused on two top tier models of the main vendors. In this post we will discuss some vulnerabilities I identified in the Italretail SpiceT.

What is a Fiscal Printer?

A fiscal printer is a thermal receipt printer that includes a special fiscal memory module.

This module is used to record every transaction processed by the printer inside an append-only internal memory and a special SD card called DGFE (Dispositivo Giornale di Fondo Elettronico/Memoria Permanente di Dettaglio) used as an electronic journal memory.

It is also used to sync online all the transaction to the Agenzia delle Entrate website (the tax regulator entity in the Italian government).

Fiscal Printer Architecture

Most of the fiscal printers follow the same architecture composed of 2 different units: the fiscal unit and the management unit.

The fiscal unit usually is an MCU that connects with the fiscal memory module, the electronic journal memories, the PoS devices like the printer, the cash drawer, secondary/customer displays, etc. The fiscal unit runs a firmware that is certified by the Agenzia delle Entrate.

On the other hand, the management unit contains the generic purpose modules like the Ethernet connections, USB controllers, touch/input panels, TFT displays. The management unit runs a fully-fledge operative system usually based on GNU/Linux or Android.

The Italretail SpiceT fiscal printer is an Android-based fiscal printer that immediately caught my interest. The SpiceT’s management unit uses a Freescale i.MX6 SoC mounting a Dual Core ARM Cortex-A9 processor. It runs Android 6 with kernel version 4.1.15 and security patches dated 1 March 2016. The fiscal unit of the SpiceT uses a Renesas MCU.

The two units exchange data by using a serial UART connection. Keep this in mind since it will be useful later.

The picture below highlights the SpiceT architecture:

Welcome to the Android Permission System

Before diving into the fiscal unit inner workings, we need to understand how the management unit is implemented, since it will be our main attack surface.

The Android 6 version that comes installed on the SpiceT is a custom ROM image. Unexpectedly, some third party apps come preinstalled as system apps, namely ES File Explorer (, Net Ping (, Cactus Player (com.freescale.cactusplayer), and Ethernet (com.fsl.ethernet).

Other than those, there are 3-4 custom apps from Italretail installed as user apps. The operator usually installs them from a USB key by using the ES File Explorer and enabling “Install packages from untrusted origins” as part of the process.

When an app is installed, the Android Operative System creates a new Linux user and group dedicated to that app. Linux users and groups for third party apps are in the u0_aN format and have id starting from 10000.

When an app is opened, the Android Runtime executes a new process (forking from the zygote one) and dropping the privileges to the Linux user and group related to that specific app.

On top of the Linux privilege and capability system providing Discretionary Access Control (DAC), Android also come with SELinux (SEAndroid) configured and enforced. SEAndroid implements a Mandatory Access Control (MAC) layer that limits privileges for subjects (processes) and objects (file, socket, device, etc.).

This allows to sandbox and isolate apps from each other and from the system, prevents privilege escalations by apps, allows application privileges to be controlled at installation and runtime, and much more.

Security contexts are the base of SEAndroid. They are used to define the environment where a subject is living (being executed). A context is made of four parts: the user, the role, the type, and the sensitivity. For example, we can define a context as the following: u:object_r:rootfs:s0.

Every object on the system must be associated to a security context. For example it’s possible to associate the /etc/passwd file with the u:object_r:rootfs:s0 context.

Finally, type-enforcement policies are defined in order to allow or deny subjects performing specific actions on objects. For example the policy allow adbd rootfs : file { read getattr execute entrypoint open } ; will instruct the kernel to allow the adbd subject to perform the read getattr execute entrypoint open syscalls on every file object in the rootfs context.

Who Can Talk to the Fiscal Unit?

Like I’ve previously introduced, the communication between the management unit and the fiscal unit is done through a UART port. This port is exposed to Android OS thanks to the i.MX6 kernel via the /dev/ttymxc4 character device.

The ttymxc4 device is owned by the system user and group but it has the following permissions rw-rw-rw- meaning that anybody can read and write to the file regarding the DAC layer.

Now let’s see what SEAndroid and the MAC layer has to say about out it.
This rule from the /initrc/file_contexts file assigns the ttymxc objects to the owntty_device SELinux context.

/dev/ttymxc[0-9]*               u:object_r:owntty_device:s0

The following rules in the sepolicy file allow untrusted_app subjects (for example third-party apps that comes from the PlayStore or from APK files) to use the read, lock, getattr, write, ioctl, open, and append syscalls on the character file objects assigned with the tty and owntty context.

allow untrusted_app owntty_device:chr_file { read lock getattr write ioctl open append };
allow untrusted_app tty_device:chr_file { read lock getattr write ioctl open append };

Basically, any Android app on the device can send commands to the fiscal unit!

Time to Larn a New Protocol 🤓

The Italretail printers support two different communication protocols when talking with the fiscal unit, the XON/XOFF protocol and the CUSTOM protocol. Those protocols are standard, and a lot of documentation is available online.

The SpiceT preinstalled applications all seem to use the CUSTOM protocol, so I took a dive into it.

CUSTOM communication uses a Baud rate of 19200 or 57600 bps, odd parity, 7 bits data length and 1 bit stop.
CUSTOM packets are structured as follows: <STX><CNT><IDENT><CMD><CKS><ETX>

  • STX is the start frame signal, always set to 0x02.
  • CNT is the frame counter, takes 2 bytes from 00 to 99 (decimal).
  • IDENT is the packet identifier, made of 1 byte ASCII character.
  • CMD contains the command to be executed (4 bytes) and its parameters (variable size).
  • CKS contains the packet checksum as the sum modulo 100 of the CNT+IDENT+CMD fields.
  • ETX is the end frame signal, always set to 0x03.

If everything is fine, the fiscal unit replies with <ACK><CMD_HEADER><RESP>

  • ACK is always set to 0x06.
  • CMD_HEADER echoes the command that was executed (4 bytes).
  • RESP contains the result of the execution.

If during the execution there was an error, the fiscal unit replies with <NACK><ERRxx>, given that NACK is always 0x15.

The possible CUSTOM commands are divided in 8 macro categories:

  • 1xxx: Data request, used to gather information about the printer.
  • 2xxx: General fiscal operations like closing the fiscal day and storing receipts.
  • 3xxx: Fiscal documents operations, used to print fiscal receipts.
  • 4xxx: Non-fiscal documents operations.
  • 5xxx: Fiscal memory print operations.
  • 6xxx-7xxx: Generic commands.
  • 8xxx: DGFE IO operations.
  • 9xxx: Administrator commands, like firmware updates.

Printing Fake Money Receipts

The devil is in the details - that’s a lesson every security researcher should know, that’s why, even though I learnt the CUSTOM protocol I chose to also write a frida script to see which packets were actually exchanged. The script simply dumped the content of the write and read syscalls used to interact with the /dev/ttymxc4 device. Once started I used the SpiceT normally to a log of what was exchanged between the management unit and the fiscal one. Hopefully my speculations were correct and I started seeing logs about commands not documented in the CUSTOM command set 🤩.

It was finally the time to show off my Java skills to develop an Android app that let me send raw commands to the fiscal unit in order to perform some good ol’ dumb fuzzing.

This way I figured some interesting vulnerabilities!

NOTE: Some partial details of the vulnerabilities follow but the full proof of concepts will not be released to avoid easy abuses.

Fake Receipts

By sending the 4003 command and stopping the printer before closing the receipt it is possible to:

  • Start a legitimate receipt.
  • Pause the fiscal printer.
  • Print some fake receipts.
  • Close the legitimate receipt.

While at a first glance this might look harmless, it is not - in fact the fiscal unit would store just a fiscal receipt in the DGFE, while the shop manager could fake as many “fiscal” receipts as they want. At the same time the shop manager could also print fake reports during a fiscal verification. As the fiscal unit is certified to be tamper-proof and secure, the auditor would blindly trust what the fiscal unit prints.

Deleting/Writing/Overwriting Files on The DGFE

And finally, as a cherry on top, I discovered that I could delete, write and overwrite files stored in the fiscal append-only DGFE memory by sending the commands 741x.

See You, Space Cowboy.

In this post we saw the fiscal printer architecture, its local attack surface and how it’s possible to arbitrarily interact with the fiscal unit from the management one on the Italretail SpiceT.
In the next post of this series, we will analyze the management unit, its Android operative system and the Italretail RistorAndro app used to manage a restaurant. 🤫 what’s now a local vulnerability will be turned in a remote one 🤫

Pitch 🗣️

Bringing the “I” in your oT product is not just a matter of doing some good R&D and fundraising - a proper Threat Analysis is fundamental to deliver a secure product, even more when fiscal frauds might been involved. If you are developing similar products and you think you might have not considered some important threats and you want people used to break things having a look into it, then you should definitely get in touch with us: Last but not least: host a security.txt file under your main domain. Security researchers might find vulnerabilities in your products and they might be willing to report them to you. Having the contacts of your security team easily reachable is becoming more and more a standard, even though the RFC is still a draft but it definitely helps security researchers to get in touch to share important information about your products security.

Disclosure Timeline 🎢

  • 18/09/2020: Shielder discloses the vulnerabilities to Italretail
  • 22/10/2020: Shielder contacts CERT-AGID since it got no reply from Italretail
  • 22/10/2020: CERT-AGID shares the vulnerabilities with CERT-MEF
  • 11/01/2021: Shielder asks CERT-AGID for update about the case
  • 21/01/2021: CERT-AGID & CERT-MEF escalate to CERT-AdE
  • 06/10/2021: Shielder asks again for update
  • 06/10/2021: CERT-AGID acknowledge Shielder’s disclosure policy
  • 19/04/2022: Public Disclosure
8 min


19 April 2022



I’m thezero, Security Researcher and Senior Penetration Tester at Shielder.
In the office I’m the one with the soldering iron.