洛阳新闻

usdt承兑商(www.payusdt.vip):Nginx_lua 100参数绕过原理详解

来源:洛阳新闻网 发布时间:2021-04-14 浏览次数:

USDT跑分平台

U交所(www.payusdt.vip)是使用TRC-20协议的Usdt官方交易所,开放USDT帐号注册、usdt小额交易、usdt线下现金交易、usdt实名不实名交易、usdt场外担保交易的平台。免费提供场外usdt承兑、低价usdt渠道、Usdt提币免手续费、Usdt交易免手续费。U交所开放usdt otc API接口、支付回调等接口。

一、环境搭建
Nginx_lua 安装

https://github.com/openresty/lua-nginx-module,installation

wget 'https://openresty.org/download/nginx-1.19.3.tar.gz'
 tar -xzvf nginx-1.19.3.tar.gz
 cd nginx-1.19.3/

 , tell nginx's build system where to find LuaJIT 2.0:
 export LUAJIT_LIB=/path/to/luajit/lib
 export LUAJIT_INC=/path/to/luajit/include/luajit-2.0

 , tell nginx's build system where to find LuaJIT 2.1:
 export LUAJIT_LIB=/path/to/luajit/lib
 export LUAJIT_INC=/path/to/luajit/include/luajit-2.1

 , Here we assume Nginx is to be installed under /opt/nginx/.
 ./configure --prefix=/opt/nginx 
         --with-ld-opt="-Wl,-rpath,/path/to/luajit/lib" 
         --add-module=/path/to/ngx_devel_kit 
         --add-module=/path/to/lua-nginx-module

 , Note that you may also want to add `./configure` options which are used in your
 , current nginx build.
 , You can get usually those options using command nginx -V

 , you can change the parallism number 2 below to fit the number of spare CPU cores in your
 , machine.
 make -j2
 make install

安装完之后可以在nginx.conf 写入设置。可以动态在Nginx 层面举行过滤和调剂

这里使用一个很简朴的方式来展示绕过的原理

location = /api2 {
        content_by_lua_block {
            tmp=''
            for i,v in pairs(ngx.req.get_uri_args()) do
              if type(i)=='string' then 
                tmp=tmp..i..' '
              end
            end
            ngx.header.content_type = "application/json;"
            ngx.status = 200
            ngx.say(tmp)
            ngx.exit(200)
        }
    }

这里是意思是接见/api2 然后返回get的所有参数。默认他是接受100个参数。当跨越100个参数的时刻会默认不会纪录。这样杀青了一个绕过的一个方式。演示如下:

首先先发送两个id 已往试试

那么试试id1->id100

a=''
for i in range(1,102):
   a=a 'id' str(i) '=11&'
print(a)
GET /api2?id1=11&id2=11&id3=11&id4=11&id5=11&id6=11&id7=11&id8=11&id9=11&id10=11&id11=11&id12=11&id13=11&id14=11&id15=11&id16=11&id17=11&id18=11&id19=11&id20=11&id21=11&id22=11&id23=11&id24=11&id25=11&id26=11&id27=11&id28=11&id29=11&id30=11&id31=11&id32=11&id33=11&id34=11&id35=11&id36=11&id37=11&id38=11&id39=11&id40=11&id41=11&id42=11&id43=11&id44=11&id45=11&id46=11&id47=11&id48=11&id49=11&id50=11&id51=11&id52=11&id53=11&id54=11&id55=11&id56=11&id57=11&id58=11&id59=11&id60=11&id61=11&id62=11&id63=11&id64=11&id65=11&id66=11&id67=11&id68=11&id69=11&id70=11&id71=11&id72=11&id73=11&id74=11&id75=11&id76=11&id77=11&id78=11&id79=11&id80=11&id81=11&id82=11&id83=11&id84=11&id85=11&id86=11&id87=11&id88=11&id89=11&id90=11&id91=11&id92=11&id93=11&id94=11&id95=11&id96=11&id97=11&id98=11&id99=11&id100=11&id101=11 HTTP/1.1
Host: 192.168.1.70
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Connection: close

返回从1-100

id76 id74 id64 id62 id60 id61 id5 id73 id71 id14 id91 id15 id20 id22 id12 id66 id13 id32 id10 id31 id33 id11 id92 id21 id84 id93 id85 id67 id30 id83 id58 id3 id88 id59 id98 id68 id69 id81 id48 id49 id8 id9 id25 id24 id26 id16 id79 id17 id36 id35 id18 id89 id99 id29 id28 id100 id97 id96 id95 id94 id6 id38 id90 id87 id39 id86 id19 id82 id80 id42 id56 id78 id52 id77 id75 id57 id44 id53 id7 id54 id72 id50 id1 id46 id55 id70 id51 id65 id23 id2 id40 id37 id4 id43 id47 id27 id41 id45 id34 id63

然则没有id101 那么这个id101 那里去了呢?

那么看看ngx.req.get_uri_args() 这个函数是怎么实现的

二、源码剖析
参考文章:

https://blog.csdn.net/liujiyong7/article/details/37692027

src/ngx_http_lua_module.c为模块主入口文件

注册函数的写法有统一的名堂:

static int
ngx_http_lua_ngx_req_get_method(lua_State *L)
{
    int                      n;
    ngx_http_request_t      *r;
    n = lua_gettop(L);
    if (n != 0) {
        return luaL_error(L, "only one argument expected but got %d", n);
    }
    r = ngx_http_lua_get_req(L);//从lua全局变量获得request结构体指针,见4.2.2
    if (r == NULL) {
        return luaL_error(L, "request object not found");
    }
    ngx_http_lua_check_fake_request(L, r);//检查r正当性

    lua_pushlstring(L, (char *) r->method_name.data, r->method_name.len);//将method压栈
    return 1;
}

注册get_uri_args 在

所有的nginx api for lua注册在lua-nginx-module/src/ngx_http_lua_util.c:ngx_http_lua_inject_ngx_api 函数中

与request有关的注册在lua-nginx-module/src/ngx_http_lua_util.c: ngx_http_lua_inject_req_api 函数中

ngx_http_lua_inject_ngx_api 函数

static void
ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf,
    ngx_log_t *log)
{
    lua_createtable(L, 0 /* narr */, 113 /* nrec */);    /* ngx.* */

    lua_pushcfunction(L, ngx_http_lua_get_raw_phase_context);
    lua_setfield(L, -2, "_phase_ctx");

    ngx_http_lua_inject_arg_api(L);

    ngx_http_lua_inject_http_consts(L);
    ngx_http_lua_inject_core_consts(L);

    ngx_http_lua_inject_log_api(L);
    ngx_http_lua_inject_output_api(L);
    ngx_http_lua_inject_string_api(L);
    ngx_http_lua_inject_control_api(log, L);
    ngx_http_lua_inject_subrequest_api(L);
    ngx_http_lua_inject_sleep_api(L);

    ngx_http_lua_inject_req_api(log, L);
    ngx_http_lua_inject_resp_header_api(L);
    ngx_http_lua_create_headers_metatable(log, L);
    ngx_http_lua_inject_shdict_api(lmcf, L);
    ngx_http_lua_inject_socket_tcp_api(log, L);
    ngx_http_lua_inject_socket_udp_api(log, L);
    ngx_http_lua_inject_uthread_api(log, L);
    ngx_http_lua_inject_timer_api(L);
    ngx_http_lua_inject_config_api(L);

    lua_getglobal(L, "package"); /* ngx package */
    lua_getfield(L, -1, "loaded"); /* ngx package loaded */
    lua_pushvalue(L, -3); /* ngx package loaded ngx */
    lua_setfield(L, -2, "ngx"); /* ngx package loaded */
    lua_pop(L, 2);

    lua_setglobal(L, "ngx");

    ngx_http_lua_inject_coroutine_api(log, L);
}

