openwall / john

John the Ripper jumbo - advanced offline password cracker, which supports hundreds of hash and cipher types, and runs on many operating systems, CPUs, GPUs, and even some FPGAs
https://www.openwall.com/john/
Other
10.32k stars 2.1k forks source link

Add support for more network hashes #2933

Closed kholia closed 6 years ago

kholia commented 6 years ago
Old related tasks
New things

Samples,

kholia commented 6 years ago

Current status,

$ tshark -q -Xlua_script:eapmd5tojohn.lua -r radius_localhost.pcapng
steve:$chap$103*ff0bf1d6e401a9cbe5b46eb943e5549a*c76e1d28726fd1c0cb671a5424168d26
steve:$chap$113*ba0bf4a7e7177359caa52e7eb10d9d0b*36d93b94f142714e95061613640ed36d

Packets 1 to 8 (EAD-MD5) are successfully handled.

Thanks to Wireshark, we don't have to worry about what the lower layers in the packet look like.

kholia commented 6 years ago

WLCCP uses LEAP, and such hashes can be cracked with the netntlm format.

$ cat hash
WDSUser:$NETNTLM$900d74be3b382664$24ae720f571ddcfdd74df0fc85f9aaf0a86c594a957b2078
$ ../run/john hash
Warning: detected hash type "netntlm", but the string is also recognized as "netntlm-naive"
Use the "--format=netntlm-naive" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (netntlm, NTLMv1 C/R [MD4 DES (ESS MD5) 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
123qwe           (WDSUser)

From https://github.com/joswr1ght/asleap,

...
By calculating all 2^16 possibilities of the last 8 bytes of the response
value, we can derive the last 2 bytes of the NT hash (HB15, HB16).  With the
last two bytes of the NT hash, we can significantly reduce the number
of potential matches in our dictionary file.

Can we use this technique by extending the hash format slightly?

Code for this technique,

int gethashlast2(struct asleap_data *asleap_ptr)
{

        int i; 
        unsigned char zpwhash[7] = { 0, 0, 0, 0, 0, 0, 0 };
        unsigned char cipher[8]; 

        for (i = 0; i <= 0xffff; i++) {
                zpwhash[0] = i >> 8;
                zpwhash[1] = i & 0xff;

                DesEncrypt(asleap_ptr->challenge, zpwhash, cipher);
                if (memcmp(cipher, asleap_ptr->response + 16, 8) == 0) {
                        /* Success in calculating the last 2 of the hash */
                        /* debug - printf("%2x%2x\n", zpwhash[0], zpwhash[1]); */
                        asleap_ptr->endofhash[0] = zpwhash[0];
                        asleap_ptr->endofhash[1] = zpwhash[1];
                        return 0;
                }
        }

        return (1);
}

This needs to be done only one time for each hash.

kholia commented 6 years ago

After PR https://github.com/magnumripper/JohnTheRipper/pull/2943,

$ tshark -q -Xlua_script:radius2john.lua -r radius_localhost.pcap
steve:$chap$168*95bbe85b56ad0aa36dd80f9b7c59067d*0574ae2c413a393f07b5564984bda740
magnumripper commented 6 years ago

Good stuff 👍

kholia commented 6 years ago

I am thinking of removing eapmd5tojohn.c. It seems that eapmd5tojohn.lua works better and does a more through job.

kholia commented 6 years ago

This ticket is mostly done now. I will double-check if something more can be added to it.

kholia commented 6 years ago

More items,

BIND "rndc" notes,

$ rndc status  # bad password
rndc: decode base64 secret: bad base64 encoding

$ rndc status  # good password
...
CPUs found: 4
worker threads: 4
UDP listeners per interface: 3
number of zones: 102
debug level: 0
xfers running: 0
xfers deferred: 0
soa queries in progress: 0
query logging is OFF
recursive clients: 0/0/1000
tcp clients: 0/100
server is up and running
kholia commented 6 years ago

DHCP OMAPI hashes (different from the "delayed authentication" stuff),

$ cat dhcpd.conf
#
# DHCP Server Configuration file.
#   see /usr/share/doc/dhcp*/dhcpd.conf.example
#   see dhcpd.conf(5) man page
#

subnet 10.0.0.0 netmask 255.255.255.0 {
        option routers                  10.0.0.254;
        option subnet-mask              255.255.255.0;

        option domain-name              "internal";
        option domain-name-servers       8.8.8.8;

    range 10.0.0.10 10.0.0.100;
}

omapi-port 7911;
omapi-key omapi_key;

key omapi_key {
     algorithm hmac-md5;
     secret "b3BlbndhbGw=";
}

$ omshell
> server localhost
> key omapi_key b3BlbndhbGw=
> connect
obj: <null>
> new host
obj: host
> set ip-address = 192.168.4.50
obj: host
ip-address = c0:a8:04:32
> create
can't open object: connection reset by peer
obj: host
ip-address = c0:a8:04:32

This should generate traffic with the "OMAPI hashes".

The https://github.com/CygnusNetworks/pypureomapi project also offers a great way to test OMAPI stuff.

kholia commented 6 years ago

Simple rndc auth implementation,

https://fossies.org/linux/misc/dns/bind9/9.11.2/bind-9.11.2.tar.gz/bind-9.11.2/bin/python/isc/rndc.py.in

The Wireshark dissector for rndc packets is not that great currently.

kholia commented 6 years ago

It would be awesome if someones has information on DHCP "delayed authentication" feature (RFC 3118). I am looking for .pcap files with such traffic and with known password(s).

kholia commented 6 years ago

Director Response Protocol (DRP) -> Protocol used by the DistributedDirector feature in IP routing on Cisco devices. This uses port 1974, and supports authentication (Keyed MD5).

kholia commented 6 years ago

https://www.pentestpartners.com/security-blog/how-to-crack-private-apn-keys-with-hashcat/

Can we already extract PPP CHAP hashes from such .pcap files?

apn2

Update:

It would be really hard to get such a .pcap sample.

kholia commented 6 years ago

Quick notes so that I don't forget.

kholia commented 6 years ago

Tracing TSIG (DNS),

$ cat update.txt 
server ipa.example.com
debug yes
zone example.com.
update add subdomain.example.com 60 A 127.0.0.1 
show
send

$ gdb --args nsupdate -y update-key:MTIzNDU2Nzg= update.txt 
(gdb) break isc_hmacmd5_init
(gdb) r
Starting program: /usr/local/bin/nsupdate -y update-key:MTIzNDU2Nzg= update.txt
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;example.com.           IN  SOA

;; UPDATE SECTION:
subdomain.example.com.  60  IN  A   127.0.0.1

Sending update to 192.168.122.142#53
[Switching to Thread 0x7ffff4c67700 (LWP 10722)]

Breakpoint 1, isc_hmacmd5_init (ctx=ctx@entry=0x7ffff7f960a8, key=key@entry=0x7ffff7f98fd0 "12345678", len=len@entry=64) at hmacmd5.c:250
250 {

https://github.com/miekg/dns/blob/master/tsig.go saves quite some effort in understanding what all data is hashed.

Also see RFC 2845, section 3.4.2. TSIG Variables.

Full GDB trace ->

$ gdb --args nsupdate -y update-key:MTIzNDU2Nzg= update.txt
(gdb) r

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x7ffff4c66490 "Ne(", len=12) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x7ffff4c66490: 0x4e    0x65    0x28    0x00    0x00    0x01    0x00    0x00
0x7ffff4c66498: 0x00    0x01    0x00    0x00 *  0x00    0x00    0x00    0x00

Updates (Wireshark) -> taken into account

Skip over "Additonal RRs: 1" field.

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x7ffff020af7c "\aexample\003com", len=43) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x7ffff020af7c: 0x07    0x65    0x78    0x61    0x6d    0x70    0x6c    0x65
0x7ffff020af84: 0x03    0x63    0x6f    0x6d    0x00    0x00    0x06    0x00
0x7ffff020af8c: 0x01 *  0x09    0x73    0x75    0x62    0x64    0x6f    0x6d
0x7ffff020af94: 0x61    0x69    0x6e    0xc0    0x0c    0x00    0x01    0x00
0x7ffff020af9c: 0x01    0x00    0x00    0x00    0x3c    0x00    0x04    0x7f
0x7ffff020afa4: 0x00    0x00    0x01 *
(gdb)
Continuing.

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x7ffff7fa1020 "\nupdate-key", len=12) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x7ffff7fa1020: 0x0a    0x75    0x70    0x64    0x61    0x74    0x65    0x2d
0x7ffff7fa1028: 0x6b    0x65    0x79    0x00
(gdb)
Continuing.

