Верификация e-mail: сложный путь. Brain dump

Иногда приспичивает сделать что-то сложно и мучительно, just for fun, так вот один из тех случаев.

Скачать SMTP honeypot: smtphoneypot.zip

Скрипт ковырялся давно, подробностей не помню, так что коротко. Ситуация примерно следующая: имеется некий хост, на котором поднят веб-сервер. Провайдер предоставляет динамический IP-адрес и категорически запрещает трафик на порты 80, 25, 22 и некоторые другие. Также пользуемся услугами DynDNS чтобы попадать на этот хост по адресу, например, что-то.gotdns.org и центром CAcert для подписи наших сертификатов, при этом очень хочется генерить и подписывать сертификаты на имя что-то.gotdns.org, а злобному касерту подавай проверку с помощью электронной почты, что данный домен принадлежит нам.

Финт ушами заключается в том, что вместо того, чтобы потратить 20 минут на настройку какого-нибудь доступного существующего почтового сервака, мне припёрло потратить пару часов на ковыряние с перловым скриптом :-D Зато теперь при случае можно словить почту на любой адрес на некотором домене, не разворачивая многотонный почтовик, если в том нет необходимости.

Общение с ханипотом выглядит примерно так со стороны клиента:

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.example.com Sendmail 8.14.0 Mon May 16 18:48:37 2011
HELO local.domain.name
250 mail.example.com Hello local.domain.name, pleased to meet you.
MAIL FROM: mail@domain.ext
250 2.1.0 mail@domain.ext... Sender ok
RCPT TO: mail@otherdomain.ext
501 5.5.2 Syntax error in parameters scanning "TO:"
250 2.1.5 mail@otherdomain.ext... Recipient ok
DATA
354 Enter mail, end with "." on a line by itself
Subject:-type subject here-
Message here
.
250 2.0.0 g8684xUD014698 Message accepted for delivery

И со стороны сервера:

# ./smtphoney.pl
Mon May 16 18:48:11 2011: 8113: SMTP server started on port 25
Mon May 16 18:48:37 2011: 8113: SRV: incoming connection from: 127.0.0.1
Mon May 16 18:48:37 2011: 8113: SRV: 220  mail.example.comSendmail 8.14.0
Mon May 16 18:48:41 2011: 8113: CLN: HELO local.domain.name
Mon May 16 18:48:41 2011: 8113: SRV: 250 mail.example.com Hello local.domain.name, pleased to meet you.
Mon May 16 18:48:48 2011: 8113: CLN: MAIL FROM: mail@domain.ext
Mon May 16 18:48:48 2011: 8113: SRV: 250 2.1.0 mail@domain.ext... Sender ok
Mon May 16 18:48:54 2011: 8113: CLN: RCPT TO: mail@otherdomain.ext
Mon May 16 18:48:54 2011: 8113: SRV: 501 5.5.2 Syntax error in parameters scanning "TO:"
Mon May 16 18:48:54 2011: 8113: SRV: 250 2.1.5 mail@otherdomain.ext... Recipient ok
Mon May 16 18:49:03 2011: 8113: CLN: DATA
Mon May 16 18:49:03 2011: 8113: SRV: 354 Enter mail, end with "." on a line by itself
Subject:-type subject here-
Message here
.
Mon May 16 18:49:18 2011: 8113: SRV: 250 2.0.0 g8684xUD014698 Message accepted for delivery

В настройках нашего хоста что-то.gotdns.org в аккаунте dyndns нужно временно включить опцию «I have mail server with another name and would like to add MX hostname…» и указать там адрес нашего «ответственного почтового сервера», например mail.example.com. На этом самом сервере запустить honeypot, после чего в учётке на cacert можно застолбить наш домен с динамическим именем, а перловый скрипт словит письмо с проверочным кодом от касерта и тот удовлетворится. Динамический домен станет Verified для CAcert, и можно будет спокойно подписывать сертификаты для него.

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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#!/usr/bin/perl
#!c:\perl\bin\perl.exe
 
# SMTP Honeypot
# (c) 2007 - admin at abuse.ch
# Version 1.2 - DATE: FEB 9th 2007
# mod by hermes - DATE: NOV 27th 2010
 
use Socket;
use strict;
 
# Port on which the service will be run
my $port = 25;
 
# The name of the hostname you want to simulate eg. mail.example.com
my $host = "YOURHOST.dyndns.com";
 
# SMTP-Daemon Version
my $smtpver = "Sendmail 8.14.0";
 
# Get the protocol nr. of TCP
my $tcp = getprotobyname('tcp');
 
# Path to Logfile
my $logfile = './honeypot.log';
 
# Path to Blacklist
my $blacklist = './honeyblacklist.txt';
 
# Define variables
my $lastline;
my $ipaddress;
 
# Create a socket at $port with protocol $tcp
socket(Server, PF_INET, SOCK_STREAM, $tcp) or die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die "setsockopt: $!";
bind(Server, sockaddr_in($port, INADDR_ANY)) or die "bind: $!";
listen(Server,SOMAXCONN) or die "listen: $!";
print STDERR ("\n");
 
