• 搜索
  • 夜间模式
    ©2015-2025  Ethan's Blog Theme by OneBlog
    搜索
    标签
    # Amule # Gargoyle # LUCI # VIM # Python # Nginx # 反代 # Ansible # Apache # LNMP
  • 首页>
  • Cisco>
  • 正文
  • Tshark抓包脚本

    2025年07月11日 102 阅读 0 评论 16963 字

    抓包过滤有如下两个格式:

    • ✅主机
    tshark -i any -f 'host 192.168.1.1/32' -w $path/timestamp-$host.pcapng
    • ✅网络号
    tshark -i any -f 'net 192.168.1.0/24' -w $path/timestamp-$host.pcapng
    貌似可用带掩码的方式,直接使用net参数过滤,不区分是主机还是网络号,例如:
    tshark -i any -f 'net 192.168.1.1/32' -w $path/timestamp-$host.pcapng
    tshark -i any -f 'net 192.168.1.0/24' -w $path/timestamp-$host.pcapng

    快速抓单目标

    #!/bin/bash
    
    iface="enp1s0"
    path="/data"
    
    # 创建目录(如果不存在)
    mkdir -p "$path"
    
    # 获取当前时间戳
    timestamp=$(date +%Y-%m-%d-%H:%M:%S)
    
    # 读取用户输入
    read -p "请输入要抓包的主机或网段 (如 192.168.1.1 或 192.168.0.0/24): " host
    
    # 判断输入是否为空
    if [ -z "$host" ]; then
        echo "抓包目标不能为空"
        exit 1
    fi
    
    # 构建过滤器
    if [[ "$host" =~ / ]]; then
        filter="net $host"
    else
        filter="host $host"
    fi
    
    # 将斜杠替换为下划线防止文件名出错
    safe_host="${host//\//_}"
    file="$path/${timestamp}-${safe_host}.pcapng"
    
    echo "开始抓包,使用接口 $iface,过滤条件: $filter"
    tshark -i "$iface" -f "$filter" -w "$file"
    
    echo "抓包完成,文件已保存为:$file"
    
    # 是否转换为可阅读文本
    read -p "是否转换为txt文本便于AI分析?(y/n, 默认 y): " answer
    answer=${answer:-y}
    
    if [[ "$answer" == "y" || "$answer" == "Y" ]]; then
        txt_file="$path/${timestamp}-${safe_host}.txt"
        echo "正在转换格式,请不要操作!"
        tshark -r "$file" \
            -T fields \
            -E header=y \
            -e frame.number \
            -e frame.time_relative \
            -e ip.src \
            -e ip.dst \
            -e tcp.srcport \
            -e tcp.dstport \
            -e _ws.col.Info > "$txt_file"
        echo "已转换为文本:$txt_file"
    fi

    交互抓包

    #!/bin/bash
    
    # 抓包输出目录
    output_dir="/data"
    mkdir -p "$output_dir"
    
    # 显示可用网卡
    echo "=== 可用网卡列表 ==="
    tshark -D
    echo "==================="
    
    # 选择网卡
    read -p "请输入要抓包的网卡编号(例如 1): " iface_num
    iface=$(tshark -D | sed -n "${iface_num}p" | cut -d. -f2- | sed 's/^[[:space:]]*//')
    
    if [ -z "$iface" ]; then
        echo "❌ 无效的网卡编号,退出。"
        exit 1
    fi
    
    # 输入主机或网段
    read -p "请输入抓包目标(IP或CIDR网段,例如 192.168.1.1 或 192.168.0.0/24): " target
    
    if [ -z "$target" ]; then
        echo "❌ 抓包目标不能为空"
        exit 1
    fi
    
    # 判断过滤器类型
    if [[ "$target" =~ / ]]; then
        filter="net $target"
    else
        filter="host $target"
    fi
    
    # 选填:抓包持续时间
    read -p "是否限制抓包时长?输入秒数(如 30),留空表示手动 Ctrl+C 停止: " duration
    
    # 安全命名(去掉斜线)
    timestamp=$(date +%Y-%m-%d-%H-%M-%S)
    safe_target="${target//\//_}"
    pcap_file="${output_dir}/${timestamp}-${safe_target}.pcapng"
    
    echo "✅ 开始抓包,接口: $iface,过滤: $filter"
    if [ -n "$duration" ]; then
        tshark -i "$iface" -f "$filter" -a duration:$duration -w "$pcap_file"
    else
        tshark -i "$iface" -f "$filter" -w "$pcap_file"
    fi
    
    echo "✅ 抓包完成,文件保存为: $pcap_file"
    
    # 是否导出为 txt
    read -p "是否转换为txt文本供AI分析?(y/n, 默认 y): " convert
    convert=${convert:-y}
    
    if [[ "$convert" =~ ^[Yy]$ ]]; then
        txt_file="${output_dir}/${timestamp}-${safe_target}.txt"
        tshark -r "$pcap_file" \
            -T fields \
            -E header=y \
            -e frame.number \
            -e frame.time_relative \
            -e ip.src \
            -e ip.dst \
            -e tcp.srcport \
            -e tcp.dstport \
            -e _ws.col.Info > "$txt_file"
        echo "✅ 转换完成,文本保存为: $txt_file"
    fi

    交互同时抓多目标

    #!/bin/bash
    
    output_dir="/data"
    mkdir -p "$output_dir"
    
    # 显示网卡
    echo "=== 可用网卡列表 ==="
    tshark -D
    echo "==================="
    
    read -p "请输入要抓包的网卡编号: " iface_num
    iface=$(tshark -D | sed -n "${iface_num}p" | cut -d. -f2- | sed 's/^[[:space:]]*//')
    [ -z "$iface" ] && echo "无效网卡编号" && exit 1
    
    read -p "请输入多个抓包目标(用空格分隔,如 192.168.1.1 192.168.0.0/24): " -a targets
    [ ${#targets[@]} -eq 0 ] && echo "目标不能为空" && exit 1
    
    read -p "是否限制抓包时长?输入秒数(默认无限制): " duration
    
    for target in "${targets[@]}"; do
        if [[ "$target" =~ / ]]; then
            filter="net $target"
        else
            filter="host $target"
        fi
    
        timestamp=$(date +%Y-%m-%d-%H-%M-%S)
        safe_target="${target//\//_}"
        pcap_file="${output_dir}/${timestamp}-${safe_target}.pcapng"
    
        echo "▶ 正在抓包 $target"
        if [ -n "$duration" ]; then
            tshark -i "$iface" -f "$filter" -a duration:$duration -w "$pcap_file"
        else
            tshark -i "$iface" -f "$filter" -w "$pcap_file"
        fi
        echo "✅ 已保存到 $pcap_file"
    done

    web控制抓单目标

    from flask import Flask, render_template_string, request
    import subprocess
    import os
    from datetime import datetime
    
    app = Flask(__name__)
    OUTPUT_DIR = "/data"
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    
    TEMPLATE = """
    <!doctype html>
    <title>抓包控制台</title>
    <h2>Web 抓包控制台</h2>
    <form method="post">
        网卡名: <input name="iface" value="enp1s0"><br><br>
        抓包目标(IP 或 网段): <input name="target"><br><br>
        抓包时长(秒,可选): <input name="duration"><br><br>
        <input type="submit" value="开始抓包">
    </form>
    {% if msg %}<p style="color:green">{{ msg }}</p>{% endif %}
    """
    
    @app.route("/", methods=["GET", "POST"])
    def index():
        msg = ""
        if request.method == "POST":
            iface = request.form["iface"]
            target = request.form["target"]
            duration = request.form.get("duration")
            if "/" in target:
                f = f"net {target}"
            else:
                f = f"host {target}"
            timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
            safe_target = target.replace("/", "_")
            pcap_path = os.path.join(OUTPUT_DIR, f"{timestamp}-{safe_target}.pcapng")
            cmd = ["tshark", "-i", iface, "-f", f, "-w", pcap_path]
            if duration:
                cmd += ["-a", f"duration:{duration}"]
            subprocess.Popen(cmd)
            msg = f"抓包已启动,保存为:{pcap_path}"
        return render_template_string(TEMPLATE, msg=msg)
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8888)

    web控制抓多目标

    from flask import Flask, render_template_string, request
    import subprocess
    import os
    from datetime import datetime
    
    app = Flask(__name__)
    OUTPUT_DIR = "/data"
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    
    TEMPLATE = """
    <!doctype html>
    <title>多目标抓包平台</title>
    <h2>Web 多目标抓包平台</h2>
    <form method="post">
        网卡名: <input name="iface" value="enp1s0"><br><br>
        抓包目标(可多个,用空格分隔): <input name="targets"><br><br>
        抓包时长(秒,可选): <input name="duration"><br><br>
        <input type="submit" value="开始抓包">
    </form>
    {% if msg %}<p style="color:green;white-space:pre-line;">{{ msg }}</p>{% endif %}
    """
    
    @app.route("/", methods=["GET", "POST"])
    def index():
        msg = ""
        if request.method == "POST":
            iface = request.form["iface"]
            targets = request.form["targets"].split()
            duration = request.form.get("duration")
    
            for target in targets:
                if "/" in target:
                    f = f"net {target}"
                else:
                    f = f"host {target}"
                timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
                safe_target = target.replace("/", "_")
                pcap_path = os.path.join(OUTPUT_DIR, f"{timestamp}-{safe_target}.pcapng")
                cmd = ["tshark", "-i", iface, "-f", f, "-w", pcap_path]
                if duration:
                    cmd += ["-a", f"duration:{duration}"]
                subprocess.Popen(cmd)
                msg += f"✅ {target} 抓包启动,保存为 {pcap_path}\n"
    
        return render_template_string(TEMPLATE, msg=msg)
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8888)
    

    web优化(终极版,推荐)

    from flask import Flask, render_template_string, request, redirect, url_for, send_from_directory, Response
    import subprocess
    import os
    from datetime import datetime
    import threading
    
    app = Flask(__name__)
    OUTPUT_DIR = "/data"
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    
    tasks = {}
    history = []
    task_id_counter = 1
    log_buffers = {}
    
    #--- 转换 TXT ---
    def convert_to_txt(pcap_path, txt_path):
        cmd = [
            "tshark", "-r", pcap_path,
            "-T", "fields", "-E", "header=y",
            "-e", "frame.number", "-e", "frame.time_relative",
            "-e", "ip.src", "-e", "ip.dst",
            "-e", "tcp.srcport", "-e", "tcp.dstport",
            "-e", "_ws.col.Info"
        ]
        with open(txt_path, "w") as f:
            proc = subprocess.Popen(cmd, stdout=f)
            proc.wait()  # 避免产生僵尸进程
    
    def async_convert(task):
        pcap_file = task["file"]
        txt_file = task["txt"]
        convert_to_txt(pcap_file, txt_file)
        for h in history:
            if h["pcap"] == os.path.basename(pcap_file):
                h["txt"] = os.path.basename(txt_file)
    
    #--- 实时输出 tshark ---
    def stream_output(tid, proc):
        log_buffers[tid] = []
        for line in iter(proc.stdout.readline, b''):
            log_buffers[tid].append(line.decode())
    
    @app.route("/")
    def index():
        return render_template_string(TEMPLATE, tasks=tasks, history=history, default_ip=request.remote_addr)
    
    @app.route("/start", methods=["POST"])
    def start_capture():
        global task_id_counter
        iface = request.form["iface"]
        targets = request.form["targets"].split()
        duration = request.form.get("duration") or "3600"
        snaplen = request.form.get("snaplen") or "400"
        auto_txt = "auto_txt" in request.form
    
        for target in targets:
            capture_filter = f"net {target}" if "/" in target else f"host {target}"
            timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
            safe_target = target.replace("/", "_")
            pcap = f"{timestamp}-{safe_target}.pcapng"
            txt = f"{timestamp}-{safe_target}.txt"
            pcap_path = os.path.join(OUTPUT_DIR, pcap)
            txt_path = os.path.join(OUTPUT_DIR, txt)
    
            cmd = ["tshark", "-i", iface, "-f", capture_filter, "-s", snaplen, "-w", pcap_path, "-l"]
            if duration:
                cmd += ["-a", f"duration:{duration}"]
            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    
            tid = task_id_counter
            task_id_counter += 1
            tasks[tid] = {
                "target": target,
                "file": pcap_path,
                "txt": txt_path if auto_txt else None,
                "pid": proc.pid,
                "proc": proc,
                "timestamp": timestamp,
                "auto_txt": auto_txt
            }
    
            threading.Thread(target=stream_output, args=(tid, proc), daemon=True).start()
    
        return redirect(url_for("index"))
    
    @app.route("/stop/<int:tid>", methods=["POST"])
    def stop_capture(tid):
        task = tasks.pop(tid, None)
        if task:
            proc = task["proc"]
            proc.terminate()
            try:
                proc.wait(timeout=3)
            except subprocess.TimeoutExpired:
                proc.kill()
    
            history.append({
                "target": task["target"],
                "timestamp": task["timestamp"],
                "pcap": os.path.basename(task["file"]),
                "txt": None
            })
    
            if task.get("auto_txt"):
                threading.Thread(target=async_convert, args=(task,), daemon=True).start()
    
        return redirect(url_for("index"))
    
    @app.route("/convert/<pcap>", methods=["POST"])
    def manual_convert(pcap):
        txt = pcap.replace(".pcapng", ".txt")
        convert_to_txt(os.path.join(OUTPUT_DIR, pcap), os.path.join(OUTPUT_DIR, txt))
        for h in history:
            if h["pcap"] == pcap:
                h["txt"] = txt
        return redirect(url_for("index"))
    
    @app.route("/logs/<int:tid>")
    def show_logs(tid):
        lines = log_buffers.get(tid, ["暂无日志"])
        content = "".join(lines)
        html = f"""
        <html><head>
            <meta charset="utf-8">
            <meta http-equiv="refresh" content="1">
            <title>实时日志</title>
            <style>body {{ background:black; color:lime; padding:10px; }}</style>
        </head><body>
        <pre>{content}</pre>
        </body></html>
        """
        return Response(html, mimetype="text/html")
    
    @app.route("/download/<filename>")
    def download(filename):
        return send_from_directory(OUTPUT_DIR, filename, as_attachment=True)
    
    #--- 前端模板 ---
    TEMPLATE = """
    <!doctype html>
    <html lang="zh">
    <head>
        <meta charset="utf-8">
        <title>WEB抓包控制台</title>
        <!--<link href="http://10.0.1.200/bootstrap.min.css" rel="stylesheet">-->
        <link href="http://192.168.20.100:8080/bootstrap.min.css" rel="stylesheet">
        <style>
            body { padding: 2rem; background-color: #f8f9fa; }
            .card { margin-bottom: 2rem; }
            .table thead th { background-color: #e9ecef; }
            .form-control, .btn { margin-bottom: 1rem; }
            pre { max-height: 300px; overflow-y: scroll; background: #000; color: #0f0; padding: 1rem; }
        </style>
    </head>
    <body>
    <div class="container">
        <h2 class="mb-4 text-primary">WEB抓包控制台</h2>
    
        <div class="card shadow-sm">
            <div class="card-header">发起新抓包任务</div>
            <div class="card-body">
                <form method="post" action="/start">
                    <div class="row">
                        <div class="col-md-3">
                            <label>网卡名</label>
                            <input class="form-control" name="iface" value="enp1s0">
                        </div>
                        <div class="col-md-3">
                            <label>抓包目标(空格分隔)</label>
                            <input class="form-control" name="targets" value="{{ default_ip }}">
                        </div>
                        <div class="col-md-2">
                            <label>时长(秒)</label>
                            <input class="form-control" name="duration" value="3600">
                        </div>
                        <div class="col-md-2">
                            <label>每包最大字节</label>
                            <input class="form-control" name="snaplen" value="400">
                        </div>
                        <div class="col-md-2">
                            <label>选项</label><br>
                            <input type="checkbox" name="auto_txt"> 自动转为TXT
                        </div>
                    </div>
                    <button type="submit" class="btn btn-success mt-2">开始抓包</button>
                </form>
            </div>
        </div>
    
        <div class="card shadow-sm">
            <div class="card-header">当前抓包任务</div>
            <div class="card-body">
                {% if tasks %}
                <div class="table-responsive">
                    <table class="table table-bordered table-hover align-middle">
                        <thead>
                            <tr><th>ID</th><th>目标</th><th>PID</th><th>操作</th><th>日志</th></tr>
                        </thead>
                        <tbody>
                            {% for tid, t in tasks.items() %}
                            <tr>
                                <td>{{ tid }}</td>
                                <td>{{ t['target'] }}</td>
                                <td>{{ t['pid'] }}</td>
                                <td>
                                    <form method="post" action="/stop/{{ tid }}">
                                        <button class="btn btn-danger btn-sm">停止</button>
                                    </form>
                                </td>
                                <td><a href="/logs/{{ tid }}" target="_blank" class="btn btn-secondary btn-sm">查看日志</a></td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                {% else %}
                <p class="text-muted">暂无运行中任务</p>
                {% endif %}
            </div>
        </div>
    
        <div class="card shadow-sm">
            <div class="card-header">抓包历史记录</div>
            <div class="card-body">
                {% if history %}
                <div class="table-responsive">
                    <table class="table table-striped table-bordered align-middle">
                        <thead>
                            <tr><th>时间</th><th>目标</th><th>PCAP 文件</th><th>TXT 文件</th></tr>
                        </thead>
                        <tbody>
                            {% for h in history %}
                            <tr>
                                <td>{{ h['timestamp'] }}</td>
                                <td>{{ h['target'] }}</td>
                                <td><a href="/download/{{ h['pcap'] }}" class="btn btn-outline-primary btn-sm">{{ h['pcap'] }}</a></td>
                                <td>
                                    {% if h['txt'] %}
                                    <a href="/download/{{ h['txt'] }}" class="btn btn-outline-secondary btn-sm">{{ h['txt'] }}</a>
                                    {% else %}
                                    <form method="post" action="/convert/{{ h['pcap'] }}">
                                        <button class="btn btn-warning btn-sm">手动转换</button>
                                    </form>
                                    {% endif %}
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                {% else %}
                <p class="text-muted">暂无历史记录</p>
                {% endif %}
            </div>
        </div>
    </div>
    </body>
    </html>
    """
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8888)
    本文著作权归作者 [ Ethan ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    — END —
    Copyright©2015-2025  All Rights Reserved.  Load:0.008 s
    Theme by OneBlog V3.6.3
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。