diff --git a/configure.ac b/configure.ac index 9321d8f..f89cc04 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([ssldump], [1.3]) +AC_INIT([ssldump], [1.4b]) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_SRCDIR([base/pcap-snoop.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/docker/debian-bullseye/Dockerfile b/docker/debian-bullseye/Dockerfile new file mode 100644 index 0000000..e59fbc9 --- /dev/null +++ b/docker/debian-bullseye/Dockerfile @@ -0,0 +1,28 @@ +FROM debian:bullseye-slim + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang libssl-dev libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CC=/usr/bin/clang CFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-strong -Wformat -Werror=format-security -g" && \ + make && \ + sudo make install + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/debian-bullseye/docker_build.sh b/docker/debian-bullseye/docker_build.sh new file mode 100755 index 0000000..382566c --- /dev/null +++ b/docker/debian-bullseye/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=debian-bullseye + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/debian-bullseye/docker_run.sh b/docker/debian-bullseye/docker_run.sh new file mode 100755 index 0000000..9af67e5 --- /dev/null +++ b/docker/debian-bullseye/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=debian-bullseye + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/docker/debian-buster/Dockerfile b/docker/debian-buster/Dockerfile new file mode 100644 index 0000000..c86ce8a --- /dev/null +++ b/docker/debian-buster/Dockerfile @@ -0,0 +1,28 @@ +FROM debian:buster-slim + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang libssl-dev libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CC=/usr/bin/clang && \ + make && \ + sudo make install + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/debian-buster/docker_build.sh b/docker/debian-buster/docker_build.sh new file mode 100755 index 0000000..9cd8f9c --- /dev/null +++ b/docker/debian-buster/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=debian-buster + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/debian-buster/docker_run.sh b/docker/debian-buster/docker_run.sh new file mode 100755 index 0000000..1c1073b --- /dev/null +++ b/docker/debian-buster/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=debian-buster + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/docker/debian-stretch/Dockerfile b/docker/debian-stretch/Dockerfile new file mode 100644 index 0000000..3e7ef88 --- /dev/null +++ b/docker/debian-stretch/Dockerfile @@ -0,0 +1,28 @@ +FROM debian:stretch-slim + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang libssl-dev libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CC=/usr/bin/clang && \ + make && \ + sudo make install + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/debian-stretch/docker_build.sh b/docker/debian-stretch/docker_build.sh new file mode 100755 index 0000000..824a84f --- /dev/null +++ b/docker/debian-stretch/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=debian-stretch + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/debian-stretch/docker_run.sh b/docker/debian-stretch/docker_run.sh new file mode 100755 index 0000000..56db0f2 --- /dev/null +++ b/docker/debian-stretch/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=debian-stretch + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/docker/mirror_traffic_to_container.sh b/docker/mirror_traffic_to_container.sh new file mode 100755 index 0000000..a553130 --- /dev/null +++ b/docker/mirror_traffic_to_container.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +local_if=ens3f0 +container_ip=172.17.0.2 + +sudo iptables -t mangle -I PREROUTING 1 -i ${local_if} -j TEE --gateway ${container_ip} +sudo iptables -t mangle -I POSTROUTING 1 -o ${local_if} -j TEE --gateway ${container_ip} + diff --git a/docker/ubuntu-bionic/Dockerfile b/docker/ubuntu-bionic/Dockerfile new file mode 100644 index 0000000..7c44668 --- /dev/null +++ b/docker/ubuntu-bionic/Dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:bionic + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang libssl-dev libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CC=/usr/bin/clang && \ + make && \ + sudo make install + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/ubuntu-bionic/docker_build.sh b/docker/ubuntu-bionic/docker_build.sh new file mode 100755 index 0000000..c9f169b --- /dev/null +++ b/docker/ubuntu-bionic/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-bionic + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/ubuntu-bionic/docker_run.sh b/docker/ubuntu-bionic/docker_run.sh new file mode 100755 index 0000000..1199905 --- /dev/null +++ b/docker/ubuntu-bionic/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-bionic + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/docker/ubuntu-focal/Dockerfile b/docker/ubuntu-focal/Dockerfile new file mode 100644 index 0000000..04502da --- /dev/null +++ b/docker/ubuntu-focal/Dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:focal + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang libssl-dev libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CC=/usr/bin/clang && \ + make && \ + sudo make install + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/ubuntu-focal/docker_build.sh b/docker/ubuntu-focal/docker_build.sh new file mode 100755 index 0000000..89e99d2 --- /dev/null +++ b/docker/ubuntu-focal/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-focal + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/ubuntu-focal/docker_run.sh b/docker/ubuntu-focal/docker_run.sh new file mode 100755 index 0000000..d4ee3af --- /dev/null +++ b/docker/ubuntu-focal/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-focal + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/docker/ubuntu-groovy/Dockerfile b/docker/ubuntu-groovy/Dockerfile new file mode 100644 index 0000000..57d520a --- /dev/null +++ b/docker/ubuntu-groovy/Dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:groovy + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang libssl-dev libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CC=/usr/bin/clang && \ + make && \ + sudo make install + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/ubuntu-groovy/docker_build.sh b/docker/ubuntu-groovy/docker_build.sh new file mode 100755 index 0000000..c700c85 --- /dev/null +++ b/docker/ubuntu-groovy/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-groovy + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/ubuntu-groovy/docker_run.sh b/docker/ubuntu-groovy/docker_run.sh new file mode 100755 index 0000000..f2ba0fa --- /dev/null +++ b/docker/ubuntu-groovy/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-groovy + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/docker/ubuntu-xenial/Dockerfile b/docker/ubuntu-xenial/Dockerfile new file mode 100644 index 0000000..493c874 --- /dev/null +++ b/docker/ubuntu-xenial/Dockerfile @@ -0,0 +1,41 @@ +FROM ubuntu:xenial + +ENV LANG C +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends ca-certificates sudo git build-essential automake autoconf clang wget libpcap-dev libnet1-dev libjson-c-dev iproute2 && \ + apt-get clean + +RUN useradd -ms /bin/bash ssldump +RUN passwd -d ssldump +RUN printf 'Defaults:ssldump env_keep=LD_LIBRARY_PATH\n' | tee -a /etc/sudoers +RUN printf 'ssldump ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER ssldump + +RUN mkdir /home/ssldump/openssl && \ + cd /home/ssldump/openssl && \ + wget https://www.openssl.org/source/openssl-1.1.1j.tar.gz && \ + tar xvfz openssl-1.1.1j.tar.gz && \ + cd openssl-1.1.1j && \ + ./config && \ + make -j 2 + +RUN cd /home/ssldump && \ + git clone https://github.com/adulau/ssldump.git build + +RUN cd /home/ssldump/build && \ + ./autogen.sh && \ + ./configure CFLAGS="-I../openssl/openssl-1.1.1j/include" LDFLAGS="-L../openssl/openssl-1.1.1j -lcrypto -lssl" && \ + make && \ + sudo make install + +ENV LD_LIBRARY_PATH /home/ssldump/openssl/openssl-1.1.1j +RUN printf '#!/bin/bash\nexport LD_LIBRARY_PATH=/home/ssldump/openssl/openssl-1.1.1j\nssldump $@\n' > /home/ssldump/run_ssldump.sh +RUN chmod +x /home/ssldump/run_ssldump.sh + +WORKDIR "/home/ssldump" + +CMD ["/bin/bash"] diff --git a/docker/ubuntu-xenial/docker_build.sh b/docker/ubuntu-xenial/docker_build.sh new file mode 100755 index 0000000..0aff63e --- /dev/null +++ b/docker/ubuntu-xenial/docker_build.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-xenial + +docker build -t "ssldump-${distribution}:${ssldump_version}" . diff --git a/docker/ubuntu-xenial/docker_run.sh b/docker/ubuntu-xenial/docker_run.sh new file mode 100755 index 0000000..8c3e8d3 --- /dev/null +++ b/docker/ubuntu-xenial/docker_run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ssldump_version=1.4b +distribution=ubuntu-xenial + +docker run -it ssldump-${distribution}:${ssldump_version} + diff --git a/ssl/ssl.enums.c b/ssl/ssl.enums.c index d441fef..56fd79f 100644 --- a/ssl/ssl.enums.c +++ b/ssl/ssl.enums.c @@ -1,4 +1,5 @@ #include +#include #include "network.h" #include "ssl_h.h" #include "sslprint.h" @@ -191,7 +192,6 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) segment *seg; Data *data; { - struct json_object *jobj; jobj = ssl->cur_json_st; json_object_object_add(jobj, "handshake_type", json_object_new_string("ClientHello")); @@ -199,6 +199,16 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) UINT4 vj,vn,cs,cslen,complen,comp,odd,exlen,ex; Data session_id,random; int r; + char *ja3_fp = NULL; + char *ja3_str = NULL; + char *ja3_ver_str = NULL; + char *ja3_cs_str = NULL; + char *ja3_ex_str = NULL; + char *ja3_ec_str = NULL; + char *ja3_ecp_str = NULL; + + ssl->cur_ja3_ec_str = NULL; + ssl->cur_ja3_ecp_str = NULL; extern decoder cipher_suite_decoder[]; extern decoder compression_method_decoder[]; @@ -209,6 +219,9 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) SSL_DECODE_UINT8(ssl,0,0,data,&vj); SSL_DECODE_UINT8(ssl,0,0,data,&vn); + ja3_ver_str = calloc(7,sizeof(char)); + snprintf(ja3_ver_str, 7, "%u", ((vj & 0xff) << 8) | (vn & 0xff)); + P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn); LF; } @@ -242,8 +255,16 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) 0,data,&cs)) return(1); ssl_print_cipher_suite(ssl,(vj<<8)|vn,P_HL,cs); + if(!ja3_cs_str) + ja3_cs_str = calloc(7, 1); + else + ja3_cs_str = realloc(ja3_cs_str, strlen(ja3_cs_str) + 7); + + snprintf(ja3_cs_str + strlen(ja3_cs_str), 7, "%u-", cs); LF; } + if(ja3_cs_str && ja3_cs_str[strlen(ja3_cs_str) - 1] == '-') + ja3_cs_str[strlen(ja3_cs_str) - 1] = '\0'; } SSL_DECODE_UINT8(ssl,"compressionMethod len",0,data,&complen); @@ -260,6 +281,13 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) explain(ssl , "extensions\n"); while(data->len) { SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex); + if(!ja3_ex_str) + ja3_ex_str = calloc(7, 1); + else + ja3_ex_str = realloc(ja3_ex_str, strlen(ja3_ex_str) + 7); + + snprintf(ja3_ex_str + strlen(ja3_ex_str), 7, "%u-", ex); + if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) { decode_extension(ssl,dir,seg,data); P_(P_RH){ @@ -269,7 +297,80 @@ static int decode_HandshakeType_ClientHello(ssl,dir,seg,data) } LF; } + if(ja3_ex_str && ja3_ex_str[strlen(ja3_ex_str) - 1] == '-') + ja3_ex_str[strlen(ja3_ex_str) - 1] = '\0'; } + + ja3_ec_str = ssl->cur_ja3_ec_str; + ja3_ecp_str = ssl->cur_ja3_ecp_str; + + if(!ja3_ver_str) { + ja3_ver_str = calloc(1, 1); + *ja3_ver_str = '\0'; + } + + if(!ja3_cs_str) { + ja3_cs_str = calloc(1, 1); + *ja3_cs_str = '\0'; + } + + if(!ja3_ex_str) { + ja3_ex_str = calloc(1, 1); + *ja3_ex_str = '\0'; + } + + if(!ja3_ec_str) { + ja3_ec_str = calloc(1, 1); + *ja3_ec_str = '\0'; + } + + if(!ja3_ecp_str) { + ja3_ecp_str = calloc(1, 1); + *ja3_ecp_str = '\0'; + } + + int ja3_str_len = + strlen(ja3_ver_str) + 1 + + strlen(ja3_cs_str) + 1 + + strlen(ja3_ex_str) + 1 + + strlen(ja3_ec_str) + 1 + + strlen(ja3_ecp_str) + 1; + ja3_str = calloc(ja3_str_len, 1); + snprintf(ja3_str, ja3_str_len, "%s,%s,%s,%s,%s", + ja3_ver_str, ja3_cs_str, ja3_ex_str, ja3_ec_str, ja3_ecp_str); + + EVP_MD_CTX *mdctx; + const EVP_MD *md; + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len, i; + + md = EVP_get_digestbyname("MD5"); + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, ja3_str, strlen(ja3_str)); + EVP_DigestFinal_ex(mdctx, md_value, &md_len); + EVP_MD_CTX_free(mdctx); + + ja3_fp = calloc(33,1); + *ja3_fp = '\0'; + for(i=0; i<16; i++) { + snprintf(ja3_fp + strlen(ja3_fp), 3, "%02x", md_value[i]); + } + + json_object_object_add(jobj, "ja3_str", json_object_new_string(ja3_str)); + json_object_object_add(jobj, "ja3_fp", json_object_new_string(ja3_fp)); + + explain(ssl, "ja3 string: %s\n", ja3_str); + explain(ssl, "ja3 fingerprint: %s\n", ja3_fp); + + free(ja3_fp); + free(ja3_str); + free(ja3_ver_str); + free(ja3_cs_str); + free(ja3_ex_str); + free(ja3_ec_str); + free(ja3_ecp_str); + return(0); } @@ -283,6 +384,12 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) int r; Data rnd,session_id; UINT4 vj,vn,exlen,ex; + char *ja3s_fp = NULL; + char *ja3s_str = NULL; + char *ja3s_ver_str = NULL; + char *ja3s_c_str = NULL; + char *ja3s_ex_str = NULL; + extern decoder extension_decoder[]; @@ -295,6 +402,9 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) SSL_DECODE_UINT8(ssl,0,0,data,&vj); SSL_DECODE_UINT8(ssl,0,0,data,&vn); + ja3s_ver_str = calloc(7,sizeof(char)); + snprintf(ja3s_ver_str, 7, "%u", ((vj & 0xff) << 8) | (vn & 0xff)); + ssl->version=vj*256+vn; P_(P_HL) {explain(ssl,"Version %d.%d ",vj,vn); LF; @@ -312,6 +422,9 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) } ssl_find_cipher(ssl->cipher_suite,&ssl->cs); + ja3s_c_str = calloc(6, 1); + snprintf(ja3s_c_str, 6, "%u", ssl->cipher_suite); + ssl_process_server_session_id(ssl,ssl->decoder,session_id.data, session_id.len); @@ -324,6 +437,13 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) explain(ssl , "extensions\n"); while(data->len) { SSL_DECODE_UINT16(ssl, "extension type", 0, data, &ex); + if(!ja3s_ex_str) + ja3s_ex_str = calloc(7, 1); + else + ja3s_ex_str = realloc(ja3s_ex_str, strlen(ja3s_ex_str) + 7); + + snprintf(ja3s_ex_str + strlen(ja3s_ex_str), 7, "%u-", ex); + if (ssl_decode_switch(ssl,extension_decoder,ex,dir,seg,data) == R_NOT_FOUND) { decode_extension(ssl,dir,seg,data); P_(P_RH){ @@ -333,8 +453,63 @@ static int decode_HandshakeType_ServerHello(ssl,dir,seg,data) } LF; } + if(ja3s_ex_str && ja3s_ex_str[strlen(ja3s_ex_str) - 1] == '-') + ja3s_ex_str[strlen(ja3s_ex_str) - 1] = '\0'; } + if(!ja3s_ver_str) { + ja3s_ver_str = calloc(1, 1); + *ja3s_ver_str = '\0'; + } + + if(!ja3s_c_str) { + ja3s_c_str = calloc(1, 1); + *ja3s_c_str = '\0'; + } + + if(!ja3s_ex_str) { + ja3s_ex_str = calloc(1, 1); + *ja3s_ex_str = '\0'; + } + + int ja3s_str_len = + strlen(ja3s_ver_str) + 1 + + strlen(ja3s_c_str) + 1 + + strlen(ja3s_ex_str) + 1; + ja3s_str = calloc(ja3s_str_len, 1); + snprintf(ja3s_str, ja3s_str_len, "%s,%s,%s", + ja3s_ver_str, ja3s_c_str, ja3s_ex_str); + + EVP_MD_CTX *mdctx; + const EVP_MD *md; + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len, i; + + md = EVP_get_digestbyname("MD5"); + mdctx = EVP_MD_CTX_new(); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, ja3s_str, strlen(ja3s_str)); + EVP_DigestFinal_ex(mdctx, md_value, &md_len); + EVP_MD_CTX_free(mdctx); + + ja3s_fp = calloc(33,1); + *ja3s_fp = '\0'; + for(i=0; i<16; i++) { + snprintf(ja3s_fp + strlen(ja3s_fp), 3, "%02x", md_value[i]); + } + + json_object_object_add(jobj, "ja3s_str", json_object_new_string(ja3s_str)); + json_object_object_add(jobj, "ja3s_fp", json_object_new_string(ja3s_fp)); + + explain(ssl, "ja3s string: %s\n", ja3s_str); + explain(ssl, "ja3s fingerprint: %s\n", ja3s_fp); + + free(ja3s_fp); + free(ja3s_str); + free(ja3s_ver_str); + free(ja3s_c_str); + free(ja3s_ex_str); + return(0); } @@ -2664,6 +2839,78 @@ static int decode_extension(ssl,dir,seg,data) return(0); } +// Extension #10 supported_groups (renamed from "elliptic_curves") +static int decode_extension_supported_groups(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int r,p; + UINT4 l,g; + char *ja3_ec_str = NULL; + SSL_DECODE_UINT16(ssl,"extension length",0,data,&l); + + if(dir==DIR_I2R){ + SSL_DECODE_UINT16(ssl,"supported_groups list length",0,data,&l); + LF; + while(l) { + p=data->len; + SSL_DECODE_UINT16(ssl, "supported group", 0, data, &g); + if(!ja3_ec_str) + ja3_ec_str = calloc(7, 1); + else + ja3_ec_str = realloc(ja3_ec_str, strlen(ja3_ec_str) + 7); + snprintf(ja3_ec_str + strlen(ja3_ec_str), 7, "%u-", g); + l-=(p-data->len); + } + if(ja3_ec_str && ja3_ec_str[strlen(ja3_ec_str) - 1] == '-') + ja3_ec_str[strlen(ja3_ec_str) - 1] = '\0'; + } + else{ + data->len-=l; + data->data+=l; + } + ssl->cur_ja3_ec_str = ja3_ec_str; + return(0); + } + +// Extension #11 ec_point_formats +static int decode_extension_ec_point_formats(ssl,dir,seg,data) + ssl_obj *ssl; + int dir; + segment *seg; + Data *data; + { + int r,p; + UINT4 l,f; + char *ja3_ecp_str = NULL; + SSL_DECODE_UINT16(ssl,"extension length",0,data,&l); + + if(dir==DIR_I2R){ + SSL_DECODE_UINT8(ssl,"ec_point_formats list length",0,data,&l); + LF; + while(l) { + p=data->len; + SSL_DECODE_UINT8(ssl, "ec point format", 0, data, &f); + if(!ja3_ecp_str) + ja3_ecp_str = calloc(5, 1); + else + ja3_ecp_str = realloc(ja3_ecp_str, strlen(ja3_ecp_str) + 5); + snprintf(ja3_ecp_str + strlen(ja3_ecp_str), 5, "%u-", f); + l-=(p-data->len); + } + if(ja3_ecp_str && ja3_ecp_str[strlen(ja3_ecp_str) - 1] == '-') + ja3_ecp_str[strlen(ja3_ecp_str) - 1] = '\0'; + } + else{ + data->len-=l; + data->data+=l; + } + + ssl->cur_ja3_ecp_str = ja3_ecp_str; + return(0); + } decoder extension_decoder[] = { { @@ -2719,12 +2966,12 @@ decoder extension_decoder[] = { { 10, "supported_groups", - decode_extension + decode_extension_supported_groups }, { 11, "ec_point_formats", - decode_extension + decode_extension_ec_point_formats }, { 12, diff --git a/ssl/ssl_h.h b/ssl/ssl_h.h index 8061d5d..ce67b19 100644 --- a/ssl/ssl_h.h +++ b/ssl/ssl_h.h @@ -109,6 +109,8 @@ typedef struct ssl_obj_ { int indent_depth; int indent_name_len; struct json_object *cur_json_st; + char *cur_ja3_ec_str; + char *cur_ja3_ecp_str; } ssl_obj; typedef struct decoder_ { diff --git a/ssl/sslprint.c b/ssl/sslprint.c index 06ec409..7580383 100644 --- a/ssl/sslprint.c +++ b/ssl/sslprint.c @@ -250,7 +250,7 @@ int ssl_expand_record(ssl,q,direction,data,len) Data d; UINT4 ct,vermaj,vermin,length; int version; - char verstr[4]; + char verstr[8]; char enumstr[20]; struct json_object *jobj; jobj = ssl->cur_json_st; @@ -272,7 +272,7 @@ int ssl_expand_record(ssl,q,direction,data,len) P_(P_RH){ explain(ssl," V%d.%d(%d)",vermaj,vermin,length); json_object_object_add(jobj, "record_len", json_object_new_int(length)); - snprintf(verstr,4,"%d.%d",vermaj,vermin); + snprintf(verstr,8,"%d.%d",vermaj,vermin); json_object_object_add(jobj, "record_ver", json_object_new_string(verstr)); }