記一次攻防演練
一、簡介:
領導通知,讓我打十天攻防,前四天,平平無奇,兩個權限,web系統都是外包的,沒打進核心內網。
這次攻防,沒有給靶標,也沒有給資產,全靠自己進行信息搜集。
由于本人不會釣魚,所以只能打打外網了。
二、前期信息搜集
信息搜集主要以廠商系統為主,通過使用fofa,云悉,查ICP備案,APP脫殼逆向,公眾號接口,小程序,天眼查查母公司以及子公司的備案和資產信息。通過能直接獲取到的資產信息,進行二次信息搜集,主要是以C段,B段和目錄掃描為主。
三、第五六七天
3.1 測試網站的功能點,想辦法黑盒獲取權限。
第五天主要是以代碼審計為主。
通過信息找到找到子公司的一個備案網站系統。

根據左上角的功能提示,發現網站存在登錄和注冊功能,因此嘗試注冊一個賬號。
點擊注冊按鈕,發現跳轉到登錄界面。很奇怪,貌似注冊功能無法正常使用。

f12查看源碼發現端倪,注冊相關的實現代碼已經被注釋掉了。
因此將注釋符號刪除,并使用注冊功能注冊了賬號

此時使用注冊功能成功注冊了一個賬號

并登錄成功。

尋找上傳接口,嘗試文件上傳。但是發現功能點似乎無法正常使用。

f12抓取上傳接口的數據包。

訪問該接口,上傳表單成功出現。

嘗試上傳正常圖片,均不能正常使用。提示都是文件大小不符合。

3.2 嘗試利用TP框架漏洞獲取權限
嘗試嘗試尋找后臺,也沒有找到。
嘗試尋找SQL注入,沒有找到。
此時發現該網站系統使用了thinkphp框架,但是具體不知道是哪個版本。
常用于獲取tp框架版本的方法都是利用報錯或者敏感文件,但是這里,似乎都沒有。
盲打一波tp5的rce,均失敗。

此時陷入瓶頸期。
想到了,該系統一定是基于tp框架開發的,但是具體是哪個CMS這里還未知,使用云悉獲取該CMS信息也失敗了。
3.3 嘗試利用cms的已知漏洞獲取網站權限和數據
此時無意間發現,上傳接口的title中,泄露了該CMS信息,該cms為pigcms。

此時搜索有關該CMS的歷史漏洞,通過cnvd平臺。

嘗試利用SQL注入漏洞,復現后均失敗。

3.4 尋找CMS源碼
注:此處找到的源碼版本不一定會和目標站點一致。
嘗試去尋找源碼。官網看了一眼,真的貴。離譜。怎么可能花錢。

通過網盤搜索,百度搜索,谷歌搜索的方式,下載了源碼。

本地環境搭建。
看著還挺像那么回事的。

確定后臺路徑。
本機后臺

目標站點后臺。

這后臺長的不怎么像,影響不大。
試了一下初始密碼,沒進去。
看了一下后臺,注入漏洞挺多的,有tp3.1的注入,也有pigcms的注入,也能文件上傳GETSHELL,也能模板注入GETSHELL。

3.5 白加黑代碼審計
3.5.1 前臺任意文件上傳GETSHELL
試了一下常規的未授權測試方法,均失敗,因此只能考慮審計出前臺漏洞了。這里用自己之前寫的一個工具,遍歷當前目錄下指定后綴的文件路徑。

將路徑文件字典導入burpsuite的intruter模塊的payload中,并去掉payload encoding前面的勾。

開始爆破。并根據response判斷哪些文件是未授權訪問的。

