Code Execution in Mathematical Context

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Code Execution in Mathematical Context

Nils Emmerich
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -g -O2 -Wno-parentheses -Wno-format-security
uname output: Linux VirtualBox 4.18.0-20-generic #21~18.04.1-Ubuntu SMP $
Machine Type: x86_64-pc-linux-gnu

Bash Version: 5.0
Patch Level: 0
Release Status: release

Description:
         It is possible to get code execution via a user supplied
variable in the mathematical context.
         I don't know if this is considered a bug or not, but if not, I
think people should be made aware that the mathematical context is unsafe.

Repeat-By:
         If this is considered a bug I would like to get in contact with
someone in charge.

--
Nils Emmerich

ERNW Research GmbH
Carl-Bosch-Str. 4
69115 Heidelberg
www.ernw.de
Tel. +49 6221 480390 (Sekretariat)
Handelsregister Mannheim HRB 723285
Geschäftsführer: Dr.-Ing. Andreas Dewald

Blog: www.insinuator.net
Conference: www.troopers.de


Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Greg Wooledge
On Tue, Jun 04, 2019 at 01:42:40PM +0200, Nils Emmerich wrote:

> Configuration Information [Automatically generated, do not change]:
> Machine: x86_64
> OS: linux-gnu
> Compiler: gcc
> Compilation CFLAGS: -g -O2 -Wno-parentheses -Wno-format-security
> uname output: Linux VirtualBox 4.18.0-20-generic #21~18.04.1-Ubuntu SMP $
> Machine Type: x86_64-pc-linux-gnu
>
> Bash Version: 5.0
> Patch Level: 0
> Release Status: release
>
> Description:
>         It is possible to get code execution via a user supplied variable in
> the mathematical context.
>         I don't know if this is considered a bug or not, but if not, I think
> people should be made aware that the mathematical context is unsafe.

It's a known behavior.  There are some workarounds, but it would help
if we could see what you're currently doing.

The first workaround is: with scalar variables, use the variable name
without a $ prefix.  This forces the variable's contents to be interpreted
by the math context instead of the regular shell context.

For example:  x=$((y + 7))   rather than   x=$(($y + 7))
The latter expands whatever is in y, even if it's not a valid math
expression.  Introducing random junk at that level can lead to surprises
when that junk hits the math context.

The second workaround is: with array variables, generally single-quote
things even when they feel redundant.

For example:  (( 'a[i]++' ))   or   let 'a[i]++'
Without quotes in the latter, there is a potential globbing issue (it
could match a file named ai++ in the current directory, or it could be
removed as a non-matching glob if nullglob is on).

Without quotes in the former, something bad happens, but I can't remember
the details off the top of my head.

It's even worse if you use the $ prefix on the index variable inside the
array's square brackets.

For example:

wooledg:~$ a=(foo bar baz)
wooledg:~$ i='$(date >&2)'
wooledg:~$ echo $(( a[$i] ))
Tue 04 Jun 2019 09:23:28 AM EDT
0

With single quotes around the expression, at least the command substitution
isn't performed.

wooledg:~$ echo $(( 'a[$i]' ))
bash: 'a[$(date >&2)]' : syntax error: operand expected (error token is "'a[$(date >&2)]' ")

So, as with most shell issues, it ultimately comes down to "Use More Quotes".

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Chet Ramey
In reply to this post by Nils Emmerich
On 6/4/19 7:42 AM, Nils Emmerich wrote:

> Bash Version: 5.0
> Patch Level: 0
> Release Status: release
>
> Description:
>         It is possible to get code execution via a user supplied variable
> in the mathematical context.
>         I don't know if this is considered a bug or not, but if not, I
> think people should be made aware that the mathematical context is unsafe.

The tokens in a mathematical expression undergo a set of word expansions.
If you could post the example you're using we can analyze its behavior.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://tiswww.cwru.edu/~chet/

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Nils Emmerich
If you run
echo "$((v))"
and v is a user supplied variable.
If the user put a specific string in v, he can execute whatever he wants
in the name of the script, because echo "$((v))" will run that code.

Am 6/4/2019 um 4:29 PM schrieb Chet Ramey:

