mfontanini / libtins

High-level, multiplatform C++ network packet sniffing and crafting library.
http://libtins.github.io/
BSD 2-Clause "Simplified" License
1.9k stars 375 forks source link

Segmentation fault when getting payload_size of a RawPDU with length of 0 #429

Closed kevsjh closed 3 years ago

kevsjh commented 3 years ago

Hi there,

I am trying to parse TCP DNS packet with libtins. From initial testing, it doesn't seemed to be supported. I have came up with the following to parse TCP DNS and was able to do so successfully.


TCP *tcp = pkt.find_pdu<TCP>();

    if (tcp)
    {
        //check if its dns ports
        if (tcp->sport() == 53 || tcp->dport() == 53)
        {
            // retrieve TCP layer PDU

            //retrieve TCP layer PDU payload
            RawPDU &raw = *tcp->find_pdu<RawPDU>();

            // check if payload size is 0, parse TCP dns if payload size is not 0
            if (raw.payload_size() == 0)
            {
                std::cout << "no dns field" << std::endl;
            }
            else
            {
                std::cout << raw.payload_size() << std::endl;
                RawPDU::payload_type &payload = raw.payload();
                // Omit the first 2 byte of DNS length field, only included
                // in TCP based on RFC7766, in order to reuse the DNS UDP parser
                payload.erase(payload.begin(), payload.begin() + 2);
                //parse the modified payload to DNS parser
                DNS dns = raw.rfind_pdu<RawPDU>().to<DNS>();
                std::cout << dns.id() << std::endl;

                for (const auto &query : dns.queries())
                {
                    std::cout << query.dname() << std::endl;
                }
            }
        }

However, one of my check before parsing TCP DNS was to check if the TCP length !=0 as that would represent the presence of DNS layer. When calling for _raw.payloadsize() for PDU with length 0, I'm getting Segmentation fault error. I tried to modified rawpdu.h so that the RawPDU object instantiated with 0 but doesn't work too

RawPDU(const uint8_t* pload, uint32_t size=0);

Any idea on this? Otherwise it works great.

image of the said tcp packet without dns field, len=0 image

mfontanini commented 3 years ago

Hello! The problem in your code is that you're getting a pointer to the RawPDU in that packet, dereferencing it and using it, even though there may not be such a layer in the packet at all. If the TCP packet contains no payload, there simply won't be a RawPDU layer in it at all.

To make your code work, you'd need to fetch a pointer to the RawPDU layer, make sure it's there, and then use it. e.g.:

// Fetch a *pointer* to it
const RawPDU* raw = tcp->find_pdu<RawPDU>();

if (raw == nullptr) {
    std::cout << "No payload in this packet!\n";
}
else {
    // It is safe to use `raw` here
}
kevsjh commented 3 years ago

Tried and tested and its working. Thank you so much for your help! I shall close this