Security Implications of using unsanitized data in Shell Arithmetic evaluation
In a comment to a recent question, Stéphane Chazelas
mentions that there are security implications to double parentheses arithmetic such as:
x=$((1-$x))
on most shells.
My Google skills seem to be rusty and I can't find anything. What are the security implications of double parentheses arithmetic?
shell security arithmetic
add a comment |
In a comment to a recent question, Stéphane Chazelas
mentions that there are security implications to double parentheses arithmetic such as:
x=$((1-$x))
on most shells.
My Google skills seem to be rusty and I can't find anything. What are the security implications of double parentheses arithmetic?
shell security arithmetic
add a comment |
In a comment to a recent question, Stéphane Chazelas
mentions that there are security implications to double parentheses arithmetic such as:
x=$((1-$x))
on most shells.
My Google skills seem to be rusty and I can't find anything. What are the security implications of double parentheses arithmetic?
shell security arithmetic
In a comment to a recent question, Stéphane Chazelas
mentions that there are security implications to double parentheses arithmetic such as:
x=$((1-$x))
on most shells.
My Google skills seem to be rusty and I can't find anything. What are the security implications of double parentheses arithmetic?
shell security arithmetic
shell security arithmetic
edited Apr 13 '17 at 12:36
Community♦
1
1
asked Dec 8 '14 at 12:57
garethTheRed
24.1k36180
24.1k36180
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The problem is in cases where the content of $x
has not been sanitized and contains data that could potentially be under the control of an attacker in cases that shell code may end up being used in a privilege escalation context (for instance a script invoked by a setuid application, a sudoers script or used to process off-the-network data (CGI, DHCP hook...) directly or indirectly).
If:
x='PATH=2'
Then:
x=$((1-$x))
has the side effect of setting PATH
to 2
(a relative path that could very well be under control of the attacker). You can replace PATH
with LD_LIBRARY_PATH
or IFS
... The same happens with x=$((1-x))
in bash, zsh or ksh (not dash nor yash which only accept numerical constants in variables there).
In bash
, zsh
and ksh
(not dash
or yash
), if x
is:
x='a[0$(uname>&2)]'
Then the expansion of $((1-$x))
or $((1-x))
causes that uname
command to be executed (for zsh
, a
needs to be an array variable, but one can use psvar
for instance for that).
Note that:
x=$((1-$x))
won't work properly for negative values of $x
in some shells that implement the (optional as per POSIX) --
(decrement) operator (as with x=-1
, that means asking the shell to evaluate the 1--1
arithmetic expression). "$((1-x))"
doesn't have the problem as x
is expanded as part of (not before) the arithmetic evaluation.
In summary, one shouldn't use uninitialised or non-sanitized external data in arithmetic expressions in shells (note that arithmetic evaluation can be done by $((...))
(aka $[...]
in bash
or zsh
) but also depending on the shell in the let
, [
/test
, declare/typeset/export...
, return
, break
, continue
, exit
, printf
, print
builtins, array indices, ((..))
and [[...]]
constructs to name a few).
To check that a variable contains a literal decimal integer number, you can use POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Beware that [0-9]
in some locales matches more than 0123456789. [[:digit:]]
should be OK but I wouldn't bet on it.
Also remember that numbers with leading zeros are treated as octal in some contexts (010
is sometimes 10, sometimes 8) and beware that the check above will let through numbers that are potentially bigger than the maximum integer supported by your system (or whatever application you will use that integer in; bash for instance treats 18446744073709551616 as 0 as that's 264).
Examples:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
More reading at:
http://www.zsh.org/mla/workers/2014/msg01041.html (where Oliver Kiddle brought thex[0$(...)]
issue to our attention).- http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9971
http://thread.gmane.org/gmane.comp.shells.bash.bugs/22737 for another mis-design potentially leading to code injection inbash
.
Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f172103%2fsecurity-implications-of-using-unsanitized-data-in-shell-arithmetic-evaluation%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The problem is in cases where the content of $x
has not been sanitized and contains data that could potentially be under the control of an attacker in cases that shell code may end up being used in a privilege escalation context (for instance a script invoked by a setuid application, a sudoers script or used to process off-the-network data (CGI, DHCP hook...) directly or indirectly).
If:
x='PATH=2'
Then:
x=$((1-$x))
has the side effect of setting PATH
to 2
(a relative path that could very well be under control of the attacker). You can replace PATH
with LD_LIBRARY_PATH
or IFS
... The same happens with x=$((1-x))
in bash, zsh or ksh (not dash nor yash which only accept numerical constants in variables there).
In bash
, zsh
and ksh
(not dash
or yash
), if x
is:
x='a[0$(uname>&2)]'
Then the expansion of $((1-$x))
or $((1-x))
causes that uname
command to be executed (for zsh
, a
needs to be an array variable, but one can use psvar
for instance for that).
Note that:
x=$((1-$x))
won't work properly for negative values of $x
in some shells that implement the (optional as per POSIX) --
(decrement) operator (as with x=-1
, that means asking the shell to evaluate the 1--1
arithmetic expression). "$((1-x))"
doesn't have the problem as x
is expanded as part of (not before) the arithmetic evaluation.
In summary, one shouldn't use uninitialised or non-sanitized external data in arithmetic expressions in shells (note that arithmetic evaluation can be done by $((...))
(aka $[...]
in bash
or zsh
) but also depending on the shell in the let
, [
/test
, declare/typeset/export...
, return
, break
, continue
, exit
, printf
, print
builtins, array indices, ((..))
and [[...]]
constructs to name a few).
To check that a variable contains a literal decimal integer number, you can use POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Beware that [0-9]
in some locales matches more than 0123456789. [[:digit:]]
should be OK but I wouldn't bet on it.
Also remember that numbers with leading zeros are treated as octal in some contexts (010
is sometimes 10, sometimes 8) and beware that the check above will let through numbers that are potentially bigger than the maximum integer supported by your system (or whatever application you will use that integer in; bash for instance treats 18446744073709551616 as 0 as that's 264).
Examples:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
More reading at:
http://www.zsh.org/mla/workers/2014/msg01041.html (where Oliver Kiddle brought thex[0$(...)]
issue to our attention).- http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9971
http://thread.gmane.org/gmane.comp.shells.bash.bugs/22737 for another mis-design potentially leading to code injection inbash
.
Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.
add a comment |
The problem is in cases where the content of $x
has not been sanitized and contains data that could potentially be under the control of an attacker in cases that shell code may end up being used in a privilege escalation context (for instance a script invoked by a setuid application, a sudoers script or used to process off-the-network data (CGI, DHCP hook...) directly or indirectly).
If:
x='PATH=2'
Then:
x=$((1-$x))
has the side effect of setting PATH
to 2
(a relative path that could very well be under control of the attacker). You can replace PATH
with LD_LIBRARY_PATH
or IFS
... The same happens with x=$((1-x))
in bash, zsh or ksh (not dash nor yash which only accept numerical constants in variables there).
In bash
, zsh
and ksh
(not dash
or yash
), if x
is:
x='a[0$(uname>&2)]'
Then the expansion of $((1-$x))
or $((1-x))
causes that uname
command to be executed (for zsh
, a
needs to be an array variable, but one can use psvar
for instance for that).
Note that:
x=$((1-$x))
won't work properly for negative values of $x
in some shells that implement the (optional as per POSIX) --
(decrement) operator (as with x=-1
, that means asking the shell to evaluate the 1--1
arithmetic expression). "$((1-x))"
doesn't have the problem as x
is expanded as part of (not before) the arithmetic evaluation.
In summary, one shouldn't use uninitialised or non-sanitized external data in arithmetic expressions in shells (note that arithmetic evaluation can be done by $((...))
(aka $[...]
in bash
or zsh
) but also depending on the shell in the let
, [
/test
, declare/typeset/export...
, return
, break
, continue
, exit
, printf
, print
builtins, array indices, ((..))
and [[...]]
constructs to name a few).
To check that a variable contains a literal decimal integer number, you can use POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Beware that [0-9]
in some locales matches more than 0123456789. [[:digit:]]
should be OK but I wouldn't bet on it.
Also remember that numbers with leading zeros are treated as octal in some contexts (010
is sometimes 10, sometimes 8) and beware that the check above will let through numbers that are potentially bigger than the maximum integer supported by your system (or whatever application you will use that integer in; bash for instance treats 18446744073709551616 as 0 as that's 264).
Examples:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
More reading at:
http://www.zsh.org/mla/workers/2014/msg01041.html (where Oliver Kiddle brought thex[0$(...)]
issue to our attention).- http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9971
http://thread.gmane.org/gmane.comp.shells.bash.bugs/22737 for another mis-design potentially leading to code injection inbash
.
Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.
add a comment |
The problem is in cases where the content of $x
has not been sanitized and contains data that could potentially be under the control of an attacker in cases that shell code may end up being used in a privilege escalation context (for instance a script invoked by a setuid application, a sudoers script or used to process off-the-network data (CGI, DHCP hook...) directly or indirectly).
If:
x='PATH=2'
Then:
x=$((1-$x))
has the side effect of setting PATH
to 2
(a relative path that could very well be under control of the attacker). You can replace PATH
with LD_LIBRARY_PATH
or IFS
... The same happens with x=$((1-x))
in bash, zsh or ksh (not dash nor yash which only accept numerical constants in variables there).
In bash
, zsh
and ksh
(not dash
or yash
), if x
is:
x='a[0$(uname>&2)]'
Then the expansion of $((1-$x))
or $((1-x))
causes that uname
command to be executed (for zsh
, a
needs to be an array variable, but one can use psvar
for instance for that).
Note that:
x=$((1-$x))
won't work properly for negative values of $x
in some shells that implement the (optional as per POSIX) --
(decrement) operator (as with x=-1
, that means asking the shell to evaluate the 1--1
arithmetic expression). "$((1-x))"
doesn't have the problem as x
is expanded as part of (not before) the arithmetic evaluation.
In summary, one shouldn't use uninitialised or non-sanitized external data in arithmetic expressions in shells (note that arithmetic evaluation can be done by $((...))
(aka $[...]
in bash
or zsh
) but also depending on the shell in the let
, [
/test
, declare/typeset/export...
, return
, break
, continue
, exit
, printf
, print
builtins, array indices, ((..))
and [[...]]
constructs to name a few).
To check that a variable contains a literal decimal integer number, you can use POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Beware that [0-9]
in some locales matches more than 0123456789. [[:digit:]]
should be OK but I wouldn't bet on it.
Also remember that numbers with leading zeros are treated as octal in some contexts (010
is sometimes 10, sometimes 8) and beware that the check above will let through numbers that are potentially bigger than the maximum integer supported by your system (or whatever application you will use that integer in; bash for instance treats 18446744073709551616 as 0 as that's 264).
Examples:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
More reading at:
http://www.zsh.org/mla/workers/2014/msg01041.html (where Oliver Kiddle brought thex[0$(...)]
issue to our attention).- http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9971
http://thread.gmane.org/gmane.comp.shells.bash.bugs/22737 for another mis-design potentially leading to code injection inbash
.
Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.
The problem is in cases where the content of $x
has not been sanitized and contains data that could potentially be under the control of an attacker in cases that shell code may end up being used in a privilege escalation context (for instance a script invoked by a setuid application, a sudoers script or used to process off-the-network data (CGI, DHCP hook...) directly or indirectly).
If:
x='PATH=2'
Then:
x=$((1-$x))
has the side effect of setting PATH
to 2
(a relative path that could very well be under control of the attacker). You can replace PATH
with LD_LIBRARY_PATH
or IFS
... The same happens with x=$((1-x))
in bash, zsh or ksh (not dash nor yash which only accept numerical constants in variables there).
In bash
, zsh
and ksh
(not dash
or yash
), if x
is:
x='a[0$(uname>&2)]'
Then the expansion of $((1-$x))
or $((1-x))
causes that uname
command to be executed (for zsh
, a
needs to be an array variable, but one can use psvar
for instance for that).
Note that:
x=$((1-$x))
won't work properly for negative values of $x
in some shells that implement the (optional as per POSIX) --
(decrement) operator (as with x=-1
, that means asking the shell to evaluate the 1--1
arithmetic expression). "$((1-x))"
doesn't have the problem as x
is expanded as part of (not before) the arithmetic evaluation.
In summary, one shouldn't use uninitialised or non-sanitized external data in arithmetic expressions in shells (note that arithmetic evaluation can be done by $((...))
(aka $[...]
in bash
or zsh
) but also depending on the shell in the let
, [
/test
, declare/typeset/export...
, return
, break
, continue
, exit
, printf
, print
builtins, array indices, ((..))
and [[...]]
constructs to name a few).
To check that a variable contains a literal decimal integer number, you can use POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Beware that [0-9]
in some locales matches more than 0123456789. [[:digit:]]
should be OK but I wouldn't bet on it.
Also remember that numbers with leading zeros are treated as octal in some contexts (010
is sometimes 10, sometimes 8) and beware that the check above will let through numbers that are potentially bigger than the maximum integer supported by your system (or whatever application you will use that integer in; bash for instance treats 18446744073709551616 as 0 as that's 264).
Examples:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
More reading at:
http://www.zsh.org/mla/workers/2014/msg01041.html (where Oliver Kiddle brought thex[0$(...)]
issue to our attention).- http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9971
http://thread.gmane.org/gmane.comp.shells.bash.bugs/22737 for another mis-design potentially leading to code injection inbash
.
Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.
edited Dec 19 '18 at 9:13
answered Dec 8 '14 at 13:29
Stéphane Chazelas
299k54564913
299k54564913
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f172103%2fsecurity-implications-of-using-unsanitized-data-in-shell-arithmetic-evaluation%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown