TLS指纹跟踪网络安全实践(C/C++代码实现)

TLS指纹识别是网络安全领域的重要技术,它涉及通过分析TLS握手过程中的信息来识别和验证通信实体的技术手段。TLS(传输层安全)协议是用于保护网络数据传输的一种加密协议,而TLS指纹则是该协议在实际应用中产生的独特标识,它包含了诸如密码套件、协议版本和加密算法等信息。

TLS指纹的原理

TLS指纹是通过检查TLS握手过程中使用的密码套件、协议版本和加密算法等信息来确定的。由于不同的TLS实现在这些参数的选择上有所差异,因此可以通过比较TLS指纹来判断通信是否来自预期的源或目标。

TLS握手过程详细解释

TLS指纹识别技术是一种网络安全技术,它通过分析TLS握手过程中的信息来识别和验证通信实体。这种技术手段主要依赖于对TLS协议中的特定数据进行提取和分析,以此来确定通信双方的身份和确保通信的完整性与安全性。以下是对该技术实施方式的详细解释:

  1. TLS握手过程:TLS握手是TLS协议中建立安全连接的关键步骤。在这一过程中,客户端和服务器协商加密算法、交换密钥并验证对方的身份。此过程涉及多个消息的传递,如ClientHello、ServerHello、Certificate、ServerKeyExchange、ClientKeyExchange等。

  2. 信息提取:在TLS指纹识别中,核心步骤是从TLS握手过程中提取关键信息。这些信息可能包括:

    • 密码套件(Cipher Suite):客户端和服务器协商使用的加密算法和密钥交换算法的组合。
    • 协议版本(Protocol Version):TLS协议的版本,不同的实现可能支持不同版本的TLS。
    • 扩展(Extensions):TLS协议中允许的额外特性或选项,如支持的椭圆曲线、应用层协议协商等。
    • 随机数(Random Numbers):TLS握手双方各自生成的随机值,用于后续的密钥生成。
  3. 特征分析:通过分析上述信息,可以构建一个唯一的或较为特定的TLS指纹,该指纹可以代表一个特定的设备、应用程序或组织。例如,某些服务器可能总是使用特定的密码套件或协议版本,这些信息可以用来区分不同的服务器。

  4. 指纹匹配与验证:将提取的TLS指纹与已知的指纹数据库进行匹配,以验证通信实体的身份。如果发现匹配的指纹,则可以较高信心确认通信实体的身份。反之,如果指纹不匹配,则可能表明存在中间人攻击或其他安全威胁。

  5. 应用场景:TLS指纹识别技术广泛应用于网络安全领域,包括但不限于:

    • 入侵检测系统(IDS):用于识别并警告异常的TLS通信模式,可能指示着潜在的攻击活动。
    • 网络流量分析:帮助网络管理员理解并管理流经网络的设备和应用程序类型。
    • 威胁情报:在网络安全领域,TLS指纹可以作为跟踪特定威胁行为体的关键指标。

TLS指纹的作用

TLS指纹主要用于检测网络欺骗、中间人攻击、间谍活动等安全威胁。此外,TLS指纹还可以用于识别和管理设备和应用程序,提高网络安全性。

TLS指纹识别是一种网络安全技术,它的作用主要包括以下几点:

  1. 服务识别:通过分析TLS握手过程中的数据,可以识别出使用的特定服务或应用程序,即使它们运行在常见的端口上,如HTTP(S)。

  2. 客户端和服务器指纹识别:可以区分不同的浏览器、操作系统或特定版本的TLS库,这有助于识别潜在的安全漏洞或配置问题。

  3. 安全漏洞检测:某些TLS实现可能包含特定的安全漏洞。通过指纹识别,可以识别出易受攻击的系统,并采取相应的安全措施。

  4. 恶意软件识别:恶意软件经常使用特定的TLS配置来进行通信。通过分析TLS指纹,可以识别出恶意流量。

  5. 合规性检查:组织可以使用TLS指纹识别来确保其系统遵守安全协议和最佳实践,例如禁用已知不安全的TLS版本或密码套件。

  6. 网络监控与入侵检测:在网络安全监控中,TLS指纹识别可以帮助识别异常通信模式,这可能是入侵或其他安全事件的迹象。

  7. 性能优化:了解客户端和服务器的TLS实现可以帮助优化TLS握手过程,提高通信效率。

  8. 协议分析与研究:研究人员可以使用TLS指纹识别来分析TLS协议的使用情况,以及不同实现之间的差异。

  9. 匿名性分析:在某些情况下,通过分析TLS指纹,可以评估通信方的匿名性水平,例如,某些客户端或服务器的TLS实现可能更容易被识别。

