pyshark to capture and parse packets in remote server - python

Can we use pyshark module to capture/parse packets in remote server ?
Found it working in local interface :
>>> import pyshark
>>> capture = pyshark.LiveCapture(interface='eth2')
>>> capture.sniff(timeout=50)
>>> capture
<LiveCapture (4 packets)>
>>>
>>> capture[3]
<CDP Packet>
>>>
>>> print capture[3]
Packet (Length: 272)
Layer ETH:
Destination: CDP/VTP/DTP/PAgP/UDLD (01:00:0c:cc:cc:cc)
.... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
Length: 258
Address: Cisco_36:59:eb (6c:9c:ed:36:59:eb)
Same needs to be done for remote server (giving IP and few more filters)

You could do this by running the rpcapd service on the remote computer (included with WinPcap on Windows, note that you must use null authentication with the flag -n) and then running pyshark with the full URL of the remote service:
pyshark.LiveCapture(interface='rpcapd://[1.2.3.4]:2002/eth2')
Filters can always be supplied with pyshark.LiveCapture(bpf_filter='tcp')
EDIT: I added a pyshark.RemoteCapture class which is just a shortcut for the above. You can see it in the GitHub repo

Related

Decoding https traffic with scapy

I am trying to capture https traffic with scapy. So far I can see the TLS handshakes, but I am having trouble decoding the application data using a NSS keyfile. I'm using scapy 2.5.0rc2.dev39.
The structure of my script is: (1) set up the conf to point to the NSS file that will be created; (2) kick off a thread to get the sniff going; and then (3) do a https request on the main thread that generates the traffic that gets sniffed on the other thread.
I suspect my problem is a chicken-and-egg problem: I'm giving scapy the name of a file that doesn't exist yet and asking sniff to use it to decode traffic. But to generate the file, I need to generate traffic. But then it is too late to set up the sniff. And so on.
I'm basing the setup on the conf file on the code example in https://github.com/secdev/scapy/pull/3374. Is there a way to get the NSS file parsed and applied after the packets are sniffed? (Note: I have looked at https://github.com/secdev/scapy/blob/master/doc/notebooks/tls/notebook3_tls_compromised.ipynb, but that example applies the NSS file to a captured pcap file. I don't see how to apply that to my scenario. Unless I export the sniffed packets to a pcap file and then apply the now-existent NSS file to it?)
Here's my code:
from scapy.all import *
from time import sleep
from IPython import embed
myiface = 'lo'
mycount = 30
response_time_delta = 0.0
NSS_SECRETS_LOG = "secrets.log"
SERVER_HOST = "127.0.0.1"
SERVER_PORT = 8443
def analyze_https_sniffed_traffic():
# sniff traffic for mycount packets
myfilter = ""
myprn = lambda x:x.summary()
sniff_out = sniff(filter=myfilter,prn=myprn,count=mycount,iface=myiface)
# iterate through the sniffed packets to report on contents
for idx,s in enumerate(sniff_out):
print("===\npacket %d\n%s" % (idx,s.summary()))
# if we can convert to a TLS packet, print out TLS summary
if s.haslayer('IP') and hasattr(s,'load'):
tls_r = TLS(s.load)
print(tls_r.summary())
# if this is TLS application data, do a complete show
if tls_r.type == 23:
print(tls_r.show())
#embed()
return
def send_https_request_and_analyze():
import http.client, ssl
# start another thread that sniffs traffic and analyzes their contents
t = threading.Thread(target=analyze_https_sniffed_traffic)
t.start()
# use python requests to make a HTTPS query to a local server
# put SSLKEYLOGFILE into the environment so I can decode captured TLS traffic
import os; os.environ["SSLKEYLOGFILE"] = NSS_SECRETS_LOG
time.sleep(3)
# unverified context: using self signed cert, make requests happy
conn = http.client.HTTPSConnection(SERVER_HOST, SERVER_PORT, context=ssl._create_unverified_context())
conn.request('GET', '/')
r = conn.getresponse()
print("response: %s" % r.read())
# wait for the sniff thread to finish up
t.join()
load_layer("tls")
# conf commands from https://github.com/secdev/scapy/pull/3374
conf.tls_session_enable = True
conf.tls_nss_filename = NSS_SECRETS_LOG
print("scapy version: %s" % scapy.__version__)
print("conf contents:\n%s" % conf)
send_https_request_and_analyze()
Here's what I get back for the first application data packet:
===
packet 22
Ether / IP / TCP 127.0.0.1:46066 > 127.0.0.1:8443 PA / Raw
TLS None:None > None:None / TLS / TLS Application Data
###[ TLS ]###
type = application_data
version = TLS 1.2
len = 91 [deciphered_len= 91]
iv = b''
\msg \
|###[ TLS Application Data ]###
| data = '\\xce\\xd2:\\x87\\xd0\\ h\x7f\\x81C\\xbd\x1af\\xd6y\\x91\x07wnn\\xca!ji3\\xb2\\xbbT\t\\xfc\\x80F#\\x88\x13<\\x83\\xa4\x08p\\x96\\xfb\\xf7\\x875u\\xfa\\xb9\x11\\x97M\\xf9\\xf5\\xb0\\x8fR\\x8c\ue650sI/ɇop\x1d\\xe2\n\\x91"\\x80\\x91la"d\\xe5\\xa0yk\\xc2\\xfa\\xe2A\\x8d\\x8dKB'
mac = b''
pad = b''
padlen = None
None
Any ideas on how I can make this work?
PS: Shout out to the devs. Scapy is amazing.
EDIT: I tried to get a write to pcap, set the NSS file in the conf, read the pcap approach, but ran into the same problem. I think I'm running into https://github.com/secdev/scapy/issues/3722.
EDIT #2: I went through the same steps decoding the raw data in https://github.com/secdev/scapy/blob/master/doc/notebooks/tls/notebook3_tls_compromised.ipynb in the section "Decrypt a PCAP file" and it worked fine. When I compared the wireshark output for the notebook's pcap file and the one I wrote with wrpcap, I see duplicate packets. It's my PCAP file that is breaking the decrypt, I think. I'm out of time today, but I will try something along the lines of Scapy: Processing partial TLS segments and report back.
I see I didn't update this with my eventual solution. In one thread I kicked off the HTTPS request and generated the NSS key files; in another thread I sniffed the traffic, then afterwards I iterated through the packetlist, updating the session with the NSS keys and mirroring the session as needed, as described in the "Decrypting Manually" section of the Scapy TLS documentation here: https://github.com/secdev/scapy/blob/master/doc/notebooks/tls/notebook3_tls_compromised.ipynb.
Example code here: https://github.com/PollyP/scapy_tls_example

