| inst/tinytest | chore: refined | |
| man | chore: refined | |
| R | chore: refined | |
| src | chore: refined | |
| tests | R 📦 repo initialization complete | |
| .gitattributes | R 📦 repo initialization complete | |
| .gitignore | chore: refined | |
| .Rbuildignore | chore: refined | |
| CONDUCT.md | R 📦 repo initialization complete | |
| DESCRIPTION | chore: refined | |
| NAMESPACE | chore: refined | |
| README.md | chore: add ref | |
| README.Qmd | chore: add ref | |
| roast.Rproj | R 📦 repo initialization complete | |
Project Status: Active – The project has reached a stable, usable state and is being actively developed. Signed by Signed commit %
roast
High-Performance OAST Subdomain Decoder
Description
Provides a vectorized C implementation for decoding Out-of-Band Application Security Testing (OAST) subdomains. Extracts metadata including timestamps, machine IDs, process IDs, and counter values from Base32hex encoded XIDs. The high-performance C implementation processes thousands of subdomains per millisecond, making it suitable for large-scale security analysis and threat hunting workflows.
Background
OAST subdomains contain encoded metadata in their first 20 characters, which represent a 12-byte Base32hex encoded XID (eXtended IDentifier). This XID follows a specific structure:
- Bytes 1-4: Unix timestamp (big-endian, 32-bit)
- Bytes 5-7: Machine identifier (3 bytes)
- Bytes 8-9: Process identifier (big-endian, 16-bit)
- Bytes 10-12: counter value (big-endian, 24-bit)
Homage
Built this thanks to John Jarocki’s epic LabsCon presentation ""Tracking the cyberspace ghost from OAST to OAST"".
What’s Inside The Tin
The following functions are implemented:
decode_oast: Decode OAST Subdomain
Installation
remotes::install_git("https://codeberg.org/hrbrmstr/roast.git")
NOTE: To use the ‘remotes’ install options you will need to have the {remotes} package installed.
Usage
library(roast)
# current version
packageVersion("roast")
## [1] '0.1.0'
Usage
Basic Usage
# Decode a single subdomain
result <- decode_oast("0123456789abcdefghij")
print(result)
## original timestamp machine_id pid counter
## 1 0123456789abcdefghij 1970年02月21日 17:27:48 c7:42:54 46645 13599845
Vectorized Usage
# Decode multiple subdomains at once
subdomains <- c(
"0123456789abcdefghij",
"abcdef0123456789ghij",
"fedcba9876543210beef"
)
results <- decode_oast(subdomains)
print(results)
## original timestamp machine_id pid counter
## 1 0123456789abcdefghij 1970年02月21日 17:27:48 c7:42:54 46645 13599845
## 2 abcdef0123456789ghij 2014年01月17日 07:09:48 01:10:c8 21277 623717
## 3 fedcba9876543210beef 2035年09月18日 15:05:13 28:39:8a 16776 2120604
Error Handling
The function gracefully handles invalid inputs by returning NA values for decoded fields:
# Mixed valid and invalid inputs
mixed <- c(
"0123456789abcdefghij", # Valid
"short", # Too short
"xyz123456789abcdefgh", # Invalid characters
"ABCDEF0123456789GHIJ" # Valid (case-insensitive)
)
results <- decode_oast(mixed)
print(results)
## original timestamp machine_id pid counter
## 1 0123456789abcdefghij 1970年02月21日 17:27:48 c7:42:54 46645 13599845
## 2 short <NA> <NA> NA NA
## 3 xyz123456789abcdefgh <NA> <NA> NA NA
## 4 ABCDEF0123456789GHIJ 2014年01月17日 07:09:48 01:10:c8 21277 623717
Return Value
The function returns a data.frame with the following columns:
original: The original subdomain stringtimestamp: POSIXct timestamp in UTC timezonemachine_id: Machine identifier formatted as "xx:xx:xx" hex stringpid: Process identifier (integer)counter: counter value (integer)
roast Metrics
| Lang | # Files | (%) | LoC | (%) | Blank lines | (%) | # Lines | (%) |
|---|---|---|---|---|---|---|---|---|
| C | 1 | 0.12 | 113 | 0.43 | 28 | 0.41 | 22 | 0.13 |
| R | 3 | 0.38 | 18 | 0.07 | 6 | 0.09 | 61 | 0.37 |
| SUM | 4 | 0.50 | 131 | 0.50 | 34 | 0.50 | 83 | 0.50 |
{cloc} 📦 metrics for roast
Code of Conduct
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.