绕过TLS指纹护盾的方法

在某些情况下,为了测试网络通信安全性、调试网络问题或访问被阻止的网站,可能需要绕过TLS指纹护盾。这可以通过使用代理服务器改变客户端的TLS指纹,或者使用自定义的TLS库来实现自定义的TLS握手过程来完成。以下是一些常见的方法:

  1. 更改默认配置:修改TLS库或应用程序的默认配置,使用非标准的密码套件、TLS版本或扩展,以减少被识别的可能性。

  2. 使用自定义TLS实现:开发或使用自定义的TLS实现,这些实现可能不遵循常见的指纹模式。

  3. 动态TLS参数:在TLS握手过程中动态选择参数,如密码套件或扩展,以避免产生一致的指纹。

  4. 使用TLS前导数据:在TLS握手之前发送一些随机数据,以混淆指纹识别工具对TLS数据的分析。

  5. 应用层加密:在TLS层之上应用额外的加密层,使得TLS指纹分析更加困难。

  6. 使用代理或VPN:通过代理服务器或VPN连接来隐藏真实的TLS指纹,因为这些中间节点可能会使用不同的TLS配置。

  7. 混淆TLS扩展:使用不常用或自定义的TLS扩展,使得指纹识别工具难以匹配已知的指纹模式。

  8. 更改客户端或服务器软件版本:定期更新或更改使用的软件版本,以避免因使用已知易受攻击或具有特定指纹的版本而被识别。

  9. 使用多证书策略:为不同的客户端或服务使用不同的TLS证书,以减少被指纹识别的可能性。

  10. 利用TLS 1.3的特性:TLS 1.3引入了一些新特性,如会话恢复和0-RTT,这些特性可以减少TLS握手过程中的可识别信息。

  11. 使用隐私保护技术:例如使用TLS的匿名DH或ECDH密钥交换算法,以减少泄露客户端或服务器的识别信息。

  12. 混淆或随机化SNI(Server Name Indication):SNI可以被用于指纹识别,通过随机化或混淆SNI值可以降低被识别的风险。

TLS指纹的应用

TLS指纹技术在网络安全领域的应用广泛,它不仅能够帮助识别和管理设备与应用程序,还能够检测网络欺骗和中间人攻击等安全威胁。同时,TLS指纹也是揭示恶意软件通信流量的关键工具。以下是TLS指纹技术的主要应用场景:

  1. Bot流量检测:通过分析TLS握手过程中的信息,TLS指纹可以用于识别和验证通信实体,从而检测和识别Bot流量。每个客户端(如浏览器、计算机软件、程序)所支持的协议版本、加密套件、扩展、加密算法等都是不同的,因此可以通过比较TLS指纹来判断通信是否来自预期的源或目标。在Bot对抗场景下,JA4指纹主要有两种应用方式:唯一性检测和一致性检测。唯一性检测是针对某些客户端程序设计的特殊性,使得这些客户端具备独一无二的JA4指纹,并且这些客户端的指纹变化周期较长,通过唯一性检测可有效识别此类异常客户端。一致性检测则是对客户端声明的设备信息(操作系统、浏览器类型、版本号)与其JA4指纹进行对比,检测是否与指纹对应的真实设备信息一致。
  2. 安全分析:TLS指纹能够指示客户端应用程序通过TLS通信的方式,而服务器端的TLS指纹能够指示服务器响应。如果两者结合起来,实质上就生成了客户端和服务器之间的加密协商的指纹[4]。
  3. 主动扫描:随着攻击者使用TLS的情况增长,通过主动探测发现同类攻击基础设施被认为是一步先手棋,有效的TLS指纹可以在消耗资源可控的情况下提供更好的效果。
  4. 恶意软件通信揭示:由于许多恶意软件会利用TLS协议来隐藏其通信流量,TLS指纹技术可以通过分析TLS数据包的特征来揭示这些恶意通信。
  5. 网络安全监控:TLS指纹技术为网络安全提供了一种有效的监控手段,帮助网络安全专业人员识别并防范各种网络威胁。
  6. 构建完整指纹库:为了成功识别Bot流量,构建一个完整的JA4指纹库是关键,这涉及到收集和更新大量的TLS指纹信息。
  7. 模块化网络指纹设计:JA4提供了一套易于使用和共享的模块化网络指纹,取代2017年起的JA3 TLS指纹标准,有助于更有效地进行威胁搜寻和分析。
  8. 绕过TLS指纹护盾:在某些特殊情况下,绕过TLS指纹护盾可能是必要的,例如进行网络安全测试或调试网络问题时。但这需要谨慎操作,并确保合法性和安全性]。

