Wireshark dissector that works with tls/ssl - ssl

I have a protocol that uses SSL/TLS over a non-standard port and transmits non-standard data (not http) through it. I'm trying to make a wireshark dissector (in lua) to dissect this protocol.
How do I do this? I can register a dissector that gets called for tcp fragments on that port
local dissector_table_tcp = DissectorTable.get("tcp.port")
dissector_table_tcp:add(1234, myprotocol)
I can get the SSL dissector to then decode all the fragments as SSL
function myprotocol.dissector(tvb, pinfo, root)
local ssl_dissector = Dissector.get("ssl")
local ssl_dissected_len = ssl_dissector:call(tvb, pinfo, root)
pinfo.cols.protocol:set("My Protocol")
At this point, if I have a premaster key file set in Wireshark (Preferences->Protocols->SSL->Master key file), I can see the decrypted contents of the packets and all is good. Sort of.
But I want to create fields for my protocol and put them in the protocol tree. How do I get at the decrypted data that the ssl dissector produced?
Update:
I'm trying to muddle through this as best as I can; there's no tutorial on how exactly you're supposed to do this. It sort of looks like Wireshark has a programming model based on fields/variables that are populated by dissectors, and that in theory it should be possible to interrogate those variables to find the output of a dissector.
To that end, I've been running the SSL dissector and then looking at fields that it declares, but it doesn't actually seem to populate them. When I run a post-dissector after the SSL dissector, none of the seemingly-useful fields, like ssl.segments or ssl.segment.data, are set:
protocol_foo = Proto("foo", "Foo protocol")
port = 4172
g_field_segment = Field.new("ssl.segment")
g_field_segment_data = Field.new("ssl.segment.data")
g_field_segments = Field.new("ssl.segments")
g_field_reassembled_data = Field.new("ssl.reassembled.data")
function protocol_foo.dissector(tvb, pinfo, root)
print("====== protocol_foo")
for k,v in pairs({ g_field_segment, g_field_segment_data, g_field_segments, g_field_reassembled_data }) do
if v() ~= nil then
print("Field " .. v.name .. " is NOT nil")
else
print("Field " .. v.name .. " is nil")
end
end
end
-- post-dissector registration
local ssl_dissector = Dissector.get("ssl")
local dissector_table_tcp = DissectorTable.get("tcp.port")
dissector_table_tcp:add(port, ssl_dissector)
register_postdissector(protocol_foo)
When I run this code on my protocol, none of those ssl.segment* variables test positive; lots of variables (like the ssl.handshake.*) variables do test positive (at least with handshake pdus), but not the ones with the decrypted contents.
Does anyone have any ideas?

Related

Bro Script: Hardcoded IP addresses

Ich have one assignment and I need a little help. I have infected.pcap and the following task:
Hardcoded IP addresses Sometimes, malware contains hardcoded IP addresses to download their payload or to communicate with their command and control (C&C) server. Find all such communication. Hint: Such IPs have no preceding DNS request.
I need to solve it with Bro script. This was my idea, but unfortunatelly all my connections have no DNS request:
#load base/protocols/dns/main.bro
event file_timeout(f: fa_file)
{
for ( cid in f$conns )
{
if(f$conns[cid]?$dns){
print f$conns[cid]$dns;
print "DNS";
}else {
print "No DNS";
}
}
}
Do you know maybe what is wrong with my code?
I would suggest that you're using the wrong event for this. The file_timeout only occurs if a file transfer was occurring and then stopped without completing. A much more interesting event correlation would be:
Track DNS address lookup responses (I would likely use event
dns_A_reply(c: connection, msg: dns_msg, ans: dns_answer, a:
addr)).
Record the addresses returned in a set; this will provide
you a set of all addresses that were discovered through a DNS query.
Examine outbound requests (where orig_h on the SYN is an internal
address)
Check to see if the address in id$resp_h is in the set of
addresses step 2. If it is, return, if it isn't,
generate a notice since you have an outbound connection attempt with
no corresponding DNS lookup.

How to get peer certificate in cowboy_http_handler

My question for today: is there an official way to obtain peer ssl socket information (peer certificate to be exact) in cowboy_http_handler's Handler:handle(Req, State)?
Of course, I can scrape Req tuple (peer socket is the second field as of today) with erlang:element/2, but this is not future-proof and just doesn't look right.
Thanks in advance!
There is an exported call:
cowboy_req:get(socket, Req)
It returns the socket, or just about everything else there is in the Req object, currently:
bindings
body_state
buffer
connection
headers
host
host_info
meta
method
multipart
onresponse
path
path_info
peer
pid
port
qs
resp_body
resp_compress
resp_headers
resp_state
socket
transport
version
I'm not sure if it is in the documentation, I can't see it, but it's a lot better and less likely to fail than just getting a numbered element value out, and you can always add a unit test that checks that it works, so if it does get stamped/broken at some point you get a heads up. I don't expect it'll go anywhere though.

OpenSSL: Specify packet size of application data