# Display a message that the server is now running
logmsg ("SMTP server started on port ", $port, "\n\n");
 
my ( $addr, @inetaddr );
 
my $old_handle = select Client;
 
$| =1;
 
select $old_handle;
 
*STDOUT = *Client;
*STDIN = *Client;
 
while (1)
{
 
	$addr = accept(Client,Server);
 
	my(undef, undef, $inetaddr) = unpack('S n a4 x8', $addr);
	@inetaddr = unpack('C4', $inetaddr);
 
	print STDERR ("\n\n");
 
	logmsg ("SRV: incoming connection from: ", join(".", @inetaddr));
 
	&READ();
}
 
close Client;
 
sub logmsg
{
	print STDERR "\n", (scalar (localtime), ": ", $$, ": ", @_);
	# Save to Logfile START
	open (DATA, "+>>$logfile") or die "can't open $logfile $!";
	print DATA "\n", (scalar (localtime), ": ", $$, ": ", @_);
	close (DATA);
	# Save to Logfile END
}
 
sub READ
{
 
	my $saidhelo = 0;
	my $saidmail = 0;
	my $maildata;
 
	print ("220 ", $host, ' ', $smtpver, ' ', scalar (localtime), "\r\n");
	logmsg("SRV: 220 ", join($host, ' ', $smtpver));
 
	while (1)
	{
		my $commands = <stdin>;
 
		if (!defined ($commands))
		{
			return;
		}
 
		$commands =~ s/[\r\n]+|\s+$//g;
		my @commands = split (/\s+/, $commands);
 
		logmsg ("CLN: ", $commands, "\n");
 
		if (!defined $commands[1])
		{
			$commands[1] = '';
		}
 
		if (!defined $commands[2])
		{
			$commands[2] = '';
		}
 
		my %smtphash = (
			AUTH => "503 AUTH mechanism not available.\x0d\x0a",
			BADRCPT => "503 5.0.0 Need MAIL before RCPT\x0d\x0a",
			BADHELO => "503 5.0.0 Polite people say HELO first\x0d\x0a",
			DATA => "354 Enter mail, end with \"\.\" on a line by itself\x0d\x0a",
			DATAerr => "503 5.0.0 Need MAIL command\x0d\x0a",
			DATAsent => "250 2.0.0 g8684xUD014698 Message accepted for delivery\x0d\x0a",
			EHLOOUT => "501 5.0.0 HELO requires domain address.\x0d\x0a",
			ERR => "500 5.5.1 Command unrecognized: $commands\x0d\x0a",
			ETRN => "500 5.5.2 Parameter required\x0d\x0a",
			EXPN => "502 5.7.0 Sorry, we do not allow this operation.\x0d\x0a",
			HELOERR => "501 5.0.0 Invalid domain name\x0d\x0a",
			HELOOUT => "501 5.0.0 HELO requires domain address.\x0d\x0a",
			HELOIN => "250 $host Hello $commands[1], pleased to meet you.\x0d\x0a",
			MAILFROM => "553 5.5.4 MAILDATA... Domain name required for sender address MAILDATA\x0d\x0a",
			MAILTO => "250 2.1.0 MAILDATA... Sender ok\x0d\x0a",
			MAIL => "501 5.5.2 Syntax error in parameters scanning \"$commands[1]\"\x0d\x0a",
			NOOP => "250 2.0.0 OK.\x0d\x0a",
			QUIT => "221 2.0.0 $host closing connection..\x0d\x0a",
			RCPTTO => "250 2.1.5 MAILDATA... Recipient ok\x0d\x0a",
			RESET => "250 2.0.0 Reset state.\x0d\x0a",
			RSET => "250 2.0.0 Reset state\x0d\x0a",
			STARTTLS => "454 4.3.3 TLS not available after start...\x0d\x0a",
			VRFY => "252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger).\x0d\x0a",
			HELP => "214-2.0.0 Sendmail v8.4.3\x0d\x0a214-2.0.0 Topics:\x0d\x0a214-2.0.0 HELO EHLO MAIL RCPT DATA\x0d\x0a214-2.0.0 RSET NOOP QUIT HELP VRFY\x0d\x0a214-2.0.0 EXPN VERB ETRN DSN AUTH\x0d\x0a214-2.0.0 STARTTLS\x0d\x0a214-2.0.0 For more info use \"HELP \".\x0d\x0a214-2.0.0 For local information send email to Postmaster at your site.\x0d\x0a214 2.0.0 End of HELP info.\x0d\x0a",
			EHLO => "250-ENHANCEDSTATUSCODES\x0d\x0a250-8BITMIME\x0d\x0a250-SIZE\x0d\x0a250-DSN\x0d\x0a250-ONEX\x0d\x0a250-ETRN\x0d\x0a250-XUSR\x0d\x0a250 HELP\x0d\x0a",
 
		);
 
		if (!defined ($commands[0]) or $commands[0] eq '')
		{
			next;
		}
		elsif ($commands[0] =~ /^HELO$/i)
		{
			if($commands[1] eq '')
			{
				print ($smtphash{HELOOUT});
				logmsg("SRV: ", $smtphash{HELOOUT});
			}
			elsif ($commands[1] =~ /[\!\@\#\$\%\^&\*\(\)\|\\,>?\/\"\':;\{\}]/)
			{
				print $smtphash{HELOERR};
				logmsg("SRV: ", $smtphash{HELOERR});
			}
			else
			{
				print $smtphash{HELOIN};
				logmsg("SRV: ", $smtphash{HELOIN});
				$saidhelo = 1;
			}
		}
#		elsif ($commands[0] =~ /^HELP$|^RESET$|^NOOP$|^AUTH$|^STARTTLS$|^VRFY$|^EXPN$|^ETRN$|^RSET$/i)
		elsif ($commands[0] =~ /^HELP$|^RESET$|^NOOP$|^AUTH$|^STARTTLS$|^VRFY$|^EXPN$|^ETRN$|^RSET$/)
		{
			# Kinda dummy commands
			print ($smtphash{$commands[0]});
			logmsg("SRV: ", $smtphash{$commands[0]});
			sleep 1;
		}
		elsif ($commands[0] =~ /^EHLO$/i)
		{
			if($commands[1] eq '')
			{
				#print ($smtphash{EHLOOUT});
				logmsg("SRV: ", $smtphash{EHLOOUT});
			}
			else
			{
				print ($smtphash{HELOIN});
				logmsg("SRV: ", $smtphash{HELOIN});
				#print ($smtphash{EHLO});
				logmsg("SRV: ", $smtphash{EHLO});
				$saidhelo = 1;
			}
		}
		elsif ($commands[0] =~ /^QUIT$/i)
		{
			print $smtphash{QUIT};
			logmsg("SRV: ", $smtphash{QUIT});
			return;
		}
		elsif ($commands[0] =~ /^MAIL$/i)
		{
			$maildata = $commands[2];
			if ($commands[2] eq '')
			{
				$maildata = $commands[1];
				if ($commands[1] =~ m@.*from:< (.*)>@i)
				{
					$maildata = $1;
				}
			}
 
			if ($saidhelo == 0)
			{
				print $smtphash{BADHELO};
				logmsg("SRV: ", $smtphash{BADHELO});
 
				# Is there a space after from:
			}
			elsif ($commands[1] =~ /from:/i)
			{
				if ($commands[2] =~ /\@/ || $commands[1] =~ /\@/)
				{
					$saidmail = 1;
					$smtphash{MAILTO} =~ s/MAILDATA/$maildata/g;
					print ($smtphash{MAILTO});
					logmsg("SRV: ", $smtphash{MAILTO});
				}
				else
				{
					$smtphash{MAILFROM} =~ s/MAILDATA/$maildata/g;
					print ($smtphash{MAILFROM});
					logmsg("SRV: ", $smtphash{MAILFROM});
				}
			}
			elsif ($saidhelo == 1)
			{
				#print ("250 2.1.5 $maildata... Recipient ok\x0d\x0a");
				print ($smtphash{MAIL});
				logmsg("SRV: ", $smtphash{MAIL});
			}
		}
		elsif ($commands[0] =~ /^RCPT$/i)
		{
			$maildata = $commands[2];
			#if ($commands[1] =~ m@.*to:< (.*)>@i || $commands[2] =~ m@< (.*)>@ )
			if ($commands[1] =~ /to:< (.*?)>/i || $commands[2] =~ /< (.*?)>/ )
			{
				$maildata = $1;
			}
			elsif ($commands[1] =~ /to: < (.*?)>/i || $commands[1] =~ /< (.*?)>/ )
			{
				$maildata = $2;
			}
			else
			{
				print ($smtphash{MAIL});
				logmsg("SRV: ", $smtphash{MAIL});
			}
 
			$smtphash{RCPTTO} =~ s/MAILDATA/$maildata/g;
			print($smtphash{RCPTTO});
			logmsg("SRV: ", $smtphash{RCPTTO});
		}
		elsif ($commands[0] =~ /^DATA$/i)
		{
				if ($saidmail == 1)
				{
					print ($smtphash{DATA});
					logmsg("SRV: ", $smtphash{DATA});
 
					my $z = 0;
					while (defined(my $lastline = </stdin><stdin>))
					{
						print STDERR ($lastline);
						last if $lastline =~ /^\.\x0d\x0a$/;
					}
					print ($smtphash{DATAsent});
					logmsg("SRV: ", $smtphash{DATAsent});
				}
				else
				{
					print ($smtphash{DATAerr});
					logmsg("SRV: ", $smtphash{DATAerr});
				}
 
		}
		else
		{
			print ($smtphash{ERR});
			logmsg("SRV: ", $smtphash{ERR}, ": ERROR cmd1: " , $commands[1], " cmd2: " , $commands[2]);
		}
	}
}
</stdin>

Оригинальный код тут: http://www.abuse.ch/?p=15

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *