netsniff恶意流量识别和匹配解读

代码整体框架

流量扫描函数调用
netsniff恶意流量识别和匹配解读

加载配置文件的代码调用
netsniff恶意流量识别和匹配解读
获取扫描的条数
netsniff恶意流量识别和匹配解读

重点匹配函数

流量eg:‘\x00\x04\x00\x01\x00\x06\x00\x16>\x10\x1d>SW\x08\x00E\x00\x00\xbf\xb3\x1a@\x00@\x06\x03\xac\xac\x18\x0e.ddd\xc8\xed\xea\x00P\x04FF\xfa\x97\xc3\x8a\xedP\x18\x00\xe5\x84$\x00\x00
GET /latest/meta-data/region-id HTTP/1.1\r\nHost: 100.100.100.200\r\nAccept: /\r\nContent-Type: application/json; charset=utf-8\r\nAgent: linux/1.0.2.580\r\n\r\n‘
前面是ip tcp的头部,后面则是http的部分。

首先判断是否是http部分,如果是扫描进入http部分,我们就开始匹配有没有出现下图中子串出现在流量里面,如果存在就返回对应的位置index,进行下一步的判断或者下一个包的扫描。因此在恶意流量匹配环节,和maltrail最大的不同就是更换了正则匹配的逻辑
netsniff恶意流量识别和匹配解读

