Skip to content

set_term_title command injection.

Low
Carreau published GHSA-29gw-9793-fvw7 Feb 10, 2023

Package

pip IPython (pip)

Affected versions

<8.10

Patched versions

>=8.10

Description

Original Report:

I have found a command injection in the Python package "ipython". The vulnerability has very specific prerequisites that make an actual impact quite unlikely. However, if the prerequisites are met, the vulnerability can be used to execute arbitrary commands on the victim's computer.

The affected function is IPython.utils.terminal.set_term_title:

except ImportError:
def _set_term_title(title):
"""Set terminal title using the 'title' command."""
global ignore_termtitle
try:
# Cannot be on network share when issuing system commands
curr = os.getcwd()
os.chdir("C:")
ret = os.system("title " + title)
finally:
os.chdir(curr)
if ret:
# non-zero return code signals error, don't try again
ignore_termtitle = True

For the vulnerability to take effect, the function must be called on Windows in a Python environment where ctypes is not available:

Python 3.7.7 (tags/v3.7.7:d7c567b08f, Mar 10 2020, 10:41:24) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> # In this Python installation _ctypes are not available
>>>
>>> # poc_dir is an empty directory that we use to illustrate the command injection
>>> import os
>>> poc_dir = 'E:\\Spielwiese\\ipython'
>>> os.listdir(poc_dir)
[]
>>>
>>> try:
...     # This will fail, because _ctypes is not available
...     from IPython.utils.terminal import toggle_set_term_title, set_term_title
... except Exception as e:
...     e
...
ModuleNotFoundError("No module named '_ctypes'")
>>> # This time IPython is already imported and the error will not occur again
>>> from IPython.utils.terminal import toggle_set_term_title, set_term_title
>>>
>>> # Inject a simple command
>>> toggle_set_term_title(True)
>>> set_term_title(f'$(echo > {poc_dir}\\poc.txt )')
>>>
>>> # Now there should be poc.txt in poc_dir
>>> os.listdir(poc_dir)
['poc.txt']
>>>

Instead of fixing the issue (for example by using subprocess.run istead of os.system), I recommend to delete the affected code. I attached a patch, that does this.

As IPython already depends on ctypes (see IPython.utils._process_win32), it is not necessary to implement the case, that ctypes is not available.

further notes from the reporter:

Some remarks on the issue:

In the context of IPython itself, I agree with you that this is not a vulnerability. The dependency on ctypes in IPython.utils._process_win32 prevents the vulnerable code from ever being reached (making it effectively dead code). However, as a library that could be used by another tool, set_term_title could introduce a vulnerability there.

IPython team response

Currently set_term_title is only called with (semi-)trusted input that contain the current working directory of the current IPython session. If an attacker can control directory names, and manage to get a user cd into this directory the attacker can execute arbitrary commands contained in the folder names.

Example:

  • On a windows machine where python is built without _ctypes, create a folder called && echo "pwn" > pwn.txt. This can be done by for example cloning a git repository.
  • call toggled_set_term_title(True), (or have the preference to true)
  • Open IPython and cd into this directory.
  • the folder now contain a pwn.txt, with pwn as content, despite the user not asking for any code execution.

With respect to cd issue the reporter said:

I consider this behaviour a vulnerability, because a user should be able to assume that they can cd into any folder safely. Of course the likelihood of this vulnerability ever coming into play is still minimal.

Impact

This likely affects a small percentage of users, as all the following

  • be on windows
  • on a build of Python without _ctypes,
  • cd into untrusted folder before starting IPython.

Patches

IPython 8.10 and above.

Is my version of IPython patched ?

Run the following snippet of code. If it returns

>>> import IPython
>>> 'CVE-2023-24816' in IPython.__patched_cves__
True

Workarounds

Set the configuration option c.TerminalInteractiveShell.term_title_format='IPython' (or to any other fixed, safe string).
When using py files, you can conditionally set this option based on the version number of IPython.

References

Severity

Low
2.2
/ 10

CVSS base metrics

Attack vector
Local
Attack complexity
High
Privileges required
Low
User interaction
Required
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
Low
CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:N/A:L

CVE ID

CVE-2023-24816