此外,在使用TLS指纹技术时,应当充分考虑安全性和隐私保护的需求,谨慎使用相关技术。正确地应用这一技术需要深入理解TLS协议的细节,以及网络安全的广泛知识。

TLS指纹的校验工具

JA3和JA3S是用于识别客户端和服务器之间的TLS协商的指纹识别方法。这种组合的指纹识别可以帮助对特定客户端与其服务器之间的加密通信产生更高保真度的识别。

TLS指纹的查看方式

TLS指纹的查看方式主要包括通过专业的网络抓包和分析工具来获取TLS握手过程中的信息。以下是具体介绍:

  • 网络抓包工具:使用如Wireshark这样的网络抓包工具可以捕获TLS握手过程中的数据包,然后通过分析这些数据包来提取TLS指纹信息。这种方法适用于网络安全专业人员进行深入分析。
  • 在线服务工具:有一些在线服务和工具提供了TLS指纹的检测功能,用户可以通过访问这些网站来查看自己或他人服务器的TLS指纹。例如,可以使用https://tls.browserleaks.com/json 这样的网站来观察不同配置下的TLS指纹变化情况。
  • 计算TLS指纹:在TLS连接开始时,客户端会发送一个TLS Client Hello数据包,该数据包由客户端应用程序生成,通知服务器它支持哪些密码以及其首选的通信方法。根据这个数据包计算得到的一串哈希值,即为TLS指纹。例如,JA3方法用于收集客户端Client Hello数据包中以下字段的字节十进制值:TLS版本、密码套件、扩展列表、椭圆曲线和椭圆曲线格式。然后,它将这些值按出现顺序连接在一起,使用“,”分隔每个字段,使用“-”分隔每个字段中的每个值[3]。
  • 模块化网络指纹设计:JA4提供了一套易于使用和共享的模块化网络指纹,取代2017年起的JA3 TLS指纹标准。JA4检测方法增加了可读性,有助于更有效地进行威胁搜寻和分析。所有JA4+指纹都具有a_b_c格式,用于分隔构成指纹的不同部分。这允许仅利用ab或ac或c进行搜索和检测。

此外,在使用这些工具和方法时,需要注意合法性和安全性的问题。确保你的行为不违反相关法律法规,并且不会对自己的网络安全造成威胁。正确地应用这一技术需要深入理解TLS协议的细节,以及网络安全的广泛知识。

...
struct teredo_header {
  u_int16_t  part_a; 
  u_int16_t  part_b;  
  u_int16_t  length;   
  u_int8_t   nxt_header;
  u_int8_t   hop_length;
  struct     in6_addr ip6_src; 
  struct     in6_addr ip6_dst;
};

#define SSL_MIN_GOOD_VERSION	0x002
#define SSL_MAX_GOOD_VERSION	0x304

#define OFFSET_HELLO_VERSION	9
#define OFFSET_SESSION_LENGTH	43
#define OFFSET_CIPHER_LIST	44

#define SSLV2_OFFSET_HELLO_VERSION	3
#define SSLV2_OFFSET_SESSION_LENGTH	6
#define SSLV2_OFFSET_CIPHER_LIST	44


char* ssl_version(u_short version) {
	static char hex[7];
	switch (version) {
		case 0x002: return "SSLv2";
		case 0x300: return "SSLv3";
		case 0x301: return "TLSv1.0";
		case 0x302: return "TLSv1.1";
		case 0x303: return "TLSv1.2";
		case 0x304: return "TLSv1.3";
	}
	snprintf(hex, sizeof(hex), "0x%04hx", version);
	return hex;
}

struct fingerprint_new {
  uint16_t  fingerprint_id;
  uint16_t  desc_length;
  char      *desc;
  uint16_t  record_tls_version;
  uint16_t  tls_version;
  uint16_t  ciphersuite_length;
  uint8_t   *ciphersuite;
  uint8_t   compression_length; 
  uint8_t   *compression;
  uint16_t  extensions_length;
  uint8_t   *extensions;
  uint16_t  curves_length;
  uint8_t   *curves;
  uint16_t  sig_alg_length;
  uint8_t   *sig_alg;
  uint16_t  ec_point_fmt_length;
  uint8_t   *ec_point_fmt;
  struct    fingerprint_new  *next;
};

