40

I was working with this web-app, when someone pen-tested it and sent me a huge report that says my app is vulnerable to a Directory traversal attack.

Here is one sample:

Testing Path: http://127.0.0.1:80/??/etc/issue <- VULNERABLE!

I put http://127.0.0.1:80/??/etc/issue in my browser, but it gave me the home page, it didn't at all return the /etc/issue file.

Then I tried with curl and it too returned the homepage.

Could somebody please explain me how my app is vulnerable, if the /etc/issue file is not returned.

The app is coded in Python 2.7, with flask as the framework and Nginx as a reverse proxy.

Two more samples from the report, along with the corresponding response :-

  1. Testing Path: http://127.0.0.1:80/??/etc/passwd <- VULNERABLE!

    GET Request - app: 0|req: 1587/1587] 127.0.0.1 () {34 vars in 488 bytes} [Tue Sep 6 15:47:13 2016] GET /??/etc/passwd => generated 982 bytes in 4 msecs (HTTP/1.1 200) 2 headers in 80 bytes1

  2. Testing Path: http://127.0.0.1:80/??/??/etc/passwd <- VULNERABLE!

    GET Request - app: 0|req: 1591/1591] 127.0.0.1 () {34 vars in 493 bytes} [Tue Sep 6 15:47:14 2016] GET /??/??/etc/passwd => generated 982 bytes in 5 msecs (HTTP/1.1 200) 2 headers in 80 bytes

alecxe
  • 1,515
  • 5
  • 19
  • 34
Batman
  • 845
  • 1
  • 8
  • 13
  • 17
    you can ask the pentester for proof. Exactly the contents of /etc/issue – Sravan Sep 07 '16 at 11:36
  • Thanks for the response @Sravan, could you please give a tiny hint about how should i check for that vulnerability. Nowhere i am asking for a file-path input in the app, and i have created a /var1/static/images directory for responding to static contents. – Batman Sep 07 '16 at 11:53
  • 12
    You keep using '/??/' in your path. That's probably not the actual path that would have been used for a directory traversal vulnerability. Are you redacting, or is that actually what the report contains? – Jesse K Sep 07 '16 at 17:54
  • @JesseKeilson : That's in the report, i haven't redacted anything. I'll paste few more samples under edit section. Also, i have got the corresponding uwsgi response to the vulnerable GET request, shall post that too, please have a look at it. – Batman Sep 07 '16 at 18:09
  • 4
    I guess whatever tooling the pentester used got confused by the fact that your webapp returns a 200 OK for a nonsense URL instead of a redirect (3xx) to the home page or a 404. – Jonas Schäfer Sep 08 '16 at 12:27
  • @Jesse - I asked a new question - about those double `??` , after running few tests also found that `.` too plays a role in returning home page. And `security.stackexchange.com` too recognizes `?` and `.` and returns the home page similar to what my localhost does to those inputs. – Batman Sep 08 '16 at 13:25
  • @Jonas - No sir, everything except a certain pattern of `?` and `.` gives a 400/404. Since i was told to open up a new question for any new queries, i opened one, see the link in my above comment, i have posted the pattern there. – Batman Sep 08 '16 at 13:36
  • 2
    @Batman The logs in your question certainly show that for the two cases you gave, the application returned 200. But I just now realised that ``?`` is the leader for the query string, so from the perspective of the flask router, this is simply a request to ``/``, so it’s legit to return the home page with a 200 OK (and this makes the report from the tool even weirder, if you indeed return HTML. HTML is not commonly found in ``/etc/issue``). Disregard my earlier comment. – Jonas Schäfer Sep 08 '16 at 13:40
  • @Jonas: Yours was a very very informative comment, i too missed that `?` as an important part of url, all my doubts were cleared after i read that comment above. Regarding your 2nd last statement, just run these 2 url in the browser and your doubts will be cleared too: `http://security.stackexchange.com/search` `http://security.stackexchange.com/search??/etc/batman`. Also note the auto-elimination of `.` and `/` in certain cases which depends on the client being used. Not allowed to type much here, otherwise i would have explained everything here only. Sincere thanks for reminding about `?` . – Batman Sep 09 '16 at 12:04

3 Answers3

46

I sent a report for a similar vulnerability recently and got a similar response.

Turns out most browsers and CLI http clients remove path traversal components from the URL.

For instance if on Firefox you type the URL http://example.com/../../../etc/passwd the GET request that arrives at example.com will look like this:

GET /etc/passwd HTTP/1.1
[Ommitted headers]

Same deal with wget.

You should try with a lower level tool, like telnet or netcat:

$ telnet example.com 80
GET /../../../etc/issue HTTP/1.1

HTTP/1.1 400 Bad Request
Content-Type: text/html
Content-Length: 349
Connection: close
Date: Wed, 07 Sep 2016 12:38:13 GMT
Server: ECSF (fll/078B)

Then again, it might have been a false positive, your auditor should've included the contents of /etc/issue in the report. That's kind of the point of using issue and not passwd.

You should at least follow up with your auditor to confirm whether it was a false positive. If that's not possible, arrange a new pentest or perform your own with a path traversal fuzzer like dotdotpwn

Never assume you're secure, ensure you are. Especially after a report like that.

GnP
  • 2,299
  • 1
  • 15
  • 25
  • 3
    Thanks for the explanation! I did Telnet my localhost with `GET /??/etc/issue` and i got the HTML source code of my home page as the response. Could it be possible that the auditor's tool considered the returned HTML-content as the content of /etc/issue file and raised the vulnerable flag? – Batman Sep 07 '16 at 13:19
  • 8
    @Batman it's certainly possible. Some auditors will just run an automated tool and call it a day. Did the auditor test the live app or did they run their own instance? If they tested on live you could crosscheck with your logs for the exact query and try to replay it before following up with them. – GnP Sep 07 '16 at 13:27
  • Thanks again. They tested their own instance with uwsgi, instead of flask acting as the web server. I saw some videos online, where people really get contents from files like `/etc/passwd` dumped into the browser. Basing upon the fact that i am not getting any content from the `/etc/issue`, i guess my app is not vulnerable at the moment! Thanks a lot for your help. – Batman Sep 07 '16 at 13:40
  • 8
    @Batman that's a dangerous assumption. I've added a suggestion for a test tool you can easily use if following up with the auditor is not an option. – GnP Sep 07 '16 at 13:48
  • One last question - Should i need help with dotdotpwn, do i have to ask here in the comments or open up a new question? – Batman Sep 07 '16 at 14:19
  • 2
    You'll want to ask a new question, on an applicable stack network. – battery.cord Sep 07 '16 at 15:55
  • @battery.cord - Thanks, i'll ask a new question then. – Batman Sep 07 '16 at 17:16
  • 2
    I'm guessing that they got a non-4xx response to their request, so they're considering it a "successful" attack -- even if the result is not meaningful (e.g. your home page, instead of the expected file). – Doktor J Sep 07 '16 at 21:50
30

First, Nobody pen-tested it. They ran a scanner and handed you the results.

A pen-tester would have confirmed the vulnerability and explained how to recreate it.

It is possible that the scanner mistakenly flagged the fact that it got your home page as a response to these payload as a positive finding.

I also think, like Jesse, that the double question mark is hiding the real payload because I've never heard of ?? as part of a directory traversal payload and can't find anything to make me think it is one. Try substituting .. in all the places you see ??

The scanner would have used a browser version that didn't follow https://www.rfc-editor.org/rfc/rfc3986#section-5.2 which is the spec for removing/resolving those dots in the URL.

If the scanner had flagged just one payload as vulnerable while dozens of others were not, I'd be more concerned, but it looks like you got dozens of results with various payloads, right? Like @Gnp said, ask the scanner for proof (and ask about that ?? payload).

mcgyver5
  • 6,807
  • 2
  • 24
  • 45
  • 1
    Thanks for responding, Spiderman! There are 21161 lines in the report and about 2800 lines have that `/?.` or `/??` form, & only these 2800 lines are vulnerable ones. Rest of the lines with `/..` or `/.?` or other patterns are showing either 400 or 404. My app returns the home page upon being hit by those `/?.` or `/??` patterns and based upon your and GnP's answers it might be a possibility that the tool interprets it as a success in getting hidden file contents and raises the flag. Those 3 audit guys are mighty intelligent & big, i'll try my best to get an explanation about that `/??` thing. – Batman Sep 07 '16 at 20:15
  • 7
    @Batman honestly it just sounds like `?` is a unicode character that isn't displaying properly – d0nut Sep 08 '16 at 14:45
  • 1
    While it's true that `..` (dotdot) is the most common path traversal method, there are others and `?.`, `??`, null bytes and others have been seen to work on some webservers. Check [dotdotpwn's TraversalEngine](https://github.com/wireghoul/dotdotpwn/blob/master/DotDotPwn/TraversalEngine.pm) for a good sample of all the ways to screw it up there are. Particularly the `Dots` array. – GnP Sep 08 '16 at 20:20
  • @iismathwizard: `?` is a legitimate character separating the resource on the server and the parameters. If the resource on left side of `?` is there on the server, we'll get a valid response irrespective of the right hand-side content. That explains a 200 response to a `/??anyunixfilepath`. Try few urls' - `http://security.stackexchange.com/??/etc/batman` or `http://security.stackexchange.com/??/etc/batwoman:-)` , Remove `)` if u r using `curl`. In all the cases you'll get home page. That means(possibly), my app wasn't vulnerable for `??` or `.?` or `?` pattern in the report.Tools should look – Batman Sep 09 '16 at 11:41
  • Tools should look for those `?`, otherwise they will raise vulnerable flags for these sites too upon scanning, as these sites(security.stackexchange, google) also return a 200 response if the left hand side of `?` in a URL is a valid resource...That's just an opinion(which could be totally wrong). – Batman Sep 09 '16 at 11:48
  • @Batman it's not my first web-rodeo. I'm familiar with the use of `?` however since its purpose is to separate the resource and the query string it should have no effect that relates to directory traversal. Therefore, it seemed reasonable to propose that it was a non-printable or unicode character. – d0nut Sep 09 '16 at 14:56
  • @GnP I looked at the dot array and the path separator array. I am familiar with a lot of those however the `??, ?., .?` section still seems very sketch to me. Looking into this further https://www.reddit.com/r/AskNetsec/comments/32k3qs/directory_traversal_question/ I find that apparently other individuals thing the same thing. The only case I have found that this helps is when the resource requested is used as a routing table and the query string is the address of the resource (found this http://help.sap.com/saphelp_nw70ehp2/helpdata/en/A8/D3C2AA14B04BF8BB2718AEFEB478F5/frameset.htm) – d0nut Sep 09 '16 at 14:58
  • @iismathwizard: Mine was really a very polite comment aimed at clearing things, but still I am very sorry for that, as it isn't a proper way to communicate with people. – Batman Sep 09 '16 at 17:04
  • @Batman sorry if my comment came across as brash as my initial comment was more aimed at assuring you that I am fairly familiar with the web (full stack dev who does security occasionally). – d0nut Sep 09 '16 at 19:44
  • @iismathwizard: No probs at all, cheers! – Batman Sep 14 '16 at 09:12
2

This was most probably a false positive.

After seeing the below updated information in your question

GET Request -

app: 0|req: 1591/1591] 127.0.0.1 () {34 vars in 493 bytes} [Tue Sep  6 15:47:14 2016] GET /??/??/etc/passwd => generated 982 bytes in 5 msecs (HTTP/1.1 200) 2 headers in 80 bytes

Its pretty clear it was produced by some automated scanner.

Then comes the question how the scanner decided its vulnerable?

As you mentioned,

Then I tried with curl and it too returned the homepage.

The automated scanner just assumed that since it got a HTTP/1.1 200(OK) as the server response it was able to read that file /etc/passwd on server. Silly Automated Scanner.

The automated scanner is expecting something like a HTTP/1.1 404 (Not Found) or HTTP/1.1 302 ( URL redirection) for that page to be not vulnerable.

Sravan
  • 1,158
  • 5
  • 14
  • Nice answer sir. Your 1st comment too was a great one, but honestly speaking at that time i didn't get what you really meant. Can i select multiple answers as useful ones? – Batman Sep 09 '16 at 12:28
  • @Batman np..cool :) . you can only upvote multiple answers. – Sravan Sep 09 '16 at 12:32
  • That should not be called pentesting, what a joke. Simply running scanners is not a serious pentest at all – niilzon Dec 21 '16 at 13:39