Skip over the "Type: TSIG" field.

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x7ffff4c66570 "", len=6) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x7ffff4c66570: 0x00    0xff    0x00    0x00    0x00    0x00
(gdb)
Continuing.

Skip over the "Data length" field.

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x83b710 <hmacmd5_ndata> "\bhmac-md5\asig-alg\003reg\003int", len=26) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x83b710 <hmacmd5_ndata>:   0x08    0x68    0x6d    0x61    0x63    0x2d    0x6d    0x64
0x83b718 <hmacmd5_ndata+8>: 0x35    0x07    0x73    0x69    0x67    0x2d    0x61    0x6c
0x83b720 <hmacmd5_ndata+16>:    0x67    0x03    0x72    0x65    0x67    0x03    0x69    0x6e
0x83b728 <hmacmd5_ndata+24>:    0x74    0x00
(gdb)
Continuing.

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x7ffff4c66570 "", len=8) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x7ffff4c66570: 0x00    0x00    0x5a    0x38    0xf8    0xbf    0x01    0x2c
(gdb)
Continuing.

Breakpoint 2, isc_hmacmd5_update (ctx=0x7ffff7f960a8, buf=0x7ffff4c66570 "", len=4) at hmacmd5.c:284
284     isc_md5_update(&ctx->md5ctx, buf, len);
3: x/64xb buf
0x7ffff4c66570: 0x00    0x00    0x00    0x00
(gdb)
Continuing.

