Handlebars template injection and RCE in a Shopify app


TL;DR

We found a zero-day within a JavaScript template library called handlebars and used it to get Remote Code Execution in the Shopify Return Magic app.

The Story:

In October 2018, Shopify organized the HackerOne event "H1-514" to which some specific researchers were invited and I was one of them. Some of the Shopify apps that were in scope included an application called "Return Magic" that would automate the whole return process when a customer wants to return a product that they already purchased through a Shopify store.

Looking at the application, I found that it has a feature called Email WorkFlow where shop owners can customize the email message sent to users once they return a product. Users could use variables in their template such as {{order.number}} , {{email}} ..etc. I decided to test this feature for Server Side Template injection and entered {{this}} {{self}} then sent a test email to myself and the email had [object Object] within it which immediately attracted my attention.

So I spent a lot of time trying to find out what the template engine was, I searched for popular NodeJs templates and thought the template engine was mustache (wrong), I kept looking for mustache template injection online but nothing came up as Mustache is supposed to be a logicless template engine with no ability to call functions which made no sense as I was able to call some Object attributes such as {{this.__proto__}} and even call functions such as {{this.constructor.constructor}} which is the Function constructor. I kept trying to send parameters to this.constructor.constructor() but failed.

I decided that this was not vulnerable and moved on to look for more bugs. Then the fate decides that this bug needs to be found and I see a message from Shopify on the event slack channel asking researchers to submit their "almost bugs" so if someone found something and feels it's exploitable, they would send the bug to Shopify security team and if the team manages to exploit it the reporter will get paid as if they found it. Immediately I sent my submission explaining what I have found and at the impact section I wrote "Could be a Server Side template injection that can be used to take over the server ¯\_(ツ)_/¯".

Two months passed and I got no response from Shopify regarding my "almost bug" submission, then I was invited to another hacking event in Bali hosted by Synack. There I met the Synack Red Team and after the Synack event has ended, I was supposed to travel back to Egypt, but only 3 hours before the flight I decided to extended my stay for three more days then fly from Bali to Japan where I was supposed to participate in the TrendMicro CTF competition with my CTF team. Some of the SRT also decided to extend their stay in Bali. One of those was Matias so I contacted him to hangout together. After swimming in the ocean and enjoying the beautiful nature of Bali, we went to a restaurant for dinner where Matias told me about a bug he found in a bug bounty program that had something to do with JavaScript sandbox escape so we spent all night missing with objects and constructors, but unfortunately we couldn't escape the sandbox.

I couldn't take constructors out of my head and I remembered the template injection bug I found in Shopify. I looked at the HackerOne report and thought that the template can't be mustache so I installed mustache locally and when I parsed {{this}} with mustache it actually returns nothing which is not the case with the Shopify application. I searched again for popular NodeJs template engines and I found a bunch of them, I looked for those  that used curly brackets {{ }} for template expressions and downloaded them locally, one of the libraries was handlebars and when I parsed {{this}} it returned [object Object] which is the same as the Shopify app. I looked at handlebars documentation and found out that it's also supposed to not have much logic to prevent template injection attacks. But knowing that I can access the function constructor I decided to give it a try and see how I can pass parameters to functions.

After reading the documentation, I found out that in handlebars developers can register functions as helpers in the template scope. We can pass parameters to helpers like this {{helper "param1" "param2" ...params}}.  So the first thing I tried was {{this.constructor.constructor "console.log(process.pid)"}} but it just returned console.log(process.pid) as a string. I went to the source code to find out what was happening. At the runtime.js file, there was the following function:

  So what this function does is that it checks if the current object is of type 'function' and if so it just calls it using current.call(context) where context is the template scope, otherwise, it would just return the object itself.

I looked further in the documentation of handlebars and found out that it had built in helpers such as "with", "blockHelperMissing", "forEach" ...etc

After reading the source code for each helper, I had an exploitation in mind using the "with" helper as it is used to shift the context for a section of a template by using the built-in with block helper. So I would be able to perform curren.call(context) on my own context. So I tried the following:

Basically that should pass console.log(process.pid) as the current context, then when the handlebars compiler reaches this.constructor.constructor and finds that it's a function, it should call it with the current context as the function argument. Then using {{#with this}} we call the returned function from the Function constructor and console.log(process.pid) gets executed.

However, this did not work because function.call() is used to invoke a method with an owner object as an argument, so the first argument is the owner object and other arguments are the parameters sent to the function being called. So if the function was called like current.call(this, context), the previous payload would have worked.

I spent two more nights in Ubud then flew to Tokyo for the TrendMicro CTF. Again in Tokyo, I couldn't take objects and constructors out of my mind and kept trying to find a way to escape the sandbox.

