內網滲透之Windows認證(二)

2022-08-02 18:02:15
  • 為什麼有這篇文章呢,因為我們知道平常的Web系統有註冊、登入是依賴資料庫和後端的加密解密演演算法。那麼Windows系統登入的時候是如何進行身份驗證的呢,是否也有一個類似資料庫的東西,或者就是一個單純的文字呢?
  • 參考--Windows內網協定學習NTLM篇之NTLM基礎介紹
  • Windows也有一個類似於資料的東西,存放在%SystemRoot%\system32\config\sam,裡面存放著使用者的憑證資訊,當然這肯定不是明文,不然Windows這麼寫也太不安全了。這裡的加密演演算法不同於常見的MD5,加密後的資料有兩種分別為LM HashNTLM Hash

LM Hash

  • LM Hash全稱LAN Manager Hash,由IBM設計一般用於Windows XPWindows 2000Windows 2003 這一類系統中。加密演演算法如下。
  • 密碼長度不能超過14個字元。
  • 密碼轉換為大寫,再轉換成16進位制的字串,沒有28位元長度的,在右邊加0。
  • 再將十六進位制的字串分為兩組14位元的字串。
  • 再將這兩組14位元的字串進行十六進位制轉二進位制,轉換完成後不滿足56位的在左邊加0。
  • 兩部分分別劃分為每組七位,在其末尾加0,再分別轉換為十六進位制。
  • 最後將這兩組資料作為DES加密所需的Key,KGS!@#$%作為需加密的字元,將DES加密後的資料依次拼接。
  • 這裡借用zjun的指令碼。
import binascii
import codecs
from pyDes import *

def DesEncrypt(str, Key):
    k = des(Key, ECB, pad=None)
    EncryptStr = k.encrypt(str)
    return binascii.b2a_hex(EncryptStr)

def ZeroPadding(str):
    b = []
    l = len(str)
    num = 0
    for n in range(l):
        if (num < 8) and n % 7 == 0:
            b.append(str[n:n + 7] + '0')
            num = num + 1
    return ''.join(b)

if __name__ == "__main__":
    passwd = sys.argv[1]
    print('你的輸入是:', passwd)
    print('轉化為大寫:', passwd.upper())

    # 使用者的密碼轉換為大寫,並轉換為 16 進位制字串
    passwd = codecs.encode(passwd.upper().encode(), 'hex_codec')
    print('轉為 hex:', passwd.decode())

    # 密碼不足 28 位,用 0 在右邊補全
    passwd_len = len(passwd)
    if passwd_len < 28:
        passwd = passwd.decode().ljust(28, '0')
    print('補齊 28 位:', passwd)

    # 28 位的密碼被分成兩個 14 位部分
    PartOne = passwd[0:14]
    PartTwo = passwd[14:]
    print('兩組 14 位的部分:', PartOne, PartTwo)

    # 每部分分別轉換成位元流,並且長度為 56 位,長度不足用 0 在左邊補齊長度
    PartOne = bin(int(PartOne, 16)).lstrip('0b').rjust(56, '0')
    PartTwo = bin(int(PartTwo, 16)).lstrip('0b').rjust(56, '0')
    print('兩組 56 位位元流:', PartOne, PartTwo)

    # 兩組分別再分為 7 位一組末尾加 0,再分別組合成新的字元
    PartOne = ZeroPadding(PartOne)
    PartTwo = ZeroPadding(PartTwo)
    print('兩組再 7 位一組末尾加 0:', PartOne, PartTwo)

    # 兩組資料轉 hex
    PartOne = hex(int(PartOne, 2))[2:]
    PartTwo = hex(int(PartTwo, 2))[2:]
    if '0' == PartTwo:
        PartTwo = "0000000000000000"
    print('兩組轉為 hex:', PartOne, PartTwo)

    # 16 位的二組資料,分別作為 DES key 為"KGS!@#$%"進行加密。
    LMOne = DesEncrypt("KGS!@#$%", binascii.a2b_hex(PartOne)).decode()
    LMTwo = DesEncrypt("KGS!@#$%", binascii.a2b_hex(PartTwo)).decode()
    print('兩組 DES 加密結果:', LMOne, LMTwo)

    # 將二組 DES 加密後的編碼拼接,得到 LM HASH 值。
    LM = LMOne + LMTwo
    print('LM hash:', LM)

  • 可以看出密碼長度小於7時,後面加密的資料是固定的,均為aad3b435b51404ee,因此其加密是不安全的。

NTML Hash

  • NTML Hash全稱NT LAN Manager , 目前 Windows 基本都使用 NTLM hash ,一個32位長度的字串。支援Net NTLM認證協定及本地認證過程中的關鍵憑據。加密演演算法如下:
  • 密碼轉換為十六進位制
  • Unicode編碼
  • MD4加密
  • Python指令碼如下:
import hashlib
import binascii
import sys

print(binascii.hexlify(hashlib.new("md4", sys.argv[1].encode("utf-16le")).digest()).decode())

  • 123456經過加密後則為32ed87bdb5fdc5e9cba88547376818d4

Windows本地認證

  • winlogon.exe -> 接收使用者密碼 -> lsass.exe -> 比對sam表。
  • winlogon就是登陸介面,接受使用者密碼之後會傳送明文到lsass.exelsass.exe會儲存一份明文,然後加密明文和sam表的hash做比對,判斷是否可以登陸。
  • Windows Logon Process(即 winlogon.exe),是Windows NT 使用者登陸程式,用於管理使用者登入和退出。LSASS用於微軟Windows系統的安全機制。它用於本地安全和登陸策略。
  • 這裡注意如果打了修補程式KB2871997,或者機器是win2012之後,則不會儲存明文密碼了。

NTLM認證協定

  • 什麼是NTLM認證協定呢?和NTLM Hash又有什麼區別呢?NTLM是一種網路認證協定,它是基於挑戰(Chalenge)/響應(Response)認證機制的一種認證模式。NTLM 網路認證協定是以 NTLM Hash 作為根本憑證進行認證的協定。
  • 在內網滲透中,經常遇到工作組環境,而工作組環境是一個邏輯上的網路環境(工作區),隸屬於工作組的機器之間無法互相建立一個完美的信任機制,只能對等,是比較落後的認證方式, 沒有信託機構。
  • 假設A主機與B主機屬於同一個工作組環境,A想存取B主機上的資料,需要將一個存在於B主機上的賬戶憑證傳送至B主機,經過認證才能夠存取B主機上的資源。
  • 早期SMB協定在網路上傳輸明文口令。後來出現LAN Manager Challenge/Response驗證機制,簡稱LM,它是如此簡單以至很容易就被破解,現在又有了NTLM以及Kerberos
  • 認證流程分為三部分,分別是:協商質詢身份驗證

協商

  • 使用者端向伺服器傳送協商請求,包含使用者名稱、密碼、認證協定版本等資訊。

質詢

  • 伺服器接收到使用者端傳送到協商資訊,這時伺服器會生成一個亂數,叫做challenge,這裡的不同的協定亂數長度不同,NTLM V1是8位元,NTLM V2是16位元。
  • 伺服器將登陸的使用者對應的NTLM Hash加密challenge,得到Net NTLM Hash,和生成的challenge一起傳送給使用者端。

驗證

  • 使用者端收到challenge後,將使用者的hash與challenge進行加密運算得到resposne,將username、response、challenge傳送給伺服器,最後伺服器進行校驗返回認證結果。

WireShark

  • 知道了基本原理自己實戰試試