Comments (7)
does this still happen in Python 3.12?
Sadly it DOES happen in Python 3.12:
(xonsh_dbg_py312) PS D:\xzc\lab\xonsh_debug\xonsh-0.14.3> Get-Content .\cmd.bat
echo "hopefully this code is not malicious"
(xonsh_dbg_py312) PS D:\xzc\lab\xonsh_debug\xonsh-0.14.3> python --version
Python 3.12.1
(xonsh_dbg_py312) PS D:\xzc\lab\xonsh_debug\xonsh-0.14.3> $Env:XONSH_DEBUG=1
(xonsh_dbg_py312) PS D:\xzc\lab\xonsh_debug\xonsh-0.14.3> xonsh
<xonsh-code>:1:0 - cls
<xonsh-code>:1:0 + ![cls]
Skipping setup. Because no `readline` implementation available.
Please install a backend (`readline`, `prompt-toolkit`, etc) to use
`xonsh` interactively.
See https://github.com/xonsh/xonsh/issues/1170
hello!
xonsh_dbg_py312xzc@Lenovo-Win11-xzc D:\xzc\lab\xonsh_debug\xonsh-0.14.3
@ mklink /?
<stdin>:1:8 - mklink /?
<stdin>:1:8 + ![mklink /?]
D:\xzc\lab\xonsh_debug\xonsh-0.14.3>echo "hopefully this code is not malicious"
"hopefully this code is not malicious"
xonsh_dbg_py312xzc@Lenovo-Win11-xzc D:\xzc\lab\xonsh_debug\xonsh-0.14.3
@ xonfig
<xonsh-code>:1:0 - xonfig
<xonsh-code>:1:0 + ![xonfig]
+------------------+-----------------------+
| xonsh | 0.14.3 |
| Python | 3.12.1 |
| PLY | 3.11 |
| have readline | False |
| prompt toolkit | None |
| shell type | readline |
| history backend | json |
| pygments | None |
| on posix | False |
| on linux | False |
| on darwin | False |
| on windows | True |
| on cygwin | False |
| on msys2 | False |
| is superuser | False |
| default encoding | utf-8 |
| xonsh encoding | utf-8 |
| encoding errors | surrogateescape |
| xontrib | [] |
| RC file 1 | C:\Users\xzc/.xonshrc |
+------------------+-----------------------+
I haven't checked if xonsh uses subprocess.run with shell=True
I searched for shell=
and .run
in the source but didn't find that. I don't know if I missed some class defaults though.
from xonsh.
With this line changed:
Line 897 in e3a6dcf
for alias in windows_cmd_aliases:
# default_aliases[alias] = ["cmd", "/c", alias]
default_aliases[alias] = [os.getenv("COMSPEC"), "/c", alias]
this is the new, hopefully safer, behaviour:
(xonsh) ~\Coding\delete @ mklink /?
Creates a symbolic link.
MKLINK [[/D] | [/H] | [/J]] Link Target
/D Creates a directory symbolic link. Default is a file
symbolic link.
/H Creates a hard link instead of a symbolic link.
/J Creates a Directory Junction.
Link Specifies the new symbolic link name.
Target Specifies the path (relative or absolute) that the new link
refers to.
(xonsh) ~\Coding\delete @ dir /A
Volume in drive C is Windows-SSD
Volume Serial Number is
Directory of ~\Coding\delete
24/12/2023 16:08 <DIR> .
12/12/2023 12:03 <DIR> ..
24/12/2023 13:43 43 cmd.bat
24/12/2023 16:06 32 legit_user_file.bat
12/11/2023 20:57 <DIR> Project1
2 File(s) 75 bytes
3 Dir(s) lots bytes free
from xonsh.
BTW my cmd.bat had also (unintentionally) tricked Visual Studio Code's python debugger to run something else while I was looking into this issue, as it uses cmd /c
too.
from xonsh.
I haven't checked if xonsh uses subprocess.run with shell=True, but does this still happen in Python 3.12?
It reminds me of this bugfix:
Changed in version 3.12: Changed Windows shell search order for shell=True. The current directory and %PATH% are replaced with %COMSPEC% and %SystemRoot%\System32\cmd.exe. As a result, dropping a malicious program named cmd.exe into a current directory no longer works.
https://docs.python.org/3/library/subprocess.html
from xonsh.
Hiya,
I've gotten to the bottom of it.
Basically the problem is in Xonsh's prefilled default aliases on Windows, which include mklink but also dir:
A fix could be as simple as replacing the string literal "cmd"
with os.getenv('COMSPEC')
if ON_WINDOWS:
# Borrow builtin commands from cmd.exe.
windows_cmd_aliases = {
"cls",
"copy",
"del",
"dir",
"echo",
"erase",
"md",
"mkdir",
"mklink",
"move",
"rd",
"ren",
"rename",
"rmdir",
"time",
"type",
"vol",
}
for alias in windows_cmd_aliases:
default_aliases[alias] = ["cmd", "/c", alias]
Line 875 in e3a6dcf
Proof:
Run a command that isn't in the aliases dict, e.g. w32tm /tz
(try to only pick examples that are harmless https://ss64.com/nt/), or make another batch file (and call it from xonsh) in the same directory as the cmd.bat
imposter. The attacker's cmd.bat
is not called.
(xonsh) ~\Coding\delete @ mklink /?
~\Coding\delete>echo "hopefully this code is not malicious"
"hopefully this code is not malicious"
(xonsh) ~\Coding\delete @ dir /A
~\Coding\delete>echo "hopefully this code is not malicious"
"hopefully this code is not malicious"
(xonsh) ~\Coding\delete @ w32tm /tz
Time zone: Current:TIME_ZONE_ID_STANDARD Bias: 0min (UTC=LocalTime+Bias)
[Standard Name:"GMT Standard Time" Bias:0min Date:(M:10 D:5 DoW:0)]
[Daylight Name:"GMT Daylight Time" Bias:-60min Date:(M:3 D:5 DoW:0)]
(xonsh) ~\Coding\delete @ legit_user_file
~\Coding\delete>echo A user's custom batch file.
A user's custom batch file.
(xonsh) ~\Coding\delete @
FYI, Xonsh uses a bunch of suprocess.capture_output s (and the other olf one) but for its main external calls it runs subprocess.POpen, via a custom class and the entire AST and parser. It took me a long time to figure that out, and will also take a long time to explain the details.
from xonsh.
With this line changed:
Line 897 in e3a6dcf
for alias in windows_cmd_aliases: # default_aliases[alias] = ["cmd", "/c", alias] default_aliases[alias] = [os.getenv("COMSPEC"), "/c", alias]
this is the new, hopefully safer, behaviour:
(xonsh) ~\Coding\delete @ mklink /? Creates a symbolic link. MKLINK [[/D] | [/H] | [/J]] Link Target /D Creates a directory symbolic link. Default is a file symbolic link. /H Creates a hard link instead of a symbolic link. /J Creates a Directory Junction. Link Specifies the new symbolic link name. Target Specifies the path (relative or absolute) that the new link refers to. (xonsh) ~\Coding\delete @ dir /A Volume in drive C is Windows-SSD Volume Serial Number is Directory of ~\Coding\delete 24/12/2023 16:08 <DIR> . 12/12/2023 12:03 <DIR> .. 24/12/2023 13:43 43 cmd.bat 24/12/2023 16:06 32 legit_user_file.bat 12/11/2023 20:57 <DIR> Project1 2 File(s) 75 bytes 3 Dir(s) lots bytes free
This is good enough to handle the cmd hijacking issue. But maybe xonsh should go one step further. For example completely ignore executables in the current directory, like what PowerShell or most *nix shells do. If the user should execute something in the working directory, they must prepend it with .\
(PowerShell) or ./
(*nix shells).
from xonsh.
It is reasonable to expect Windows cmd users to check the directory first for executables and batch files of that name, before running that name as a command. That's what they should be doing already.
It is not reasonable to expect Windows cmd users of Xonsh to check every directory for a file called cmd.bat, when the very act of looking for a malicious cmd.bat
using dir /A in Xonsh, would execute it.
If running on top of cmd, Xonsh isn't now any less secure than cmd (or won't be, once my PR is merged, or the issue is fixed some other way).
In the code base, there was a deliberate decision to support windows / cmd users running scripts without specifying a file extension or .\ .
Line 260 in e3a6dcf
if ON_WINDOWS:
# Windows users expect to be able to execute files in the same
# directory without `./`
local_bin = next((fn for fn in possibilities if os.path.isfile(fn)), None)
A strong case needs to be made to push out such a wide ranging breaking change.
from xonsh.
Related Issues (20)
- xpip fails to correctly install on fedora HOT 12
- General on_pre_spec_run that runs for all commands
- stdin not set in all callable aliases
- Environment tests fail if $UPDATE_OS_ENVIRON = True
- Error `Bad file descriptor` in `prompt_toolkit` on ctrl+C interrupt HOT 17
- Error `Bad file descriptor` in `prompt_toolkit` > 3.0.40 HOT 22
- subprocess call in @events.on_post_rc causes bash to make xonsh background process instead of main process
- AppImage: Input/output error in prompt toolkit HOT 3
- Requires old Sphinx (<5): TypeError: object of type 'LazyObject' has no len() HOT 1
- cd subdir && gives false errors
- ; doesn't split commands inside $()
- Parser fail with numerical and logical AND HOT 3
- FAILED tests/completers/test_bash_completer.py::test_equal_sign_arg[command_context1-completions1-4-False] HOT 2
- Is it possible to use fzf for TAB completions? HOT 5
- Renewal of Xon.sh domain (before Feb 9th), and transfer to another provider ? HOT 2
- Bring consistency to `which` HOT 14
- Show alias function description using superhelp
- Unhelpful "Operation timed out" when failing to load history
- Piping seems broken in windows HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from xonsh.