Security Implications of using unsanitized data in Shell Arithmetic evaluation












15














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?










share|improve this question





























    15














    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?










    share|improve this question



























      15












      15








      15


      5





      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?










      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Apr 13 '17 at 12:36









      Community

      1




      1










      asked Dec 8 '14 at 12:57









      garethTheRed

      24.1k36180




      24.1k36180






















          1 Answer
          1






          active

          oldest

          votes


















          19














          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 the x[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 in bash.


          • Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.






          share|improve this answer























            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
            });


            }
            });














            draft saved

            draft discarded


















            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









            19














            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 the x[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 in bash.


            • Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.






            share|improve this answer




























              19














              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 the x[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 in bash.


              • Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.






              share|improve this answer


























                19












                19








                19






                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 the x[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 in bash.


                • Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.






                share|improve this answer














                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 the x[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 in bash.


                • Security implications of forgetting to quote a variable in bash/POSIX shells where that and leaving a variable unquoted can aggravate each other.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 19 '18 at 9:13

























                answered Dec 8 '14 at 13:29









                Stéphane Chazelas

                299k54564913




                299k54564913






























                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    Morgemoulin

                    Scott Moir

                    Souastre