QR Chaos
by Edward Miro (a.k.a. c1ph0r)
Introduction
Malicious QR codes are not a new concept. They're built into the Social Engineering Toolkit (SET) and QRLJacking is going to be seen more and more with the ever growing use of "login with QR Code" on IoT devices, mobile apps, and Smart TVs.
Despite the inherent risk, the convenience of QR codes seems to be winning that proverbial struggle with security.
I live and teach cybersecurity for a community college in California and I was curious how easy it would be to get people in my town to scan QR codes in a completely unsolicited way. And in a way anyone can try themselves.
In the following article, I will present a write-up of my methodology and hopefully deliver it in a way to make it repeatable, interesting and informative.
Preparation
My plan for this experiment was to generate a trackable batch of QR codes with no text:
For this experiment, I will seek to establish a baseline by using unsolicited blank codes. It seems intuitive that coupling phrases such as "Free Beer!", "Scan Me!", "Hot Singles!", etc. would naturally increase the scan rate and hopefully this article will inspire further study and repeat experiments in this area.
I used Python3 to generate a batch of 100 ten-character random strings using only uppercase and lowercase alphabetic characters:
# python3 # qr.py import string import random N = 10 for i in range (100): qr = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase, k = N)) print(qr, end = "\n") #print()Saved that as qr.py, chmod +x, then run:
$ python3 qr.py > out.txtLooking at out.txt, we see that it created a list of strings:
$ cat out.txt ... LaQAULXkir GIMSZmUwst xtguldmsKF kyYJdEDolc ...Now we run:
$ sed -e 's#^#https://mirolabs.info/qrchaos.php?loc=#' out.txt > out2.txtThis will take each of our 100 random strings and prefix a URL to a very simple web page with a basic PHP script to create a log of interactions:
$ cat out2.txt ... https://mirolabs.info/qrchaos.php?loc=LaQAULXkir https://mirolabs.info/qrchaos.php?loc=GIMSZmUwst https://mirolabs.info/qrchaos.php?loc=xtguldmsKF https://mirolabs.info/qrchaos.php?loc=kyYJdEDolc ...The PHP code utilized on the back-end was:
<?php $ip = $_SERVER['REMOTE_ADDR']; $browser = $_SERVER['HTTP_USER_AGENT']; $referrer = $_SERVER['HTTP_REFERER']; $date = new DateTime('now'); $timestamp = $date->format('Y-m-d\TH:i:s.u'); if ($referrer == "") $referrer = "Location(http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']})"; error_log("$timestamp\nVisitor IP address: $ip\nBrowser: $browser\nReferrer: $referrer\n\n", 3, "2510522188994354"); ?>Nothing too crazy here. Just collecting the time stamp, device's IP address, device's browser, and the GET variable which is loc = (one of our random strings).
I pasted them into qrexplore.com/generate and then printed them in sheets with the filename added:
Now I have 100 QR codes that I cut into stacks of ten, and precut the filename so whoever placed the code can tear it off. That way, later on the details of placement can be logged and then future scans will tell us which locations were successful.
I provided all my volunteers a shared Google Sheet that they could use to log placements:
Execution
I personally placed 30 codes, mostly on campus and a few other public parks and public places. I passed out the remaining seven ten-packs to students in the computer science club on campus and to a few close friends. I encouraged them to place them in publicly accessible areas and didn't give them too much guidance. In hindsight, I'd be more specific due to some of my codes ending up on a WalMart shelf strip.
Of the remaining 70, only ten were logged on my sheet, and I found later on that I didn't make the logging necessity and procedure as clear as I should have to many of my volunteers. If you repeat or expand this experiment with your students or cybersecurity club, I recommend walking all the participants through the logging process and explaining the reasoning behind it.
That being said, the experiment immediately lost any scientific integrity because it's not really possible for us to know just how many were placed and where. I'm happy to downgrade this article to a proof-of-concept in the spirit of accuracy.
I let the experiment run from November 1, 2019 to February 1, 2020 for a total of 92 days. My original plan was to let it run until it had been 30 days since the last scan, expecting it to only last a month or so due to codes being lost or removed through natural process.
However, I kept getting scans all the way until January 31, 2020, so clearly my hypothesis that they would eventually be removed organically through maintenance or user interaction was not accurate. Indeed, some of them are still out there and I removed the PHP script from the page and also added this message:
Results
Total logs: 16 Unique codes scanned: 7 Top performers: poUw4fqXRG x 4 JEML2YzIWN x 3 MBxNRuigUK x 2 uZ77BL6nAl x 2 brpoOaYIOW x 2 HOedSV4fkm x 1 QvKBMyPMSt x 1 Scan x 1For the curious, those location variables map to the following locations:
poUw4fqXRG= ButteCollegeMain/garden/gate JEML2Yz1WN= ButteCollegeMain/MediaCenter/bulletin-board MBxNRuigUK= BidwellParkTrailhead/bulletin-board uZ77BL6nA1= ButteCollegeMain/PhysSciBldg/bulletin-board-1 brpoOaYI0W= ButteCollegeMain/PhysSc iBldg/bulletin-board-2 HOed5V4fkm= ButteCollegeChico/1stFloor/bulletin-boar d QvKBMyPMSt= ChicoStateMain/GlennHall/bulletin-board scan= [unknown]Other Stats
- Seven of the 16 IP addresses using campus access points.
- Four were using the Verizon network.
- Three were scanned from a group chat on Facebook.
- One was using AT&T.
- One was from www.qrstuff.com in Dublin, Ireland.
- Six were using Android, all of which were Samsung.
- Six were using iPhone.
- Three of the devices used Snapchat to scan code.
Full Log
2019-11-01T17:58:40.756004 Visitor IP address: [REDACTED] Browser: Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-T380) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/10.1 Chrome/71.0.3578.99 Safari/537.36 Referrer: Location(http://mirolabs.info/qrchaos.php?loc=poUw4fqXRG) 2019-11-02T17:19:45.275127 Visitor IP address: [REDACTED] Browser: facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) Referrer: Location(http://mirolabs.info/qrchaos.php?loc=poUw4fqXRG) 2019-11-02T17:22:04.550677 Visitor IP address: [REDACTED] Browser: facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) Referrer: Location(http://mirolabs.info/qrchaos.php?loc=poUw4fqXRG) 2019-11-02T20:59:51.173048 Visitor IP address: [REDACTED] Browser: facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) Referrer: Location(http://mirolabs.info/qrchaos.php?loc=poUw4fqXRG) 2019-11-12T22:27:43.615346 Visitor IP address: [REDACTED] Browser: Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Snapchat/10.69.5.72 (iPhone12,1; iOS 13.1.3; gzip) Referrer: Location(http://mirolabs.info/qrchaos.php?loc=HOed5V4fkm ) 2019-11-14T03:15:40.643039 Visitor IP address: [REDACTED] Browser: Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Referrer: Location(http://mirolabs.info/qrchaos.php?loc=MBxNRuigUK) ....Conclusion
Of the 38 QR codes that were placed and logged, we had a 42 percent success rate.
This data supports my initial hypothesis that random people will scan an unsolicited and unmarked QR code in the wild.
Obviously, if an attacker used this vector and directed users' devices to phishing pages, malware, etc., we can expect this to have a high rate of success.
Ideas For Higher Scan Rates
- Utilizing fun or enticing phrases on malicious codes.
- Making counterfeit flyers or posters.
- Pasting malicious codes over legitimate codes.
- Injecting malicious codes into the production process/supply chain.
I would predict a sufficiently motivated attacker could have a major impact.
Attacks could also be geographically targeted in a way that differs from other "-ishing" vectors.
Recommendations
The QR code attack vector will require utilizing some of the same techniques used in detecting attacks such as phishing:
- Don't scan QR codes - you can't ever truly know if the QR code you're about to scan is safe or not.
- Inspect the code - use a QR code app that allows you to look at the URL before opening it in a browser.
- Check to see if it's a sticker. If the code has been added after printing, do not scan it.
- Use a security-centric QR code scanning app that scans links. I won't make any recommendations, but they do exist
Special Thanks: Butte College Computer Science Club students, Gary Adams, Kevin Johnson, NM. If you have any questions or want to contact me: Edward Miro (a.k.a. c1ph0r, c1ph0r.github.io, @c1ph0r, c1ph0r@protonmail.com.
Code: qr.py