...
void print_usage(char *bin_name) {
	fprintf(stderr, "Usage: %s <options>\n\n", bin_name);
	fprintf(stderr, "Options:\n");
	fprintf(stderr, "    -h                This message\n");
	fprintf(stderr, "    -i <interface>    Sniff packets from specified interface\n");
	fprintf(stderr, "    -p <pcap file>    Read packets from specified pcap file\n");
	fprintf(stderr, "    -P <pcap file>    Save packets to specified pcap file for unknown fingerprints\n");
	fprintf(stderr, "    -j <json file>    Output JSON fingerprints\n");
	fprintf(stderr, "    -l <log file>     Output logfile (JSON format)\n");
	fprintf(stderr, "    -d                Show reasons for discarded packets (post BPF)\n");
	fprintf(stderr, "    -f <fpdb>         Load the (binary) FingerPrint Database\n");
	fprintf(stderr, "    -u <uid>          Drop privileges to specified username\n");
	fprintf(stderr, "    -D                Do not discard padding (don't do without understanding what this does)\n");
	fprintf(stderr, "\n");
	return;
}

/* 测试另一种搜索内存中数据库的方法 */
uint shard_fp (struct fingerprint_new *fp_lookup, uint16_t maxshard) {
				return (((fp_lookup->ciphersuite_length) + (fp_lookup->tls_version)) & (maxshard -1));
}

