ข้ามไปที่เนื้อหาหลัก

ทำความเข้าใจ LM, NTLM, NTLMv2

ทำความเข้าใจ LM, NTLM, NTLMv2 

วันนี้เราจะมาทำความเข้าใจเกี่ยวกับรูปแบบการเก็บ password ของ Windows โดยแต่ก่อนจนถึงปัจจุบันก็มีพัฒนาการมาเรื่อยๆครับ ซึ่งจะเริ่มจาก

LM (Lan Manager) hash

โดย LM นั้นเป็นรูปแบบดั้งเดิมในการเก็บ password ของ Windows ตั้งแต่ยุค 1980 ซึ่งในช่วงนั้นยังมีจำนวน charset ที่ยังจำกัดอยู่(16-bits characters) ซึ่งทำให้การ crack password นั้นทำได้ง่ายมากโดยดึงจาก SAM database บน Windows หรือว่า NTDS บน Domain Controller (Active Directory) ได้เลย
โดยขั้นตอนการเปลี่ยน password อยู่ในรูปแบบ LM hash คือ
  1. เปลี่ยนอักษรทั้งหมดเป็นตัวใหญ่
  2. หากตัวอักษรไม่ครบ 14 ตัวอักษรก็จะเติมตัวอักษรทั้งหมดให้เต็มด้วย NULL characters
  3. แบ่งเป็น 2 กลุ่ม กลุ่มละ 7 ตัวอักษร
  4. สร้าง DES key จาก character 7 ตัวทั้ง 2 กลุ่ม ก็จะได้ DES key 2 ชุด (ชุดละ 64 bit)
  5. นำ DES key ไปเข้ารหัส static string “KGS!@#$%” ด้วย DES (ECB)
  6. นำ encrypted strings ทั้ง 2 อันมาต่อกัน ก็จะได้เป็น LM Hash
เช่น สมมติ password เป็น password
  1. password => password000000
  2. PASSWORD000000
  3. PASSWOR, D000000
  4. นำ PASSWOR ซึ่งเป็น 56bit ไปแปลงเป็น 64bit โดยการใส่ parity bit เข้าไปต่อท้ายทุกๆ byte
    • DES Key ที่ได้จะเป็น
      • 0101000000100000010101000110101000110101101110100011110110100100111000001000001101110000101000011111010101010101
      • 0100010000011000000011000000011000000011100000011100000001100000000100000000010011010000101111100001001101010110
  5. นำ DES Key ไปเข้ารหัส string “KGS!@#$%” โดยใช้ Algorithm ECB จะได้เป็น 
    • e52cac67419a9a22
    • 4a3b108f3fa6cb6d
  6. ผลลัพธ์จะได้เป็น e52cac67419a9a224a3b108f3fa6cb6d

ตัวอย่าง source code สำหรับการเข้ารหัส LM Hash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <stdint.h>
#include <inttypes.h>
#include <openssl/des.h>
#include <string.h>
#include <ctype.h>
static void password_to_key(const uint8_t password[7], uint8_t key[8])
{
    /* make room for parity bits */
    key[0] =                        (password[0] >> 0);
    key[1] = ((password[0]) << 7) | (password[1] >> 1);
    key[2] = ((password[1]) << 6) | (password[2] >> 2);
    key[3] = ((password[2]) << 5) | (password[3] >> 3);
    key[4] = ((password[3]) << 4) | (password[4] >> 4);
    key[5] = ((password[4]) << 3) | (password[5] >> 5);
    key[6] = ((password[5]) << 2) | (password[6] >> 6);
    key[7] = ((password[6]) << 1);
}
char* stringToBinary(char* s) {
    if(s == NULL) return 0; /* no input string */
    size_t len = strlen(s);
    char *binary = malloc(len*8 + 1); // each char is one byte (8 bits) and + 1 at the end for null terminator
    binary[0] = '\0';
    for(size_t i = 0; i < len; ++i) {
        char ch = s[i];
        for(int j = 7; j >= 0; --j){
            if(ch & (1 << j)) {
                strcat(binary,"1");
            } else {
                strcat(binary,"0");
            }
        }
    }
    return binary;
}
static void des(const uint8_t password[7], const uint8_t data[8], uint8_t result[])
{
    DES_cblock key;
    DES_key_schedule schedule;
    password_to_key(password, key);
    DES_set_odd_parity(&key);
    DES_set_key_unchecked(&key, &schedule);
    DES_ecb_encrypt((DES_cblock*)data, (DES_cblock*)result, &schedule, DES_ENCRYPT);
}
int main()
{
char result[16];
size_t           i;
uint8_t          password1[7];
uint8_t          password2[7];
     uint8_t          kgs[] = "KGS!@#$%";
     uint8_t          hash1[8];
     uint8_t          hash2[8];
char password[]="password";
/* Initialize passwords to NULLs. */
memset(password1, 0, 7);  
memset(password2, 0, 7);
/* Copy passwords over, convert to uppercase, they're automatically padded with NULLs. */
for(i = 0; i < 7; i++)
{
if(i < strlen(password))
password1[i] = toupper(password[i]);
if(i + 7 < strlen(password))
password2[i] = toupper(password[i + 7]);
}
/* Do the encryption. */
des(password1, kgs, hash1);
des(password2, kgs, hash2);
/* Copy the result to the return parameter. */
        memcpy(result + 0, hash1, 8);
        memcpy(result + 8, hash2, 8);
//printf("Hash is %s\n",result);
printf("Hash is ");
for (size_t i = 0; i < sizeof(result); ++i) printf("%02x", result[i]);
return 0;
}