> On 6/4/19 7:42 AM, Nils Emmerich wrote:
>
>> Bash Version: 5.0
>> Patch Level: 0
>> Release Status: release
>>
>> Description:
>>          It is possible to get code execution via a user supplied variable
>> in the mathematical context.
>>          I don't know if this is considered a bug or not, but if not, I
>> think people should be made aware that the mathematical context is unsafe.
> The tokens in a mathematical expression undergo a set of word expansions.
> If you could post the example you're using we can analyze its behavior.
>
--
Nils Emmerich

ERNW Research GmbH
Carl-Bosch-Str. 4
69115 Heidelberg
www.ernw.de
Tel. +49 6221 480390 (Sekretariat)
Handelsregister Mannheim HRB 723285
Geschäftsführer: Dr.-Ing. Andreas Dewald

Blog: www.insinuator.net
Conference: www.troopers.de


Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Ilkka Virta
In reply to this post by Greg Wooledge
On 4.6. 16:24, Greg Wooledge wrote:
> On Tue, Jun 04, 2019 at 01:42:40PM +0200, Nils Emmerich wrote:
>> Bash Version: 5.0
>> Patch Level: 0
>> Release Status: release
>>
>> Description:
>>          It is possible to get code execution via a user supplied variable in
>> the mathematical context.

> For example:  (( 'a[i]++' ))   or   let 'a[i]++'

> Without quotes in the former, something bad happens, but I can't remember
> the details off the top of my head.

If the bad user supplied variable contains array indexing in itself,
e.g. bad='none[$(date >&2)]' then using it in an arithmetic expansion
still executes the 'date', single quotes or not (the array doesn't need
to exist):

   $ a=(123 456 789) bad='none[$(date >&2)]'
   $ unset none
   $ (( a[bad]++ ))
   Tue Jun  4 22:00:38 EEST 2019
   $ (( 'a[bad]++' ))
   Tue Jun  4 22:00:42 EEST 2019

Same here, of course:

   $ (( bad ))
   Tue Jun  4 22:04:29 EEST 2019
   $ (( 'bad' ))
   Tue Jun  4 22:04:32 EEST 2019

So, it doesn't seem the single-quotes help. They do seem to break the
whole expression within "$(( ))", though:

   $ echo "$(( 'a[2]' ))"
   bash: 'a[2]' : syntax error: operand expected (error token is "'a[2]' ")
   $ i=2
   $ echo "$(( 'a[i]' ))"
   bash: 'a[i]' : syntax error: operand expected (error token is "'a[i]' ")
   $ echo "$(( 'a[$i]' ))"
   bash: 'a[2]' : syntax error: operand expected (error token is "'a[2]' ")


Maybe it would be better to try to sanity-check any user-provided values
first:

   $ case $var in *[^0123456789]*) echo "Invalid input" >&2; exit 1;; esac
   $ (( a[var]++ ))      # safe now?