int main(int argc, char **argv) {
...



	setlinebuf(stdout);

	if (argc == 1) {
		print_usage(argv[0]);
		exit(-1);
	}

	for (i = arg_start; i < argc && argv[i][0] == '-' ; i++) {
		switch (argv[i][1]) {
			case '?':
			case 'h':
				print_usage(argv[0]);
				exit(0);
				break;
			case 'p':
				/* Open the file */
				/* 检查接口是否已设置 */
				if (handle != NULL) {
					printf("-p and -i are mutually exclusive\n");
					exit(-1);
				}
				handle = pcap_open_offline(argv[++i], errbuf);
				printf("Reading from file: %s\n", argv[i]);
				break;
			case 'P':
				/* Open the file */
				output_handle = pcap_dump_open(pcap_open_dead(DLT_EN10MB, 65535), argv[++i]);
				if (output_handle != NULL) {
					printf("Writing samples to file: %s\n", argv[i]);
				} else {
					printf("Could not save samples: %s\n", errbuf);
					exit(-1);
				}
				break;
			case 'i':
				/* Open the interface */
				/* 检查文件是否已成功打开,如果文件名不正确,我们可能无法嗅探 */
				if (handle != NULL) {
					printf("-p and -i are mutually exclusive\n");
					exit(-1);
				}
				handle = pcap_open_live(argv[++i], SNAP_LEN, 1, 1000, errbuf);
				printf("Using interface: \033[1;36m%s\033[1;m\n", argv[i]);
				break;
			case 'j':
				/* JSON output to file */
				if((json_fd = fopen(argv[++i], "a")) == NULL) {
					printf("Cannot open JSON file for output\n");
					exit(-1);
				}
				// Buffering is fine, but linebuf needed for tailers to work properly
				setlinebuf(json_fd);
				break;
			case 'l':
				/* Output to log file */
				if((log_fd = fopen(argv[++i], "a")) == NULL) {
					printf("Cannot open log file for output\n");
					exit(-1);
				}
				// 缓冲很好,但需要linebuf才能让裁缝正常工作
				setlinebuf(log_fd);
				break;
			case 's':
				/* JSON output to stdout */
				if((json_fd = fopen("/dev/stdout", "a")) == NULL) {
					printf("Cannot open JSON file for output\n");
					fprintf(json_fd, "FD TEST\n");
					exit(-1);
				}
				break;
			case 'd':
				/* 显示丢弃的数据包信息 */
				show_drops = 1;
				break;
			case 'D':
				/* 丢弃填充物 */
				discard_pad = 0;
				break;
			case 'u':
				/* 用于将权限丢弃到的用户 */
				priv_passwd = getpwnam(argv[++i]);
				if(priv_passwd == NULL) {
					printf("Cannot find user: %s\n", argv[i]);
					exit(-1);
				}
				unpriv_user = priv_passwd->pw_uid;
				break;
			case 'f':
				/*二进制指纹数据库 */
				/* 将来这将覆盖默认位置,因为这将是默认格式 */
				if((fpdb_fd = fopen(argv[++i], "r")) == NULL) {
					printf("Cannot open fingerprint database file\n");
					exit(-1);
				}

				break;
			default :
				printf("Unknown option '%s'\n", argv[i]);
				exit(-1);
				break;

		}
	}

	if(fpdb_fd == NULL) {
		/* 未设置文件名,正在尝试当前目录 */
		if((fpdb_fd = fopen("tlsfp3.db", "r")) == NULL) {
			printf("Cannot open fingerprint database file (try -f)\n");
			printf("(This is a new feature, tlsfp.db should be in the source code directory)\n");
			exit(-1);
		}

	}

	if (unpriv_user != -1) {
		if (setgroups(0, NULL) == -1) {
			fprintf(stderr, "WARNING: could not set groups to 0 prior to dropping privileges\n");
		} else {
			fprintf(stderr, "Dropped effective group successfully\n");
		}
		if (setgid(getgid()) == -1) {
  			fprintf(stderr, "WARNING: could not drop group privileges\n");
		} else {
			fprintf(stderr, "Dropped effective group successfully\n");
		}
		if (setuid(unpriv_user) == -1) {
			fprintf(stderr, "WARNING: could not drop privileges to specified UID\n");
		} else {
			fprintf(stderr, "Changed UID successfully\n");
		}
	}

	// Register signal Handlers
	if(!(register_signals())) {
		printf("Could not register signal handlers\n");
		exit(0);
	}

	/* 如果没有设置log_fd,我们可以直接打印到stdout */
	if(log_fd == NULL) {
		log_fd = stdout;
	}


	if(fpdb_fd != NULL) {
		/* 查找文件大小 */
		fseek(fpdb_fd, 0L, SEEK_END);
		filesize = ftell(fpdb_fd);
		fseek(fpdb_fd, 0L, SEEK_SET);

		/* 分配内存并将文件存储在fpdb_raw中 */
		fpdb_raw = malloc(filesize);
		if (fread(fpdb_raw, 1, filesize, fpdb_fd) == filesize) {
			// printf("Yay, looks like the FPDB file loaded ok\n");
			fclose(fpdb_fd);
		} else {
			printf("There seems to be a problem reading the FPDB file\n");
			fclose(fpdb_fd);
			exit(-1);
		}
	}

	/* 检查并移过版本标题(如果错误则退出) */
	if (*fpdb_raw == 0) {
		fpdb_raw++;
	} else {
		printf("Unknown version of FPDB file\n");
		exit(-1);
	}

	int x, y;
	struct fingerprint_new *fp_current;
	extern struct fingerprint_new *search[8][5];

	/* 初始化,以便知道何时处于任何一个链中的第一个 */
	for (x = 0 ; x < 8 ; x++) {
		for (y = 0 ; y < 5 ; y++) {
			search[x][y] = NULL;
		}
	}


	for (x = 0 ; x < (filesize-1) ; fp_count++) {


		/* 为一个签名分配内存 */
		fp_current = malloc(sizeof(struct fingerprint_new));


		fp_current->fingerprint_id = (uint16_t) ((uint16_t)*(fpdb_raw+x) << 8) + ((uint8_t)*(fpdb_raw+x+1));
		x += 2;
		fp_current->desc_length =  (uint16_t) ((uint16_t)*(fpdb_raw+x) << 8) + ((uint8_t)*(fpdb_raw+x+1));
		fp_current->desc = (char *)fpdb_raw+x+2;

		x += (uint16_t) ((*(fpdb_raw+x) >> 16) + (*(fpdb_raw+x+1)) + 1); // Skip the description

		fp_current->record_tls_version = (uint16_t) ((uint16_t)*(fpdb_raw+x+1) << 8) + ((uint8_t)*(fpdb_raw+x+2));
		fp_current->tls_version = (uint16_t) ((uint16_t)*(fpdb_raw+x+3) << 8) + ((uint8_t)*(fpdb_raw+x+4));
		fp_current->ciphersuite_length = (uint16_t) ((uint16_t)*(fpdb_raw+x+5) << 8) + ((uint8_t)*(fpdb_raw+x+6));
		fp_current->ciphersuite = fpdb_raw+x+7;

		x += (uint16_t) ((*(fpdb_raw+x+5) >> 16) + (*(fpdb_raw+x+6)))+7; // Skip the ciphersuites

		fp_current->compression_length = *(fpdb_raw+x);
		fp_current->compression = fpdb_raw+x+1;

		x += (*(fpdb_raw+x))+1; // Skip over compression algo's

		fp_current->extensions_length = (uint16_t) ((uint16_t)*(fpdb_raw+x) << 8) + ((uint8_t)*(fpdb_raw+x+1));
		fp_current->extensions = fpdb_raw+x+2;

		/* If discarding padding, strip out here.  In future, if this becomes default I will remove it at the database creation time */
		if(discard_pad == 1) {
			int counter;
			int debug_counter;
			for (counter = 0; counter < fp_current->extensions_length; counter += 2) {
				/* This is the two byte value for the padding extension */
				if(fp_current->extensions[counter] == 0 && fp_current->extensions[counter+1] == 21) {

					memmove(fp_current->extensions+(counter), fp_current->extensions+(counter+2), (fp_current->extensions_length - (counter + 2)));
					fp_current->extensions_length -= 2;


		x += (uint16_t)((*(fpdb_raw+x) >> 16) + *(fpdb_raw+x+1))+2;



		fp_current->curves_length = (uint16_t) ((uint16_t)*(fpdb_raw+x) << 8) + ((uint8_t)*(fpdb_raw+x+1));

		if(fp_current->curves_length == 0) {
			fp_current->curves = NULL;
		} else {
			fp_current->curves = fpdb_raw+x+2;
		}

		x += (uint16_t)((*(fpdb_raw+x) >> 16) + *(fpdb_raw+x+1))+2;  // 跳过曲线

		fp_current->sig_alg_length = (uint16_t) ((uint16_t)*(fpdb_raw+x) << 8) + ((uint8_t)*(fpdb_raw+x+1));

		if(fp_current->sig_alg_length == 0) {
			fp_current->sig_alg = NULL;
		} else {
			fp_current->sig_alg = fpdb_raw+x+2;
		}

		x += (uint16_t)((*(fpdb_raw+x) >> 16) + *(fpdb_raw+x+1))+2;  // 跳过过去的签名算法

		fp_current->ec_point_fmt_length = (uint16_t) ((uint16_t)*(fpdb_raw+x) << 8) + ((uint8_t)*(fpdb_raw+x+1));

		if(fp_current->ec_point_fmt_length == 0) {
			fp_current->ec_point_fmt = NULL;
		} else {
			fp_current->ec_point_fmt = fpdb_raw+x+2;
		}
		x += (uint16_t)((*(fpdb_raw+x) >> 16) + *(fpdb_raw+x+1))+2;

		/* 指向适当(较小)列表的多个指针数组 */
		fp_current->next = search[((fp_current->ciphersuite_length & 0x000F) >> 1 )][((fp_current->tls_version) & 0x00FF)];
		search[((fp_current->ciphersuite_length & 0x000F) >> 1 )][((fp_current->tls_version) & 0x00FF)] = fp_current;
	}

	printf("Loaded %i signatures\n", fp_count);


	if(json_fd == NULL) {
		if((json_fd = fopen("/dev/null", "a")) == NULL) {
			printf("Cannot open JSON file (/dev/null) for output\n");
			exit(-1);
		}
	}

	if (handle == NULL) {
		fprintf(stderr, "Couldn't open source %s: %s\n", dev, errbuf);
		exit(EXIT_FAILURE);
	}

	/* 确保我们在以太网设备上进行捕获[2] */
	if (pcap_datalink(handle) != DLT_EN10MB) {
		fprintf(stderr, "%s is not an Ethernet\n", dev);
		exit(EXIT_FAILURE);
	}


	if (pcap_compile(handle, &fp, default_filter, 0, 0) == -1) {
		fprintf(stderr, "Couldn't parse filter %s: %s\n",
		    filter_exp, pcap_geterr(handle));
		exit(EXIT_FAILURE);
	}

	if (pcap_setfilter(handle, &fp) == -1) {
		fprintf(stderr, "Couldn't install filter %s: %s\n",
		    filter_exp, pcap_geterr(handle));
		exit(EXIT_FAILURE);
	}
	/* 用于日志的etup主机名变量(在多个主机的情况下) */
	if(gethostname(hostname, HOST_NAME_MAX) != 0) {
		snprintf(hostname, sizeof("unknown"), "unknown");
	}

	/* 设置回调函数 */
	pcap_loop(handle, -1, got_packet, NULL);

	fprintf(stderr, "Reached end of pcap\n");

	/* cleanup */
	pcap_freecode(&fp);
	pcap_close(handle);

	return 0;
}

在命令行中运行编译后的程序,捕获网络流量。
这里的 -i ens33 是一个示例参数,表示从 ens33 网络接口捕获数据包。根据需要替换为其他参数。
可以尝试不同的命令行参数来测试程序的不同功能。例如:

-i <interface> 从指定的网络接口捕获数据包。
-p <pcap file> 从指定的pcap文件中读取数据包。
-j <json file> 将TLS指纹以JSON格式输出到文件。
...


用curl产生tls流量,想要活动pcap文件,可以使用tcpdump抓取tls流量;

If you need the complete source code, please add the WeChat number (c17865354792)

总结

TLS指纹识别是一项重要的网络安全技术,它通过对TLS握手过程中的信息进行分析,帮助识别和验证通信实体。

参考:RFC 5246、RFC 2246、RFC 6176、RFC 4346、RFC 7525

We also undertake the development of program requirements here. If necessary, please follow the WeChat official account 【程序猿编码】and contact me

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/700350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.0 Android中Activity的基础知识

一&#xff1a;Activity的定义 Activity是一个应用组件&#xff0c;它提供了一个用户界面&#xff0c;允许用户执行一个单一的、明确的操作&#xff0c;用户看的见的操作都是在activity中执行的。Activity的实现需要在manifest中进行定义&#xff0c;不让会造成程序报错。 1.…

第一百零四节 Java面向对象设计 - Java内部类成员

Java面向对象设计 - Java内部类成员 内部类可以访问其所有实例成员&#xff0c;实例字段和其封闭类的实例方法。 class Outer {private int value 2014;public class Inner {public void printValue() {System.out.println("Inner: Value " value);}} // Inner …

SAP PP学习笔记17 - MTS(Make-to-Stock) 按库存生产 的策略70,策略59

上几章讲了几种策略&#xff0c;策略10&#xff0c;11&#xff0c;30&#xff0c;40。 SAP PP学习笔记14 - MTS&#xff08;Make-to-Stock) 按库存生产&#xff08;策略10&#xff09;&#xff0c;以及生产计划的概要-CSDN博客 SAP PP学习笔记15 - MTS&#xff08;Make-to-St…

linux用户态操作GPIO首先需要export导出

在使用系统调用来实现 GPIO&#xff08;通用输入输出端口&#xff09;的输入输出操作时&#xff0c;同样需要先通过 export 属性文件来导出 GPIO&#xff0c;这是因为 Linux 内核对 GPIO 的管理和访问机制决定了这一点。 以下是具体原因&#xff1a; 内核设备模型&#xff1a…

Linux C语言:输入输出(printf scanf)

一、数据输出 1、C语言I/O操作由函数实现 #include <stdio.h> 2、字符输出函数 格式: int putchar( int c ) 参数: c为字符常量、变量或表达式 功能&#xff1a;把字符c输出到显示器上 返值&#xff1a;putchar函数的返回值是参数的ASCLL码值&#xff1b; #inclu…

【CTF-Events】R3CTF/YUANHENGCTF 2024 两道密码题记录一下

R3CTF2024 WP 文章目录 R3CTF2024 WPCryptoR0System考点&#xff1a;代码审计 ECDH R1System考点&#xff1a;代码审计 ECDH Crypto R0System 考点&#xff1a;代码审计 ECDH 打开代码后有两个小系统&#xff0c;看一下功能 然后再看一下登录之后有哪些功能 其实到这里就可以…

干货分享!2024年Instagram营销必备插件

Instagram是营销人员常用的社交媒体平台&#xff0c;通过提升品牌知名度来推动业务增长。今天给大家分享一些超实用的Instagram营销插件&#xff0c;无论是下载图片视频&#xff0c;还是预先发布帖子&#xff0c;这些工具都可以是你的得力助手&#xff0c;让你的INS运营效率蹭蹭…

spring常用注解(八)@Async

一、介绍 1、介绍 二、原理 三、集成与使用 1、集成方法 &#xff08;1&#xff09;开启 使用以下注解开启 EnableAsync &#xff08;2&#xff09;使用 在需要异步处理的方法上加上 Async 2、返回值 Async注解的方法返回值只能为void或者Future<T>。 &…

纠删码是什么?有什么作用?

在阿里云对象存储中使用的是用基于纠删码、多副本的数据冗余存储机制&#xff0c;将每个对象的不同冗余存储在同一个区域内多个设施的多个设备上&#xff0c;确保硬件失效时的数据持久性和可用性。这里我们来详细介绍一下什么是纠删码。 纠删码&#xff08;Erasure Coding&…

什么是覆盖索引 ?

走当前索引就足够&#xff0c;而无需回表就能找到所有数据&#xff0c;就叫覆盖索引。 比如 key1 上有索引。&#xff08;它是一个普通的二级索引&#xff09;。 那么select key1 from s1 where key1 a 这种就叫覆盖索引。 表现就是explain时&#xff0c; Extra 那里显示 …

【深度学习】使用 LSTM 网络预测水位数据

使用 LSTM 网络预测水位数据 在本文中&#xff0c;我们将介绍如何使用 LSTM&#xff08;长短期记忆&#xff09;神经网络来预测水位数据。我们将使用 Python 中的一些流行库&#xff0c;如 NumPy、Pandas 和 Keras。首先&#xff0c;我们将加载数据&#xff0c;然后预处理它以…

基于 Transformer 的大语言模型

语言建模作为语言模型&#xff08;LMs&#xff09;的基本功能&#xff0c;涉及对单词序列的建模以及预测后续单词的分布。 近年来&#xff0c;研究人员发现&#xff0c;扩大语言模型的规模不仅增强了它们的语言建模能力&#xff0c;而且还产生了处理传统NLP任务之外更复杂任务…

Pixi.js学习 (五)动画效果与变量逻辑控制

目录 前言 一、动画效果 1.1 帧频 1.2 帧频函数 二、变量逻辑控制 2.1 定义变量的语法 2.2 使用变量控制逻辑 2.3 使用变量控制追加效果 三、实战 例题一&#xff1a;完成天天酷跑 例题一代码&#xff1a; 总结 前言 为了提高作者的代码编辑水品&#xff0c;作者在使用博客的时…

遥感和GIS在滑坡、泥石流风险普查中的技术应用教程

原文链接&#xff1a;感和GIS在滑坡、泥石流风险普查中的技术应用教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247606346&idx5&snb98d2e84b0273507ec23d3d1212b8421&chksmfa8261adcdf5e8bb26dfa824d320d1754e83b5e0ca523545704e59a3cda8aa370387…

强烈推荐!Windows 11 24H2 版本系统下载(新功能多多)

微软向 Windows 11 Version 24H2 用户推送了 KB5036908 更新&#xff0c;标志着 24H2 版本的首次累积更新&#xff0c;更新后用户的系统版本号将升级至 26100.268。在新版本中&#xff0c;最显著的变化包括对文件资源管理器的改进、整合的 Copilot 功能、编辑 PNG 文件元数据的…

AI实时免费在线图片工具4:WordArt艺术字生成;IC-Light打光模型;screenshot to code图像直接生成网页

1、艺术字生成WordArt https://modelscope.cn/studios/WordArt/WordArt/summary?reftop.aibase.com 2、打光模型IC-Light https://huggingface.co/spaces/lllyasviel/IC-Light Screenshot to Code图像直接生成网页 https://huggingface.co/spaces/HuggingFaceM4/screen…

AI大模型智慧政务解决方案

随着AI大模型技术的蓬勃发展和普及应用&#xff0c;我们的政务治理正迎来一场波澜壮阔的革新巨浪。这场革新&#xff0c;不仅是技术层面的飞跃&#xff0c;更是一场深刻改变治理理念的伟大变革。它彻底颠覆了传统政务治理中依赖人力、效率低下、响应迟缓的“人盯人”模式&#…

10_Transformer预热---注意力机制(Attention)

1.1 什么是注意力机制(attention) 注意力机制&#xff08;Attention Mechanism&#xff09;是一种在神经网络中用于增强模型处理特定输入特征的能力的技术。它最早被应用于自然语言处理&#xff08;NLP&#xff09;任务中&#xff0c;特别是在机器翻译中&#xff0c;如Google的…

uniapp录音播放功能

ui效果如上。 播放就开始倒计时&#xff0c;并且改变播放icon&#xff0c;另外录音则停止上一次录音。 播放按钮&#xff08;三角形&#xff09;是播放功能&#xff0c;两竖是暂停播放功能。 const innerAudioContext wx.createInnerAudioContext();export default{data(){ret…

16个免费学习Python的网站和教程(2024年最新资源)

16个免费学习Python的网站和教程&#xff08;2024年最新资源&#xff09; 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff…