2019-02-04 13:45:00
Well! It's been an interesting month, between work and a few vulnerabilities that I'd reported to a vendor. And now there's this little surprise!
Imagine that you're using Powershell's Invoke-WebRequest command in your management scripts, to access an API or to pull in some data. It happens, right? Nothing out of the ordinary! While I was pentesting one particular API, I decided to poke at it manually using Invoke-WebRequest, only to be met with a surprising bonus! The Javascript code I'd sent to the API for an XSS-attack was returned as part of the reply by the API. Lo and behold! My I-WR ran the Javascript locally!
Screenshot 1 shows the server-side of my proof-of-concept: Python running a SimpleHTTPServer, serving up "testpage.html" from my laptop's MacOS.
In the image above you'll also see the Unix/Linux/MacOS version of curl, which simply pulls down the whole HTML file without parsing it.
Now, the image below shows what happens when you pull in the same page through Invoke-WebRequest in Powershell:
Fun times!
This means that every time you run a curl or Invoke-WebRequest on Windows, you'd better be darn sure about the pages you're calling! This Javascript alert is benign enough, but we all know the dangers of cross-site scripting attacks or just plain malevolent Javascript! Annoyingly, I have not yet found a way to disable JS-parsing in these commands. Looks like it can't be done.
What's worse: these commands are often included in scripts that are run using service accounts or by accounts with administrative privileges! That runs afoul of Critical Security Control #5: controlled use of administrative privileges! (More info here @Rapid7). Basically, you're running a whole web browser in your scripting and tooling!
So be careful out there folks! Think before you run scripts! Check before you call to URLs you're not familiar with! Trust, but verify!
EDIT: I've sent an email to Microsoft's security team, see what they think about all this. I mean, I'm sure it's a well-known and documented fact, but personally I'd feel a lot safer if I had the option to disable scripting (like JS) in Invoke-WebRequest.
EDIT: It looks like the only way to disable Javascript in Invoke-WebRequest, is to disable it in the Internet Explorer browser. Guess that makes sense, because doesn't I-WR use the IE engines?
After discussing the matter with the security team of Microsoft, I have come to understand that I have misunderstood the documentation provided for Invoke-WebRequest. It turns out that you can easily protect yourself from this particular problem by always adding the flag -UseBasicParsing.
kilala.nl tags: work, sysadmin,
View or add comments (curr. 3)
Posted by Tess
Oh, you're absolutely right: it is definitely the developer's own responsibility to check that the site they're talking to is safe.
Unfortunately, all the checking in the world beforehand cannot protect you against an XSS-attack weeks later. So there's that problem. Basically, one should always assume remote data to be potentially harmful, meaning that you should NEVER run these commands with admin or elevated privileges. Which is going to be another problem, because many of these scripts -are- admin scripts.
Of course, one thing that can help prevent XSS is something I've been applying to my own site the past week: CSP, content security policies. See here -> https://www.kilala.nl/index.php?id=2444
If the external datasource applies CSP and other methods, they can protect you (the visitor) from XSS attacks.
Posted by The Saint
I agree it's not very good that I-WR isn't just grabbing the data, but is It not a little bit eh responsibility of the person doing the request to check it's not getting any dangerous data? Kind of the same category as people blindly clicking links in emails....?
All content, with exception of "borrowed" blogpost images, or unless otherwise indicated, is copyright of Tess Sluijter. The character Kilala the cat-demon is copyright of Rumiko Takahashi and used here without permission.
0000-00-00 00:00:00
Posted by Tess
Huh, would you look at that? Looks like my comment form is no longer entering the time :D