java代码审计小tips

审计

1
2
3
4
5
6
1、找最新版的版本较低的,例如1.11.2
2、找github star不多的
3、找源码总容量小的
1、如果cms版本高,说明开发有经常维护,同时也说明里面的简单漏洞已经被发现并且被提交并整改了。(具体这个可以看看CMS官网放出的更新日志)
2、为什么找github star不多的cms?很简单,使用的人不多,没人标星,功能也比较少。
3、源码少容易看啊,而且想着源代码就那么点,看着也不会太心累。

-javaagent:G:\dongtai-agent.jar

接下来我要突破瓶颈了 不搞那些浅显的东西了 至于低级的东西这里也不会讲了

接下来我将会学习涵盖各种cc链 各种代码框架rce流程

各种骚姿势。各种内存码写法 各种利用方式。为了节约时间 那些基础的东西也不讲了

这里只有精华

1.combo

2.重点看这个文章里运

用了哪些技巧,比如如何绕过过滤、用了哪些偏门gadget。其次关注这个产品、这个组件它的整体框架逻辑是什么样的,他有哪些有趣的功能机制是可以拿来串联链。

3.我们可以忽略什么?繁琐的各种函数跟进,根本毫无意义,随便看看就行了,除非你也专门研究这个产品的0day挖掘那么你可以细致的看一看,如果你想用它来挖别的产品那么你可以直接忽略掉很多没有用的函数跟进,只看那些对数据有一定复杂过滤操作的典型函数就行了。

4.即使我不懂Go,我知道我需要找到什么、需要去串联什么,剩下的不过是百度百度看不懂的语法罢了。总之就是一句话:just do it

-javaagent:G:\桌面文件夹\任务\第三阶段\作业二\审计框a架靶场\dongtai-agent.jar

image-20220601115349651image-20220601115521088

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
53
54
55
56
57
58
59
60
61
密码硬编码最容易找,直接用 Sublime Text 打开项目目录,然后按 Ctrl + Shift + F 进行全局 搜索 password key关键词:

反射型 XSS 一般 fortify 一般都能扫描出来

存储型 XSS 审计方法:方法有主要有两种: 1. 全局搜索数据库的插入语句(关键词:insert,save,update),然后找到该插入语句所属的方 法名如(insertUser()),然后全局搜索该方法在哪里被调用,一层层的跟踪。直到 getParamter()或者getpara(有的工程师为了方便用的getpara)方法获取请求参数的地方停止,如果没有全局 XSS 过滤器,跟踪的整个流 程都没有对获取的参数过滤,则存在存储型 XSS。

\2. 从 getParameter 关键词开始 ,跟踪请求参数,直到插入数据库的语句,如果中间没有过 滤参数,则存在存储型 XSS。

SQL 注入一般 fortify 一般都能扫描出来 手动找的话,一般直接搜索 select、update、delete、insert 关键词就会有收获 如果 sql 语句中有出现+ append、 $() getConnection连接数据库# 等字眼,如果没有配置 SQL 过滤文件,则判断存 在 SQL 注入漏洞
limit,orderby后面是不能预编译

当找到某个变量关键词有 SQL 注入漏洞时,还可以直接全局搜索那个关键词找出类似漏洞 的文件,

任意文件下载 审计方法:全局搜索以下关键词 fileName filePath getFile getWriter

6 任意(越权)文件删除 审计方法:任意文件删除漏洞搜索以下关键词可以找到: delete, UserController deleteFile,fileName ,filePath

文件上传 审计方法: 文件上传可以搜索以下关键词:(需注意有没有配置文件上传白名单) upload,write,fileName ,filePath 在查看时,主要判断是否有检查后缀名,同时要查看配置文件是否有设置白名单或者黑名单

命令注入 审计方法:可以搜索以下关键词: getRuntime,exec,cmd,shell

缓冲区溢出 审计方法:主要通过搜索关键词定位,再分析上下文 可搜索以下关键字:
strcpy,strcat,scanf,memcpy(md5memcpy不存在缓冲区溢出),memmove,memeccpy Getc(),fgetc(),getchar;read,printf

0XML 注入 审计方法: XML 解析一般在导入配置、数据传输接口等场景可能会用到,可通过搜索以下关键字定位: DocumentBuilder、XMLStreamReader、SAXBuilder、SAXParser、SAXReader 、XMLReader、 SAXSource 、TransformerFactory 、SAXTransformerFactory 、SchemaFactory 涉及到 XML 文件处理的场景可留意下 XML 解析器是否禁用外部实体,从而判断是否存在 XXE

日志记录敏感信息 审计方法: 通过搜索关键词 log.info logger.info 来进行定位 (怎么审计?)

URL跳转 审计方法:通过搜索以下关键词定位: sendRedirect、setHeader、forward 需注意有没有配置 url 跳转白名单

敏感信息泄露及错误处理 审计方法:查看配置文件是否配置统一错误页面(在pm.xml查找是否含有errorpage或者404.jsp 500.jsp等醒目代码),如果有则不存在此漏洞,如果没有再通过 搜索以下关键词搜索定位, Getmessage、exception

反序列化漏洞 审计方法: Java 程序使用 ObjectInputStream 对象的 readObject 方法将反序列化数据转换为 java 对象。 但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化 产生非预期的对象,在此过程中执行构造的任意代码。 反序列化操作一般在导入模版文件、网络通信、数据传输、日志格式化存储、对象数据落磁 盘或 DB 存储等业务场景,在代码审计时可重点关注一些反序列化操作函数并判断输入是否 可控,如下: ObjectInputStream.readObject ObjectInputStream.readUnshared XMLDecoder.readObject Yaml.load XStream.fromXML ObjectMapper.readValue JSON.parseObject

不安全组件暴露 审计方法: 通过查看配置文件 AndroidManifest.xml,查看属性有没有配置 false AndriodManifest.xml 文件中,代码 24 行处 activity 组件添加属性,没有配置 false, 默认组件可被导出

.1CSRF
审计方法:通过查看配置文件有没有配置 csrf 全局过滤器,如果没有则重点看每个操作前有
没有添加 token 的防护机制
在 Smpkpiappealcontroller.java 中 200 处,直接用用 ids 控制删除操作,而没有添加防
csrf 的随机 token 验证检查,存在 csrf 漏洞。

越权操作
审计方法:重点关注用户操作请求时查看是否有对当前登陆用户权限做校验从而确定是否存
在漏洞,有些厂商会使用一些主流的权限框架,例如 shiro ,spring security 等框架,那么需要
重点关注框架的配置文件以及实现方法

会话超时设置
审计方法:
Javaweb 应用会话超时设置一般有俩种方法:
一是在配置文件 web.xml 设置
二是通过 java 代码设置


敏感数据弱加密
审计方法:
敏感数据弱加密主要看数据传输中的加密方法,一般写在工具类 util 中以下文件中为 base64 编码方法

未授权 init dofilter destory @WebInitParam
yf-exam-lite\exam-api\src\main\java\com\yf\exam\config\ShiroConfig.java 查看是否有shiro配置不当的未授权

application.yml可以找到框架包

1
2
3
4
5
6
网站路由
控制器(app/Http/Controllers)
中间件(app/Http/Middleware)
Model(app/Models)
网站配置(config)
第三方扩展(composer.json)

usercontroller等各种controller中的getmapping都可以看一下存不存在缺少过滤

filename参数一般出现在Content-Dispostion:

一般sql查询都在service层

1
isAbsolute() 判断抽象文件是不是绝对路径

分析新的补丁去反向查找历史漏洞

幽灵代码

1.AOP

很多java漏洞的修复没有用到任何过滤,却被修复了 这就是java的幽灵代码 和AOP等有很大关系 多看一看这些注解代码image-20220607143601141

