[HN Gopher] A QR code that sends you to a different destination ...
       ___________________________________________________________________
        
       A QR code that sends you to a different destination - lenticular
       and adversarial
        
       Author : zdw
       Score  : 517 points
       Date   : 2025-01-23 23:55 UTC (23 hours ago)
        
 (HTM) web link (mstdn.social)
 (TXT) w3m dump (mstdn.social)
        
       | ShakataGaNai wrote:
       | That is gnarly. My iPhone tended to lock into one or the other,
       | rotating the phone seemed to help it go one way or the other. But
       | a couple times it did flash back and forth between the Mastadon
       | and GitHub links.
        
       | re wrote:
       | (Scroll up from the starting position to see the lenticular one)
        
         | dang wrote:
         | Should we change the top link to
         | https://mstdn.social/@isziaui/113874436953157913?
        
           | winternewt wrote:
           | Yes please
        
             | dang wrote:
             | Weirdly, it already is! I don't understand what's going on
             | there. Are we getting sent to a different spot on the page
             | depending on what angle we click from?
        
       | 65 wrote:
       | This would be cool to use in a scavenger hunt.
        
         | TOMDM wrote:
         | Maybe make it so that you need the results of both (all?) QR
         | codes to get the final code/link/key.
        
           | rhet0rica wrote:
           | I summon QR Exodia!
        
       | buildbot wrote:
       | Interestingly, MacOS only sees the mastodon link when right
       | clicking on the QR code.
        
         | etrautmann wrote:
         | That makes sense, I would imagine it would require some
         | variability via a camera with different angles/lighting
         | conditions in order to get both links at different times.
        
         | tzs wrote:
         | That's also what Mathematica's BarcodeRecognize[] sees.
        
         | smashah wrote:
         | Can MacOS natively scan QR codes?
        
         | yoz-y wrote:
         | Funnily though, iOS recognizes the GitHub part when long
         | pressing on it.
        
       | Normal_gaussian wrote:
       | I guess an interesting attack would be a screen in a public
       | setting that alters the QR code based on information it has about
       | the current user, without appearing to change significantly.
       | 
       | setup:
       | 
       | - make the QR code as a half/half code
       | 
       | - have a system to decide preference of target based on external
       | input (e.g. camera based characteristic evaluation)
       | 
       | - make slight dynamic alterations to the colours of the code to
       | bias the probability of it being picked up as the desired target.
       | Desirable black/white can be made blacker/whiter, less desirable
       | less so.
       | 
       | Where to use it maliciously:
       | 
       | - anywhere where people provide feedback - present alternate
       | feedback forms to different demographics to engender the most
       | positive (or negative) results.
       | 
       | - pretend to offer some form of probabilistic chance to win a
       | prize, but bias winning to some identifiable characteristic. e.g.
       | race, age, "beauty"
       | 
       | - target a specific person - have them join a different WiFi
       | network, alter a payment page, etc.
       | 
       | In a static setting its less effective. I can't immediately think
       | of a static attack that benefits from siphoning some reduced
       | fraction of users.
       | 
       | I'm doubtful most people would notice a QR code dynamically
       | changing, particularly in most public lighting.
        
         | pockmarked19 wrote:
         | You don't need any of this if you control the app doing the
         | scanning (or the website/app handling the result).
        
           | Normal_gaussian wrote:
           | You wouldn't control the app doing the scanning.
           | 
           | The attack is that a user looking at a QR code cannot
           | determine that they are being served a different code to
           | another person.
           | 
           | In a public setting a user would have no idea they are even
           | capable of being targetted and treated differently.
        
             | t_mann wrote:
             | You don't even need to change the QR code to treat users
             | differently, that's the point. You just send users to some
             | fixed URL, which is by far the most common use for QR codes
             | (hence completely unsuspicious), and you decide who gets
             | served what there, based on whatever data you gathered
             | about them. And the users that would care are already
             | acutely aware that that's how a majority of the web works
             | nowadays, QR codes or not.
        
               | Normal_gaussian wrote:
               | The value of an attack vector is not negated by there
               | being other ways to achieve it.
               | 
               | This particular vector has the strength of being able to
               | manipulate things other than URLs; QR codes support WiFi
               | credentials, contact details, call, text (with content),
               | email (with content), calendar events. Additionally, many
               | app specific URIs never leave the device.
               | 
               | It has the significant downside of being plainly visible
               | as a possibility to those in the know.
               | 
               | However, I suspect it may still be desirable to do this
               | on the device rather than the server.
               | 
               | The other properties it varies are the obvious lack of
               | reliance on a server. The improved "transparency" of
               | showing the target URL for trust. The removal of the need
               | for an internet connection.
               | 
               | But for an implementer I'd imagine the most beneficial
               | upside is not needing to manage a timing-attack, and
               | gaining additional targetting accuracy in the common case
               | of a picture. There may also be organisational complexity
               | reduction in pushing all the decisioning to the
               | display/camera system.
               | 
               | Its fun to think about, with the significant weakness in
               | both its visibility and its probabilistic nature I
               | wouldn't expect widespread use.
        
             | csomar wrote:
             | Static Qr-Code but serve different content? If you are
             | targeting by the camera, you can try to link the person to
             | the time the QrCode was scanned and have each QrCode print
             | identified.
        
         | alan wrote:
         | Static a/b testing?
        
         | Normal_gaussian wrote:
         | Identifying this should be relatively easy in the core
         | libraries; finding alternate valid QR codes using "less
         | optimal" grids.
         | 
         | Of course the API confusion here becomes non-trivial, which
         | hampers securing against it. And with existing libraries being
         | widespread, its going to linger as an attack for a long time.
        
         | tbrownaw wrote:
         | > _pretend to offer some form of probabilistic chance to win a
         | prize, but bias winning to some identifiable characteristic.
         | e.g. race, age, "beauty"_
         | 
         | Do a facial recognition lookup against the RealID database (I'm
         | sure _someone_ must be selling a leaked or hacked copy by now)
         | and make the prize depend on the first letter of the person 's
         | last name.
        
         | t_mann wrote:
         | All of those could be done much more stealthily server-side,
         | though, I don't get what the QR code modification would add
         | here? Also, neither use case makes use of the hack described in
         | the OP. Where I could see an attack based on that hack would be
         | where an attacker plasters their code over a legitimate one. It
         | would be kind of random which code gets read, so they could
         | send some %-age of users to the original destination, hence
         | possibly delaying detection. But it doesn't seem a given that
         | this would compensate for the reduced traffic to their link.
        
           | post-it wrote:
           | Some sort of MITM attack by someone who owns the display but
           | not the server, maybe. Like a malicious ad company.
        
             | t_mann wrote:
             | Ok, but then I'd still prefer a method that sends users to
             | a unique URL. OP's method may help with obfuscating the
             | changing of the code, but I'm sure there are ways to better
             | achieve that without having to introduce this quasi-
             | randomness. The simplest would probably be to just to
             | regularly hide/show the code (which would happen anyway on
             | a typical digital ad display that cycles through a number
             | of ads).
        
               | post-it wrote:
               | But hypothetically, the owner of the ad might pop in and
               | make sure
               | 
               | 1. the ad looks correct, and
               | 
               | 2. the URL is the one they expect
               | 
               | So there may be a use case for a QR code that looks
               | _almost_ identical but goes somewhere else, allowing them
               | to swap it out while someone is looking at it without
               | them realizing.
               | 
               | A niche use case, to be sure, but being able to exploit a
               | niche vulnerability is a skill.
        
             | michaelmior wrote:
             | But if you own the display, you can send the user to
             | whatever server you want.
        
           | dspillett wrote:
           | _> All of those could be done much more stealthily server-
           | side, though, I don 't get what the QR code modification
           | would add here?_
           | 
           | Even if the adversary controls the server side as well, you
           | need to tell the server the information needed to make a
           | decision If you control everything that is easy enough too,
           | but perhaps you want to keep the decision-making process
           | local - for plausible deniability server-side, just to reduce
           | server & bandwidth load, or because you are sending people to
           | completely different destinations not just altering link
           | parameters.
           | 
           | Replacing the QR code more statically sends everyone to the
           | new address, not just the target(s), altering the QR code by
           | a bit or two (and the relevant error correction bits too) in
           | response to a pile of information available at the QR reading
           | site (feeds from cameras, and such) would be how the server
           | knows to react differently without having access to that
           | collection of information itself. You might want to use some
           | clever analysis to minimise the visual effect if you are
           | altering the QR code while it is already displayed - the two
           | examples here look very different, but the change could be
           | much more subtle. If sending to very different destinations,
           | so the codes for the URLs will look very different, then
           | adding a link anonymiser between would keep the change
           | minimal.
           | 
           |  _> Also, neither use case makes use of the hack described in
           | the OP._
           | 
           | True.
        
         | eieio wrote:
         | I appreciate you laying out malicious use-cases instead of just
         | having the setup section; I would have struggled to think of
         | those!
         | 
         | FWIW the place my brain went was some kind of magic trick,
         | since having control of this could function kind of like a
         | forcing a specific card or something
        
         | nroets wrote:
         | I guess similarly you can carefully craft a poster with a QR
         | code and put it on a wall in a room with two LED bulbs. The
         | bulbs will have different color temperature and the decoding
         | will be dependent on which bulb is lit.
         | 
         | Another idea would be a poster that's not quite flat: Each
         | pixel that is different is slightly raised (pyramid shaped) and
         | the sides of the pyramid is colored differently. So the QR code
         | scans differently from different sides.
         | 
         | One of the dominant banks here in Tbilisi allows sharing of
         | IBAN number as QR codes. In theory, the trick could be used to
         | steal money, but in practice, there are many safeguards such as
         | the banking app displaying the name of the beneficiary before
         | completing the process.
        
           | chii wrote:
           | > banking app displaying the name of the beneficiary
           | 
           | and the scammer make an account with a name that look similar
           | at a glance (e.g., swap the l with a 1, or something of the
           | sort).
        
             | fxtentacle wrote:
             | Most likely, they have <1s bank transfers, too, like pretty
             | much all of Asia. That way, if you pay someone with a QR
             | code, they'll immediately get the notification that they
             | received your payment. And if they don't, you immediately
             | know that something went wrong.
        
               | echoangle wrote:
               | But then it's too late, you have to find out before send
               | the money.
        
               | fxtentacle wrote:
               | Most scammers will try to avoid situations where you can
               | punch them in the face. => If scams usually get notified
               | before the perpetrator can run away, that will discourage
               | scamming. => In practice, it might be "good enough" if
               | you know immediately after sending money.
        
           | heeen2 wrote:
           | you could use glossy/matte or metallic finish, then the
           | reflected light could appear brighter than the white parts
        
         | michaelt wrote:
         | There are actually attacks based on changing public QR codes
         | already!
         | 
         | They don't need anything as sophisticated as this dual QR code,
         | though - the attackers just go to a car park with a "pay by
         | phone" sign, slap their own QR code over the "scan to pay"
         | code, and wait for the credit card details to start coming in.
        
           | Terr_ wrote:
           | Hmmm, there might be some criminal utility in capturing <100%
           | of visitors, so that the true owner doesn't easily realize
           | that activity for that location has ceased. In other words,
           | giving up a certain number of victims in order to keep the
           | attack going for longer.
           | 
           | That said, it'd probably be easier to implement that in
           | software, where the phishing site redirects a certain portion
           | of visits back to the legitimate one.
           | 
           |  _P.S.:_ There 's also the physical stealth aspect, but I
           | think a lenticular design would probably be _easier_ for a
           | human worker to notice, compared to a regular flat sticker
           | which just happens to encode a typo-squatting URL.
        
         | hnlmorg wrote:
         | > alters the QR code based on information it has about the
         | current user, without appearing to change significantly.
         | 
         | I doubt many people would notice if your average QR code was to
         | change significantly. Most machine readable formats are just
         | indistinguishable white noise to most people.
        
       | nixpulvis wrote:
       | The most interesting thing about this to me is that on iOS a long
       | press on the image claimed it's going to github.com, while the
       | preview itself was for mastadon. This indicates that it's parsing
       | the QR code twice and getting different results? I could see this
       | being used to mislead some people, though I'm not sire how many
       | people look at the long press dropdown URL.
        
         | noitpmeder wrote:
         | now THIS sounds like an exploit
        
         | codetrotter wrote:
         | Tangential but once in a blue moon I come by some situation
         | where I'm on my phone and I'm looking at something that has a
         | QR code showing on the screen of the phone itself.
         | 
         | And so I do something silly like airdropping a screenshot of it
         | to my laptop so I can scan it with my phone camera, or I get
         | someone else (friends, family) to use their phone to scan the
         | code from my phone screen with the camera app on their phone.
         | 
         | And all this time I was annoyed why I couldn't just get the
         | link directly from the image on my phone without involving
         | another device, and without having to install yet another
         | third-party app.
         | 
         | And today I learned that all I had to do was long press the QR
         | code in the screenshot in my camera roll and it would actually
         | parse it and make it so I could visit the link!
         | 
         | I think I must have tried long pressing QR code in an image in
         | the camera roll years ago because it always seemed like
         | something that would make sense to support via long press.
         | Maybe they introduced this feature after I had tried to long
         | press a QR code in an image in the past. Or maybe it was always
         | possible and I didn't actually ever try to long press it. Or
         | maybe I long pressed the wrong part of the image that first one
         | or two times I ever tried to do it in the past. Either way,
         | very happy to have learned that this is actually possible.
        
           | davchana wrote:
           | Yes, I usually share it with Google App, and Lens tab.
        
           | kccqzy wrote:
           | Long pressing still doesn't work for me. Perhaps because I
           | turned off some features related to image intelligence.
        
             | poglet wrote:
             | On iOS I believe the option is in Settings > General >
             | Language & Region > Live Text. This was introduced in iOS
             | 15.
        
         | _august wrote:
         | When I long-press on iOS, it shows me the mastadon link as the
         | main "Open" link, as well as "Open in Github" (app link) in the
         | context menu.
        
         | the_arun wrote:
         | QRCode should also show the target url in text, so the user
         | knows where it is taking - something like explicit consent.
        
           | jimjimwii wrote:
           | Yep, like how browsers show users urls in their location
           | bars.
        
         | russellbeattie wrote:
         | I can totally see two parts of the OS both using their own QR
         | parsing code - SmartText using one, and the imaging system
         | another. Apparently each one has their own slightly different
         | error correction implementation.
         | 
         | I bet it'd be possible to create a standard QR Code with a
         | deliberate error that does the same thing. You'd just have to
         | figure out how they're correcting the error differently.
         | 
         | Seems like you discovered a bug-bounty bug just waiting for
         | someone to claim.
        
         | layer8 wrote:
         | This is likely the typical case of related code calling the
         | same function or getter method twice in a context where it is
         | imperative for both calls to return the same result.
         | 
         | It is reminds me of code like                  if
         | someCondition(getFoo())         then doSomethingWith(getFoo())
         | 
         | or even just                   doSomethingWith(getFoo())
         | doAnotherThingWith(getFoo())
         | 
         | which is always a code smell, as opposed to
         | foo := getFoo()         if someCondition(foo)          then
         | doSomethingWith(foo)
         | 
         | and                   foo := getFoo()
         | doSomethingWith(foo)         doAnotherThingWith(foo)
        
           | pas wrote:
           | Usually it's called a TOCTOU bug/vuln
           | 
           | https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use
        
             | layer8 wrote:
             | I often see it in multiple-time-of-use scenarios as well
             | that need to be consistent, i.e. no check vs. use involved.
        
       | daft_pink wrote:
       | I don't really understand the value of this compared to just
       | putting another QR code right over the pre-existing code? Why
       | bother getting a fraction of users, when you can get all of them.
        
         | notRobot wrote:
         | The value is that it's cool.
        
       | hammock wrote:
       | Can someone explain how it works?
        
         | jkingsman wrote:
         | A QR code is just a series of square pixels, and whether the
         | pixel is black or white contributes to the data. This has two
         | QR codes, essentially overlayed one on the other. Some pixels
         | are half black/half white, so depending on the angle you hold
         | your phone at, the software that decodes QR codes will detect a
         | different color as being centered in the pixel it's examining.
         | So, based on the angle you hold your phone (some people had
         | better success with rotation), you get one QR code or the
         | other.
        
           | hammock wrote:
           | What is half black/white though? I don't see any gray. Only
           | black and white
           | 
           | Did he subdivide the qr code cell into four sub pixels and
           | make the left two one color and the right two another? That's
           | what I would have guessed for the "lenticular" effect at
           | different angles. But the subpixels I see are more
           | checkerboard ish
        
             | layer8 wrote:
             | QR code decoders usually work by sampling the values from a
             | dot grid overlayed on the camera image (or something along
             | those lines). If a QR square isn't actually uniform, the
             | sampled value for that square will change if you move the
             | camera a bit. When you hold a QR code in front of the
             | camera, the picture is continuously sampled, yielding
             | different bit values all the time because you don't hold
             | the camera a 100% still (in addition to sensor noise and
             | the like). The QR decoder is however satisfied as soon as
             | the result passes the QR checksum verification.
             | 
             | The image recognition that outputs the bit pattern of the
             | QR code is inherently heuristic in nature, and only the
             | checksum verification is what decides if the recognition
             | worked successfully. The trick in TFA is to produce an
             | image where two different results of the heuristics can
             | both pass the checksum verification, so which one you get
             | depends on circumstantial factors.
        
               | hammock wrote:
               | More non-deterministic than I would have thought. Your
               | explanation makes sense tho thanks
        
       | dwheeler wrote:
       | Shouldn't one of the URLs implement a Rick Roll :-) ?
        
       | jdoe1337halo wrote:
       | Hey guys I made a website so yall can try this out yourself! I
       | don't have the exact methodology that Christian uses, so here is
       | how I did it:
       | 
       | The ambiguous QR code in this application works by combining two
       | different QR codes into a single image using a diagonal split
       | pattern. When two QR codes have different patterns at the same
       | position, the cell is split diagonally - one half represents the
       | first QR code and the other half represents the second QR code.
       | When both QR codes have the same pattern at a position (both
       | black or both white), the cell is filled with a solid color. Due
       | to the high error correction capability of QR codes (using error
       | correction level 'H'), QR code scanners can still read either URL
       | depending on the scanning angle, though as noted in the UI, it
       | tends to favor the second URL more frequently.
       | 
       | https://dualqrcode.com/
        
         | HenryBemis wrote:
         | It didn't work for me. I generated two links (BBC, CNN) and
         | tried on my Android, with the app "QR & Barcode Scanner"
         | v2.2.47. I also tried with the stock camera of an iPhone 13. In
         | both they couldn't 'read' them.
        
           | Aachen wrote:
           | Doesn't scan from a screenshot in
           | https://f-droid.org/packages/com.atharok.barcodescanner/
           | either
        
           | jdoe1337halo wrote:
           | Strange, I am using an iPhone 12 pro max and it works for me.
           | I am going to keep playing around with different pixel
           | painting techniques and see if I can get a more reliable,
           | 50/50 split on both links. Thanks for trying!
        
       | sschueller wrote:
       | I had some trouble with the QR codes readers on my android but I
       | found this demo app[1] (they make a code reader SDK) that work
       | really well (you can also enable continues scanning so you can
       | see the result change as you change the angle).
       | 
       | [1]
       | https://play.google.com/store/apps/details?id=com.scandit.de...
        
       | mkl wrote:
       | My phone (Samsung Galaxy Note 20) seems to reject almost all of
       | these, and not recognise them as QR codes. I got one to work for
       | one URL by moving way away from the screen.
        
       | Joker_vD wrote:
       | Wait, don't QR codes have checksums in them? Or do they have some
       | sort of error correction built-in? That's the only way I can
       | imagine it can possibly work with e.g. 85% of one QR-code blended
       | with 15% of another one.
        
         | blueflow wrote:
         | Yes, but the checksum is in the same bitstream, so it is
         | swapped together with the data.
        
       | soheil wrote:
       | With the same link you can serve different content, QR codes
       | typically resolve to links.
       | 
       | Looking up user IP (and thus country of origin), user agent, etc
       | is enough to determine what content needs to be served.
        
       | andrewla wrote:
       | If you want to try it out, here's some quick and dirty code.
       | 
       | Install the qrcode python package and run this code:
       | import qrcode              bar = qrcode.QRCode(border=0)
       | bar.add_data('bar')         bar.make()         bar_mat =
       | bar.get_matrix()              foo = qrcode.QRCode(border=0)
       | foo.add_data('foo')         foo.make()         foo_mat =
       | foo.get_matrix()              for l, r in zip(foo_mat, bar_mat):
       | line = ''             for lc, rc in zip(l, r):
       | line = line + (lc and '\u2588' or ' ')                 line =
       | line + (rc and '\u2588' or ' ')             print(line)
       | print(line)
       | 
       | What you get is indeed a dualing qrcode (which I can't quite
       | paste here because no unicode on HN, and using "8" or "0" isn't
       | enough to get my phone to recognize it).
        
       | danvoell wrote:
       | This is such a cool concept! If you're focusing on the end goal,
       | another approach could be using a "switch" at the URL destination
       | --something that redirects users to a different page based on a
       | randomizer, user data, or other criteria. For anyone exploring
       | this kind of functionality and interested in testing physical
       | stickers for their projects, I work with a lot of SaaS companies
       | on variable labels and would be happy to share insights, print
       | some samples or collaborate.
        
       | trebligdivad wrote:
       | Someone needs to define a human-readable attachment to QR that
       | can be checked by the QR reader; e.g. the root of the URL printed
       | above the QR code at a specific position offset or with a
       | specific mark; so then the QR decoder could OCR it and verify it
       | matched the URL encoded. Only the root of the URL would be
       | included so the QR could include a specific to that location
       | complex path. Now, we just need to backronym SPQR to fit...
        
       | johnea wrote:
       | QR codes, like shortened URLs, are just begging to exploit.
       | 
       | It's an inherently unreadable URL, you really have no idea where
       | you will be sent, or how many times you will be redirected.
       | 
       | I don't use them...
        
       ___________________________________________________________________
       (page generated 2025-01-24 23:01 UTC)