summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xexportpdu.py45
-rwxr-xr-xextcap/ssh-tcpdump4
-rw-r--r--lua/tls-alerts.lua136
-rwxr-xr-xsync-build.sh10
4 files changed, 165 insertions, 30 deletions
diff --git a/exportpdu.py b/exportpdu.py
index cb910d7..62c3fb0 100755
--- a/exportpdu.py
+++ b/exportpdu.py
@@ -1,18 +1,19 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
import argparse
import struct
# So slow... let's import what we need.
#from scapy.all import *
+from scapy.config import conf
from scapy.fields import StrField
from scapy.packet import Packet
from scapy.utils import wrpcap
-# From epan/exported_pdu.h
+# From wsutil/exported_pdu_tlvs.h (used in epan/exported_pdu.h)
EXP_PDU_TAG_END_OF_OPT = 0
EXP_PDU_TAG_OPTIONS_LENGTH = 10
EXP_PDU_TAG_LINKTYPE = 11
-EXP_PDU_TAG_PROTO_NAME = 12
-EXP_PDU_TAG_HEUR_PROTO_NAME = 13
+EXP_PDU_TAG_DISSECTOR_NAME = 12
+EXP_PDU_TAG_HEUR_DISSECTOR_NAME = 13
EXP_PDU_TAG_DISSECTOR_TABLE_NAME = 14
EXP_PDU_TAG_IPV4_SRC = 20
EXP_PDU_TAG_IPV4_DST = 21
@@ -27,24 +28,14 @@ EXP_PDU_TAG_ORIG_FNO = 30
EXP_PDU_TAG_DVBCI_EVT = 31
EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL = 32
EXP_PDU_TAG_COL_PROT_TEXT = 33
+EXP_PDU_TAG_TCP_INFO_DATA = 34
+EXP_PDU_TAG_P2P_DIRECTION = 35
+EXP_PDU_TAG_COL_INFO_TEXT = 36
-class TagField(StrField):
- def __init__(self, name, default):
- StrField.__init__(self, name, default)
-
- def m2i(self, pkt, x):
- tag_type, tag_len = struct.unpack_from('!HH', x)
- x = x[4:]
- if tag_len > len(x):
- # XXX error?
- return
- tag_data, x = x[:tag_len], x[tag_len:]
- return[tag_type, tag_data]
+# For backwards compatibility, since Wireshark v4.1.0rc0-197-ge5951765d8.
+EXP_PDU_TAG_PROTO_NAME = EXP_PDU_TAG_DISSECTOR_NAME
+EXP_PDU_TAG_HEUR_PROTO_NAME = EXP_PDU_TAG_HEUR_DISSECTOR_NAME
- def i2m(self, pkt, x):
- tag_type, tag_data = x
- tag_len = len(tag_data)
- return struct.pack('!HH', tag_type, tag_len) + tag_data
class TagsField(StrField):
islist = 1
@@ -69,6 +60,15 @@ class TagsField(StrField):
def _convert_data(self, tag_type, tag_data):
if type(tag_data) is int:
return struct.pack('!I', tag_data)
+ # Wireshark pads some strings to align them at four bytes. Although not
+ # strictly necessary for use in Wireshark, replicate it. See
+ # https://gitlab.com/wireshark/wireshark/-/issues/19284
+ tag_len = len(tag_data)
+ if tag_type in (EXP_PDU_TAG_DISSECTOR_NAME,
+ EXP_PDU_TAG_HEUR_DISSECTOR_NAME,
+ EXP_PDU_TAG_DISSECTOR_TABLE_NAME) and (tag_len & 3):
+ pad_len = 4 - (tag_len & 3)
+ tag_data += pad_len * b'\0'
return tag_data
def i2m(self, pkt, x):
@@ -85,6 +85,9 @@ class WiresharkUpperPdu(Packet):
name = "WiresharkUpperPdu"
fields_desc = [ TagsField("tags", []) ]
+DLT_WIRESHARK_UPPER_PDU = 252
+conf.l2types.register(DLT_WIRESHARK_UPPER_PDU, WiresharkUpperPdu)
+
udp_bootp = WiresharkUpperPdu(tags = [
(EXP_PDU_TAG_DISSECTOR_TABLE_NAME, b'udp.port'),
#(EXP_PDU_TAG_PORT_TYPE, 3), # UDP (3)
@@ -101,7 +104,7 @@ ip_udp = WiresharkUpperPdu(tags = [
def make_pcap(filename, pkt):
# Link Type: Wireshark Upper PDU export (252)
- wrpcap(filename, pkt, linktype=252)
+ wrpcap(filename, pkt, linktype=DLT_WIRESHARK_UPPER_PDU)
parser = argparse.ArgumentParser()
parser.add_argument("filename")
diff --git a/extcap/ssh-tcpdump b/extcap/ssh-tcpdump
index 02fcca6..d04b5e0 100755
--- a/extcap/ssh-tcpdump
+++ b/extcap/ssh-tcpdump
@@ -22,6 +22,7 @@ parser.add_argument('--extcap-interfaces', action='store_true')
parser.add_argument('--extcap-dlts', action='store_true')
parser.add_argument('--extcap-config', action='store_true')
parser.add_argument('--capture', action='store_true')
+parser.add_argument('--extcap-version')
parser.add_argument('--extcap-interface', metavar='IFACE')
@@ -72,13 +73,14 @@ def extcap_capture(iface, cfilter, outfile):
else:
ssh_user = os.getenv('USER')
tcpdump_args = [
- "sudo",
"tcpdump",
"-i", iface,
"-p",
"-U",
"-w", "-",
]
+ if ssh_user != 'root':
+ tcpdump_args = ["sudo"] + tcpdump_args
# Change to a less-privileged user
if ssh_user:
tcpdump_args += ["-Z", ssh_user]
diff --git a/lua/tls-alerts.lua b/lua/tls-alerts.lua
new file mode 100644
index 0000000..be79dc9
--- /dev/null
+++ b/lua/tls-alerts.lua
@@ -0,0 +1,136 @@
+--
+-- Wireshark listener to identify unusual TLS Alerts and associated domains.
+-- Author: Peter Wu <peter@lekensteyn.nl>
+--
+-- Load in Wireshark, then open the Tools -> TLS Alerts menu, or use tshark:
+--
+-- $ tshark -q -Xlua_script:tls-alerts.lua -r some.pcapng
+-- shavar.services.mozilla.com 1x Bad Certificate (42)
+-- aus5.mozilla.org 3x Bad Certificate (42), 1x Unknown CA (48)
+--
+
+--local quic_stream = Field.new("quic.stream")
+local tls_sni = Field.new("tls.handshake.extensions_server_name")
+local tls_alert = Field.new("tls.alert_message.desc")
+
+-- Map from TCP stream -> SNI
+local snis
+-- Map from SNI -> (map of alerts -> counts)
+local alerts
+
+local tw
+local function reset_stats()
+ snis = {}
+ alerts = {}
+ if gui_enabled() then
+ tw:clear()
+ end
+end
+
+local function tap_packet(pinfo, tvb, tcp_info)
+ local tcp_stream = tcp_info.th_stream
+ if not tcp_stream then
+ print('TCP stream somehow not found, is this QUIC? pkt=' .. pinfo.number)
+ return
+ end
+
+ local f_sni = tls_sni()
+ if f_sni then
+ snis[tcp_stream] = f_sni.value
+ end
+ -- Ignore "Close Notify (0)" alerts since these are not unusual.
+ local f_alert = tls_alert()
+ if f_alert and f_alert.value ~= 0 then
+ local sni = snis[tcp_stream] or string.format("<unknown SNI on tcp.stream==%d>", tcp_stream)
+ -- Store counters for SNI -> Alerts mappings
+ local sni_alerts = alerts[sni]
+ if not alerts[sni] then
+ sni_alerts = {}
+ alerts[sni] = sni_alerts
+ end
+ local count = sni_alerts[f_alert.display]
+ if not count then
+ sni_alerts[f_alert.display] = 1
+ else
+ sni_alerts[f_alert.display] = count + 1
+ end
+ end
+end
+
+local function round_to_multiple_of(val, multiple)
+ local rest = val % multiple
+ if rest == 0 then
+ return val
+ else
+ return val - rest + multiple
+ end
+end
+
+local function output_all(callback, need_newline)
+ -- Align the domain to a multiple of four columns
+ local max_length = 16
+ for sni in pairs(alerts) do
+ if #sni > max_length then
+ max_length = round_to_multiple_of(#sni + 1, 4) - 1
+ end
+ end
+ local fmt = "%-" .. max_length .. "s %s"
+ if need_newline then fmt = fmt .. "\n" end
+
+ for sni, alert_counts in pairs(alerts) do
+ table.sort(alert_counts, function(a, b) return a > b end)
+ local all_alerts
+ for alert, count in pairs(alert_counts) do
+ local sep = ""
+ local chunk = string.format("%dx %s", count, alert)
+ if all_alerts then
+ all_alerts = all_alerts .. ", " .. chunk
+ else
+ all_alerts = chunk
+ end
+ end
+ callback(string.format(fmt, sni, all_alerts))
+ end
+end
+
+-- Called periodically in the Wireshark GUI
+local function gui_draw()
+ tw:clear()
+ output_all(function(text)
+ tw:append(text .. "\n")
+ end)
+end
+
+-- Called at the end of tshark
+local function cli_draw()
+ output_all(print)
+end
+
+local function activate_tap()
+ -- Match TLS Client Hello with SNI extension or TLS alerts.
+ local tap = Listener.new("tcp", "(tls.handshake.type==1 and tls.handshake.extensions_server_name) or tls.alert_message")
+
+ if gui_enabled() then
+ tw = TextWindow.new("TLS Alerts")
+ tw:set_atclose(function()
+ tap:remove()
+ tw = nil
+ end)
+ tap.draw = gui_draw
+ else
+ tap.draw = cli_draw
+ end
+
+ tap.packet = tap_packet
+ tap.reset = reset_stats
+ reset_stats()
+ if gui_enabled() then
+ retap_packets()
+ end
+end
+
+if gui_enabled() then
+ register_menu("TLS Alerts", activate_tap, MENU_TOOLS_UNSORTED)
+else
+ activate_tap()
+end
diff --git a/sync-build.sh b/sync-build.sh
index bcd4c47..19da4e3 100755
--- a/sync-build.sh
+++ b/sync-build.sh
@@ -50,13 +50,6 @@ CXX=${CXX:-c++}
# "<optimized out>".
# -O1 -g -gdwarf-4 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer
_default_flags=-fdiagnostics-color
-if $CC --version | grep -qE 'clang version ([89]|[1-9][0-9])'; then
- # Require Clang and at least LLD 8.0 to avoid broken binaries and crashes.
- # https://bugs.llvm.org/show_bug.cgi?id=37303
- _default_flags+=\ -fuse-ld=lld
-else
- _default_flags+=\ -fuse-ld=gold
-fi
# -fdebug-prefix-map is supported in GCC since 2007 (?), but only in Clang 3.8
# In GDB, use "dir /tmp/wireshark" to add the source directory anyway.
# -fmacro-prefix-map and -ffile-prefix-map were added in GCC 8. Hopefully it
@@ -123,13 +116,14 @@ if $force_cmake || [ ! -e $builddir/CMakeCache.txt ]; then
-DCMAKE_INSTALL_PREFIX=/tmp/wsroot \
-DENABLE_SMI=0 \
-DCMAKE_BUILD_TYPE=Debug \
- -DDISABLE_WERROR=1 \
+ -DENABLE_WERROR=0 \
-DENABLE_ASAN=1 \
-DENABLE_UBSAN=1 \
$remotesrcdir \
-DCMAKE_LIBRARY_PATH=$LIBDIR \
-DCMAKE_C_FLAGS=$(printf %q "$CFLAGS") \
-DCMAKE_CXX_FLAGS=$(printf %q "$CXXFLAGS") \
+ -DCMAKE_{EXE,SHARED,MODULE}_LINKER_FLAGS=-fuse-ld=lld \
-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
$(printf ' %q' "${cmake_options[@]}")
fi &&