博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nginx1.3.9和1.4.0 的 chunked 溢出漏洞
阅读量:4934 次
发布时间:2019-06-11

本文共 4098 字,大约阅读时间需要 13 分钟。

新闻:nginx 1.3.9-1.4.0版本文件http/ngx_http_parse.c代码中的ngx_http_parse_chunked()函数在对 chunked的长度进行解析时未考虑到该值为负数的情况,导致后续发生基于栈的缓冲区溢出。远程攻击者无需认证即可利用此漏造成nginx拒绝服务,甚 至执行任意代码。

 

ngx_int_t

ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
    ngx_http_chunked_t *ctx)
{
    u_char     *pos, ch, c;
    ngx_int_t   rc;
    enum {
        sw_chunk_start = 0,
        sw_chunk_size,
        sw_chunk_extension,
        sw_chunk_extension_almost_done,
        sw_chunk_data,
        sw_after_data,
        sw_after_data_almost_done,
        sw_last_chunk_extension,
        sw_last_chunk_extension_almost_done,
        sw_trailer,
        sw_trailer_almost_done,
        sw_trailer_header,
        sw_trailer_header_almost_done
    } state;
    state = ctx->state;
    if (state == sw_chunk_data && ctx->size == 0) {
        state = sw_after_data;
    }
    rc = NGX_AGAIN;
    for (pos = b->pos; pos < b->last; pos++) {
        ch = *pos;
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http chunked byte: %02Xd s:%d", ch, state);
        switch (state) {
        case sw_chunk_start:
            if (ch >= '0' && ch <= '9') {
                state = sw_chunk_size;
                ctx->size = ch - '0';
                break;
            }
            c = (u_char) (ch | 0x20);
            if (c >= 'a' && c <= 'f') {
                state = sw_chunk_size;
                ctx->size = c - 'a' + 10;
                break;
            }
            goto invalid;
        case sw_chunk_size:
            if (ch >= '0' && ch <= '9') {
                ctx->size = ctx->size * 16 + (ch - '0');
                break;
            }
            c = (u_char) (ch | 0x20);
            if (c >= 'a' && c <= 'f') {
                ctx->size = ctx->size * 16 + (c - 'a' + 10);
                break;
            }
            if (ctx->size == 0) {
                switch (ch) {
                case CR:
                    state = sw_last_chunk_extension_almost_done;
                    break;
                case LF:
                    state = sw_trailer;
                    break;
                case ';':
                case ' ':
                case '\t':
                    state = sw_last_chunk_extension;
                    break;
                default:
                    goto invalid;
                }
                break;
            }
            switch (ch) {
            case CR:
                state = sw_chunk_extension_almost_done;
                break;
            case LF:
                state = sw_chunk_data;
                break;
            case ';':
            case ' ':
            case '\t':
                state = sw_chunk_extension;
                break;
            default:
                goto invalid;
            }
            break;
        case sw_chunk_extension:
            switch (ch) {
            case CR:
                state = sw_chunk_extension_almost_done;
                break;
            case LF:
                state = sw_chunk_data;
            }
            break;
        case sw_chunk_extension_almost_done:
            if (ch == LF) {
                state = sw_chunk_data;
                break;
            }
            goto invalid;
        case sw_chunk_data:
            rc = NGX_OK;
            goto data;
        case sw_after_data:
            switch (ch) {
            case CR:
                state = sw_after_data_almost_done;
                break;
            case LF:
                state = sw_chunk_start;
            }
            break;
        case sw_after_data_almost_done:
            if (ch == LF) {
                state = sw_chunk_start;
                break;
            }
            goto invalid;
        case sw_last_chunk_extension:
            switch (ch) {
            case CR:
                state = sw_last_chunk_extension_almost_done;
                break;
            case LF:
                state = sw_trailer;
            }
            break;
        case sw_last_chunk_extension_almost_done:
            if (ch == LF) {
                state = sw_trailer;
                break;
            }
            goto invalid;
        case sw_trailer:
            switch (ch) {
            case CR:
                state = sw_trailer_almost_done;
                break;
            case LF:
                goto done;
            default:
                state = sw_trailer_header;
            }
            break;
        case sw_trailer_almost_done:
            if (ch == LF) {
                goto done;
            }
            goto invalid;
        case sw_trailer_header:
            switch (ch) {
            case CR:
                state = sw_trailer_header_almost_done;
                break;
            case LF:
                state = sw_trailer;
            }
            break;
        case sw_trailer_header_almost_done:
            if (ch == LF) {
                state = sw_trailer;
                break;
            }
            goto invalid;
        }
    }
data:
    ctx->state = state;
    b->pos = pos;
    switch (state) {
    case sw_chunk_start:
        ctx->length = 3 /* "0" LF LF */;
        break;
    case sw_chunk_size:
        ctx->length = 2 /* LF LF */
                      + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
        break;
    case sw_chunk_extension:
    case sw_chunk_extension_almost_done:
        ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
        break;
    case sw_chunk_data:
        ctx->length = ctx->size + 4 /* LF "0" LF LF */;
        break;
    case sw_after_data:
    case sw_after_data_almost_done:
        ctx->length = 4 /* LF "0" LF LF */;
        break;
    case sw_last_chunk_extension:
    case sw_last_chunk_extension_almost_done:
        ctx->length = 2 /* LF LF */;
        break;
    case sw_trailer:
    case sw_trailer_almost_done:
        ctx->length = 1 /* LF */;
        break;
    case sw_trailer_header:
    case sw_trailer_header_almost_done:
        ctx->length = 2 /* LF LF */;
        break;
    }
 //这是1.4.1升级后的补救措施,1.3.9和1.4.0没有这个代码判断
    if (ctx->size < 0 || ctx->length < 0) {
        goto invalid;
    }
    return rc;
done:
    ctx->state = 0;
    b->pos = pos + 1;
    return NGX_DONE;
invalid:
    return NGX_ERROR;
}

 

关于chunked介绍博客:

http://blog.xiuwz.com/2012/01/10/talk-nginx-with-http/

 

转载于:https://www.cnblogs.com/samurail/archive/2013/05/10/3070327.html

你可能感兴趣的文章
PHPCMS V9{loop subcat(0,0,0,$siteid) $r}怎么解释?
查看>>
避免内存重叠memmove()性能
查看>>
jquery实现简单抽奖功能
查看>>
[leetcode]250. Count Univalue Subtrees统计节点值相同的子树
查看>>
理解Backtracking
查看>>
T3 光
查看>>
搭建交叉调试环境 arm-linux-gdb配合gdbserver
查看>>
使用Jsoup 抓取页面的数据
查看>>
使用命令批量对文件中出现的字符串进行替换
查看>>
C#获取URL参数值
查看>>
Struts 框架 之 文件上传下载案例
查看>>
【重走Android之路】【路线篇(二)】知识点归纳
查看>>
graphviz入门
查看>>
tomcat 系统架构与设计模式 第二部分 设计模式 转
查看>>
scanf中的%[^\n]%*c格式
查看>>
启动Eclipse报Initializing Java Tooling错误解决方法
查看>>
用jquery来实现类似“网易新闻”横向标题滑动的移动端页面
查看>>
(原)基于物品的协同过滤ItemCF的mapreduce实现
查看>>
CSS可以和不可以继承的属性
查看>>
eclipse每次当我按ctrl+鼠标点击代码,自动关闭,产生原因及解决办法!!
查看>>