今天顺手写个汉字转拼音的脚本,意外发现有个字会导致产生语法错误:

print("乗")

稍微多试了几次,发现这么写反而没有错误:

print("乗"")

这个汉字实际上是导致 Lua loadstring 函数判断结束的引号出了问题,误以为字符串还没有结束,具体原因得有空追一下 Lua 的源码才知道。只是觉得如果谁使用 Lua 用作服务器脚本处理语言,用户可以利用这个字符,在读写用户数据的时候进行注入攻击。

后续

断点跟踪看了下, Lua 在处理字符串转义时的函数是按照 ASCII 值按位转义的。

static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
  size_t l;
  const char *s = luaL_checklstring(L, arg, &l);
  luaL_addchar(b, '"');
  while (l--) {
    switch (*s) {
      case '"': case '\\': case '\n': {
        luaL_addchar(b, '\\');
        luaL_addchar(b, *s);
        break;
      }
      case '\r': {
        luaL_addlstring(b, "\\r", 2);
        break;
      }
      case '\0': {
        luaL_addlstring(b, "\\000", 4);
        break;
      }
      default: {
        luaL_addchar(b, *s);
        break;
      }
    }
    s++;
  }
  luaL_addchar(b, '"');
}

而很巧的是,这些汉字在 GBK 编码下,后半部分的 ASCII 码恰好和\相同,所以 Lua 的转义、解析函数会自动在前面添加/删除转义符。