Lua Scripts

ADVANCED TOPICS
ANALYZE PCAP
OBTAIN PCAP
GET STARTED
SharkFu

Scripting with Wireshark's Lua API
6 min |  Ross Jacobs |  March 3, 2019

Table of Contents

Quicklinks: Wireshark: Lua API docs | Lua Examples


Lua scripting allows you to dynamically access info that might not be available in Wireshark normally! Examples will be added at some point.

To use a lua script with tshark, use option -X lua_script:<path/to/script>.
Obligatory Hello World example, capturing one packet:

bash$ echo 'print("Hello World!")' > temp.lua
bash$ tshark -X lua_script:temp.lua -c 1
Hello World!
Capturing on 'Wi-Fi: en0'
    1   0.000000 178.33.111.155 → mbp.attlocal.net TLSv1.2 839 Application Data
5 packets dropped from Wi-Fi: en0
1 packet captured

Extension Options (-X)

⚠️ AI-Generated Content: This section was added using Claude Code (Opus 4.6) and requires validation by the community. Please verify accuracy before relying on this information in production environments.

The -X flag enables advanced extension options for tshark, including loading custom Lua scripts, passing arguments to scripts, and controlling read formats. This is critical for custom dissectors, proprietary protocols, and IoT/ICS environments.

Basic Syntax

tshark -X <key>:<value>

Loading Lua Scripts

Load custom dissectors or analysis scripts:

# Load a custom dissector
tshark -X lua_script:custom_dissector.lua -r capture.pcap

# Load multiple scripts
tshark -X lua_script:dissector1.lua \
       -X lua_script:dissector2.lua \
       -r capture.pcap

Real-world use cases:

  • Proprietary protocol dissection
  • IoT/ICS protocol analysis
  • Custom field extraction
  • Real-time packet manipulation

Passing Arguments to Lua Scripts

Pass configuration to loaded Lua scripts using lua_scriptnum:argument:

# Load script and pass an argument to it
tshark -X lua_script:my_parser.lua \
       -X lua_script1:config_value \
       -r capture.pcap

# Pass arguments to multiple scripts
tshark -X lua_script:script1.lua \
       -X lua_script:script2.lua \
       -X lua_script1:arg_for_script1 \
       -X lua_script2:arg_for_script2 \
       -r capture.pcap

Script indexing: Scripts are numbered in the order they’re loaded (1, 2, 3, etc.).

Example Lua script that uses arguments:

-- my_parser.lua
-- Access the argument via arg global variable
local function init()
    local config = arg or "default_value"
    print("Script started with config: " .. config)
end

init()

Usage:

tshark -X lua_script:my_parser.lua \
       -X lua_script1:production_mode \
       -r capture.pcap

Custom Read Formats

Override the file format detection to force tshark to read a file as a specific format:

# Read file as a specific format
tshark -r unusual.bin \
       -X read_format:Custom_Format \
       -X lua_script:custom_format_handler.lua

Use cases:

  • Proprietary capture formats
  • Custom binary logs
  • Non-standard packet captures

Practical Examples

Custom Protocol Dissector for IoT

-- iot_protocol.lua
-- Simple dissector for proprietary IoT protocol

local iot_proto = Proto("iot", "Custom IoT Protocol")

local f_type = ProtoField.uint8("iot.type", "Packet Type", base.DEC)
local f_device_id = ProtoField.uint32("iot.device_id", "Device ID", base.HEX)
local f_data = ProtoField.bytes("iot.data", "Payload Data")

iot_proto.fields = {f_type, f_device_id, f_data}

function iot_proto.dissector(buffer, pinfo, tree)
    pinfo.cols.protocol = "IoT"

    local subtree = tree:add(iot_proto, buffer())
    subtree:add(f_type, buffer(0,1))
    subtree:add(f_device_id, buffer(1,4))
    subtree:add(f_data, buffer(5))
end

-- Register on specific UDP port
local udp_table = DissectorTable.get("udp.port")
udp_table:add(5000, iot_proto)

Usage:

# Analyze IoT traffic with custom dissector
tshark -X lua_script:iot_protocol.lua \
       -r iot_capture.pcap \
       -Y "iot.device_id==0x12345678" \
       -T fields -e iot.type -e iot.data

Field Extraction with Configuration

-- field_extractor.lua
-- Extract specific fields based on configuration

local config = arg or "ip.src,ip.dst"
print("Extracting fields: " .. config)

-- Add extraction logic here

Usage:

# Extract configured fields
tshark -X lua_script:field_extractor.lua \
       -X lua_script1:"tcp.stream,tcp.port,http.host" \
       -r web.pcap

MODBUS/ICS Analysis

-- modbus_analyzer.lua
-- Analyze MODBUS function codes for anomalies

local modbus_proto = Proto("modbus_ext", "MODBUS Analyzer")

function modbus_proto.dissector(buffer, pinfo, tree)
    -- Check for dangerous function codes
    local func_code = buffer(7,1):uint()

    if func_code == 0x06 or func_code == 0x10 then
        pinfo.cols.info:prepend("[WRITE OPERATION] ")
        tree:add_expert_info(PI_SECURITY, PI_WARN, "MODBUS write detected")
    end
end

DissectorTable.get("tcp.port"):add(502, modbus_proto)

