IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> snort的gtp解码源码分析 -> 正文阅读

[网络协议]snort的gtp解码源码分析

GTP 全称为GPRS Tunneling Protocol即GPRS隧道协议。GTP(GPRS隧道协议)用于建立核心通信网络GSN(GPRS服务节点)之间的通道。snort提供的GTP解码和预处理器提供通过GTP解决对这些网络的入侵企图的方法。它还使检测新攻击更容易。

GTP解码器提取GTP PDU内的有效载荷;GTP预处理器检查所有信令消息,并提供关键字以供进一步检查。

启用和配置解码器后,解码器将剥离GTP头并解析底层IP/TCP/UDP封装的数据包。因此,所有规则和检测工作就像没有GTP头一样。

例子:

大部分数据包时以下格式:

IP -> UDP -> GTP -> IP -> TCP -> HTTP

如果您有一个标准HTTP规则"alert tcp any any -> ?any $HTTP_PORTS (msg:
"Test HTTP"; flow:to_server,established; content:"SOMETHINGEVIL"; http_uri;?
?.... sid:X; rev:Y;)",如果你配置了GTP decoder(config enable_gtp),它可以对被gtp协议包含内部的http内容发出报警。

下面我们以源码的形式来分析解码过程,关于预处理器在另一篇博客中讲解。

其中关于解析的原理可以参考之前写过的博客snort 源码分析之模式匹配引擎。根据这篇博客我们知道:

config enable_gtp

的解析过程。

ParseConfigFile=》snort_conf_keywords[i].parse_func(sc, p, args)=》ParseConfig=》config_opts[i].parse_func(sc, opts)=》ConfigEnableGTPDecoding 通过这一系列的调用,gtp decoder的配置就算是解析完成了。

void ConfigEnableGTPDecoding(SnortConfig *sc, char *args)
{
    PortObject *portObject;
    int numberOfPorts = 0;

    if (sc == NULL)
        return;

    DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Enabling GTP decoding\n"););
    sc->enable_gtp = 1;//设置启用标志

    /*Set the ports*/
    //解析端口配置 在snort.conf中配置了portvar GTP_PORTS [2123,2152,3386],所以会成功
    portObject = PortVarTableFind( sc->targeted_policies[getParserPolicy(sc)]->portVarTable, "GTP_PORTS");
    if (portObject)
    {
       sc->gtp_ports =  PortObjectCharPortArray(sc->gtp_ports,portObject, &numberOfPorts);//65536大小的数组
    }

    if (!sc->gtp_ports || (0 == numberOfPorts))
    {
        /*No ports defined, use default GTP ports*/
        sc->gtp_ports = (char *)SnortAlloc(UINT16_MAX);
        sc->gtp_ports[GTP_U_PORT] = 1;
        sc->gtp_ports[GTP_U_PORT_V0] = 1;

    }
}

?之前的数据包,上层协议是udp 所以在snort中的DecodeUDP函数中调用了DecodeGTP


void DecodeUDP(const uint8_t * pkt, const uint32_t len, Packet * p)
{
.......
    if (ScGTPDecoding() &&/*为true*/
         (ScIsGTPPort(p->sp)||ScIsGTPPort(p->dp)))/*端口配置 2152 所以为true*/
    {
        if ( !p->frag_flag )//没有分段
            DecodeGTP(pkt + sizeof(UDPHdr), len - sizeof(UDPHdr), p);//调用gtp解码函数
    }

}

ScGTPDecoding:

static inline int ScGTPDecoding(void)
{
    return snort_conf->enable_gtp;//在解析配置的时候,设置为1
}


//--------------------------------------------------------------------
// decode.c::GTP
//--------------------------------------------------------------------

/* Function: DecodeGTP(uint8_t *, uint32_t, Packet *)
 *
 * GTP (GPRS Tunneling Protocol) is layered over UDP.
 * Decode these (if present) and go to DecodeIPv6/DecodeIP.
 *
 */

