打印"显示" tshark

时间:2015-04-30 15:07:22

标签: wireshark tshark

上下文

我有一个包含一堆信标帧的pcap文件(换句话说,我将我的Wi-Fi适配器置于监控模式,在过滤时开始捕获" wlan.fc.type_subtype == 0x08",并保存了。)

现在,我想以某种方式显示这些数据包的特定字段。其中包括:

  • SSID(wlan_mgt.ssid)
  • MAC(wlan.ta)
  • 当前频道(wlan_mgt.ds.current_channel)
  • Group Cipher(wlan_mgt.rsn.gcs.type)
  • PairWise Ciphers(wlan_mgt.rsn.pcs.type)
  • Authentication Suite(wlan_mgt.rsn.akms.type)

我并不十分关心代表性:纯文本,xml,json,csv,X。我很喜欢它。我只是不想要比我真正需要的更多数据,输出需要对人类(wireshark newb)眼睛有意义。

最后,我还想过滤pcap以获得一个唯一的集合并计算出现次数(有些" | sort | uniq -c"会这样做),但是不要去那里现在

到目前为止我的解决方案

第一步可能是,例如:

$ tshark -r capture.pcap -c 1 -T fields -e wlan_mgt.ssid -e wlan.ta -e wlan_mgt.ds.current_channel -e wlan_mgt.rsn.gcs.type -e wlan_mgt.rsn.pcs.type -e wlan_mgt.rsn.akms.type
MySSID  XX:XX:XX:XX:XX:XX   2   4   4   2

在(手动)将数字与其文本含义匹配之后,您会得到:

  • SSID = MySSID
  • MAC(wlan.ta)= XX:XX:XX:XX:XX:XX
  • 当前频道= 2
  • Group Cipher = Group Cipher Suite类型:AES(CCM)(4)
  • PairWise Ciphers =成对密码套件类型:AES(CCM)(4)
  • Authentication Suite =身份验证密钥管理(AKM)类型:PSK(2)

这就是我正在寻找的。但是,如上所述,我必须手动完成,这不是一种选择。

问题

上面你可以看到我目前接近上述目标的方法。通过做

tshark -r capture.pcap -c 1 -T pdml

我得到了,例如(剪掉):

<field name="wlan_mgt.rsn.pcs.list" showname="Pairwise Cipher Suite List 00-0f-ac (Ieee8021) AES (CCM)" size="4" pos="112" show="" value="">
    <field name="wlan_mgt.rsn.pcs" showname="Pairwise Cipher Suite: 00-0f-ac (Ieee8021) AES (CCM)" size="4" pos="112" show="1027076" value="000fac04">
        <field name="wlan_mgt.rsn.pcs.oui" showname="Pairwise Cipher Suite OUI: 00-0f-ac (Ieee8021)" size="3" pos="112" show="4012" value="000fac"/>
        <field name="wlan_mgt.rsn.pcs.type" showname="Pairwise Cipher Suite type: AES (CCM) (4)" size="1" pos="115" show="4" value="04"/>
    </field>
</field>

...,它告诉我tshark确实拥有我需要的信息(以&#34; showsame&#34;属性的形式)。

显然,当使用&#34; -T字段-e X&#34;时,tshark会输出&#34; show&#34;中的值。属性&#34 ;.我觉得我想要&#34; showame&#34;属性。不幸的是,在烦恼谷歌一段时间之后,我仍然不知道这是怎么回事。

我也对完全不同的想法持开放态度,但主要的意思是我不能从pcap文件(排除iwlist,kismet等)中分离出来。我也最好不要开始编写搜索和替换规则,用他们的文本表示来代替无意义的数字。我希望以更清洁的方式解决它。

1 个答案:

答案 0 :(得分:1)

我一直在搞乱tshark,直到我认为它无法完成。使用令人惊奇的C ++库libtins进行一些编程让我得到了我需要的位置。

来源低于下方。享受:)

#include <tins/tins.h>

#include <algorithm>
#include <iostream>
#include <map>
#include <string>

using namespace Tins;
using namespace std;


/*
 * Container class for the data that is retrieved from the beacon.
 */
class Unit {
public:
    /*
     * Constructor. Parses the Dot11Beacon object and takes all the necessary
     * data from it.
     */
    Unit(Dot11Beacon& beacon);
    Unit() = default;
    unsigned getCount();
    void incrementCount();

    /*
     * Prints this object onto the command line, in CSV format
     */
    void print();

private:
    string ssid;
    string bssid;
    unsigned channel;
    unsigned count;

    string gcs; // Group Cipher Suite
    string pcs; // Pairwise Cipher Suite
    string akm; // Authentication suite

    /*
     * Returns a string representation of a RSNInformation::CypherSuites enum value
     */
    string type_to_string(const RSNInformation::CypherSuites& type);

    /*
     * Returns a string representation of a RSNInformation::AKMSuites enum value
     */
    string type_to_string(const RSNInformation::AKMSuites& type);
};

Unit::Unit(Dot11Beacon& beacon) :
    count {1} /* When this unit is created, it has been seen exactly once */ {
    ssid = beacon.ssid();
    bssid = beacon.addr3().to_string();
    channel = unsigned(beacon.ds_parameter_set());

    RSNInformation rsn;
    for(const auto &opt : beacon.options()) {
        if (opt.option() == Dot11::RSN) {
            rsn = beacon.rsn_information();

            // Put all authentication suite types in a string
            const RSNInformation::akm_type& akmTypeList = rsn.akm_cyphers();
            for (const auto& akmIt : akmTypeList) {
                if (akm.size() == 0)
                    akm += type_to_string(akmIt);
                else
                    akm += ";" + type_to_string(akmIt);
            }

            // Put all group cipher types in a string
            const RSNInformation::CypherSuites& gcsType = rsn.group_suite();
            gcs = type_to_string(gcsType);


            // Put all pairwise ciphers in a string
            const RSNInformation::cyphers_type& pcsTypeList = rsn.pairwise_cyphers();
            for (const auto& pcsIt : pcsTypeList) {
                if (pcs.size() == 0)
                    pcs += type_to_string(pcsIt);
                else
                    pcs += ";" + type_to_string(pcsIt);
            }
        }
    }
}

unsigned Unit::getCount() {
    return count;
}

void Unit::incrementCount() {
    count += 1;
}

void Unit::print() {
    string ssid_to_print;
    if (ssid.length() == 0) {
        ssid_to_print = "<ZERO_LENGTH>";
    } else if (!isprint(ssid[0])) {
        ssid_to_print = to_string(static_cast<int>(ssid[0]));
    } else {
        ssid_to_print = ssid;
    }
    if (find(ssid_to_print.begin(), ssid_to_print.end(), ',') != ssid_to_print.end()) {
        ssid_to_print = "\"" + ssid_to_print + "\"";
    }
    cout <<  ssid_to_print << ","
         << bssid << ","
         << to_string(channel) << ","
         << to_string(count) << ","
         << gcs << ","
         << pcs << ","
         << akm << endl;
}

string Unit::type_to_string(const RSNInformation::CypherSuites& type) {
    switch (type) {
    case RSNInformation::CypherSuites::CCMP:
        return "CCMP";
        break;
    case RSNInformation::CypherSuites::TKIP:
        return "TKIP";
        break;
    case RSNInformation::CypherSuites::WEP_104:
        return "WEP_104";
        break;
    case RSNInformation::CypherSuites::WEP_40:
        return "WEP_40";
        break;
    }
}

string Unit::type_to_string(const RSNInformation::AKMSuites& type) {
    switch (type) {
    case RSNInformation::AKMSuites::PMKSA:
        return "PMKSA";
        break;
    case RSNInformation::AKMSuites::PSK:
        return "PSK";
        break;
    }
}

/*
 * Class that reads the pcap, keeps track of the units and writes out one
 * beacon frame in pcap format for each unique AP it finds. This file is called
 * "unique_beacons.pcap"
 */
class PCAPParser {
public:
    /*
     * Constructor. It takes the exact parameters that it will pas on to its
     * FileSniffer object (a FileSniffer is actually just a file reader).
     */
    PCAPParser(const string& pcapFilename, const string& filter);

    /*
     * Start reading the file.
     */
    bool run();

    /*
     * Print CSV header and ask all of our collected Unit objects to print themselves
     */
    void print();

private:
    FileSniffer sniffer;
    PacketWriter writer;
    map<string, Unit> apMap; // stands for Access Point Map

    bool handler(PDU&);
};

PCAPParser::PCAPParser(const string& pcapFilename, const string& filter) :
    sniffer {pcapFilename, filter},
    writer {"unique_beacons.pcap", PacketWriter::RADIOTAP}  {
    for (auto it = apMap.begin(); it != apMap.end(); it++) {
        it->second.print();
    }
}

bool PCAPParser::run() {
    sniffer.sniff_loop( [this] (PDU& pdu) { return (bool) this->handler (pdu); } );
    return true;
}

bool PCAPParser::handler(PDU& pdu) {
    Dot11Beacon& beacon = pdu.rfind_pdu<Dot11Beacon>();

    // An ESSID may span multiple BSSID's. Also, it's nice to keep track of what
    // channels an AP has been on. Therefore, the combination of SSID, BSSID and
    // channel is considered key.
    const string& ssid = beacon.ssid();
    const string& mac = beacon.addr3().to_string();
    const unsigned channel = unsigned(beacon.ds_parameter_set());
    const string key = ssid + mac + to_string(channel);
    if (apMap.find(key) == apMap.end()) { // we've got a new one
        Unit unit(beacon);
        apMap[key] = unit;
        writer.write(pdu);
    } else {
        apMap[key].incrementCount();
    }
    return true;
}

void PCAPParser::print() {
    // Print the headers for the CSV output
    cout << "SSID,BSSID,Current_channel,Count,Group_Cipher,Pairwise_Ciphers,Authentication_Suite" << endl;

    // Ask each of the units to print themselves for the CSV output
    for (auto it = apMap.begin(); it != apMap.end(); it++) {
        it->second.print();
    }
}

int main(int argc, char *argv[]) {
    if(argc != 2) {
        std::cout << "Usage: " << *argv << " <PCAP_FILE>\n";
        return 1;
    }

    PCAPParser pcapParser(argv[1], "wlan type mgt subtype beacon");
    pcapParser.run();
    pcapParser.print();
}

编译:

g++ pcapreader.cpp -o pcapreader -O3 -std=c++11 -lpthread -ltins

输出结果为:

$ ./pcapreader capture.pcap
SSID,BSSID,Current_channel,Count,Group_Cipher, Pairwise_Ciphers,Authentication_Suite
MyWiFi,XX:XX:XX:XX:XX:XX,13,2,TKIP,TKIP;CCMP,PSK
... 
...

最后注意事项:如果您打开unique_beacons.pcap,您可能会发现很多[Malformed Packet]。显然,如果错误地接收到某些标记参数,仍然可以成功解析帧。您可以尝试修改代码,以便它只将帧写入完全完整的pcap文件。