ngx_http_lua_inject_req_api 函数

void
ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L)
{
    /* ngx.req table */

    lua_createtable(L, 0 /* narr */, 23 /* nrec */);    /* .req */

    ngx_http_lua_inject_req_header_api(L);
    ngx_http_lua_inject_req_uri_api(log, L);
    ngx_http_lua_inject_req_args_api(L);
    ngx_http_lua_inject_req_body_api(L);
    ngx_http_lua_inject_req_socket_api(L);
    ngx_http_lua_inject_req_misc_api(L);

    lua_setfield(L, -2, "req");
}

看着应该是ngx_http_lua_inject_req_uri_api 和 ngx_http_lua_inject_req_args_api 对照像 跟踪一下这两个函数

ngx_http_lua_inject_req_uri_api

void
ngx_http_lua_inject_req_uri_api(ngx_log_t *log, lua_State *L)
{
    lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri);
    lua_setfield(L, -2, "set_uri");
}

ngx_http_lua_inject_req_args_api

ngx_http_lua_inject_req_args_api(lua_State *L)
{
    lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri_args);
    lua_setfield(L, -2, "set_uri_args");

    lua_pushcfunction(L, ngx_http_lua_ngx_req_get_post_args);
    lua_setfield(L, -2, "get_post_args");
}}

这里只有set_uri_args 和get_post_args 并没有找到get_uri_args

这里陷入了深深的沉思

,

U交所

U交所(www.payusdt.vip),全球頂尖的USDT場外擔保交易平臺。

,

全局搜索下只有ngx_http_lua_ffi_req_get_uri_args 这一个函数是相关的 。

这个函数在src/ngx_http_lua_args.c

三、查看get_post_args 这个函数历程
首先看一下get_post_args 这个一个历程吧

注册为get_post_args 那么nginx内部的挪用方式为ngx.req.get_post_args

lua_pushcfunction(L, ngx_http_lua_ngx_req_get_post_args);
lua_setfield(L, -2, "get_post_args");

ngx_http_lua_ngx_req_get_post_args 函数体

static int
ngx_http_lua_ngx_req_get_post_args(lua_State *L)
{
    ngx_http_request_t          *r;
    u_char                      *buf;
    int                          retval;
    size_t                       len;
    ngx_chain_t                 *cl;
    u_char                      *p;
    u_char                      *last;
    int                          n;
    int                          max;

    n = lua_gettop(L);

    if (n != 0 && n != 1) {
        return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n);
    }

    if (n == 1) {
        max = luaL_checkinteger(L, 1);
        lua_pop(L, 1);

    } else {
        max = NGX_HTTP_LUA_MAX_ARGS;
    }

    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request object found");
    }

    ngx_http_lua_check_fake_request(L, r);

    if (r->discard_body) {
        lua_createtable(L, 0, 0);
        return 1;
    }

    if (r->request_body == NULL) {
        return luaL_error(L, "no request body found; "
                          "maybe you should turn on lua_need_request_body?");
    }

    if (r->request_body->temp_file) {
        lua_pushnil(L);
        lua_pushliteral(L, "request body in temp file not supported");
        return 2;
    }

    if (r->request_body->bufs == NULL) {
        lua_createtable(L, 0, 0);
        return 1;
    }

    /* we copy r->request_body->bufs over to buf to simplify
     * unescaping query arg keys and values */

    len = 0;
    for (cl = r->request_body->bufs; cl; cl = cl->next) {
        len  = cl->buf->last - cl->buf->pos;
    }

    dd("post body length: %d", (int) len);

    if (len == 0) {
        lua_createtable(L, 0, 0);
        return 1;
    }

    buf = ngx_palloc(r->pool, len);
    if (buf == NULL) {
        return luaL_error(L, "no memory");
    }

    lua_createtable(L, 0, 4);

    p = buf;
    for (cl = r->request_body->bufs; cl; cl = cl->next) {
        p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos);
    }

    dd("post body: %.*s", (int) len, buf);

    last = buf   len;

    retval = ngx_http_lua_parse_args(L, buf, last, max);

    ngx_pfree(r->pool, buf);

    return retval;
}