Breakpoint 1, isc_hmacmd5_sign (ctx=0x7ffff7f960a8, digest=0x7ffff7fa1030 '\276' <repeats 16 times>, "P\020\372\367\377\177") at hmacmd5.c:291
291 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {

Corresponding .pcap file -> tsig-1-12345678-another.pcap.txt

kholia commented 6 years ago

https://github.com/rthalley/dnspython would be very helpful in parsing these "TSIG" packets.

Sample code,

#!/usr/bin/env python3

from __future__ import print_function

import dns.message
import dns.tsigkeyring

keyring = dns.tsigkeyring.from_text({
    'update-key' : 'MTIzNDU2Nzg='
    })

wire = "4e6528000001000000010001076578616d706c6503636f6d000006000109737562646f6d61696ec00c000100010000003c00047f0000010a7570646174652d6b65790000fa00ff00000000003a08686d61632d6d6435077369672d616c670372656703696e740000005a38f8bf012c001062baf26f68deab15ebc6f4c4565338414e6500000000".decode("hex")

xyz = dns.message.from_wire(wire, keyring=keyring)
print(xyz)

The data comes from the above post.

kholia commented 6 years ago

I can brute-force, and crack client-to-server TSIG traffic now, but I am unable to crack server-to-client TSIG responses.

Notes on debugging named,

$ sudo debuginfo-install bind -y

$ sudo gdb -p `pidof named`
(gdb) break isc_hmacmd5_init
(gdb) break isc_hmacmd5_update

GDB helper script,

#!/usr/bin/gdb -x
#
# Based on https://github.com/crossbowerbt/GDB-Python-Utils
#
# Tested on CentOS 7.4 64-bit.

import gdb
import binascii
import traceback
import struct

def usage():
    print("Usage:")
    print("\t./helper.py -p <pid>")
    gdb.execute('quit')

class isc_hmacmd5_update(gdb.Breakpoint):
    def __init__(self):
        super(isc_hmacmd5_update, self).__init__('isc_hmacmd5_update')

    def stop(self):
        # man syscall
        try:
            length = int(gdb.parse_and_eval('$rdx'))
            print("isc_hmacmd5_update() with length %d" % length)
            gdb.execute("x/%dbx $rsi" % length)
            print("")
        except:
            traceback.print_exc()
            return True

        return False

class isc_hmacmd5_init(gdb.Breakpoint):
    def __init__(self):
        super(isc_hmacmd5_init, self).__init__('isc_hmacmd5_init')

    def stop(self):
        # man syscall
        try:
            length = int(gdb.parse_and_eval('$rdx'))
            print("isc_hmacmd5_init() with length %d" % length)
            gdb.execute("p/x $rdi")
            gdb.execute("x/%dbx $rsi" % length)
            print("")
        except:
            traceback.print_exc()
            return True

        return False

# GDB setup
# gdb.execute("set print repeats unlimited")
# gdb.execute("set print elements unlimited")
gdb.execute("set pagination off")
gdb.execute("handle SIGUSR1 nostop")
gdb.execute("handle SIGUSR1 noprint")

# generate breakpoints
isc_hmacmd5_update()
isc_hmacmd5_init()

# run and sniff
gdb.execute('continue')

# gdb.execute('detach')
# gdb.execute('quit')

Sample .pcap file and GDB trace,

debug.txt debug.pcap.txt

Hmm. I can't spot the bug. Everything seems to be in good order!

It seems that server-to-client response stuff passes some initial extra data to the HMAC function. The dnspython project has code to handle this stuff but I haven't figured out how to use it correctly.

Update: This extra data in the response packet processing is the mac_length + mac value present in the request packet.

Update 2: Now we can crack both the request and response TSIG "hashes".

kholia commented 6 years ago

Use a command line nsupdate -y hmac-sha256:update-key:w6RiYw== update.txt to try the various supported HMAC schemes.

magnumripper commented 6 years ago

Good stuff

kholia commented 6 years ago

This issue can be closed now. Hopefully, we will learn about more network protocols to attack in the near future.

kholia commented 6 years ago

https://github.com/kholia/rfc-3118 has stuff related to delayed authentication in DHCP.

kholia commented 6 years ago

Also see https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1025 (Bug 1025 - dhcp packet crashes wireshark) for a little more information on delayed authentication in DHCP.

kholia commented 6 years ago

https://github.com/rsmarples/dhcpcd (DHCP client) has support for delayed authentication :-)

I couldn't find a DHCP server implementation with support for delayed authentication though.