{"id":989,"date":"2010-12-30T14:27:32","date_gmt":"2010-12-30T19:27:32","guid":{"rendered":"http:\/\/www.kickflop.net\/blog\/?p=989"},"modified":"2011-02-25T13:24:01","modified_gmt":"2011-02-25T18:24:01","slug":"when-shell-globbing-attacks","status":"publish","type":"post","link":"https:\/\/www.kickflop.net\/blog\/2010\/12\/30\/when-shell-globbing-attacks\/","title":{"rendered":"When Shell Globbing Attacks"},"content":{"rendered":"<p>Since when does &#8220;S&#8221; fall in the range a-z?  Beware of the LC_COLLATE environment variable.<!--more--><\/p>\n<pre>\r\nsomehost# mkdir STOCK\r\nsomehost# mv [a-z]* STOCK\r\nmv: cannot move `STOCK' to a subdirectory of itself, `STOCK\/STOCK' \r\nsomehost#\r\n<\/pre>\n<p>It did move everything but &#8220;STOCK&#8221;.  Let&#8217;s move the files back and fire up strace:<\/p>\n<pre>\r\nsomehost# mv STOCK\/* .\r\nsomehost# strace -f mv [a-z]* STOCK\r\n...\r\nexecve(\"\/bin\/mv\", [\"mv\", \"lmhosts\", \"secrets.tdb\", \"smb.conf\", \"smbpasswd\", \"smbusers\",\r\n\"STOCK\", \"STOCK\"], [\/* 28 vars *\/]) = 0\r\n...\r\n<\/pre>\n<p>Happens at least under with BASH 2.05b1 and BASH 3.2.  At the smart prodding of a coworker, let&#8217;s check the manpage for bash:<\/p>\n<pre>\r\nnocaseglob        If set, bash matches filenames in a case-insensitive fashion when performing\r\n                       pathname expansion (see Pathname Expansion above).\r\n<\/pre>\n<p>No, &#8220;set -o&#8221; shows that&#8217;s not set.<\/p>\n<pre>\r\nPattern Matching\r\n\r\n[...]                 Matches any one of the enclosed characters. A pair of characters\r\n                      separated by a hyphen denotes a range expression; any character that\r\n                      sorts between those two characters, inclusive, using the current\r\n                      locale's collating sequence and character set, is matched. If the first\r\n                      character  following the \u00e2\u20ac\u02dc[\u00e2\u20ac\u2122 is a \u00e2\u20ac\u02dc!\u00e2\u20ac\u2122 or a \u00e2\u20ac\u02dc^\u00e2\u20ac\u2122 then any character not\r\n                      enclosed is matched. A \u00e2\u20ac\u02dc\u00e2\u02c6\u2019\u00e2\u20ac\u2122 may be matched by including it as the first or\r\n                      last character in the set. A \u00e2\u20ac\u02dc]\u00e2\u20ac\u2122 may be matched by including it as the\r\n                      first character in the set. The sorting order of characters in range\r\n                      expressions is determined by the current locale and the value of the\r\n                      LC_COLLATE shell variable, if set.\r\n\r\n                      For example, in the default C locale, \u00e2\u20ac\u02dc[a-dx-z]\u00e2\u20ac\u2122 is equivalent to '[abcdxyz]\u00e2\u20ac\u2122.\r\n                      Many locales sort characters in dictionary order, and in these locales\r\n                      \u00e2\u20ac\u02dc[a-dx-z]\u00e2\u20ac\u2122 is typically not equivalent to \u00e2\u20ac\u02dc[abcdxyz]\u00e2\u20ac\u2122; it might be equivalent\r\n                      to \u00e2\u20ac\u02dc[aBbCcDdxXyYz]\u00e2\u20ac\u2122, for example. To obtain the traditional interpretation\r\n                      of ranges in bracket expressions, you can force the use of the C locale\r\n                      by setting the LC_COLLATE or LC_ALL environment variable to the value\r\n                      \u00e2\u20ac\u02dcC\u00e2\u20ac\u2122.\r\n<\/pre>\n<p>Hmmmmm.<\/p>\n<pre>\r\nsomehost# echo $LC_COLLATE\r\nen_US.UTF-8\r\nsomehost# LC_COLLATE=C\r\nsomehost# mv STOCK\/* .\r\nsomehost# mv [a-z]* STOCK\r\nsomehost#\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Since when does &#8220;S&#8221; fall in the range a-z? Beware of the LC_COLLATE environment variable.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"class_list":["post-989","post","type-post","status-publish","format-standard","hentry","category-sysadmin"],"_links":{"self":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts\/989","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/comments?post=989"}],"version-history":[{"count":10,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts\/989\/revisions"}],"predecessor-version":[{"id":1194,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts\/989\/revisions\/1194"}],"wp:attachment":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/media?parent=989"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/categories?post=989"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/tags?post=989"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}