奇安信攻防社区-浅析JAVA代码审计中的“幽灵代码” (butian.net)

2.拦截器(Interceptor)image-20220607151242486

跟进代码的话是看不到拦截的 跟进注释也没用

只能主动搜素Interceptor 或 addInterceptor

然后找到拦截器 然后找到相似方法image-20220607151256643

跟进找到拦截方法image-20220607151312690

3.Fliter

先找前面两个 没找到就只能是这个了

到web.xml里面搜索filterimage-20220607152104885

下面那个表示只过滤secret

这种通用逻辑不仅可以处理权限类型的问题,也可以实现SQL注入、命令注入、XSS等各种漏洞关键字过滤。

1、在java安全开发中若需要用到对xml进行解析的话,应考虑xml组件默认有没有禁用外部实体引用或者其他安全问题,针对补充安全配置以防止功能点在引用到不安全的xml解析器的时候引发一系列的安全问题

有些安全人员开发了新的代码用了新的java版本后 没有向下顾虑java低版本的安全性 可能造成漏洞

Runtime是调用的ProcessBuilder
而ProcessBuilder是调用的ProcessImpl
所以上面三种方式本质都是调用ProcessImpl创建进程,命令执行

工控段有很多命令执行 一定要抓包改着都试一试

1
2
3
如果找到了不稳定的文件上传点,可以用一个文件包含来和上面这段代码中的 删除 操作进行竞争,在文件被删除之前包含它,来达到执行代码的效果(因为需要条件竞争,可以考虑把这个上传包放到 intruder 里重放个几百次,然后在上传的过程中,去尝试包含 /tmp/TempClass.php ,来达到竞争的效果。)
https://xz.aliyun.com/t/9319
一旦包含成功,那么在实例化 TempClass 的时候,会写入一个新的 TempClass2,这下可没有代码会去 unlink(删除) 它了,可以被稳定的利用。
1
在js找相关接口 上传的话就看有没有type: 'POST'啥的
1
有的时候尝试访问之后发现这个上传接口不能随意访问,所以还得从程序入口开始审计哪里做了鉴权。鉴权的话找找hook类
1
2
内省一个实际就是获取到这个Bean相关的所有方法

1
2
3
如果发现有反序列化漏洞的话(使用了低版本的cc链)

直接找readobject
1
2
3
4
5
如果发现有log4j的话(使用了低版本的log4j链)、
寻找漏洞利用点,搜索有没有存在参数可控的 logger.error

只要参数可控 就算多重参数 选取其中一个可控的就行
即使参数加密 我们反加密就行
1
2
3
4
上传漏洞下断点的位置
HttpServletRequest request = getRequest();有点Java知识的人都认识这个,所以第一个断点设置在这里。
第二个断点,审计的上传漏洞,肯定设置在上传方法里
比如: responsedata = fm.add()
1
先黑盒并抓包判断访问位置,然后白盒确定过滤和防护等并绕过
1
ssti模板注入 如framwork 注意检查大部分国产模板

简单写个payload

1
2
3
4
5
6
我们且看第一行,按照上面给出简单案例方法,我们应该这样子就可以了@java.lang.Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(newInstance(),"calc")
但是直接String.class直接写模板是找不到的,所以我们得继续构造payload,将String.class转化@java.lang.Class.forName("java.lang.String")的形式,然后payload就变成下面这样子了。@java.lang.Class.forName("java.lang.Runtime").getMethod("exec",@java.lang.Class.forName("java.lang.String")).invoke(newInstance(),"calc")
照道理上面就可以直接使用了,但是呢Runtime类没有无参构造方法,因此不能使用newInstance()方法来实例化。只能通过调用getRuntime()方法来进行实例化。所以newInstance()得替换成@java.lang.Class.forName("java.lang.Runtime").getMethod("getRuntime",null)最终payload就变成了下面这样子。
${@java.lang.Class.forName("java.lang.Runtime").getMethod("exec",@java.lang.Class.forName("java.lang.String")).invoke(@java.lang.Class.forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null),"calc")}