void DecodeGTP(const uint8_t *pkt, uint32_t len, Packet *p)
{
    uint32_t header_len;
    uint8_t  next_hdr_type;
    uint8_t  version;
    uint8_t  ip_ver;
    GTPHdr *hdr;

    DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Start GTP decoding.\n"););

    hdr = (GTPHdr *) pkt;

    if (p->GTPencapsulated)
    {
        DecoderAlertEncapsulated(p, DECODE_GTP_MULTIPLE_ENCAPSULATION,
                DECODE_GTP_MULTIPLE_ENCAPSULATION_STR,
                pkt, len);
        return;
    }
    else
    {
        p->GTPencapsulated = 1;
    }
    /*Check the length*/
    if (len < GTP_MIN_LEN)//检查数据包长度
       return;
    /* We only care about PDU*/
    if ( hdr->type != 255)
       return;
    /*Check whether this is GTP or GTP', Exit if GTP'*/
    if (!(hdr->flag & 0x10))
       return;

    /*The first 3 bits are version number*/
    version = (hdr->flag & 0xE0) >> 5;
    switch (version)//检查版本
    {
    case 0: /*GTP v0 0版本*/
        DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "GTP v0 packets.\n"););

        header_len = GTP_V0_HEADER_LEN;//数据包头固定长度
        /*Check header fields*/
        if (len < header_len)
        {
            DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
            return;
        }

        p->proto_bits |= PROTO_BIT__GTP;

        /*Check the length field. */
        if (len != ((unsigned int)ntohs(hdr->length) + header_len))
        {
            DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Calculated length %d != %d in header.\n",
                    len - header_len, ntohs(hdr->length)););
            DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
            return;
        }

        break;
    case 1: /*GTP v1 1版本*/
        DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "GTP v1 packets.\n"););

        /*Check the length based on optional fields and extension header*/
        if (hdr->flag & 0x07)
        {

            header_len = GTP_V1_HEADER_LEN;//1版本的头长度

            /*Check optional fields*/
            if (len < header_len)
            {
                DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
                return;
            }
            next_hdr_type = *(pkt + header_len - 1);//下一个扩展属性的类型

            /*Check extension headers*/
            while (next_hdr_type)//循环解码扩展属性,然后更新header_len 的值
            {
                uint16_t ext_hdr_len;
                /*check length before reading data*/
                if (len < header_len + 4)
                {
                    DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
                    return;
                }

                ext_hdr_len = *(pkt + header_len);

                if (!ext_hdr_len)
                {
                    DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
                    return;
                }
                /*Extension header length is a unit of 4 octets*/
                header_len += ext_hdr_len * 4;

                /*check length before reading data*/
                if (len < header_len)
                {
                    DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
                    return;
                }
                next_hdr_type = *(pkt + header_len - 1);
            }
        }
        else
            header_len = GTP_MIN_LEN;

        p->proto_bits |= PROTO_BIT__GTP;

        /*Check the length field. */
        if (len != ((unsigned int)ntohs(hdr->length) + GTP_MIN_LEN))
        {
            DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Calculated length %d != %d in header.\n",
                    len - GTP_MIN_LEN, ntohs(hdr->length)););
            DecoderEvent(p, EVARGS(GTP_BAD_LEN), 1, 1);
            return;
        }

        break;
    default:
        DEBUG_WRAP(DebugMessage(DEBUG_DECODE, "Unknown protocol version.\n"););
        return;

    }

    PushLayer(PROTO_GTP, p, pkt, header_len);//添加gtp头这一层,保存了这一层的相关信息,比如开始地址、长度、协议信息

    if ( ScTunnelBypassEnabled(TUNNEL_GTP) )
        Active_SetTunnelBypass();

    len -=  header_len;//去除gtp头长度,所以如果看起gtp解码,则可以顺利去除这一层,然后重新解码ip层和传输层
    if (len > 0)//如果还有数据,继续处理
    {
        ip_ver = *(pkt+header_len) & 0xF0;//前面的截图,可以看出,内部的数据接下来为ip层
        if (ip_ver == 0x40)//如果ipv4,调用DecodeIP进行解码
            DecodeIP(pkt+header_len, len, p);
        else if (ip_ver == 0x60)
            DecodeIPV6(pkt+header_len, len, p);
        p->packet_flags &= ~PKT_UNSURE_ENCAP;
    }

}

大致的流程就这些了。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 11:07:19  更:2021-08-02 11:10:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 17:18:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码