I wrote a python script using scapy to sniff TCP packets in my WIFI network and see if there was a connection between two destinations.
It works if i sniff the packets when i not in monitor mode, but when i sniff on monitor mode interface it's not working.
Any ideas how can make it work?
Snippet:
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
import time
class deferring_delete(object):
def __init__(self, d):
self._dict = d
def __enter__(self):
self._deletes = set()
return self
def __exit__(self, type, value, tb):
for key in self._deletes:
try:
del self._dict[key]
except KeyError:
pass
del self._deletes
def __delitem__(self, key):
if key not in self._dict:
raise KeyError(str(key))
self._deletes.add(key)
packet_count = 0
packets = {}
accepted = {}
YOUR_IP = '10.0.0.1'
FILTER = "tcp and host not {0}".format(YOUR_IP)
def handshake_status(packet):
global packets,accepted,packet_count
flag = packet[0][1].sprintf('%TCP.flags%')
src_ip = packet[0][1].src
dst_ip = packet[0][1].dst
if flag == 'S':
packets[packet_count] = {'src_ip': src_ip, 'dst_ip': dst_ip, 'time': time.ctime() , 'flag': flag}
print "%s ==> %s SYN_SENT" % (src_ip, dst_ip)
packet_count += 1
if flag == 'SA':
for key , packet in packets.iteritems():
if packet['src_ip'] == dst_ip:
accepted[key] = packet
if len(accepted) > 0:
with deferring_delete(packets) as p:
for key in accepted.keys():
print "%s ==> %s ESTABLISHED" % (packets[key]['src_ip'], packets[key]['dst_ip'])
del p[key]
with deferring_delete(accepted) as a:
for key in accepted.keys():
del a[key]
if __name__ == '__main__':
sniff(iface="mon0", filter=FILTER ,prn=handshake_status)
The problem lies with the following lines:
flag = packet[0][1].sprintf('%TCP.flags%')
src_ip = packet[0][1].src
dst_ip = packet[0][1].dst
Try rewriting them as follows:
flag = packet.getlayer(TCP).sprintf('%TCP.flags%')
src_ip = packet.getlayer(IP).src
dst_ip = packet.getlayer(IP).dst
Related
I'd like to continue my last related thread in my attempt to understand and build a BitTorrent search engine. While listening the network for "get_peers" messages, I manage to grab infohashes. I proceed to ask the corresponding DHT node for it's peers. In my understanding in order to find out if the infohash is valid, (for starters) I have to send a BitTorrent handshake to the peers and compare the responses. However, besides the connection refused errors which I ignore for now, most peers reply with empty responses. Am I doing something wrong here? Note that the following code samples are not a great implementation, I just want to understand the flow.
Handshake function:
import socket
def handshake(infohash, peer):
peer_id = b"-TR2940-k8hj0wgej6ch"
handshake = b'\x13'
handshake += b'BitTorrent protocol'
handshake += b'\x00\x00\x00\x00\x00\x10\x00\x00'
handshake += infohash
handshake += peer_id
try:
ClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ClientSocket.settimeout(3)
ClientSocket.connect(peer)
print("Connected to peer.")
ClientSocket.sendall(handshake)
response = ClientSocket.recv(68)
if not response:
print("Empty response.")
return
print(f"Handshake completed, resp: {response}")
ClientSocket.close()
except Exception as e:
print(e)
Utilities to get peers from given infohash and DHT node:
import random
import uuid
import bencode
import socket
from struct import unpack
import handshake
def newTID(tidlen):
tid = ""
for i in range(0, tidlen):
tid += chr(random.randint(97, 122))
return tid
def newID():
return uuid.uuid4().hex[0:20]
def split_nodes(nodes):
length = len(nodes)
if (length % 26) != 0:
return
for i in range(0, length, 26):
nid = nodes[i:i+20]
ip = socket.inet_ntoa(nodes[i+20:i+24])
port = unpack("!H", nodes[i+24:i+26])[0]
yield nid, ip, port
UDPClientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
UDPClientSocket.settimeout(4)
def get_peers_from_infohash(infohash, node):
get_peers_query = {"t":"aa", "y":"q", "q":"get_peers", "a": {"id":newID(), "info_hash":infohash}}
get_peers_query = bencode.encode(get_peers_query)
UDPClientSocket.sendto(get_peers_query, node)
received = UDPClientSocket.recvfrom(65536)
msg = received[0]
decoded = bencode.decode(msg)
peers = split_nodes(decoded["r"]["nodes"])
for nid, ip, port in peers:
print(infohash, infohash.hex(), ip, port)
handshake.handshake(infohash, (ip, port))
My DHT crawler:
import bencode
import socket
import uuid
from struct import unpack
import threading
import random
import dhtutils
def newTID(tidlen):
tid = ""
for i in range(0, tidlen):
tid += chr(random.randint(97, 122))
return tid
def newID():
return uuid.uuid4().hex[0:20]
def handle_message(msg, node):
if msg.get("e"):
# print(msg.get("e"))
pass
elif msg.get("y") == "r":
handle_response(msg, node)
elif msg.get("y") == "q":
handle_query(msg, node)
def handle_query(msg, node):
try:
if msg["q"] == "get_peers":
infohash = msg["a"]["info_hash"]
# print(infohash.hex(), msg, node)
print(infohash.hex())
dhtutils.get_peers_from_infohash(infohash, node)
except:
pass
def handle_response(msg, node):
global all_nodes
if msg.get("r").get("nodes"):
# response from find_nodes
nodes = msg.get("r").get("nodes")
if nodes:
nodes = split_nodes(nodes)
for id, ip, port in nodes:
find_nodes(id, (ip, port))
all_nodes.append((id, (ip, port)))
elif msg.get("t") == "pg":
# response from ping
id = msg["r"]["id"]
all_nodes.append((id, node))
def split_nodes(nodes):
length = len(nodes)
if (length % 26) != 0:
return
for i in range(0, length, 26):
nid = nodes[i:i+20]
ip = socket.inet_ntoa(nodes[i+20:i+24])
port = unpack("!H", nodes[i+24:i+26])[0]
yield nid, ip, port
def find_nodes(id, node):
global UDPClientSocket
find_node_query = {"t":newTID(2), "y":"q", "q":"find_node", "a": {"id":newID(), "target":id}}
find_node_query = bencode.encode(find_node_query)
UDPClientSocket.sendto(find_node_query, node)
def ping(node):
global UDPClientSocket
ping_query = {"t":"pg", "y":"q", "q":"ping", "a":{"id":newID()}}
ping_query = bencode.encode(ping_query)
UDPClientSocket.sendto(ping_query, node)
def listen():
while True:
try:
received = UDPClientSocket.recvfrom(65536)
msg = received[0]
src = received[1]
decoded = bencode.decode(msg)
handle_message(decoded, src)
except Exception as e:
pass
UDPClientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
T = threading.Thread(target=listen)
T.start()
nodes = [
("router.bittorrent.com", 6881),
("dht.transmissionbt.com", 6881),
("router.utorrent.com", 6881)
]
for node in nodes:
ping(node)
all_nodes = []
while True:
if len(all_nodes) > 0:
for node in all_nodes:
find_nodes(node[0], node[1])
Your DHT lookup is incorrect since you're looking at the nodes response field which contains DHT nodes used for finding other DHT nodes when performing an iterative lookup in the DHT.
It is not the values field that contains bittorrent contacts.
You're only going to get the latter when you have properly routed to the target region that covers an infohash in the DHT keyspace.
I am working with the bitalino board and I wanted to print the data with python but when I run the proper code, it shows me the message
Global name 'bluetooth' is not defined
According to my pc the board is connected via bluetooth. I don't know what the problem is, could you help me?
Pd: I am using Mac OS X.
This is part of the code where the problem may be:
try:
import bluetooth
from bluetooth import discover_devices
except ImportError:
pass
import serial
from serial.tools import list_ports
import time
import math
import numpy
class BITalino(object):
def __init__(self):
"""
BITalino class: interface to the BITalino hardware.
"""
self.socket = None
self.analogChannels = []
self.number_bytes = None
self.macAddress = None
self.serial = False
def find(self, serial=False):
"""
Search for bluetooth devices nearby
Output: tuple with name and mac address of each device found
"""
try:
if serial:
nearby_devices = list(port[0] for port in list_ports.comports() if 'bitalino' or 'COM' in port[0])
else:
nearby_devices = discover_devices(lookup_names=True)
return nearby_devices
except:
return -1
def open(self, macAddress=None, SamplingRate=1000):
"""
Connect to bluetooth device with the mac address provided.
Configure the sampling Rate.
Kwargs:
macAddress (string): MAC address of the bluetooth device
SamplingRate(int): Sampling frequency (Hz); values available: 1000, 100, 10 and 1
Output: True or -1 (error)
"""
Setup = True
while Setup:
if macAddress != None:
try:
if ":" in macAddress and len(macAddress) == 17:
self.socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
self.socket.connect((macAddress, 1))
else:
self.socket = serial.Serial(macAddress, 115200)
self.serial = True
time.sleep(2)
# Configure sampling rate
if SamplingRate == 1000:
variableToSend = 0x03
elif SamplingRate == 100:
variableToSend = 0x02
elif SamplingRate == 10:
variableToSend = 0x01
elif SamplingRate == 1:
variableToSend = 0x00
else:
self.socket.close()
raise TypeError, "The Sampling Rate %s cannot be set in BITalino. Choose 1000, 100, 10 or 1." % SamplingRate
return -1
variableToSend = int((variableToSend<<6)|0x03)
self.write(variableToSend)
Setup = False
except Exception, e:
print e
return -1
else:
raise TypeError, "A MAC address or serial port is needed to connect"
return -1
else:
self.macAddress = macAddress
return True
Hopefully this will help:
http://lightblue.sourceforge.net/
This is an API for python's bluetooth feature
It's generally better to let the import fail if something is wrong so I would remove the try..except and just do a normal import.
The only reason to use it in an import if you are indifferent about what library you want to use:
try:
import json
except ImportError:
import simplejson as json
I have a problem with my script. For a test i want to print an src and dst ip address but the characters displayed are special and after many researches i still don't understand why ...
I'm sure this is a simply problem but i didnt get it ...
This is the output:
And this is my script:
import pcapy
import dpkt
from threading import Thread
import re
import binascii
liste=[]
listip=[]
piece_request_handshake = re.compile('13426974546f7272656e742070726f746f636f6c(?P<reserved>\w{8})(?P<info_hash>\w{20})(?P<peer_id>\w{20})')
piece_request_tcpclose = re.compile('(?P<start>\w{12})5011')
class PieceRequestSniffer(Thread):
def __init__(self, dev='eth0'):
Thread.__init__(self)
self.expr = 'udp or tcp'
self.maxlen = 65535 # max size of packet to capture
self.promiscuous = 1 # promiscuous mode?
self.read_timeout = 100 # in milliseconds
self.max_pkts = -1 # number of packets to capture; -1 => no limit
self.active = True
self.p = pcapy.open_live(dev, self.maxlen, self.promiscuous, self.read_timeout)
self.p.setfilter(self.expr)
#staticmethod
def cb(hdr, data):
eth = dpkt.ethernet.Ethernet(str(data))
ip = eth.data
#Select Ipv4 packets because of problem with the .p in Ipv6
if eth.type == dpkt.ethernet.ETH_TYPE_IP6:
return
else:
#Select only TCP protocols
if ip.p == dpkt.ip.IP_PROTO_TCP:
tcp = ip.data
try:
#Return hexadecimal representation
hex_data = binascii.hexlify(tcp.data)
except:
return
fin_flag = ( tcp.flags & dpkt.tcp.TH_FIN ) != 0
if fin_flag:
print " -------------------FIN filtered-------------------"
src_ip = ip.src
dst_ip = ip.dst
#listip.append(theip)
print "\n"
print "src_ip %s %s dst_ip %s" % (src_ip,"\n", dst_ip)
#for element in zip(str(listip),str(thedata)):
#print(element)
def stop(self):
#logging.info('Piece Request Sniffer stopped...')
self.active = False
def run(self):
while self.active:
self.p.dispatch(0, PieceRequestSniffer.cb)
sniffer = PieceRequestSniffer()
sniffer.start()
First, import socket, then use:
src_ip = socket.inet_ntoa(ip.src)
dst_ip = socket.inet_ntoa(ip.dst)
I'd like to know how to write TCP tunnel/relay/bridge/proxy (you name it) using twisted.
I did some research in google, twisted doc/forum etc. etc but couldn't find anwser.
I already done it in pure python using socket, threading and select.
Here is code:
#!/usr/bin/env python
import socket
import sys
import select
import threading
import logging
import time
class Client(threading.Thread):
def __init__(self, client, address, id_number, dst_ip, dst_port):
self.log = logging.getLogger(__name__+'.client-%s' % id_number)
self.running = False
self.cl_soc = client
self.cl_adr = address
self.my_id = id_number
self.dst_ip = dst_ip
self.dst_port = dst_port
threading.Thread.__init__(self)
def stop(self):
self.running = 0
def run(self):
try:
self.dst_soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.dst_soc.connect((self.dst_ip,self.dst_port))
except:
self.log.error('Can\'t connect to %s:%s' % (self.dst_ip, self.dst_port))
else:
self.running = True
self.log.info('Bridge %s <-> %s created' % (
'%s:%s' % self.dst_soc.getpeername(), '%s:%s' % self.cl_adr))
try:
while self.running:
iRdy = select.select([self.cl_soc, self.dst_soc],[],[], 1)[0]
if self.cl_soc in iRdy:
buf = self.cl_soc.recv(4096)
if not buf:
info = 'Ended connection: client'
self.running = False
else:
self.dst_soc.send(buf)
if self.dst_soc in iRdy:
buf = self.dst_soc.recv(4096)
if not buf:
info = 'Ended connection: destination'
self.running = False
else:
self.cl_soc.send(buf)
except:
self.log.error('Sth bad happend', exc_info=True)
self.running = False
self.log.debug('Closing sockets')
try:
self.dst_soc.close()
except:
pass
try:
self.cl_soc.close()
except:
pass
class Server(threading.Thread):
def __init__(self, l_port=25565, d_ip='127.0.0.1', d_port=None):
self.log = logging.getLogger(__name__+'.server-%s:%s' % (d_ip,d_port))
threading.Thread.__init__(self)
self.d_ip = d_ip
if d_port == None:
self.d_port = l_port
else:
self.d_port = d_port
self.port = l_port
binding = 1
wait = 30
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
while binding:
try:
self.s.bind(('',self.port))
except:
self.log.warning('Cant bind. Will wait %s sec' % wait)
time.sleep(wait)
else:
binding = 0
self.log.info('Server ready for connections - port %s' % d_port)
def run(self):
self.s.listen(5)
input = [self.s, sys.stdin]
running = 1
self.cl_threads = []
id_nr = 0
while running:
iRdy = select.select(input, [], [],1)[0]
if self.s in iRdy:
c_soc, c_adr = self.s.accept()
c = Client(c_soc, c_adr, id_nr, self.d_ip, self.d_port)
c.start()
self.cl_threads.append(c)
id_nr += 1
if sys.stdin in iRdy:
junk = sys.stdin.readline()
print junk
running = 0
try:
self.s.close()
except:
pass
for c in self.cl_threads:
c.stop()
c.join(5)
del c
self.cl_threads = None
self.log.info('Closing server')
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
s = Server(1424, '192.168.1.6', 1424)
s.run()
this is actually, already built into twisted, from the command line you can type:
$ twistd --nodaemon portforward --port 1424 --host 192.168.1.6
to get the exact behavior you seem to be looking for.
If you'd like to roll your own, you can still use all of the bits, in twisted.protocols.portforward
I have an IRC bot and I'm trying to get information for game server (GTA SA Multiplayer).
I have ready-to-use query, but I can't implement it into my bot. It works if I try to load the same script, but without getting it into bot's structure. The error it gives me is
NameError: name 'ip' is not defined
I've tried adding the ip address as argument in def(inp,say=None), but it still didn't work. That's the code:
from util import Query
from util import hook
import sys
#hook.command
def serverinfo(inp,ip="",port="",say=None):
ip = "78.129.221.58"
port = 7777
if len(sys.argv) >= 3:
ip = str(sys.argv[1])
port = int(sys.argv[2])
query = Query(ip,port)
info = query.GetInformation()
say(info)
if info['players'] <= 100:
say(query.GetPlayers())
say(query.GetDetailedPlayers())
else: say('can\' get players because players is above 100')
say(query.Ping())
query.Close()
That's Query that I import:
import socket, struct, random, datetime
from cStringIO import StringIO
class Query:
def __init__(self, ip, port):
self.ip, self.port = socket.gethostbyname(ip), port
self.data = StringIO("")
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.connect((ip, port))
self.sock.settimeout(1)
def CreatePacket(self, opcode):
ips = self.ip.split('.');
packet = "SAMP{0}{1}{2}{3}{4}{5}{6}".format(chr(int(ips[0])), chr(int(ips[1])), chr(int(ips[2])), chr(int(ips[3])), chr(self.port & 0xFF), chr(self.port >> 8 & 0xFF), opcode)
if opcode == 'p':
packet += struct.pack("BBBB", random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
return packet
def GetInformation(self):
try:
self.sock.send(self.CreatePacket('i'))
info = {}
self.data = StringIO(self.sock.recv(2048))
self.data.read(11)
info['passworded'] = struct.unpack('?', self.data.read(1))[0]
info['players'] = struct.unpack('h', self.data.read(2))[0]
info['maxplayers'] = struct.unpack('h', self.data.read(2))[0]
info['hostname'] = self.data.read(struct.unpack('i', self.data.read(4))[0])
info['gamemode'] = self.data.read(struct.unpack('i', self.data.read(4))[0])
info['mapname'] = self.data.read(struct.unpack('i', self.data.read(4))[0])
except socket.timeout:
info['error'] = 1
return info
def GetRules(self):
try:
self.sock.send(self.CreatePacket('r'))
rules = {}
self.data = StringIO(self.sock.recv(2048))
self.data.read(11)
rulecount = struct.unpack('h', self.data.read(2))[0]
for i in range(rulecount):
name = self.data.read(struct.unpack('b', self.data.read(1))[0])
rules[name] = self.data.read(struct.unpack('b', self.data.read(1))[0])
except socket.timeout:
rules['error'] = 1
return rules
def GetPlayers(self):
try:
self.sock.send(self.CreatePacket('c'))
players = []
self.data = StringIO(self.sock.recv(2048))
self.data.read(11)
playercount = struct.unpack('h', self.data.read(2))[0]
for i in range(playercount):
name = self.data.read(struct.unpack('b', self.data.read(1))[0])
players.append([name, struct.unpack('i', self.data.read(4))[0]])
except socket.timeout:
players = {'error': 1}
return players
def GetDetailedPlayers(self):
try:
self.sock.send(self.CreatePacket('d'))
players = []
self.data = StringIO(self.sock.recv(2048))
self.data.read(11)
playercount = struct.unpack('h', self.data.read(2))[0]
for i in range(playercount):
playerid = struct.unpack('b', self.data.read(1))[0]
name = self.data.read(struct.unpack('b', self.data.read(1))[0])
score = struct.unpack('i', self.data.read(4))[0]
ping = struct.unpack('i', self.data.read(4))[0]
players.append([playerid, name, score, ping])
except socket.timeout:
players = {'error': 1}
return players
def Close(self):
self.sock.close()
def Ping(self):
packet = self.CreatePacket('p')
a = datetime.datetime.now()
self.sock.send(packet)
self.sock.recv(2048)
b = datetime.datetime.now()
c = b - a
return int((c.days * 24 * 60 * 60 + c.seconds) * 1000 + c.microseconds / 1000.0)
class Rcon:
def __init__(self, ip, port, password):
self.ip, self.port, self.password = socket.gethostbyname(ip), port, password
self.data = StringIO("")
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.connect((ip, port))
self.sock.settimeout(0.5)
def CreatePacket(self, opcode, password, command):
ips = self.ip.split('.');
packet = "SAMP{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}".format(chr(int(ips[0])), chr(int(ips[1])), chr(int(ips[2])), chr(int(ips[3])), chr(self.port & 0xFF), chr(self.port >> 8 & 0xFF), opcode, chr(len(password) & 0xFF), chr(len(password) >> 8 & 0xFF), password, chr(len(command) & 0xFF), chr(len(command) >> 8 & 0xFF), command)
return packet
def Send(self, command):
self.sock.send(self.CreatePacket('x', self.password, command))
output = []
while 1:
try:
self.data = StringIO(self.sock.recv(2048))
self.data.read(11)
strlen = struct.unpack('h', self.data.read(2))[0]
if strlen == 0: break
output += [self.data.read(strlen)]
except: break;
return output
def Close(self):
self.sock.close()
Any ideas?
Edit: After some changes I did, gives me the following error:
query = Query(ip,port)
TypeError: 'module' object is not callable
I've basically changed the location of ip and port, moved it out of the serverinfo command.
from util import Query
from util import hook
ip = "78.129.221.58"
port = 7777
query = Query(ip,port)
info = query.GetInformation()
#hook.command
def serverinfo(inp,ip="",port="",say=None):
say(info)
if info['players'] <= 100:
say(query.GetPlayers())
say(query.GetDetailedPlayers())
else: say('can\' get players because players are above 100')
say(query.Ping())
query.Close()
Try adding this to the start of the python code :
ip = "78.129.221.58"
port = 7777
Try
query = Query.Query(ip, port)
The problematic line is this one:
query = Query(ip,port)
If the initialization using the command line parameters fail or if you pass in insufficient arguments, ip will not be initialized resulting in the said error.
Also, a better way of testing out scripts is something like this:
def main():
if len(sys.argv) >= 3:
ip = str(sys.argv[1])
port = int(sys.argv[2])
query = Query(ip,port)
# start using query
else:
raise Exception("Insufficient args passed in")
if __name__ == '__main__':
main()
Raising an exception/error or printing out something guarantees that you know that insufficient args are passed in. Also, maybe move all that code out in the open to some function?