--
Ilkka Virta / [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Chet Ramey
On 6/4/19 3:26 PM, Ilkka Virta wrote:

> On 4.6. 16:24, Greg Wooledge wrote:
>> On Tue, Jun 04, 2019 at 01:42:40PM +0200, Nils Emmerich wrote:
>>> Bash Version: 5.0
>>> Patch Level: 0
>>> Release Status: release
>>>
>>> Description:
>>>          It is possible to get code execution via a user supplied
>>> variable in
>>> the mathematical context.
>
>> For example:  (( 'a[i]++' ))   or   let 'a[i]++'
>
>> Without quotes in the former, something bad happens, but I can't remember
>> the details off the top of my head.
>
> If the bad user supplied variable contains array indexing in itself, e.g.
> bad='none[$(date >&2)]' then using it in an arithmetic expansion still
> executes the 'date', single quotes or not (the array doesn't need to exist):

Because the value is treated as an expression, not an integer constant.


> Same here, of course:
>
>   $ (( bad ))
>   Tue Jun  4 22:04:29 EEST 2019
>   $ (( 'bad' ))
>   Tue Jun  4 22:04:32 EEST 2019

Quoting a string doesn't make it a non-identifier in this context.

>
> So, it doesn't seem the single-quotes help. They do seem to break the whole
> expression within "$(( ))", though:
>
>   $ echo "$(( 'a[2]' ))"
>   bash: 'a[2]' : syntax error: operand expected (error token is "'a[2]' ")

The expression between the parens is treated as if it were within double
quotes, where single quotes are not special.


--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://tiswww.cwru.edu/~chet/

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Ilkka Virta
On 5.6. 17:05, Chet Ramey wrote:
> On 6/4/19 3:26 PM, Ilkka Virta wrote:
>> If the bad user supplied variable contains array indexing in itself, e.g.
>> bad='none[$(date >&2)]' then using it in an arithmetic expansion still
>> executes the 'date', single quotes or not (the array doesn't need to exist):
>
> Because the value is treated as an expression, not an integer constant.

And I suppose that's by design, or just required by the arithmetic
expression syntax, right? I think that was part of the original question.

>>    $ (( 'bad' ))
>>    Tue Jun  4 22:04:32 EEST 2019
>
> Quoting a string doesn't make it a non-identifier in this context.

So is there some other "simple" way of preventing that, then?

>>    $ echo "$(( 'a[2]' ))"
>>    bash: 'a[2]' : syntax error: operand expected (error token is "'a[2]' ")
>
> The expression between the parens is treated as if it were within double
> quotes, where single quotes are not special.

I did put the double-quotes around the $((...)), but the same happens
even without them. Is this just a difference between ((...)) and
$((...)) for some reason?

--
Ilkka Virta / [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Chet Ramey
On 6/5/19 1:39 PM, Ilkka Virta wrote:

> On 5.6. 17:05, Chet Ramey wrote:
>> On 6/4/19 3:26 PM, Ilkka Virta wrote:
>>> If the bad user supplied variable contains array indexing in itself, e.g.
>>> bad='none[$(date >&2)]' then using it in an arithmetic expansion still
>>> executes the 'date', single quotes or not (the array doesn't need to
>>> exist):
>>
>> Because the value is treated as an expression, not an integer constant.
>
> And I suppose that's by design, or just required by the arithmetic
> expression syntax, right? I think that was part of the original question.

OK. Yes, that's been part of the design since I implemented it in 1990.
The goal at the time was compatibility with ksh88. ksh93 still supports
the same thing.

>
>>>    $ (( 'bad' ))
>>>    Tue Jun  4 22:04:32 EEST 2019
>>
>> Quoting a string doesn't make it a non-identifier in this context.
>
> So is there some other "simple" way of preventing that, then?

Maybe we could expand the effect of the assoc_expand_once option to cover
this case.

>
>>>    $ echo "$(( 'a[2]' ))"
>>>    bash: 'a[2]' : syntax error: operand expected (error token is "'a[2]' ")
>>
>> The expression between the parens is treated as if it were within double
>> quotes, where single quotes are not special.
>
> I did put the double-quotes around the $((...)), but the same happens even
> without them. Is this just a difference between ((...)) and $((...)) for
> some reason?

When you use $((...)), the expression between the parens is treated as if
it were within double quotes, as per POSIX:

"The expression shall be treated as if it were in double-quotes, except
that a double-quote inside the expression is not treated specially. The
shell shall expand all tokens in the expression for parameter expansion,
command substitution, and quote removal."

I think this is an unfortunate difference between ((...)), which is
supposed to be equivalent to `let "..."' and $((...)). I think it should
probably be a syntax error in both cases.


--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://tiswww.cwru.edu/~chet/

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

David
In reply to this post by Ilkka Virta
On Thu, 6 Jun 2019 at 03:40, Ilkka Virta <[hidden email]> wrote:

> On 5.6. 17:05, Chet Ramey wrote:
> > On 6/4/19 3:26 PM, Ilkka Virta wrote:
>
> >>    $ echo "$(( 'a[2]' ))"
> >>    bash: 'a[2]' : syntax error: operand expected (error token is "'a[2]' ")
> >
> > The expression between the parens is treated as if it were within double
> > quotes, where single quotes are not special.
>
> I did put the double-quotes around the $((...))

Hi Ilkka Virta

In case of any confusion...

Please note no-one is talking about putting double quotes around $((...))
which would be "$((...))"

Regarding $((...)) when Chet refers above to "the expression between the parens"
he means whatever is between the parentheses, in this case the three dots.

If I understand correctly, Chet is saying there that $((...)) is
parsed as if it was written
$(("...")) and therefore any single quotes inside the parentheses are
not special.

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Greg Wooledge
On Thu, Jun 06, 2019 at 11:33:56AM +1000, David wrote:
> Regarding $((...)) when Chet refers above to "the expression between the parens"
> he means whatever is between the parentheses, in this case the three dots.
>
> If I understand correctly, Chet is saying there that $((...)) is
> parsed as if it was written
> $(("...")) and therefore any single quotes inside the parentheses are
> not special.

But...

On Tue, Jun 04, 2019 at 09:24:27AM -0400, Greg Wooledge wrote:
> wooledg:~$ a=(foo bar baz)
> wooledg:~$ i='$(date >&2)'
> wooledg:~$ echo $(( a[$i] ))
> Tue 04 Jun 2019 09:23:28 AM EDT
> 0

> wooledg:~$ echo $(( 'a[$i]' ))
> bash: 'a[$(date >&2)]' : syntax error: operand expected (error token is "'a[$(date >&2)]' ")

I definitely got different results when I added single quotes.

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Ilkka Virta
On 6.6. 15:53, Greg Wooledge wrote:
>> wooledg:~$ echo $(( a[$i] ))
>> Tue 04 Jun 2019 09:23:28 AM EDT
>> 0
>
>> wooledg:~$ echo $(( 'a[$i]' ))
>> bash: 'a[$(date >&2)]' : syntax error: operand expected (error token is "'a[$(date >&2)]' ")
>
> I definitely got different results when I added single quotes.

Well, yes... The point I was trying to make before (and which Chet
seemed to confirm) is that the quotes break the $((..)) expression
completely, even if 'i' there is just a number, and not any fancier than
that.

   $ a=(123 456 789)
   $ i=2
   $ echo $(( a[$i] ))
   789
   $ echo $(( 'a[$i]' ))
   bash5.0.3: 'a[2]' : syntax error: operand expected (error token is
"'a[2]' ")
   $ echo $(( 'a[2]' ))
   bash5.0.3: 'a[2]' : syntax error: operand expected (error token is
"'a[2]' ")

And with ((..)), the command substitution runs with a slightly different
i, quotes or not and with $i or i:

   $ i='a[$(date >&2)]'
   $ (( a[$i]++ ))
   Thu Jun  6 16:46:06 EEST 2019
   bash5.0.3: a[]: bad array subscript
   bash5.0.3: a[]: bad array subscript
   $ (( a[i]++ ))
   Thu Jun  6 16:46:12 EEST 2019
   $ (( 'a[$i]++' ))
   Thu Jun  6 16:46:18 EEST 2019
   $ (( 'a[i]++' ))
   Thu Jun  6 16:46:31 EEST 2019


So if we want "valid" values in the index to work, and invalid ones to
not do anything nasty, I can't seem to find a case where quotes would
help with that.

--
Ilkka Virta / [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Code Execution in Mathematical Context

Chet Ramey
In reply to this post by Greg Wooledge
On 6/6/19 8:53 AM, Greg Wooledge wrote:

> On Thu, Jun 06, 2019 at 11:33:56AM +1000, David wrote:
>> Regarding $((...)) when Chet refers above to "the expression between the parens"
>> he means whatever is between the parentheses, in this case the three dots.
>>
>> If I understand correctly, Chet is saying there that $((...)) is
>> parsed as if it was written
>> $(("...")) and therefore any single quotes inside the parentheses are
>> not special.
>
> But...
>
> On Tue, Jun 04, 2019 at 09:24:27AM -0400, Greg Wooledge wrote:
>> wooledg:~$ a=(foo bar baz)
>> wooledg:~$ i='$(date >&2)'
>> wooledg:~$ echo $(( a[$i] ))
>> Tue 04 Jun 2019 09:23:28 AM EDT
>> 0
>
>> wooledg:~$ echo $(( 'a[$i]' ))
>> bash: 'a[$(date >&2)]' : syntax error: operand expected (error token is "'a[$(date >&2)]' ")
>
> I definitely got different results when I added single quotes.

These two things are consistent. If you treat the expression as if it
were within double quotes for expansion, the single quotes are preserved
(they're not special in double quotes and aren't removed by quote
removal) and the arithmetic evaluator doesn't know what to do with them.


--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://tiswww.cwru.edu/~chet/