Using Faketime for Ad-Hoc Kerberos Authentication
Installing Faketime
sudo apt install faketime
faketime -h
This will run the specified 'program' with the given 'arguments'.
The program will be tricked into seeing the given 'timestamp' as its starting date and time.
The clock will continue to run from this timestamp. Please see the manpage (man faketime)
for advanced options, such as stopping the wall clock and make it run faster or slower.
Example Usage
Running bloodhound-python in my local lab, the KDC on the target domain controller throws a clock skew error. So, we'll use ntpdate to synchronize with the KDC and feed that to faketime and then make the connection.
Before
bloodhound-python -c All -u joan.hesther -p 'madison' -d ad.lab -ns 10.80.80.2
KRB_AP_ERR_SKEW(Clock skew too great) indicates the Kerberos client (Kali in this case) and the KDC have too wide a drift between their clocks. To resolve, we can run an ad-hoc ntpdate sync and feed that to faketime to spoof the clock to bloodhound-python (or whichever Kerberos-authenticated app you're using).
After
faketime "$(ntpdate -q dc01.ad.lab | cut -d ' ' -f 1,2)" \
bloodhound-python -c All -u joan.hesther -p 'madison' -d ad.lab -ns 10.80.80.2
Internal or via ligolo-ng (or similar) layer 3 tunnel
proxychains -q faketime "$(ntpdate -q dc01.ad.lab | cut -d ' ' -f 1,2)" \
bloodhound-python -c All -u joan.hesther -p 'madison' -d ad.lab -ns 10.80.80.2 --dns-tcp
External via SOCKS proxy -- e.g. chisel or ssh
Function for Convenience
You can add this to your shell .rc file -- e.g. .zshrc -- so that it is sourced in every time you open your terminal.
function faketime () {
# Store the time server globally for future function calls
if [[ -z "$TIME_SERVER" ]] ; then
if [[ $(echo $0) -eq '-zsh' ]] ; then
# zsh-style user prompt
read TIME_SERVER?"Enter the FQDN or IP of the time server: "
else
# bash-style user prompt
read -p "Enter the FQDN or IP of the time server: " TIME_SERVER
fi
export TIME_SERVER="$TIME_SERVER"
fi
# Make sure the user has passed a valid target server
if ! /usr/sbin/ntpdate -t 1 -q "$TIME_SERVER" > /dev/null ; then
echo "Connectivity test to time server failed: ${TIME_SERVER}"
unset TIME_SERVER
return
# Target NTP server is reachable, proceed
else
/usr/bin/faketime "$(/usr/sbin/ntpdate -q $TIME_SERVER | /usr/bin/cut -d ' ' -f 1,2)" $@
fi
}
This function does the following:
- Checks if a global
$TIME_SERVERvariable containing the KDC FQDN or IP has been set- And if not set, prompt the user to set it
- Do a quick NTP client connectivity check to the specified server
- If connectivity fails, throw an error
- Otherwise proceed to invoke the process and arguments designated by
$@
Usage of faketime after these changes looks like:
faketime <process> [args]
Removes the need for adding the sub-shell call to ntpdate and cut
faketime impacket-getTGT -hashes ':NT_HASH_HERE' -dc-ip "10.10.100.20" 'ad.lab/john.doe'@dc01.ad.lab
KRB5CCNAME=john.doe.ccache faketime net rpc user password 'jane.doe' --use-kerberos=required -S "$TIME_SERVER"