上述的要害的在于

max = NGX_HTTP_LUA_MAX_ARGS;

找到界说的NGX_HTTP_LUA_MAX_ARGS 默以为100

ifndef NGX_HTTP_LUA_MAX_ARGS
    define NGX_HTTP_LUA_MAX_ARGS 100
endif

然后走到了ngx_http_lua_parse_args 这个函数

int
ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max)
{
    u_char                      *p, *q;
    u_char                      *src, *dst;
    unsigned                     parsing_value;
    size_t                       len;
    int                          count = 0;
    int                          top;

    top = lua_gettop(L);

    p = buf;

    parsing_value = 0;
    q = p;

    while (p != last) {
        if (*p == '=' && ! parsing_value) {
            /* key data is between p and q */

            src = q; dst = q;

            ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                      NGX_UNESCAPE_URI_COMPONENT);

            dd("pushing key %.*s", (int) (dst - q), q);

            /* push the key */
            lua_pushlstring(L, (char *) q, dst - q);

            /* skip the current '=' char */
            p  ;

            q = p;
            parsing_value = 1;

        } else if (*p == '&') {
            /* reached the end of a key or a value, just save it */
            src = q; dst = q;

            ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                      NGX_UNESCAPE_URI_COMPONENT);

            dd("pushing key or value %.*s", (int) (dst - q), q);

            /* push the value or key */
            lua_pushlstring(L, (char *) q, dst - q);

            /* skip the current '&' char */
            p  ;

            q = p;

            if (parsing_value) {
                /* end of the current pair's value */
                parsing_value = 0;

            } else {
                /* the current parsing pair takes no value,
                 * just push the value "true" */
                dd("pushing boolean true");

                lua_pushboolean(L, 1);
            }

            (void) lua_tolstring(L, -2, &len);

            if (len == 0) {
                /* ignore empty string key pairs */
                dd("popping key and value...");
                lua_pop(L, 2);

            } else {
                dd("setting table...");
                ngx_http_lua_set_multi_value_table(L, top);
            }

            if (max > 0 &&   count == max) {
                lua_pushliteral(L, "truncated");

                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                               "lua hit query args limit %d", max);
                return 2;
            }

        } else {
            p  ;
        }
    }

    if (p != q || parsing_value) {
        src = q; dst = q;

        ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                  NGX_UNESCAPE_URI_COMPONENT);

        dd("pushing key or value %.*s", (int) (dst - q), q);

        lua_pushlstring(L, (char *) q, dst - q);

        if (!parsing_value) {
            dd("pushing boolean true...");
            lua_pushboolean(L, 1);
        }

        (void) lua_tolstring(L, -2, &len);

        if (len == 0) {
            /* ignore empty string key pairs */
            dd("popping key and value...");
            lua_pop(L, 2);

        } else {
            dd("setting table...");
            ngx_http_lua_set_multi_value_table(L, top);
        }
    }

    dd("gettop: %d", lua_gettop(L));
    dd("type: %s", lua_typename(L, lua_type(L, 1)));

    if (lua_gettop(L) != top) {
        return luaL_error(L, "internal error: stack in bad state");
    }

    return 1;
}

如上代码。读取即是号之前的作为key 然后& 之前的作为value 。然后举行保留到内存中然后举行判断是否大于即是max

获取key

src = q; dst = q;

            ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                      NGX_UNESCAPE_URI_COMPONENT);

            dd("pushing key %.*s", (int) (dst - q), q);

            /* push the key */
            lua_pushlstring(L, (char *) q, dst - q);

            /* skip the current '=' char */
            p  ;

            q = p;
            parsing_value = 1;

