您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關怎么利用升級系統一鍵GetShell的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
1.第一步安裝系統
2.第二步這里要創建數據庫,不然他不會自動創建。
3.第三步完成安裝,然后我們點擊進入后臺。
4.第四步進入后臺-》程序升級-》升級配置
5.第五步,服務端構建代碼,創建`index.php`放在網頁根目錄
6.第六步,后臺-》程序升級-》在線升級,我這里改下1999-09-09 09:09:09
代表是我服務器的升級軟件
7.第七步,我們點擊升級,在用D盾監聽下目錄是否上傳成功木馬文件。
8.第八步,訪問木馬文件,看看是否能訪問成功
漏洞所在文件:\framework\admin\update_control.php(在后臺程序升級)
漏洞文件代碼:(只貼上相關代碼)
首先我們看第369行,$file = $this->get('file','int');
,這里我們看到他這里是接收GET
變量中的file
值,那么int
就是把接收的值轉換成int
類型。
第370行,if(!$file)
判斷$file
變量是否有賦值,如果沒有復制那么就提示一個JSON
數據。
第373行,$urlext = 'file='.rawurlencode($file);
,rawurlencode
函數代表空格轉換成%20
。
第374行,$rs = $this->service(5,$urlext);
,這里可以看到調用本身文件中的service
方法,那我們進入這個方法看看,在文章的第465行。
第465行,if(!file_exists($this->dir_root.'data/update.php'))
,file_exists
函數代表檢查文件或目錄是否存在。
第470行,$uconfig = array();
,申明一個空數組。
第471行,include($this->dir_root.'data/update.php');
,include
函數代表引入一個文件,如果沒有找到這個文件只會提示個警告不會終止錯誤。
第478行,if(file_exists($this->dir_root.'data/update.xml'))
,file_exists
函數代表檢查文件或目錄是否存在。
第486行,if(substr($url,-1) != '/')
,substr
函數代表字符串切割,并且判斷不等于/
那么就進入487行區間。
第489行,$url .= 'index.php?version='.rawurlencode(trim($info['version'])).'&time='.$this->time.'&type='.$type;
,URL地址拼接,rawurlencode
函數代表空格轉換成%20
,trim
函數代表移除字符串兩側的空白字符。
第493行,if($type == 1 || $type == 4)
,判斷外部傳入的$type
是否等于1或者等于4。
第494行,$onlyid = $uconfig['onlyid'] ? $uconfig['onlyid'] : $this->_onlyid();
,這里使用了3元運算符。
第495行,$domain = $this->lib('server')->domain($this->config['get_domain_method']);
,這里代表是獲取當前訪問的網址。
第496行,$client_ip = $this->lib('common')->ip();
,獲取客戶端Ip
第497行,$url .= "&domain=".rawurlencode($domain)."&ip=".rawurlencode($client_ip);
,URL地址拼接,rawurlencode
函數代表空格轉換成%20
。
第498行,$url .= "&onlyid=".$onlyid."&phpversion=".PHP_VERSION;
,也是URL地址拼接。
第499行,if(function_exists('php_uname'))
,function_exists
函數代表判斷是否有某函數。
第502行,$soft = $_SERVER['SERVER_SOFTWARE'];
,獲取服務器PHP版本。
第506行,$mysqlversion = $this->db->version('server');
,獲取服務端mysql版本號。
第511行,$this->lib('html')->setting('timeout',900);
,這里是設置CURL請求的超時時間。
第513行,$this->lib('html')->ip($uconfig['ip']);
,設置請求IP。
第515行,$info = $this->lib('html')->get_content($url);
,請求URL地址,返回XML
內容。
下面就是返回XML
數據,那么我們回到第一張圖片。
第375行,$rs = $this->lib('json')->decode($rs);
,這里代表是把接收到的XML
內容轉換成JSON
數據。
第376行,if($rs['status'] != 'ok')
,判斷$rs['status']
不等于ok
。
第379行,if(!$rs['content'])
,判斷是否為空。
第382行,$info = base64_decode($rs['content']);
,把接收到的$rs['content']
值,從base64
轉換成實體。
第383行,file_put_contents($this->dir_root.'data/tmp.zip',$info);
,寫入當前文件,第一個參數代表路徑,第二個參數代表內容。
第384行,$this->lib('phpzip')->unzip($this->dir_root.'data/tmp.zip','data/update/');
,我們看到這里的意思就是解壓文件到某個目錄。
第386行,$this->lib('file')->rm($this->dir_root.'data/tmp.zip');
,刪除寫入的文件。
第386行,$verinfo = substr($file,0,1).".".substr($file,1,1).".".substr($file,2);
,這里是字符串切割。
第387行,$info = $this->update_load($verinfo);
,這里調用自定義方法,也是在本文章第152行。
第154行,$list = array();
,定義一個空數組。
第155行,$this->lib('file')->deep_ls($this->dir_root.'data/update/',$list);
,這里大概意思是遍歷當前文件所有文件名,這里我就不去找代碼,就把代碼直接復制出來。
那么代碼路徑在framework\libs\file.php
中第297-313行
/** * 獲取文件夾及子文件夾等多層文件列表(無限級,長度受系統限制) * @參數 $folder 文件夾 * @參數 $list 引用變量 **/ public function deep_ls($folder,&$list) { $this->read_count++; $tmplist = $this->_dir_list($folder); foreach($tmplist AS $key=>$value){ if(is_dir($value)){ $this->deep_ls($value,$list); }else{ $list[] = $value; } } }
第156行,if(!$list || count($list) < 1)
,判斷$list
是否為空,并且判斷他的數據是不是小于1。
第159行,$strlen = strlen($this->dir_root."data/update/");
,strlen
代表統計字符串長度。
第162行,foreach($list as $key=>$value)
,foreach
循環遍歷數組。
第163行,$value = trim($value);
,trim
代表移除字符串兩側的字符。
第165行,continue;
,這里代表跳出循環。
第167行,$tmp = substr($value,$strlen);
,substr
代表字符串切割。
第168行,if($tmp == 'version.txt')
,這里判斷$tmp
是否等于version.txt
。
第169行,$verinfo = trim(file_get_contents($value));
,trim
代表移除字符串兩側的字符,file_get_contents
代表寫入文件。
第183行,if(substr($tmp,0,10) == 'framework/')
,substr
代表字符串切割,從0到10切割判斷等于framework/
。
第185行,if(is_file($value))
,is_file
代表判斷文件是否存在。
第187行,$this->lib('file')->mv($value,$this->dir_phpok.$tmp1);
,剪切文件到某個目錄。
第189行,if(is_dir($value) && !is_dir($this->dir_phpok.$tmp1))
,is_dir
代表判斷目錄是否存在,并且判斷臨時文件是否不存在。
第190行,$this->lib('file')->make($this->dir_phpok.$tmp1,'folder');
,創建目錄。
第194行,if(is_file($value) && $tmp != 'table.sql')
,is_file
代表判斷文件是否存在,并且判斷$tmp
不等于table.sql
文件的進入區間。
第194行-第210行都是一樣,剪切和創建目錄。
第205行,$dlist = file($delfile);
,file
代表整個文件讀入一個數組中。
第209行,foreach($dlist AS $key=>$value)
,foreach
代表數組循環。
第213行,$value = trim($value);
,trim
代表移除字符串兩側的字符。
第214行,if($value && is_file($this->dir_root.$value))
,判斷$value
是否有值,并且判斷文件是否存在。
第215行,$this->lib('file')->rm($this->dir_root.$value);
,代表刪除文件。
第218行,if($value && is_dir($this->dir_root.$value))
,判斷$value
是否有值,并且判斷目錄是否存在。
第225行,$this->update_table();
這里又看到調用自己的方法。
我們接下來繼續往下分析,這里的話我就把代碼Copy出來,代碼太多截圖不好看。
我這里挑重要的函數講解下,這里都是sql執行語句,沒有什么可以分析的。
函數:
file_exists
,代表檢查文件或目錄是否存在。
file_get_contents
,代表讀取文件,如果攜帶2個參數那么就是寫入。
str_replace
,代表字符串替換。
strlen
,代表查看字符串長度。
substr
,代表字符串切割。
unset
,代表變量刪除。
explode
,代表把字符串切割成數組。
trim
,代表移除字符串兩側的字符。
private function update_table() { if(!file_exists($this->dir_root.'data/update/table.sql')){ return false; } //創建新表臨時 $prefix = 'tmp_'.$this->db->prefix; $sqlcontent = file_get_contents($this->dir_root.'data/update/table.sql'); $sqlcontent = str_replace('qinggan_',$prefix,$sqlcontent); $this->sql_run($sqlcontent); //比較新表結果 $list = $this->db->list_tables(); $tblist = array(); $nlength = strlen($prefix); $olength = strlen($this->db->prefix); foreach($list as $key=>$value){ //跳過擴展表 $continue_1 = substr($value,0,strlen($prefix.'list_')); $continue_2 = substr($value,0,strlen($this->db->prefix.'list_')); if($continue_1== $prefix.'list_' || $continue_2 == $this->db->prefix."list_"){ continue; } if(substr($value,0,$nlength) == $prefix){ $tblid = substr($value,$nlength); $tblist[$tblid]['new'] = $value; } if(substr($value,0,$olength) == $this->db->prefix){ $tblid = substr($value,strlen($this->db->prefix)); $tblist[$tblid]['old'] = $value; } } foreach($tblist as $key=>$value){ if(!$value['new']){ continue; } if(!$value['old']){ $sql = "SHOW CREATE TABLE ".$value['new']; $rs = $this->db->get_one($sql); if(!$rs['Create Table']){ continue; } $rs['Create Table'] = str_replace($prefix,$this->db->prefix,$rs['Create Table']); $this->db->query($rs['Create Table']); continue; } //比較新表 $nlist = $this->db->list_fields_more($value['new']); $olist = $this->db->list_fields_more($value['old']); foreach($nlist as $k=>$v){ if($olist[$k] && $olist[$k]['type'] == $v['type']){ continue; } if(!$olist[$k]){ $sql = "ALTER TABLE ".$value['old']." ADD `".$k."` ".$v['type']." "; }else{ $sql = "ALTER TABLE `".$value['old']."` CHANGE `".$k."` `".$k."` ".$v['type']." "; } if($v['null'] == 'NO'){ $sql .= " NOT NULL "; if($v['default'] != ''){ $sql .= " DEFAULT ".$v['default']." "; } }else{ $sql .= " DEFAULT ".($v['default'] != '' ? $v['default'] : ' NULL ')." "; } if($value['extra']){ $sql .= " ".$v['extra']." "; } if($v['comment']){ $sql .= " COMMENT '".$v['comment']."'"; } $this->db->query($sql); } unset($nlist,$olist); } //刪除臨時表操作 foreach($list as $key=>$value){ if(substr($value,0,$nlength) == $prefix){ $sql = "DROP TABLE ".$value; $this->db->query($sql); } } unset($list,$tbllist); return true; } private function sql_run($sql='') { $sql = str_replace("\r","\n",$sql); $ret = array(); $num = 0; foreach(explode(";\n", trim($sql)) as $query){ $queries = explode("\n", trim($query)); foreach($queries as $query){ $ret[$num] .= $query[0] == '#' || $query[0].$query[1] == '--' ? '' : $query; } $num++; } foreach($ret as $query){ $query = trim($query); if($query){ $this->db->query($query); } } return true; }
好了 我們回到上上張圖片。
第231行,$info = trim(file_get_contents($value));
,trim
代表移除字符串兩側的字符,file_get_contents
代表寫入文件。
第233行,$info = str_replace('qinggan_',$this->db->prefix,$info);
,str_replace
代表字符串替換。
第240行,if(file_exists($this->dir_root."data/update/run.php"))
,file_exists
代表檢查文件或目錄是否存在。
第241行,include($this->dir_root.'data/update/run.php');
,include
引入一個文件。
第243行,$this->lib('file')->rm($this->dir_root.'data/update/');
,代表刪除文件。
第244行,$list = $this->lib('file')->ls($this->dir_root.'data/update/');
,代表把目錄結構挪列出來。
第245行,if($list && count($list)>0)
,判斷$list
值是否存在,并且判斷他的數量是否小于0。
第247行,$this->lib('file')->rm($value,'folder');
,這里代表循環刪除某個文件。
第251行,$this->success_version($verinfo);
這里又進入一個自定義方法區間。
老樣子,Copy代碼,代碼量不多我就Copy出來。
//更新成功后,修改記錄 private function success_version($version='') { if(!$version){ return false; } //寫入到最新版本 $html = '<?xml version="1.0" encoding="utf-8"?>'."\n"; $html.= '<phpok>'."\n"; $html.= "\t".'<version>'.trim($version).'</version>'."\n"; $html.= "\t".'<time>'.date("Y-m-d H:i:s",$this->time).'</time>'."\n"; $html.= '</phpok>'; file_put_contents($this->dir_root.'data/update.xml',$html); if(is_writeable($this->dir_root.'version.php') && file_exists($this->dir_data.'version.tpl')){ $info = file_get_contents($this->dir_data.'version.tpl'); $info = str_replace('{version}',trim($version),$info); $info = str_replace('{updatetime}',date("Y年m月d日 H時i分s秒",$this->time),$info); file_put_contents($this->dir_root.'version.php',$info); } $this->lib('file')->rm($this->dir_root.'data/tpl_admin/'); $this->lib('file')->rm($this->dir_root.'data/tpl_www/'); $this->lib('file')->rm($this->dir_cache); return true; }
那么我們還是做簡單的介紹下重要函數。
trim
,代表移除字符串兩側的字符。
is_writeable
,判斷文件是否可寫。
file_exists
,代表檢查文件或目錄是否存在。
str_replace
,字符串替換。
file_put_contents
,寫入文件或讀取文件。
這里已經介紹完畢了,整個審計分析邏輯在上面。
路徑:\framework\admin\update_control.php
第152行,方法里面的foreach
循環加上這段代碼去過濾。
$verinfo = str_replace(['eval','assert','system','phpinfo'], ['eval','assert','system','phpinfo'], strtolower(trim(file_get_contents($value))));
,這里我只寫了比較有危害的關鍵字。
感謝各位的閱讀!關于“怎么利用升級系統一鍵GetShell”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。