Path traversal while uploading results in RCE

As the program is private; Program Name, Endpoints are replaced.

Hey guys, Today i’ll show you how i gained a Remote Code Execution on a HackerOne’s Private Program. This is chaining of multiple issues, which were addressed separately and all were marked as Critical/P1.

This program had a ABC Enterprise installation and a Normal Installation which have some less features, Program hosted enterprise edition for researchers with admin credentials given. While Normal was available to download and host locally.

Normal Installation

  • Less features,
  • Less bounty,
  • Gives basic idea how the app is hosted, structure and working on backend.

Information i gained using Normal Installation

  • Some internal services.
  • Web app structure.

Lets go ahead and start with program hosted enterprise with many more features / endpoints.

Sensitive Unauthenticated Endpoint

There was option to download logs, Which have all kind of logs of the service. Which leaked api_keys which was infact the password of user it self. But because we’re admin this is not very useful, So if we able to downloads logs while being unauthenticated or with low level user priv. this will be a good issue, i tired download the log while being normal user & unauthenticated and it got downloaded. Using this an attacker can download logs while being unauth to instance and then further exploit it with api_key/password retrieved from logs.

Recon the logs

I noticed a request in logs;

GET /api/v1/upload?username=xxx&api_key=xxx&dcid=xxx&timestamp=xxx

Request

GET /api/v1/upload?username=xxx&api_key=xxx&dcid=ggg&timestamp=123
Content-Length: 0
Host: [redacted]
Connection: close
Accept-Encoding: gzip, deflate

Response location [302]

/api/v1/upload?id=ggg&filename=blah_ggg_timestamp.tar.gz

Started making requests to this url, Tried to POST data but didn’t worked, Changed upload to download (may be there’s an download endpoint too?), But no luck.

Seems like a dead end :( Then i thought lets make an OPTIONS request.

Request

OPTIONS /api/v1/upload?id=ggg&filename=blah_ggg_timestamp.tar.gz HTTP/1.1
Content-Length: 0
Host: [redacted]
Connection: close
Accept-Encoding: gzip, deflate

Response

HTTP/1.1 200 OK
Cache-Control: max-age=0
Content-Type: text/html; charset=UTF-8
Connection: Close


Content Length can’t be 0

Sent raw data and response was 200 OK, my 2c were, its creating a file with name blah_ggg_timestamp.tar.gzwith our input (request body) if the id is valid, id is created when valid credentials passed at /api/v1/upload?username=xxx&api_key=xxx&dcid=ggg&timestamp=123 That looks promising.

Lets change file name to ../../../../../../../../../tmp/harsh.txt

PUT /api/v1/upload?id=ggg&filename=../../../../../../../../../tmp/harsh.txt HTTP/1.1
Content-Length: 0
Host: [redacted]
Connection: close
Accept-Encoding: gzip, deflate

Testing

Response : 200 OK

Request : Filename=../../../../../../../../../etc/harsh.txt

Response : 500 Internal Server Error

Permission Denied (/opt/xxx/api/uploads/../../../../../../../../etc/harsh.txt)

Awesome, This confirms we do have a arbitrary file creation on server.

Why i used etc ? Web server in most cases won’t have access write in /etc/ which might cause some exception which is what happened in this case.

Challenge accepted : Getting RCE

The analyst response actually made sense, What if this was not unauth, I challenged myself to use this endpoint independently and get Code Execution.

And within few minutes i realized a normal user credentials also accepted at /api/v1/upload?username=xxx&api_key=xxx&dcid=ggg&timestamp=123 and hence a normal user can create files on server.

Going back to logs and Normal Installation for gaining info how this issue can get me a Code Execution.

The web app is getting started from /opt/xxx/bin/xlink, So this was simple all an attacker need to do is overwrite xlink with reverse shell script, and wait server admin to restart (just make some files not usable which will force admin to restart) the server by doing sh xlink restart/stop/start and as soon as he trigger this condition we will have a rev shell however this is not reliable on further research i found a better way.

There was an phantomjs binary was in use and getting executed from a endpoint on a web app, I found a OS command injection using that endpoint but that’s a story of another blog, I had its full path saved during my recon on log file. I confirmed that this can overwrite files and luckily the file was getting created with executable permission.

So all a normal user needed to do was overwrite the phantomjs binary with malicious code and use the endpoint which will execute it(phantomjs binary) and normal user uploaded code will be executed.


That's all folks :) Share/Retweet is much appreciated. Doubt? DM me at @rootxharsh