某OA系统的审计(新手学习)

admin 2024年1月6日12:27:38评论28 views字数 3531阅读11分46秒阅读模式
原文地址:https://forum.butian.net/share/2448原文作者:Duck

一次偶然机会,找人要了套源码,是Stuts2和spring框架混用的系统,比较简单适合入门学习

0x01 SQL注入

该项目是基于mvc框架开发的,与数据库交互的代码在DAO目录下,在core/base/dao中存在IBaseDao类属于该项目的数据库操作的基类

某OA系统的审计(新手学习)

根据其定义的函数名,都能看出是传入SQL语句进行查询,我们找的他的实现类

某OA系统的审计(新手学习)

可以看到其方法实现也是传入SQL语句字符串直接它通过hibernateTemplate API直接进行查询。其实现SQL查询的方法也有很多。

某OA系统的审计(新手学习)

同时我们发现该baseDao类有七百多个继承者

某OA系统的审计(新手学习)

跟进去发现基本都继承了BaseDao的方法,并没有进行重载,于是我们全局搜索相关危险方法,这里以sqlFind方法为例

某OA系统的审计(新手学习)

发现在构造SQL语句是用了?占位符,这样的语法是无法进行注入的,于是我们寻找直接拼接参数到SQL语句字符串中的方法

某OA系统的审计(新手学习)

根据sqlFind方法的重装情况,当参数param为空则不会进行占位符参数绑定,于是我们可以缩小搜索范围

向下翻找就找到在BaseDataService类中listBaseDataByFlowId方法,存在直接拼接参数构造SQL语句的情况,

某OA系统的审计(新手学习)

这里直接将flowId等参数拼接到语句中调用sqlFind方法进行数据库查询,我们向上找是哪个controller调用该危险方法

最终定位在BaseDataController中的listBaseDataByFlowId方法中

某OA系统的审计(新手学习)

这里直接将请求中type和flowId传入service层进行查询,我们构造该接口的请求

某OA系统的审计(新手学习)

提示我们没有登录,应该是spring进行了拦截处理

0x02 权限绕过

我们查看spring配置文件,找的拦截器的实现类

某OA系统的审计(新手学习)

可以看到该项目有个全局拦截器PermissionInterceptor,我们跟进到里面,根据spring拦截器实现原理直接来到prehandle方法,主要处理逻辑如下

某OA系统的审计(新手学习)

该拦截器定义了两个成员数组UN_LOGIN_EXPOSE_CONTROLLERSUN_LOGIN_EXPOSE_SERVLET_PATH,当我们请求的控制器或者接口url在这两个数组中是会放行我们的请求,也就是定义了白名单请求,很遗憾我们的listBaseDataByFlowId方法的请求不在白名单中,会进入if判断。

首先判断session中是否有登录凭证(显然没有),如果没有会获取请求中jwt参数的值进行JSON Web Token的认证,检查token的有效性。

看到jwt 认证,很快就想到会不会硬编码jwt 密钥,因为在初期翻配置文件中没看到有jwt 密钥的定义

于是我们跟进到jwtCheck方法,果然验证了我们的猜想

某OA系统的审计(新手学习)于是我们根据密钥生成token

某OA系统的审计(新手学习)

带着jwt token访问目标接口,发现不在提示未登录

某OA系统的审计(新手学习)

根据配置文件该系统是属于了sql server数据库,于是构造语句

flowId = 1'+(case when (1=1) then '' else char(1/0) end)+'

当为正是,正常返回

某OA系统的审计(新手学习)

为假是进行char(1/0)构造报错会返回500

某OA系统的审计(新手学习)

证明存在SQL注入

0x03 总结

1、mvc框架中service层一般是负责sql语句的封装,dao层一般负责与数据库交互,所以我们可以在dao层中找直接执行sql语句的方法,在service层调用可疑查询方法处查看sql语句构造情况,找的可能存在sql注入的点,向上找的controller层的具体调用接口

2、主要还是看鉴权,通过配置文件找的鉴权类,如使用了request.getRequestUri等危险方法来获取请求url做判断时很容易就被bypass,或是看jwt等第三方鉴权组件硬编码的问题

0x04 另外发现

1、未授权文件上传

在鉴权文件中存在白名单controller类和接口数组UN_LOGIN_EXPOSE_CONTROLLERSUN_LOGIN_EXPOSE_SERVLET_PATH,我们关注一下

某OA系统的审计(新手学习)

翻找未授权类时在appCallController中,有文件操作的方法

@RequestMapping({"uploadFile"})    @ResponseBody    @Transactional(        readOnly = false    )    public String uploadFile(@RequestParam(value = "file",required = false) MultipartFile file) {        try {            String id = UUIDUtils.getuid();            String extension = StringUtils.getFilenameExtension(file.getOriginalFilename());            if (StringUtils.hasText(extension)) {                extension = "." + extension;            }
String fileUrl = "../xxx_Ueditor_File/app/files/" + id + extension; String savePath = getCurRequest().getSession().getServletContext().getRealPath(fileUrl); File saveFile = new File(savePath); if (!saveFile.exists()) { saveFile.mkdirs(); }
file.transferTo(saveFile); APPFiles af = new APPFiles(); af.setFileLength(file.getSize()); af.setId(id); af.setFilePath(saveFile.getAbsolutePath()); af.setFileName(file.getOriginalFilename()); af.setTime(new Date()); af.setFileType(file.getContentType()); af.setMsgId(""); af.setType(2); this.dao.save(af); return id; } catch (Exception var8) { var8.printStackTrace(); return ""; } }

该方法是获取随机数id,然后取到表单上传中的文件名后缀名,然后将其保存在/xxx_Ueditor_File/app/files/目录中,最后讲随机数id返回给前端,因为未对文件后缀名做限制导致可以上传jsp文件

某OA系统的审计(新手学习)

某OA系统的审计(新手学习)

成功上传文件

2、未授权SQL注入

该项目除了用到spring框架外还用到了st2框架,在struts.xml查看配置信息,这里也定义了拦截器

某OA系统的审计(新手学习)

具体实现逻辑在doIntercept()方法中

某OA系统的审计(新手学习)

可以看到这里也是定义白名单方法名和类名

private Set<String> UN_LOGIN_EXPOSE_METHODS = new HashSet<String>() {        {            this.add("saveStaffInfo");            this.add("updateStaffInfo");            this.add("listRegionTree");            this.add("CostCloudProject");            ...            this.add("handle");            this.add("listProjAuditQGC");            this.add("getlistProjAuditDataQGC");        }    };    private static List<Class<?>> TEMP_USER_EXPOSE_ACTIONS = new ArrayList<Class<?>>() {        {            this.add(IndexAction.class);            ...        }    };    private static List<String> TEMP_USER_EXPOSE_METHODS = new ArrayList<String>() {        {            this.add("showPhoto");            this.add("download");        }    };

看到白名单方法中有些get操作的函数,如getlistProjAuditDataQGC看名称是获取list数据,跟进其中

某OA系统的审计(新手学习)

可以看到调用findByBusinessByQueryQGC方法进行查询,来到findByBusinessByQueryQGC方法实现,可以看到其是获取请求中的特定参数,并将其直接拼接在sql变量中

某OA系统的审计(新手学习)

最后调用sqlFindPage拼接sql变量执行

某OA系统的审计(新手学习)

某OA系统的审计(新手学习)此处也是存在SQL注入

某OA系统的审计(新手学习)

某OA系统的审计(新手学习)

原文始发于微信公众号(WebSec):某OA系统的审计(新手学习)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月6日12:27:38
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   某OA系统的审计(新手学习)https://cn-sec.com/archives/2370625.html

发表评论

匿名网友 填写信息