此時成功找到了未授權的入口文件。
并發現了兩處關于文件上傳的函數。
action_picUpload
public function action_picUpload(){ $error=0; if (isset($_FILES['thumb'])){ $photo=$_FILES['thumb']; if(substr($photo['type'], 0, 5) == 'image') { switch ($photo['type']) { case 'image/jpeg': case 'image/jpg': case 'image/pjpeg': $ext = '.jpg'; break; case 'image/gif': $ext = '.gif'; break; case 'image/png': case 'image/x-png': $ext = '.png'; break; default: $error=-1; break; } if($error==0){ $time=SYS_TIME; $year=date('Y',$time); $month=date('m',$time); $day=date('d',$time); $pathInfo=upFileFolders($time); $dstFolder=$pathInfo['path']; $dstFile=ABS_PATH.'upload'.DIRECTORY_SEPARATOR.'temp'.$ext; //the size of file uploaded must under 1M if($photo['size']>2000000){ $error=-2; return $error; } }else { return $error; } //if no error if($error==0){ $rand=randStr(4); //delete primary files if(file_exists($dstFolder.$time.$rand.$ext)){ unlink($dstFolder.$time.$rand.$ext); } if ($ext!='.gif'&&$ext!='.png'){ //save the temporary file move_uploaded_file($photo['tmp_name'],$dstFile); $imgInfo=getimagesize($dstFile); //generate new files $imageWidth=intval($_POST['width'])!=0?intval($_POST['width']):$imgInfo[0]; $imageHeight=intval($_POST['height'])!=0?intval($_POST['height']):$imgInfo[1]; bpBase::loadSysClass('image'); image::zfResize($dstFile,$dstFolder.$time.$rand.'.jpg',$imageWidth,$imageHeight,1|4,2); $ext='.jpg'; // }else { move_uploaded_file($photo['tmp_name'],$dstFolder.$time.$rand.$ext); } if (isset($_POST['channelid'])){//內容縮略圖 $channelObj=bpBase::loadAppClass('channelObj','channel'); $thisChannel=$channelObj->getChannelByID($_POST['channelid']); $articleObj=bpBase::loadAppClass('articleObj','article'); $articleObj->setOtherThumb($thisChannel,$dstFile,$dstFolder,$time.$rand,'jpg'); } if ($ext!='.gif'&&$ext!='.png'){ @unlink($dstFile); } $location='http://'.$_SERVER['HTTP_HOST'].CMS_DIR_PATH.'/upload/images/'.$year.'/'.$month.'/'.$day.'/'.$time.$rand.$ext; $error=0; } }else { $error=-1; } }else { $error=-1; } if ($error==0){ echo $location; }else { $errors=array(-1=>'你上傳的不是圖片',-2=>'文件不能超過2M',-3=>'圖片地址不正確'); echo $errors[intval($error)]; } }
action_picUpload的邏輯是,上傳的圖片文件時,name=thumb,content-type的值為switch選擇結構中的image/jpg時,指定上傳后,文件的后綴名ext是jpg。文件名的命名是隨機的,根據時間指定。
讀懂邏輯后發現,此處的action_picUpload是無法上傳文件獲取權限的。
繼續審計第二次上傳的函數。
action_flashUpload

閱讀第二個上傳函數的邏輯發現,當name的值是filepath,并且content-type的值是flash格式時,能夠上傳成功,上傳后的后綴名是由filename的文件名后綴來確定的。
構造文件上傳的poc數據包

發現上傳成功,回顯php文件路徑。
查看本地監聽的文件路徑生成情況,并確定php文件的最后路徑。

訪問后,phpinfo被成功執行。

嘗試上傳到目標站點,并上傳成功。

此時跟隊友分享喜悅,并準備周一打內網。
由于和裁判溝通后,裁判要求,漏洞盡量要周一交。(意思是周末不攻防)
并得知提交0day漏洞是有額外加分。

3.5.2 藍隊周末居然上班
等到周六后,下午訪問一下phpinfo看看。結果發現,藍隊居然上班了。phpinfo的頁面內容變成了hack.


頁面不是phpinfo?重新上傳一下,好家伙,不講武德,裁判都說休戰了,你居然給我搞事情。

這是之前已經成功執行的截圖。

離譜的一批。
繼續審計
3.5.3 數據導出+可能的任意文件寫入漏洞。
周日,開始重新審計。現在審計的思路主要是想辦法拿到數據,并進入后臺改配置,這樣只要網站不關閉,我就有的是辦法做webshell層面的權限維持,后面再做系統層面的權限維持。

private function export_database($tables,$sqlcompat,$sqlcharset,$sizelimit,$action,$fileid,$random,$tableid,$startfrom) { $dumpcharset = $sqlcharset ? $sqlcharset : str_replace('-', '', DB_CHARSET);
$fileid = ($fileid != '') ? $fileid : 1; if($fileid==1 && $tables) { if(!isset($tables) || !is_array($tables)) showMessage('請選擇要備份的表'); $random = mt_rand(1000, 9999); setCache('backupTables',serialize($tables)); } else { if(!$tables = unserialize(getCache('backupTables'))) showMessage('請選擇要備份的表'); } if($sqlcharset) { $this->db->query("SET NAMES '".$sqlcharset."';\n\n"); } $tabledump = '';
$tableid = ($tableid!= '') ? $tableid - 1 : 0; $startfrom = ($startfrom != '') ? intval($startfrom) : 0; for($i = $tableid; $i < count($tables) && strlen($tabledump) < $sizelimit * 1000; $i++) { global $startrow; $offset = 100; if(!$startfrom) { if($tables[$i]!=AUTO_TABLE_PREFIX.'session') { $tabledump .= "DROP TABLE IF EXISTS `$tables[$i]`;\n"; } $createtable = $this->db->query("SHOW CREATE TABLE `$tables[$i]` "); $create = $this->db->fetch_next(); $tabledump .= $create['Create Table'].";\n\n"; $this->db->free_result($createtable); if($sqlcompat == 'MYSQL41' && $this->db->version() < '4.1') { $tabledump = preg_replace("/TYPE\=([a-zA-Z0-9]+)/", "ENGINE=\\1 DEFAULT CHARSET=".$dumpcharset, $tabledump); } if($this->db->version() > '4.1' && $sqlcharset) { $tabledump = preg_replace("/(DEFAULT)*\s*CHARSET=[a-zA-Z0-9]+/", "DEFAULT CHARSET=".$sqlcharset, $tabledump); } if($tables[$i]==AUTO_TABLE_PREFIX.'session') { $tabledump = str_replace("CREATE TABLE `".DB_PRE."session`", "CREATE TABLE IF NOT EXISTS `".DB_PRE."session`", $tabledump); } } $numrows = $offset; while(strlen($tabledump) < $sizelimit * 1000 && $numrows == $offset) { if($tables[$i]==AUTO_TABLE_PREFIX.'session') break; $sql = "SELECT * FROM `$tables[$i]` LIMIT $startfrom, $offset"; $numfields = $this->db->num_fields($sql); $numrows = $this->db->num_rows($sql); $fields_name = $this->db->get_fields($tables[$i]); $rows = $this->db->query($sql); $name = array_keys($fields_name); $r = array(); while ($row = $this->db->fetch_next()) { $r[] = $row; $comma = ""; $tabledump .= "INSERT INTO `$tables[$i]` VALUES("; for($j = 0; $j < $numfields; $j++) { $tabledump .= $comma."'".mysql_real_escape_string($row[$name[$j]])."'"; $comma = ","; } $tabledump .= ");\n"; } $this->db->free_result($rows); $startfrom += $offset; } $tabledump .= "\n"; $startrow = $startfrom; $startfrom = 0; } if(trim($tabledump)) { $tabledump = "# time:".date('Y-m-d H:i:s')."\n# bupu auto system:http://www.bupu.net\n# --------------------------------------------------------\n\n\n".$tabledump; $tableid = $i; $filename = date('Ymd').'_'.$random.'_'.$fileid.'.sql'; $altid = $fileid; $fileid++; $backUpFolder=ABS_PATH.DIRECTORY_SEPARATOR.'backup'; if (!file_exists($backUpFolder)&&!is_dir($backUpFolder)){ mkdir($backUpFolder,0777); } $bakfile_path = ABS_PATH.'backup'.DIRECTORY_SEPARATOR.'data'.date('Y-m-d',SYS_TIME); if (!file_exists($bakfile_path)&&!is_dir($bakfile_path)){ mkdir($bakfile_path,0777); } $bakfile = $bakfile_path.DIRECTORY_SEPARATOR.$filename; if(!is_writable($bakfile_path)) showMessage('backup文件夾不可寫'); file_put_contents($bakfile, $tabledump); @chmod($bakfile, 0777); showmessage('正在備份,請不要關閉瀏覽器'." $filename ", '?m=manage&c=database&a=action_export&sizelimit='.$sizelimit.'&sqlcompat='.$sqlcompat.'&sqlcharset='.$sqlcharset.'&tableid='.$tableid.'&fileid='.$fileid.'&startfrom='.$startrow.'&random='.$random.'&allow='.$allow); } else { $bakfile_path = ABS_PATH.'backup'.DIRECTORY_SEPARATOR.'database'; //file_put_contents($bakfile_path.DIRECTORY_SEPARATOR.'index.html',''); delCache('backupTables'); showmessage('備份成功,數據備份在了“/backup/data'.date('Y-m-d',SYS_TIME).'”文件夾中'); } }
通過閱讀此處的代碼邏輯,發現指定數據表名稱,即可導出數據。
找到該sql文件路徑。

前端訪問并下載成功。

可以通過此方法,拿到后臺管理員賬號密碼。

繼續審計發現,此處的導出時,文件名可控,內容可控。


此時可以發現,可能可以截斷后綴。
嘗試截斷,并成功。

尷尬的是,文件內容并沒有寫入。

查了相關資料后發現。

用冒號截斷的確會這樣,但是用windows文件流截斷,文件也并沒有生成。這就很麻煩了。

此處也沒有想到比較好的方法去繞過。
就暫時放著了。
下午的時候嘗試去下一下數據表的文件,結果發了幾個數據包。
藍隊直接將admin.php這個入口文件給刪了。牛逼牛逼。
跟隊友說了一下情況。

3.5.4 藍隊不講武德,直接關站
晚上準備寫博客。
準備打開目標站點截幾個圖。
結果發現,藍隊直接給你關站了。笑死。

一片紅,笑死我了,和隊友吐槽大無語事件。

等周一明天舉報了。
四、總結
缺乏攻防經驗,沒有在第一天拿到權限后,做權限維持。
五、后續
跟裁判反饋后,漏洞最后通過給了一百分,麻了。不過通過這次攻防增長了不少見識大概懂了一些惡心人的做法。
以后拿到權限,一定做好權限維持,不要相信裁判的鬼話,也不要信紅藍隊會守規矩。