I had another idea of using Array.map() to call Function constructor on my context, but it didn't work because the compiler always passes an extra argument to any function I call which is an object containing the template scope which causes an error as my payload is considered a function argument not the function body.



There seemed to be many possible ways to escape the sandbox but I had one big problem facing me which is that whenever a function is called within the template, the template compiler sends the template scope Object as the last parameter.

For example, if I try to call something like constructor.constructor("test","test"), the compiler will call it like constructor.constructor("test", "test", this) and this will be converted to a string by calling Object.toString() and the anonymous function created will be:
which will cause an error.

I tried many other things but still no luck, then I decided to open the JavaScript documentation for Object prototype and look for something that could help escape the sandbox.

I found out that I could overwrite the Object.prototype.toString() function using Object.prototype.defineProperty() so that it calls a function that returns a user controlled string (my payload).

Since I can't define functions using the template, all I have to do is to find a function that is already defined within the template scope and returns a user controlled input.

For example, the following nodejs application should be vulnerable:
test.js
example.html

Now if you run this template, console.log(process.pid) gets executed.
I reported that to Shopify and mentioned that if there was a function within the scope that returns a user controlled string, it would have been possible to get RCE.

Later, when I met Ibrahim (@the_st0rm) I told him about my idea and he told me that I can use bind() to create a new function that when called will return my RCE payload.
From JavaScript documentation:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.


So now the idea is to create a string  with whichever code I want to execute then bind its toString() to a function using bind() after that overwrite the Object.prototype.toString() function with that function.

I spent a lot of time trying to apply this using handlebars templates, and eventually during my flight back to Egypt I was able to get a fully working PoC with no need to use functions defined in the template scope.



Basically, what the template above does is:

And when I tried it with Shopify, I got:

Matias also texted me with an exploitation that he got which is much simpler than the one I used:

With that said, I was able to get RCE on Shopify's Return Magic application as well as some other websites that used handlebars as a template engine.

The vulnerability was also submitted to npm security and handlebars pushed a fix that disables access to constructors. The advisory can be found here: https://www.npmjs.com/advisories/755

In a nutshell

You can use the following to inject Handlebars templates:


Matias also had his own exploitation that is much simpler:

Sorry for the long post, if you have any questions please drop me a tweet @Zombiehelp54

Comments

  1. nice finding. keep it up and keep posting such interesting issues

    ReplyDelete
  2. the 2nd

    `{{#with (string.sub.apply 0 codelist)}}`

    its right?

    i think its should be `{{#with (this.apply 0 codelist)}}`

    ReplyDelete
    Replies
    1. When the template compiler calls `apply()` it calls it on the current context, which in this case is `conslist[0]` which is the function constructor. So the way you call `apply()` doesn't really matter as the compiler will always call it on the current context.
      Matias used `#each` helper to shift the context for the section where `apply()` is called to the Function constructor.
      Btw it wouldn't have been possible to use `#with` as the with helper has the following line in its implementation:
      ```
      if (_utils.isFunction(context)) {
      context = context.call(this);
      }
      ```
      Basically what this does is that it checks if the context is a function, and if so it calls it and sets the context to whichever the function returns and in that case it will be an anonymous function returned by the function constructor rather than the Function constructor itself.
      In my exploit, I used `#blockHelperMissing` which does the same thing as `#with` except that it doesn't have the `_utils.isFunction(context)` check.

      Thanks for the question.

      Delete
    2. Your comment actually made me rethink about how I used `apply()` to call `bind()` in my initial exploit. I should have just used `bind()` the same way `apply()` was used (by shifting the context to `str.toString`). I've modified the exploit so it becomes more clean and easy to understand.

      Thanks again, Unknown person!

      Delete
    3. Hi bro ... i found a company using handlebars with this same version ..can u send me your poc pls..

      Delete
  3. السلام عليكم اخي انا اريد ان اصبح باحث امني ارجو ان تساعدني باجوبة بسيطة اريد مسدر لتعلم الثغرات البرمجية و ما هي لغات البرمجة التي احتاجها مع العلم اني عندي خلفية بسيطة في الجافا و c++ و الاسامبلي

    ReplyDelete
  4. Great finding. I have been recently finding a most secure template engine for node.js. I went through all and most of them are not sandboxed i.e. allows RCE easily. Is it fixed by handlebars ?

    ReplyDelete
  5. it'll be nice to know which versions you've been referring to. RCE and XSS are not new to handlebars; were they using an outdated version?
    The link you referred to dates back to 2016, but your blog is in 2019.
    Great post btw! Thanks for sharing the details!

    ReplyDelete
    Replies
    1. Versions of handlebars prior to 4.0.14 were vulnerable. Also, the link date is Feb 14th, 2019.

      Delete
  6. Thanks for posting. Its an Important topic to be read.Node JS training in hyderabad

    ReplyDelete
  7. This is great information and all relevant to me. I know when I engage with my readers on my blog posts, not only does it encourage others to leave comments, but it makes my blog feel more like a community – exactly what I want!
    Data Science Training in Hyderabad

    Hadoop Training in Hyderabad

    Java Training in Hyderabad

    Python online Training in Hyderabad

    Tableau online Training in Hyderabad

    Blockchain online Training in Hyderabad

    informatica online Training in Hyderabad

    devops online Training

    ReplyDelete
  8. I like your post very much. It is very much useful for everyone. I hope you will share more info about this.
    Node JS Online training
    Node JS training in Hyderabad

    ReplyDelete
  9. I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously in their life, he/she can earn his living by doing blogging.thank you for thizs article. best devops online training

    ReplyDelete
  10. If you are suffering from muscle spasms, then visit wayrightmeds.com to get medication online of muscle spasms. You may also buy these products by clicking these below links.

    Buy Carisoprodol Online
    Buy Carisoprodol 350mg Online

    Buy Flexeril Online
    Buy Flexeril 5mg Online
    Buy Flexeril 10mgOnline

    Buy Soma Online
    Buy soma 250mg online
    Buy soma 350mg online

    ReplyDelete
  11. Welcome to the world of develop for MSK clinic.Best services provider in clinic. We provide genuine likes, followers and views to your Ultrasound guided injection.
    Regards
    Ultrasound guided injection

    ReplyDelete
  12. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    top servicenow online training

    ReplyDelete

  13. It was great experience after reading this. thanks for sharing such good stuff with us.
    JavaScript Institute in Delhi

    ReplyDelete
  14. This comment has been removed by the author.

    ReplyDelete
  15. This is the best operating system. Here anyone earn money easily. It is indeed an activity that can launched without great investment and which has many advantages such as automated order management and no stock management. shopify

    ReplyDelete
  16. If you are feeling very depressed, have any panic disorders, Mental Stress, Anxiety Disorders visit the page and resolve all these problams and also New Year Offer begain offer limited period.
    Call Now For Buy Anxiety Medicines at very cheap price as compair to other dealer: +1-850-424-1335
    Website: https://redditpharma.com/product/adderall-dosage/
    https://redditpharma.com/product/ambien-dosage/
    https://redditpharma.com/buy-alprazolam-online/
    https://redditpharma.com/buy-hydrocodone-online/
    https://redditpharma.com/buy-oxycodone-online/
    https://redditpharma.com/buy-codeine-online/

    ReplyDelete
  17. Tramadolus.org is a site with a mean to give quality substance to the perusers. The data about physician endorsed medications is spread across various stages over the web. Be that as it may, the believability of the data is constantly under steady discussion.
    Visit Us :-Tramadolus.org
    CALL US :- + 1-850-424-1335
    CONTACT US :- info@tramadolus.org
    Tramadolus|
    Tramadol Addiction/ Tramadol stay in system
    Tramadol Dosage| how log does tramadol 50mg stay in your system
    Tramadol SideEffects |How long does it take Tramadol to get out of your system

    ReplyDelete
  18. Buy highest quality generic drugs, xanax online, SSD chemical solution Online, with fast & free services.

    ReplyDelete
  19. topmedsreview: Provide the best information about anxiety, panic disorder, mental stress, depression, Hyperactivitys issuse. Top meds review is a social platform providing the best medical information, medicine review, and health guidance. Our website provides credible information, depth reference material about health subjects that matter to everyone.

    Anxiety Medicines
    Soma Addiction
    Types Of Xanax Bars

    ReplyDelete
  20. Buy Medicines Online from Ship From CA. No prescription is required for Buy Hydrocodone, Oxycodone, Percocet, Vicodin and Oxycontin Online Overnight from us
    Ship From CA
    Buy hydrocodone online
    Buy oxycodone online
    Buy vicodin online
    Buy norco online
    Buy percocet online
    Buy oxycontin online
    Buy adderall online
    Buy ambien online

    ReplyDelete
  21. Buy Hydrocodone Online. We provide Hydrocodone, Oxycodone, Percocet, Adderall without prescription also get discounts up to 35%. Call us +802-323-1095.
    Buy medionline

    ReplyDelete
  22. We are passionate pet lovers especially dogs and cats. At ImPetLover, we cover from Pet Resources, Gifts Guide, How to, Informational and everything else about their breeds and tricks.
    impetlover

    ReplyDelete
  23. Thanks for sharing this article. Save you huge money & time. Download the Tracedeals Online Deals & Coupons&Sign In to get daily alerts from your favorite stores
    Offers,Coupons & Deals App
    Coupons and Offers App for Shopping Online
    Online Shopping Deals & Coupons App
    Online Shopping Offers & Coupons App

    ReplyDelete
  24. We are passionate pet lovers especially dogs and cats. At impetlover, we cover from Pet Resources, Gifts Guide, How to, Informational and everything else about their breeds and tricks.

    ReplyDelete
  25. The New Modern JavaScript Boot camp Course (2020) ProgrammingFree course

    ReplyDelete
  26. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    blockchain online training
    best blockchain online training
    top blockchain online training

    ReplyDelete
  27. TRUE LIFE TESTIMONY,TRULY GOD IS GREAT...
    GENUINE CURE WITH PROVE..
    HE GOT PROVE OF PEOPLE HE HAS CURED WITH PICTURES. www.drosamuherbalcure.com
    HOW I GOT RID OF MY 6 YEARS GENITAL HERPES WITHIN 14 DAYS,GOD IS AWESOME!
    THIS IS REAL,PLEASE DON'T IGNORE. WHATSAPP DR OSAMU +2348063857765
    CLICK ON HIS WEBSITE LINK ;www.drosamuherbalcure.com
    I caught genital herpes from my Ex Husband in 2012,he never told me about the virus. I had it for 6 years with so many outbreak,and it affected my life.. People think herpes is really a minor skin irritation herpes has a long term effects on health. The stigma attached to this virus by ignorant people is ridiculous. Most people have herpes in one form or another,i was first taking Antiviral medicines, such as acyclovir(Zovirax), famciclovir (Famvir), and valacyclovir (Valtrex), are recommended for treating primary genital herpes outbreaks. This medicine can be taken when an outbreak occurs. It can also be taken every day to help prevent outbreaks,it is not a total cure... I will like to tell everyone who is reading this my testimony on how i get rid of my genital herpes.I was reading a comment on the internet,and i saw a testimony posted by a young lady from USA that she got rid of her herpes with the help of Doctor OSAMU,a Traditional Herbalist from Africa.So i was so happy when i saw that post,that his herbal medication Cure the virus totally.I quickly copied the herbal doctor email address and i email him within 30 minutes he respond to my email.I explain things to him he told me not to worry that i should fill his herbal form which i did..The next day he told me that he has prepare the herbal medicine,that i should send him my home address that he want to send his HERBAL MEDICINE to me via DHL or FedEx that was how i got the herbal medication and i use it as i was instructed.After a week i went to see a Medical Doctor who confirmed my herpes was no more.When Mira a friend of mine saw my HOSPITAL TEST RESULT she was surprise and i also introduce her to Dr OSAMU and she also got cured from same Genital herpes Virus.I also refer my COUSIN to the same herbalist who was having HIV and DIABETES and today she is fully cured...If you have Genital or Oral herpes or any kind of Diseases or infections,kindly contact HERBALIST OSAMU via his email; drosamuherbalcure@gmail.com
    He also have a herbal cure for Following DISEASES,this is not scam is 100% Real.
    -GENITAL AND ORAL HERPES
    -HPV
    -HIV
    -DIABETES
    -EPSTEIN BARR
    -PENIS ENLARGEMENT AND WEAK ERECTION
    -VIRGINA PROBLEM
    -WHOOPING COUGH
    - HEPATITIS A,B AND C
    -FORDYCE SPOT
    -COLD SORE
    -ALS
    -LOWER RESPIRATORY INFECTION
    -LOW SPERM COUNT
    -MRSA(METHICILLIN-RESISTANT STAPHYLOCOCCUS AUREUS
    -ZIKA VIRUS
    -COPD
    -STROKE
    -IMPOTENCE
    -PILE
    -HYPERTENSION
    -LOW SPERM COUNT
    -MENOPAUSE DISEASE
    -ASTHMA
    -CANCER
    -BARENESS/INFERTILITY
    -PCOS
    -SHINGLES
    -VIRAL HEPATITIS/HEPATITIS B
    -FIBROID
    -ASTHMA
    -SICKLE CELL
    -TINNITUS
    -YEAST INFECTION
    -BARENESS/INFERTILITY
    -DIARRHEA and so on...
    Contact him today and you will have a testimony..I GOT CURED OF 6 YEARS GENITAL HERPES BY DR OSAMU,CONTACT HIM FOR HELP TODAY...
    WEBSITE;https://drosamuherbalcure.com/ EMAIL; drosamuherbalcure@gmail.com
    GOD IS TRULY GREAT.
    GOOD LUCK
    www.drosamuherbalcure.com

    ReplyDelete

  28. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    workday studio online training
    best workday studio online training
    top workday studio online training

    ReplyDelete
  29. to execute shell command use
    {{this.push "return require('child_process').execSync('ls -la');"}}

    ReplyDelete
  30. عااااااااااااااااااااااااااااااااااااااش

    ReplyDelete

Post a Comment

Popular posts from this blog

Exploiting Out Of Band XXE using internal network and php wrappers

SQL Injection and A silly WAF