遇到使用了模板的解析CMS可以根据模板解析语言尝试执行命令,若遇到函数警用的情况可以尝试一些Bypass方法,比例一些反射、反序列化、字节码修改等。SSTI注入难的其实如何构造Payload,构造好了之后一切自然而然了。
1
2
黑盒中f12网络的各个显示的链接 都可以点一下 长一点的链接优先,然后跟进白盒

1
2
3
前台随便审一下就行,主要是看下有没有权限,并记下记录,万一后面后台rce要用到
审的时候一个流程一个流程来 每个流程的小流程都写一下流程

内存码

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
Agent内存码篇

由于实际环境中我们通常遇到的都是已经启动着的,所以 premain 那种方法不合适内存马注入,所以我们这里利用 agentmain 方法来尝试注入我们的内存马

由于某些中间件(例如nginx)只记录GET请求,使用POST方式发送数据会更加隐蔽。

由于在Filter层过滤了http请求,访问任意的路由都可以执行恶意代码,为了隐蔽性不建议使用不存在的路由。

agent可以注入多个,但是相同类名的transformer只能注入一个,所以要再次注入别的agent的时候记得更改一下类名。

这种内存马一旦注入到目标程序中,除了重启没有办法直接卸载掉,因为修改掉了原本的类的字节码。

既然如此,那我再把它改回去不就得了嘛。这就是我为什么选择doFilter方法的原因——逻辑简单,方便还原。它的逻辑只是调用了internalDoFilter()方法(简单来说)。还原就只需要setBody()即可:

拓展、
当我们能够改变类的字节码,那能做的事情可多了去了,下面我提出两个例子,抛砖引玉。

1.路由劫持
再来假设这么一个情况:拿下来了站点A,同时其他的资产暂时没有更大的收获,需要使用其他方法来扩展攻击面。在A的/login中使用了/static/js/1.js,那就可以劫持这个路由,回显给他恶意的js代码。
实现的话,只需要在start.txt也就是即将插入的代码块中,判断一下当前访问的路由。
String uri = request.getRequestURI();
if (uri.equals("/static/js/1.js")) {
response.getWriter().write([恶意js代码]);
return;
}
那么当访问到/login的时候,浏览器发现引用了外部js——/static/js/1.js,就会去请求它,然而请求被我们修改后的ApplicationFilterChain#doFilter()拦截,返回了一个虚假的页面,导致资源被“替换”,恶意代码发挥作用。

2.替换shiro的key
在解析rememberMe的时候,先将其base64解码,然后使用AES解密,在AES解密的时候,会调用org.apache.shiro.mgt.AbstractRememberMeManager#getDecryptionCipherKey(),更改掉这个函数的返回值,就可以更改解密的密钥。实现也很简单,只需要改掉上面的常量和start.txt即可:


还有就是之前看大哥们说过,在有的环境下agent内存马注入之后网站会崩掉,听他们说是有可能因为虚拟内存不够了而导致的,所以具体使用的话还是需要事先斟酌一下
还有就是关键类寻找不对等情况也有可能导致网站被打挂

选中类按F4能够知道此类的长继承关系

几个关于断点调试的小技巧

1.断点打上后右键断点:b:可以编辑 不如设置x=50就能断点到x=50之前所有的回显 不用自己手动一次一次放过

2.热重载 边断点调试边改代码

3.多线程往往执行都是无顺序的 因为是多线程 那么其中如果为了打断点只要回显一个线程的所有报文 应该打开调试-窗体-线程

就能看到所有线程,且每个线程会有对应的id 我们只需要右键断点编辑其中的筛选器设置“thread=‘线程id’”


java代码审计小tips
http://example.com/java代码审计小tips.html
Author
CDxiaodong
Posted on
September 2, 2022
Licensed under