Use Python scapy to send TCP RST to prevent client access problems

I used SCAPY to write a program deployed in the WEB server and would like to send TCP RST using SCAPY to block some specific HTTP client access.
After running the program, the client uses Telnet to connect to the server WEB listening port can be SCAPY program interrupt, but the use of browser access can not interrupt. Why is it so?
The code is as follows:
# coding: utf-8
# web server : 10.28.16.20 ;
# http client : 10.28.1.70;
from scapy.all import *
def pkgs(pkg):
if pkg.getlayer(TCP) and pkg[IP].dst=="10.28.16.20" and "10.28.1.70" in pkg[IP].src:
resp=IP(dst=pkg[IP].src,src=pkg[IP].dst)/TCP(dport=pkg[TCP].sport,sport=pkg[TCP].dport,flags="RA",seq=pkg[TCP].ack,ack=pkg[TCP].seq+(len(pkg[TCP].payload) if pkg.getlayer(Raw) else 1))
send(resp,count=2,verbose=0)
if __name__=="__main__":
conf.L3socket=L3RawSocket
sniff(filter="tcp",prn=pkgs,store=0)
Program code screenshot
I think the best way is to get into "Scapy"
then paste that code and enter:
#!/usr/bin/python
from scapy.all import *
ip = IP(src="10.28.16.20", dst="10.28.1.70")
tcp = TCP(sport=80, dport=####, flags=####, seq=####, ack=####)
pkt = ip/tcp
ls(pkt)
send(pkt,verbose=0)
You need to change dport to the source port from the PC, flags to the action you want to do, seq&ack follow the packets you started from.
I have solved it.import threading.

How to query gateway for DNS adress by Python or Perl

The Linux/Windows can get DNS address from the router
I need to write a local dns proxy and how can I get the DNS server addresses like the OS does, are there any Perl or Python modules can do this?
Update
The question should be clear, I need some thing to simulate the interface start and the protocol talking with local router, I can not take a tcpdump before a interface starts. Not sure if there is an sample trace file on internet. Possiblely it's not IP protocol which I am not familiar with.
Update2
As I use local DNS proxy server, the TCP configuration is like showing in picture
If I query Net::DNS::Resolver, I get result: 127.0.0.1 which is not what I needed
Really long, formatted comment supporting Steffen's answer.
TLDR: Steffen is correct (+1 BTW). Net::DNS::Resolver should get you the information you need.
Example:
#!perl
use strict;
use warnings;
use Net::DNS::Resolver;
#configure a resolver object using your OS's current config.
my $resolver = Net::DNS::Resolver->new;
print join "\n", $resolver->nameservers;
Tested on Windows & OS X.
If you are serous in your quest for the rope to hang yourself, the protocol you're asking about is DHCP (Dynamic Host Configuration Protocol).
Using DHCP like your OS does, is not a mere "Query" for DNS servers, but a request for a (new/renewed) lease of an IP Address. The fact that things like Gateway, Time Servers & DNS Servers are included are also important, but secondary. If done incorrectly, you may either screw up the relationship between your OS and the DHCP server or convince your DHCP server that your program is another (false) machine on the network for which it should maintain lease information.
gethostbyname uses the resolver function of the underlying OS library. If you want to have more direct access to the DNS packets use Net::DNS::Resolver.
inspired by Steffen Ullrich
I got the issue resolved, by managed taking a DHCP trace and simulated by Net::DHCP::Packet, fortunately it's simple UDP protocol
You need to findout IP/Mac/GW address before using the script
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use Net::DHCP::Packet;
use Net::DHCP::Constants;
srand();
# creat DHCP Packet
my $discover = Net::DHCP::Packet->new(
Xid => int(rand(0xFFFFFFFF)), # random xid
Flags => 0x0000,
DHO_DHCP_MESSAGE_TYPE() => DHCPREQUEST(),
);
$discover->ciaddr('192.168.1.5');
$discover->chaddr('5cc5d43ca078');
my $handle = IO::Socket::INET->new(
Proto => 'udp',
ReuseAddr => 1,
PeerPort => '67',
LocalPort => '68',
PeerAddr => '192.168.1.1'
) or die "socket: $#";
$handle->send($discover->serialize());
my $newmsg;
if ($handle->recv($newmsg, 1024)) {
my $packet = Net::DHCP::Packet->new($newmsg);
print STDERR $packet->toString();
}
Execution result:
op = BOOTREPLY
htype = HTYPE_ETHER
hlen = 6
hops = 0
xid = eaba416c
secs = 0
flags = 0
ciaddr = 192.168.1.5
yiaddr = 192.168.1.5
siaddr = 0.0.0.0
giaddr = 0.0.0.0
chaddr = 5cc5d43ca078
sname =
file =
Options :
DHO_DHCP_MESSAGE_TYPE(53) = DHCPACK
DHO_SUBNET_MASK(1) = 255.255.255.0
DHO_ROUTERS(3) = 192.168.1.1
DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
DHO_DHCP_SERVER_IDENTIFIER(54) = 192.168.1.1
DHO_DHCP_LEASE_TIME(51) = 86400
DHO_VI_VENDOR_SPECIFIC_INFOMATION(125) = \x00\x00\x00\x00\x14\x02\x06HGW-CT\x0A\x02\x00\x00\x0B\x02\x00U\x0D\x02\x00.
padding [247] = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
We can see
DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
Is the DNS server address

TCP port scanner written in Python using Scapy yields no response

I’m trying to make a TCP port scanner, but I’m sticking to a very simple example that I lined together from a more advanced example I found online.
I don’t get any errors.
I’m expecting the code to show me that port 80 is open since I started my Apache server on my Linux box.
Here is the code:
#!/usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
ip = "127.0.0.1"
port = 80
response = sr1(IP(dst=ip)/TCP(dport=port, flags="S"),verbose=False, timeout=0.2)
if response :
if response[TCP].flags == 18 :
print "Port open"
Warning I had (but that does not show up any more):
WARNING: No route found for IPv6 destination :: (no default route?)
I read that including these two lines below would help on the error:
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
Nmap scan:
STATE SERVICE
80/tcp open http
The output is… Nothing at all.
I tried several things like changing the port to different other ports, some which I had open and some which I did not.
Any ideas as to what I did wrong?
The scapy docs mention that the loopback address is a special case
The loopback interface is a very special interface. Packets going
through it are not really assembled and dissassembled. The kernel
routes the packet to its destination while it is still stored an
internal structure. What you see with tcpdump -i lo is only a fake to
make you think everything is normal. The kernel is not aware of what
Scapy is doing behind his back, so what you see on the loopback
interface is also a fake. Except this one did not come from a local
structure. Thus the kernel will never receive it.
In order to speak to local applications, you need to build your
packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a
PF_PACKET/SOCK_RAW (or its equivalent on other systems that Linux):
>>> conf.L3socket
<class __main__.L3PacketSocket at 0xb7bdf5fc>
>>> conf.L3socket=L3RawSocket
>>> sr1(IP(dst="127.0.0.1")/ICMP())
<IP version=4L ihl=5L tos=0x0 len=28 id=40953 flags= frag=0L ttl=64 proto=ICMP chksum=0xdce5 src=127.0.0.1 dst=127.0.0.1 options=''
|\>
However testing this on my OS-X machine results in the following error:
>>> conf.L3socket=L3RawSocket
>>> sr1(IP(dst="127.0.0.1")/ICMP())
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/sendrecv.py", line 334, in sr1
s=conf.L3socket(filter=filter, nofilter=nofilter, iface=iface)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/supersocket.py", line 64, in __init__
self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
AttributeError: 'module' object has no attribute 'AF_PACKET'
So your mileage may vary
EDIT
Apparently this is a known bug in scapy on BSD like systems (including OS-X): http://bb.secdev.org/scapy/issue/174/sniffing-loopback-in-mac-os-x-darwin

Gmail mail server

I used use Google’s slick interface to get my mail and It’s always going to be here:
https://mail.google.com/a/yourdomainhere.com
I want to write python script that send mail so i failed to configure server settings
smtp = smtplib.SMTP('mail server should be what?', what is the port)
smtp.login('username#yourdomainhere.com', 'pass')
Please could any one help me ??
Thanks
All on gmail's support site, see http://mail.google.com/support/bin/answer.py?hl=en&answer=13287
Look at the help:
http://mail.google.com/support/bin/answer.py?hl=en&answer=13287
Its smtp.gmail.com
The preferred method for SMTP message forwarding is using your ISP's SMTP server. The job of locating Google's Message transfer agent is handled by such servers.
To use Google's servers directly, you need to look up the MX records provided by google via DNS. From a Python program, a DNS library is needed. Here is an example, using dnspython, a A DNS toolkit for Python.
>>> from dns import resolver
>>> mxrecs = resolver.query('gmail.com', 'MX')
>>> [mx for mx in mxrecs]
[<DNS IN MX rdata: 20 alt2.gmail-smtp-in.l.google.com.>,
<DNS IN MX rdata: 40 alt4.gmail-smtp-in.l.google.com.>,
<DNS IN MX rdata: 30 alt3.gmail-smtp-in.l.google.com.>,
<DNS IN MX rdata: 10 alt1.gmail-smtp-in.l.google.com.>,
<DNS IN MX rdata: 5 gmail-smtp-in.l.google.com.>]
>>> mx.exchange.to_text()
'gmail-smtp-in.l.google.com.'
>>> mx.preference
5
>>>
The preferred mail-exchange server here is gmail-smtp-in.l.google.com, which can be used with smtplib to forward messages.

Categories