value

src = q; dst = q;

    ngx_http_lua_unescape_uri(&dst, &src, p - q,
                              NGX_UNESCAPE_URI_COMPONENT);

    dd("pushing key or value %.*s", (int) (dst - q), q);

    /* push the value or key */
    lua_pushlstring(L, (char *) q, dst - q);

判断长度是否即是max

if (max > 0 &&   count == max) {
                lua_pushliteral(L, "truncated");

                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
                               "lua hit query args limit %d", max);
                return 2;
            }

然则现在尚有一个疑问就是get_uri_args 这个怎么获取的呢? 如上是获取了get_post_args

四、get_uri_args
参考大量的代码发现。他这个是内置的一个名堂ngx_http_lua_ffi 开头。我也没有找到他内部怎么注册流程。

例如:

ngx_http_lua_ffi_encode_base64

ngx_http_lua_ffi_unescape_uri

ngx_http_lua_ffi_time

暂时没有找到他的内部注册的逻辑。这里先不做讨论了。若是有大佬可以指出那里是注册流程话记得艾特一下我

ngx_http_lua_ffi_req_get_uri_args 代码如下

int
ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf,
    ngx_http_lua_ffi_table_elt_t *out, int count)
{
    int                          i, parsing_value = 0;
    u_char                      *last, *p, *q;
    u_char                      *src, *dst;

    if (count <= 0) {
        return NGX_OK;
    }

    ngx_memcpy(buf, r->args.data, r->args.len);

    i = 0;
    last = buf   r->args.len;
    p = buf;
    q = p;

    while (p != last) {
        if (*p == '=' && !parsing_value) {
            /* key data is between p and q */

            src = q; dst = q;

            ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                      NGX_UNESCAPE_URI_COMPONENT);

            dd("saving key %.*s", (int) (dst - q), q);

            out[i].key.data = q;
            out[i].key.len = (int) (dst - q);

            /* skip the current '=' char */
            p  ;

            q = p;
            parsing_value = 1;

        } else if (*p == '&') {
            /* reached the end of a key or a value, just save it */
            src = q; dst = q;

            ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                      NGX_UNESCAPE_URI_COMPONENT);

            dd("pushing key or value %.*s", (int) (dst - q), q);

            if (parsing_value) {
                /* end of the current pair's value */
                parsing_value = 0;

                if (out[i].key.len) {
                    out[i].value.data = q;
                    out[i].value.len = (int) (dst - q);
                    i  ;
                }

            } else {
                /* the current parsing pair takes no value,
                 * just push the value "true" */
                dd("pushing boolean true");

                if (dst - q) {
                    out[i].key.data = q;
                    out[i].key.len = (int) (dst - q);
                    out[i].value.len = -1;
                    i  ;
                }
            }

            if (i == count) {
                return i;
            }

            /* skip the current '&' char */
            p  ;

            q = p;

        } else {
            p  ;
        }
    }

    if (p != q || parsing_value) {
        src = q; dst = q;

        ngx_http_lua_unescape_uri(&dst, &src, p - q,
                                  NGX_UNESCAPE_URI_COMPONENT);

        dd("pushing key or value %.*s", (int) (dst - q), q);

        if (parsing_value) {
            if (out[i].key.len) {
                out[i].value.data = q;
                out[i].value.len = (int) (dst - q);
                i  ;
            }

        } else {
            if (dst - q) {
                out[i].key.data = q;
                out[i].key.len = (int) (dst - q);
                out[i].value.len = (int) -1;
                i  ;
            }
        }
    }

    return i;
}

首先呢。他这个也是获取一个key 和一个value 的历程。然后判断一下是否是i==count

i 这个地方是一个整数。每次设置好值之后i

这里画了一个图

发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片