0

I am working with an application that runs commands in bash. This is the "template" it is using:

sh -c '<command> "<argument>"'

Please note that I cannot edit the quotes, only thing I can edit is the command and argument. I cannot escape the dollar sign either.

This "template" works fine unless there is a dollar sign in the argument:

sh -c 'echo "x=test$test"'

gives the following output:

x=test

How can I get the exact output, which is:

x=test$test

I could do this if I could switch the quotes:

sh -c "echo '"'x=test$test'"'"
x=test$test

Any way to accomplish this?

Iokanaan Iokan
  • 704
  • 3
  • 12
  • 26
  • 1
    This is *exceedingly* bad design, as in, nearly impossible to secure against shell injection attacks. Correct usage is to invoke an out-of-process shell in a manner akin to `execlp("sh", "sh", "-c", script, "_", arg1, arg2, ..., NULL)`, where the command refers to `"$1"`, `"$2"`, etc. to refer to those out-of-band arguments. I'd suggest filing a ticket for a security bug against whatever larger program, library or framework is giving you these constraints. – Charles Duffy Oct 19 '16 at 15:34
  • BTW, why do you say you can edit both command and argument, but also that you can't escape the dollar sign? Escaping the dollar sign is just a subset of editing the argument, no? – Charles Duffy Oct 19 '16 at 15:37
  • BTW, you have this tagged `bash`, but then you're calling `sh`. Is `bash` being used to call `sh`, or is this really a mistagged `sh` question? POSIX sh is a very different shell language from bash. – Charles Duffy Oct 19 '16 at 15:39
  • The argument is in the form of a variable that is being expanded by the application. I can change how the variable looks by adding quotes around it but cannot edit its value. In the application, the argument is in the form of x={VALUE} and application changes it into x=something. So all I could do is x="{VALUE}", x='{VALUE}' or similar things. – Iokanaan Iokan Oct 19 '16 at 15:42
  • I still need to know which shell is actually interpreting this code (obviously the one started by `sh -c` is POSIX sh, but the question is which one is parsing the command that does that). I have a solution that will work if and only if that shell is bash, but not if it's baseline-POSIX. – Charles Duffy Oct 19 '16 at 15:44
  • it is bash interpreting the code – Iokanaan Iokan Oct 19 '16 at 15:45
  • Okay. Had a mismatch between what I was testing and my answer, but it's in working order now. Do note, however, that it only works for cases where the argument doesn't contain `'` literals; that can't be fixed without modifying the argument (as with `argument=${argument//"'"/$'\\\''}` prior to the substitution), or replacing the template with something less broken-by-design. – Charles Duffy Oct 19 '16 at 15:55

1 Answers1

1

If your sh -c command is being run by bash (not by a baseline POSIX shell), and your argument doesn't contain ' literals, then you can do some trickery, as follows:

#!/bin/bash
sh -c 'echo ""'$'\'x=test$test\'""'

That is to say, that the string "'$'\' should be prepended to <argument>, and \'" should be appended.

Note that this is ABSOLUTELY NOT SECURE against shell injection attacks. To make it so, we'd need to modify the inner contents of argument; at bare minimum, replacing \ with \\ and ' with \'.


Even better (particularly from a security perspective) would be to fix the program you're working with to pass arguments out-of-band from code. To do that would mean an argv looking like the following (given below in Python syntax suitable for subprocess.Popen(cmd, shell=False)):

['sh', '-c', 'echo "$1"', '_', 'x=test$test']
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • This works from the bash shell but it did not work when run through the application so I am assuming that it does not have it interpreted by bash. I've found the function that performs this operation. I'm not a programmer myself but would be great if you could take a look at it: https://github.com/satterly/zabbix-stats/blob/master/src/libs/zbxexec/execute.c Function is called zbx_popen – Iokanaan Iokan Oct 19 '16 at 16:06
  • it's not interpreted by *any* shell at all, there -- they're directly `exec`ing `sh`. Anyhow, while that code does rule out the best-practice approach of passing arguments out-of-band from code, it certainly doesn't enforce the template you asked this question about; where's that coming from? – Charles Duffy Oct 19 '16 at 16:10
  • ...which is to say, where did you get the ` ""` template as a requirement from? – Charles Duffy Oct 19 '16 at 16:12
  • I've seen that format in the debug logs of the application and I've assumed that. Now that you have pointed it out, It might as well be just a formatting for logging purposes... See the log entry here: https://gist.github.com/anonymous/5fda313bf98a23af3255f9f4aaef8104 – Iokanaan Iokan Oct 19 '16 at 16:20
  • What the application does is basically passes that message you see in the log as an argument to a python script. During the process, item_value=MSSQL$test1 is converted to item_value=MSSQL – Iokanaan Iokan Oct 19 '16 at 16:24
  • Sorry -- I don't do pastebin.com. (They may have cleaned up their practices since -- I understand they're using doubleclick as their ad network -- but they used to be a hive of scum, villany, and animated ads from questionable sources). Could you repost to https://gist.github.com/? – Charles Duffy Oct 19 '16 at 16:24
  • Ahh. So, yeah -- they're using double quotes there, but the actual implementation of `zbx_popen()` doesn't require that; you can use single-quotes without it being any kind of an issue. Of course, yes, you still need to escape any literal single quotes inside those syntactic single-quotes... but, well, that's not so horribly hard to do in C, just a little tedious. – Charles Duffy Oct 19 '16 at 16:26
  • 1
    Thanks for your help. I've found out that they have fixed this in the new version of the application so I'll plan for an update. – Iokanaan Iokan Oct 20 '16 at 08:41