1
2
3
4
5
gcc -o test password_key.c -lssl -lcrypto
./test
Hash1 is e52cac67419a9a22
Hash2 is 4a3b108f3fa6cb6d
Hash is ffffffe52cffffffac6741ffffff9affffff9a224a3b10ffffff8f3fffffffa6ffffffcb6d

วันนี้เอาเริ่มต้นแค่นี้ก่อน เดี๋ยวมาต่อกันเรื่อง NTLM และ NTLMv2 ต่ออีกทีครับ
ส่วนวิธีการ crack นั้นในที่นี้จะใช้ John-The-Ripper, Hashcat ครับ โดยใช้คำสั่งเป็น
1
2
john --format=lm hash.txt
hashcat -m 3000 -a 3 hash.txt

NTLM และ NTLMv2 NTHash

      สำหรับ LM นั้นเป็น Format ของการเก็บ password ใน Windows ก่อนรุ่น Windows Me แต่หลังจากนั้นก็เป็น NTLM โดยเก็บใน SAM Database file ใน Windows ทั่วไป ซึ่งสามารถถูกดึงออกมาได้ด้วย Mimikatz ซึ่งบน Domain Controller (Windows Active Directory Server) ที่มีการเก็บ username, password ใน NTDS file ก็ใช้ NTLM เช่นกัน โดยปกติ Microsoft จะเรียกมันว่า “NTHash” โดย Algorithm ในการสร้าง hash คือ
1
MD4(UTF-16-LE(password))

โดยการ crack NTHash นั้นจะใช้คำสั่งเป็น
1
2
john --format=nt hash.txt
hashcat -m 1000 -a 3 hash.txt

NTLMv1

ส่วน NTLM นั้นจะแตกต่างกับ NTHash ตรงที่ NTLM นั้นเป็น protocol ที่ใช้ NTHash ในการติดต่อคุยกัน (challenge/response) ระหว่าง server และ client โดย หากเป็น NTLMv1 จะใช้ได้ทั้ง NTHash และ LM Hash ขึ้นอยู่กับ configuration ของ Windows Server
โดยการทำ Challenge จะเป็นการ random ค่า 8 ตัวอักษรจาก Server แล้วส่งไปให้กับทาง Client
โดยการทำ Response ฝั่ง Client จะเป็นดังนี้
  1. Pad ส่วนของ LM Hash หรือ NTHash ด้วย NULL byte (0,\0) ให้เป็น 21 bytes
  2. แบ่ง 21 bytes ให้เป็น string 3 ชุด ชุดละ 7 byte
  3. แปลงแต่ละชุดให้กลายเป็น 64bit DES key โดยการ add parity bit เข้าไปต่อท้าย  (เหมือนๆกับตอนที่เราทำของ LMHash)
  4. ทำการเข้ารหัส 8 byte ที่เป็น Challenge จาก Server ด้วย key แต่ละอัน ทำให้มี encrypt string 3 ชุด โดยชุดละ 8 byte
  5. เอาทั้งหมดมาต่อกันกลายเป็น 24 byte แล้วส่งกลับไปให้ Server
พอ Server ได้รับก็จะเอา password ที่มีในการถอดรหัสด้วยกระบวนการที่คล้ายๆกัน
โดยหากเป็นการ crack ตัว Hash ที่เราอาจจะดักจับมาได้ด้วยกระบวนต่างๆเช่น การใช้ Responsder ในการปลอมเป็น Server เป็นต้น สามารถทำได้โดย

NTLMv2

พอเป็น NTLMv2 ก็จะคล้ายคลึงกับ NTLMv1 ซึ่งตัว NTLMv2 นั้นสร้างมาเพื่อการเพิ่มความแข็งแกร่งของกระบวนการแลกเปลี่ยนให้มันมั่นคงมากขึ้น 
โดย NTLMv2 จะคล้ายคลึงกับ NTLMv1 แต่แตกต่างกันที่
  • NTLMv2 จะมีการส่ง response 2 แบบกลับไปยัง Server
  • เปลี่ยนจาก DES กลายเป็นใช้ HMAC-MD5 แทน
  • 1 ใน response กลับไปยัง Server มีชื่อเรียกว่า variable length client challenge ซึ่งสร้างจาก (1) เวลาขณะนั้นในลักษณะ NT Time format, (2) 8-byte random value, (3) domain name และ (4) ค่ามาตรฐานบางอย่าง
โดยเขียนสรุป Algorithm ของ NTLMv2 ได้เป็น
หากเราได้ hash ของ NTLMv2 มาจะ crack ได้โดยการใช้คำสั่งเป็น

Source::









ความคิดเห็น

โพสต์ยอดนิยมจากบล็อกนี้

วิธีใช้ Google Form ส่งข้อความเข้า LINE Notify

วิธีใช้ Google Form ส่งข้อความเข้า LINE Notify           ขั้นตอนต่อไปนี้จะข้ามส่วนของรายละเอียดบางอย่างไป ซึ่งก่อนจะทำตรงนี้ควรจะรู้แล้วว่า LINE Notify ใช้ทำอะไร และ Access Token จะเอามาจากไหน แต่จะพยายามอธิบายให้ครอบคลุมที่สุดก็แล้วกัน Update: 2019/06/10 ในท้ายบทความได้เพิ่มคำอธิบายเรื่องการส่งข้อมูลหลายกล่องข้อมูล (คอลั่ม) พร้อมกับ code ที่วนลูปข้อมูลทุกกล่อง เพื่อความสะดวกในการส่งข้อมูลในรูปแบบเดิม สร้าง Google Form วิธีสร้างก็ง่ายแสนง่าย เข้าไปที่  https://docs.google.com/forms  จากนั้น คลิกตรงเครื่องหมาย + ตามภาพ จะได้ form หน้าตาแบบนี้มา แก้ไขตามสะดวกเลย ตัวอย่างเอาแบบนี้แล้วกัน จะลองส่งข้อความคลิกที่รูป “ตา” พิมพ์ข้อความอะไรก็ได้ แล้ว กด Submit โลด กลับไปหน้า Form ของเราใน tab แรก มันก็จะมี RESPONSES เข้ามา เมื่อคลิกดูก็จะพบข้อความที่เราเพิ่งพิมพ์ไปเมื่อตะกี้ ใส่ code ใน Script Editor คลิกที่ จุด 3 จุด ด้านขวาบน แล้วเลือก  <> Script Editor จะพบหน้าเปล่าๆ ที่ไม่คุ้นเคย ตรงนี้แหละที่เราจะมาใส่ code ใ...

คาร์บอนฟุตพริ้นท์ (Carbon Footprint)

คาร์บอนฟุตพริ้นท์ ( Carbon Footprint) คาร์บอนฟุตพริ้นท์ ( Carbon Footprint) คืออะไร ในภาวะโลกร้อนที่นับวันยิ่งทวีความรุนแรงขึ้น ซึ่งสาเหตุที่สำคัญคงหนึไม่พ้นเกิดจากกิจกรรมต่างของมนุษย์เรานั่นเอง ทั้งจากการใช้พลังงาน การทำลายทรัพยากรธรรมชาติเช่น การตัดไม้ทำลายป่า การขนส่ง และการขยายตัวของภาคอุตสาหกรรม และในปัจจุบันเราจะพบว่าในหลาย ๆ ประเทศได้มีความตื่นตัวในเรื่องเกี่ยวกับภาวะโลกร้อนกันมากขึ้น และสิ่งหนึ่งที่ให้ความสนใจก็คือ การที่จะร่วมมือกันผลิตและบริโภคผลิตัณฑ์ที่เป็นมิตรกับสิ่งแวดล้อม โดยมีทั้งการเชิญให้ผู้ผลิตได้เข้าร่วมโครงการเพื่อให้ได้รับเครื่องหมายคาร์บอนฟุตพริ้นท์ และเชิญชวนให้ผู้บริโภคหันมาซื้อผลิตภัณฑ์ที่มีฉลากแสดงข้อมูลคาร์บอนฟุตพริ้นท์อีกด้วย คาร์บอนฟุตพริ้นท์ ( Carbon Footprint, CF) คือ การวัดผลกระทบสิ่งแวดล้อมด้านการเปลี่ยนแปลงภูมิอากาศ ซึ่งเกี่ยวข้องกับปริมาณการปล่อยก๊าซเรือนกระจก ( Greenhouse Gases, GHGs) จากกระบวนการผลิตสินค้าตลอดวัฎจักรชีวิต ( Product Life Cycle) โดยเริ่มตั้งแต่ การจัดหาวัตถุดิบนำไปแปรรูป ผลิต จดจำหน่าย การใช้งาน และการจัดการหลังจากผลิ...