static int matchFound(void *user, void *tree, int index, void *data, void *neglist) {
  char logbuf[256];

  struct BnfaResponse *resp = (struct BnfaResponse *) data;
  match_item *entry = (match_item *) user;

  // WRITE_LOG(" -- Regex::Bnfa::MatchFound | index %ld", r->index);

  // save matched info
  (resp->matchedCount)++;
  resp->matchedEntries[resp->matchedCount - 1] = entry;
  printf("MatchFound line %d, index %d\n", entry->idx, index);
#if 0
  if (r->isOnBlackList)
  {
      resp->isOnBlackList = true;
      return 1;
  }
  else
  {
      resp->isOnBlackList = false;
  }
#endif
//        流量eg:‘\x00\x04\x00\x01\x00\x06\x00\x16>\x10\x1d>SW\x08\x00E\x00\x00\xbf\xb3\x1a@\x00@\x06\x03\xac\xac\x18\x0e.ddd\xc8\xed\xea\x00P\x04FF\xfa\x97\xc3\x8a\xedP\x18\x00\xe5\x84$\x00\x00
//data    GET /latest/meta-data/region-id HTTP/1.1\r\nHost: 100.100.100.200\r\nAccept: /\r\nContent-Type: application/json; charset=utf-8\r\nAgent: linux/1.0.2.580\r\n\r\n‘
//idx是规则配置的编号 匹配不到后面的
  if (entry->idx < (int) HTP_TAG_END)  // http
  {
    switch (entry->idx) {
      case HTP_TAG_HTTP:
//                    index为 HTTP/ 这标签的后一位  if语句就是判断是否是http打头
//                    entry->length_of_tag user对象传进来获取的
        if (index == entry->length_of_tag) {
          resp->startWithHTTP = true;
          return SEARCH_CONTINUE;
        }
        break;
      case method_post:
      case method_get:
      case method_connect:
        if (index < resp->dataLength) {
          resp->hasHost = true;
//          获得路径/latest/meta-data/region-id的其实位置
          resp->path = resp->data + index;
          resp->hasPath = true;
        }
        break;
      case WHITELIST_cgi:
      case WHITELIST__vti_bin:
      case WHITELIST_bin:
      case WHITELIST_bios:
      case WHITELIST_pc:
      case WHITELIST_pub:
      case WHITELIST_scripts:
      case sig:
        resp->hasPath = false;
      case SUS_apk:
      case SUS_chm:
      case SUS_dll:
      case SUS_egg:
      case SUS_exe:
      case SUS_hta:
      case SUS_hwp:
      case SUS_pac:
      case SUS_ps1:
      case SUS_scr:
      case SUS_sct:
      case SUS_xpi:
        if (resp->hasPath){
          int len = snprintf(logbuf,
                             256,
                             "TRAIL.HTTP,%s:%d,%s:%d,%d,direct download (suspicious)",
                             resp->pkt->src_ip,
                             resp->pkt->src_port,
                             resp->pkt->dst_ip,
                             resp->pkt->dst_port,
                             entry->idx);
          fwrite(logbuf, 1, len, resp->pkt->context->tcp_syn_log);
          return SEARCH_CONTINUE;
        }
      case PATH_START_HTTP:
        resp->hasBadPath = true;
        break;
      case path_probe:
      case path_proxy:
      case path_echo:
      case path_check:
        if (resp->hasBadPath){
          int len = snprintf(logbuf,
                             256,
                             "TRAIL.HTTP,%s:%d,%s:%d,%d,potential proxy probe (suspicious)",
                             resp->pkt->src_ip,
                             resp->pkt->src_port,
                             resp->pkt->dst_ip,
                             resp->pkt->dst_port,
                             entry->idx);
          fwrite(logbuf, 1, len, resp->pkt->context->tcp_syn_log);
          return SEARCH_CONTINUE;
        }
        break;
      case GENERIC_SINKHOLE_START:
      case GENERIC_SINKHOLE_2:
      case GENERIC_SINKHOLE_3:
      case GENERIC_SINKHOLE_4:
      case GENERIC_SINKHOLE_5:
      case GENERIC_SINKHOLE_6:
      case GENERIC_SINKHOLE_7:
      case GENERIC_SINKHOLE_8:
      case GENERIC_SINKHOLE_9:
      case GENERIC_SINKHOLE_10:
      case GENERIC_SINKHOLE_11:
      case GENERIC_SINKHOLE_12:
      case GENERIC_SINKHOLE_13:
      case GENERIC_SINKHOLE_END:
        if (resp->startWithHTTP) {
          // log_event((sec, usec, src_ip, src_port, dst_ip, dst_port, PROTO.TCP, TRAIL.HTTP, trail, "sinkhole response (malware)", "(heuristic)"), packet)
          int len = snprintf(logbuf,
                             256,
                             "TRAIL.HTTP,%s:%d,%s:%d,%d,sinkhole response (malware)",
                             resp->pkt->src_ip,
                             resp->pkt->src_port,
                             resp->pkt->dst_ip,
                             resp->pkt->dst_port,
                             entry->idx);
          fwrite(logbuf, 1, len, resp->pkt->context->tcp_syn_log);
          return SEARCH_CONTINUE;
        }
        break;
      case HTP_TAG_CONTENTTYPE:
//                    如果小于整包长度
        if (index < resp->dataLength) {
//
          resp->hasContentType = true;
//                        下面的data是 tcp和ip的之后的 负载数据
          resp->contentType = resp->data + index;//才是指向index当前的数据
          resp->lengthOfContentType = getStringLength(resp->contentType, resp->dataLength - index + 1);
        }
        break;
      case SUSPICIOUS_CONTENT_START:
      case SUSPICIOUS_CONTENT_2:
      case SUSPICIOUS_CONTENT_3:
      case SUSPICIOUS_CONTENT_4:
      case SUSPICIOUS_CONTENT_5:
      case SUSPICIOUS_CONTENT_6:
      case SUSPICIOUS_CONTENT_7:
      case SUSPICIOUS_CONTENT_8:
      case SUSPICIOUS_CONTENT_END:
        if (resp->hasContentType) {
          // log_event((sec, usec, src_ip, src_port, dst_ip, dst_port, PROTO.TCP, TRAIL.HTTP, content_type, "content type (suspicious)", "(heuristic)"), packet)
          int len = snprintf(logbuf,
                             256,
                             "TRAIL.HTTP,%s:%d,%s:%d,%d,content type (suspicious)",
                             resp->pkt->src_ip,
                             resp->pkt->src_port,
                             resp->pkt->dst_ip,
                             resp->pkt->dst_port,
                             entry->idx);
          fwrite(logbuf, 1, len, resp->pkt->context->tcp_syn_log);
          return SEARCH_CONTINUE;
        }
        break;
      case HTP_TAG_HOST:
        if (resp->hasHost) {
//          data+index是指向host的后一位,获取到host ip第一位的指针
          resp->host_ip = resp->data+index;
          resp->hostIpIndex = getStringLength(resp->host_ip,resp->dataLength-index+1);
          string hostIP;
          int index = 0;
          while (index<resp->hostIpIndex){
            //          如果遇到大写字母变成小写字母
            hostIP+=strlwr(resp->host_ip);
            resp->host_ip++;
            index++;
          }
          if (endsWith(hostIP,":80")==1){
            hostIP = hostIP[sizeof(hostIP)-3];
          }
//          遍历trails log输出。host and host[0].isalpha() and dst_ip in trails
          auto ret = g_ip4MalwareAddrs.find(resp->pkt->raw_dst);
          if (ret != g_ip4MalwareAddrs.end()){
            int len = snprintf(logbuf,
                               256,
                               "tcpsyn,%s:%d,%s:%d,%d",
                               resp->pkt->src_ip,
                               resp->pkt->src_port,
                               resp->pkt->dst_ip,
                               resp->pkt->dst_port,
                               entry->idx);
            fwrite(logbuf, 1, len, pkt->context->tcp_syn_log);
            return SEARCH_CONTINUE;
          }else{
            resp->IsIotMalware = true;
          }
        }
        break;
      case Host_arm:
      case Host_m68k:
      case Host_mips:
      case Host_mpsl:
      case Host_powerpc:
      case Host_ppc:
      case Host_x86:
      case Host_x32:
      case Host_x64:
      case Host_i586:
      case Host_i686:
      case Host_sparc:
      case Host_sh:
      case Host_yarn:
      case Host_zte:
        if (resp->IsIotMalware){
          int len = snprintf(logbuf,
                             256,
                             "tcpsyn,%s:%d,%s:%d,%d,potential iot-malware download (suspicious)",
                             resp->pkt->src_ip,
                             resp->pkt->src_port,
                             resp->pkt->dst_ip,
                             resp->pkt->dst_port,
                             entry->idx);
          fwrite(logbuf, 1, len, pkt->context->tcp_syn_log);
        }
        break;
      case HTP_TAG_UA:
        break;
      case HTP_TAG_TITLE_BEGIN:
      case HTP_TAG_TITLE_END:resp->hasHTTPTitle = true;
        return SEARCH_CONTINUE;
        break;
      case SEIZED_DOMAIN_BEGIN:
      case SEIZED_DOMAIN_END:
        if (resp->hasHTTPTitle) {
          // log_event((sec, usec, src_ip, src_port, dst_ip, dst_port, PROTO.TCP, TRAIL.HTTP, title, "seized domain (suspicious)", "(heuristic)"), packet)
          int len = snprintf(logbuf,
                             256,
                             "TRAIL.HTTP,%s:%d,%s:%d,%d,seized domain (suspicious)",
                             resp->pkt->src_ip,
                             resp->pkt->src_port,
                             resp->pkt->dst_ip,
                             resp->pkt->dst_port,
                             entry->idx);
          fwrite(logbuf, 1, len, resp->pkt->context->tcp_syn_log);
          return SEARCH_CONTINUE;
        }
        break;
      default:;
    }

  } // else if

  if (resp->matchedCount == REGEX_MAX_MATCH_ITEM) {
    //WRITE_LOG(" -- Regex::Bnfa::MatchFound | Can‘t save more info, matched index", r->index);


    return SEARCH_REACHMAX;
  }

  return 0;
}

netsniff恶意流量识别和匹配解读

上一篇:c++学习笔记2(c++简单程序)


下一篇:GeoJSON