When I do something like this, apps/openssl s_client -connect 10.102.113.3:443 -ssl3, client-server communication is created using openSSL.
Now, I want to send application data from the client to the server. For example, after doing apps/openssl s_client -connect 10.30.24.45:443 -ssl3, I get something like this:
...certificate and session details...
---
GET /path/to/file
The GET /path/to/file all goes in one SSL record. I want to send it in multiple records.
I assume I have to edit apps/s_client.c, and find the place where the SSL_write or similar happens.
How do I go about something like that?
For a properly designed application the TCP packet sizes and SSL frame sizes should not matter. But there are badly designed applications out there which expect to get like the HTTP request inside a single read, which often means that it must be inside the same SSL frame. If you want to run tests against applications to check for this kind of behavior you either have to patch your s_client application or you might use something else, like
#!/usr/bin/perl
use strict;
use IO::Socket::SSL;
my $sock = IO::Socket::SSL->new('www.example.com:443') or die "$!,$SSL_ERROR";
print $sock "GE";
print $sock "T / HT";
print $sock "TP/1.0\r\n\r\n";
This will send the HTTP request header within 3 SSL frames (which might still get put together into the same TCP packet). Since on lots of SSL stacks (like OpenSSL) one SSL_read reads only a single SSL frame this will result in 3 reads necessary to read the full HTTP request.
Okay, I figured out that I needed to change the number of bytes I'm writing using the SSL_write.
This is a code snippet, starting at line 1662 of s_client.c:
if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
{
k=SSL_write(con,&(cbuf[cbuf_off]), (unsigned int)cbuf_len);
.......
}
To make the application data be sent in multiple records instead of just the one, change the last parameter in the SSL_write.
For example, do this:
if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
{
k=SSL_write(con,&(cbuf[cbuf_off]), 1);
.......
}
This will result in something like this:
Notice the multiple records for Application Data instead of just the one.

Get IP addresses from PCAP file in scapy

Is there a smart and fast way to get all IP addresses from a PCAP file?
I need only (destination address, source address) tuples.
Currently I'm using Scapy's rdpcap function like this:
from scapy.all import *
pcap = rdpcap('file.pcap')
ips = set([(p[IP].fields['src'], p[IP].fields['dst']) for p in pcap if p.haslayer(IP) == 1])
But it takes about two minutes on my machine to parse a 70MB PCAP file with 370 unique extracted entries...
The "best" way to do what I think (based on the code you provided, I suppose you want the couples (IP source address, IP destination address) rather than IP packets) you want is :
>>> set((p[IP].src, p[IP].dst) for p in PcapReader('file.pcap') if IP in p)
You don't waste memory with the whole PCAP file, the set object is built packet by packet.
If it's not fast enough, you can instruct Scapy not to dissect packets after the IP layer since you don't use the IP payload:
>>> IP.payload_guess = []
And then run the previous command.

How to display the ip address and port number in an text box that should be generated dynamically

Is there a way to display the system ip address and port number in a text box that is generated dynamically???
I want the system to put the ip address into a text box according to the machine.
Siddharth
Since you mentioned a text box, I can only postulate that you are talking about a web browser, and in that case 99.9% of the time you are talking about http and then 99.999% of the time a TCP connection. This means that your connection will have a 4-Tuple consisting of the source ip:port and the destination ip:port. In most cases the port numbers are fairly standard (80) for the destination (client).
Then you get into the very common issues of NAT and the like, so again I think you need to clarify what type of ip address you want. The publicly routable ip address is obtained server side and the LAN address will be obtained from the localhost.
For the more interesting case (publicly routable ip) I would just use a server side script (python, PHP, C, etc...) to read the incoming ip address and then use a little ajax to set the value of the text box. I did something similar for a project and it worked really well. Our client program was written in Python and C but this will give you an idea...
# Returns the client's public IP address (past any NATs)
def get_public_ip():
return urllib.urlopen('http://ddih.org/ip.php').read().strip()
I think something like set the inner html... from that webpage...
Hope this helps.
Your system does not have a port number. Port numbers are a software concept to differentiate different IP or UDP applications that might want to listen for connections on your IP address.
Also, it is quite possible to have more than one IP address. In fact, your system almost always has two if you count the loopback address (127.0.0.1). Even if you don't these days even many consumer PC's have multiple ethernet jacks.
You didn't say you were using Win32 so I don't know that it will be useful to you, but here's some code I wrote once that puts all local IP addresses (loopback excepted) into a an MFC CComboBox. It's a bit more C-ish than I'd like to see these days, but here it is.
size_t const Max_Expected_Addresses = 20; // Something rediculous
unsigned long IPADDRTBL_Size = sizeof(DWORD) + sizeof(MIB_IPADDRROW) * Max_Expected_Addresses;
PMIB_IPADDRTABLE IP_Address_Table = (PMIB_IPADDRTABLE) malloc (IPADDRTBL_Size);
if (GetIpAddrTable (IP_Address_Table, &IPADDRTBL_Size, TRUE) == NO_ERROR) {
for (DWORD i = 0; i < IP_Address_Table->dwNumEntries; i++) {
// Skip the loopback.
if (IP_Address_Table->table[i].dwAddr == 0x0100007f) continue;
if (m_IP_Address == "") m_IP_Address = String_Address(IP_Address_Table->table[i].dwAddr);
m_IP_Address_List.AddString (String_Address(IP_Address_Table->table[i].dwAddr));
};
}
m_IP_Address_List is an MFC control defined as a CComboBox which gets filled in by this snippet.
m_IP_Address is a CString tied to an MFC textbox control (IIRC) which I use to store the currently selected (or first found on startup) IP address.