Usage:

# Monitor MODBUS traffic for write operations
tshark -X lua_script:modbus_analyzer.lua \
       -i eth0 \
       -f "tcp port 502" \
       -Y "modbus_ext"

Automation with Extension Options

CI/CD Custom Protocol Testing

#!/bin/bash
# Test custom protocol implementation

tshark -X lua_script:protocol_validator.lua \
       -X lua_script1:strict_mode \
       -r test_capture.pcap \
       -q > validation_results.txt

if grep -q "VALIDATION FAILED" validation_results.txt; then
    echo "Protocol validation failed!"
    exit 1
fi

Multi-Protocol IoT Analysis Pipeline

#!/bin/bash
# Analyze mixed IoT protocols

declare -a protocols=("zigbee" "zwave" "custom_rf")

for proto in "${protocols[@]}"; do
    tshark -X lua_script:${proto}_dissector.lua \
           -r iot_capture.pcap \
           -Y ${proto} \
           -T json > ${proto}_data.json
done

Available Extension Keys

While -X primarily focuses on lua_script and read_format, it can also be used for other internal options. Check the tshark man page for the most current list:

man tshark | grep -A 20 "^[[:space:]]*-X"

Troubleshooting

Script Not Loading

# Verify script syntax
lua script.lua

# Check tshark recognizes the script
tshark -X lua_script:script.lua -v

Arguments Not Passed Correctly

# Debug: Print all arguments in Lua
print("Args:", table.concat({...}, ", "))

Dissector Not Triggering

-- Ensure protocol is registered correctly
local function register()
    print("Registering protocol...")
    DissectorTable.get("tcp.port"):add(12345, my_proto)
end

register()

Performance Considerations

Lua scripts add processing overhead. Optimize by:

  1. Filter early: Use -Y to reduce packets processed by Lua

    tshark -Y "tcp.port==502" -X lua_script:heavy_script.lua -r capture.pcap
    
  2. Disable unnecessary protocols: Speed up dissection

    tshark --disable-all-protocols \
           --enable-protocol ip --enable-protocol tcp \
           -X lua_script:custom.lua -r capture.pcap
    
  3. Minimize string operations: Use buffers directly in Lua

Further Reading

Metaprogramming

There are two libraries I came across that are more metaprogramming that lua dissectors:

  • kaitai-to-wireshark: Convert a Kaitai struct binary file description to a Lua Plugin. Only some elements are supported.
  • pyreshark: Use Python instead of Lua to communicate with Wireshark. Limited to Python 2.6/ 2.7.

Lua Dissectors

I’ve compiled a list of the most popular lua dissectors on github.

Have a dissector you want added to this list? Has a dissector been merged into Wireshark? Make a pull request.

Repo Metrics

A ✔ is given for each of the following (in order of importance):

  • D: Has Documentation in the form a README. Ideally, this includes separate installation and usage sections.
  • T: One or more of: Test code / CICD / Examples folder
  • I: Has Issues opened or closed by a different user
  • R: Has github Release or version. Lacking one may mean that the project is not yet stable.
  • C: Has multiple Contributors (>1)

Star/Fork count in 2019 Aug [★] and can be converted to an in-browser javascript github API query. Repos below are on github and have at least 5 stars. None of these repos have been tested.

Note: Any derivative works of Wireshark MUST use a GPL2-compatible license.

Github Dissector List

NameProtocolDTIRCLicenseLast Updated★ForksLang
protobuf_dissectorprotobuf✔✔MIT2015-099243Lua
h264extractorH.264, opus✔✔✔GPL22016-066632Lua
SAP-Dissection-plug-in-for-WiresharkSAP Various✔✔✔✔✔GPL22019-055121C
suriwireSuricata Alert✔✔✔✔GPL32018-06496Lua
lightning-dissectorLightning Network (crypto)✔✔✔MIT2019-05416Lua
ethereum_devp2p_wireshark_dissectordevp2p (crypto)✔✗2018-06385Lua
wireshark-pluginsCAPN PROTO✔✔✔Apache22016-083410Lua
cautious-rotary-phoneErlang Trace✔Apache22018-06242Lua
wireshark-http-extraHTTP with extras✔✔✗2011-09236Lua
wireshark-pluginInterface for Cloudshark✔✔✔✔GPL22019-01206Lua
hep-wiresharkHEP3✔✔✔GPL22019-01138Lua
WiresharkLIFXDissectorLIFX✔GPL32018-02120Lua
wireshark-plugin-dashDash (crypto)✔✔✔GPL22018-10113C
amos-ss16-proj3DOIP✔✔✔✔✔AGPL32017-0186C
wireshark-plugin-mqttMQTT✔✔GPL22014-0284None
wireshark-stomp-pluginSTOMP✔GPL22017-0574Lua
wireshark-plugin-afdxAFDX✔✔✔GPL22019-0661C
tox_decoderTox✔✗2018-1062C
wireshark-plugin-rhcsRedhat Cert Protocols✔GPL22014-0152C
some-ip-dissectorSOME/IP✔GPL22019-0152Lua
lppbprotobuf✔✔GPL32016-0352Lua
rfc8450-vc2-dissectorRFC8450✔✔GPL22018-0950Lua