@cryptotaxi247 / CoPilot / commits / 5f767a76

logic to run remote commands via velociraptor (#42)

taylor_socfortress committed Jul 17, 2023 at 13:16 UTC 5f767a76f15e6133ce43725f9094af5ca0fe279a
3 files changed +148 -4
backend/app/routes/velociraptor.py
+36
@@ -118,3 +118,39 @@ def collect_artifact():
118 artifact=artifact_name,
119 )
120 return artifact_results
121 +
122 +
123 +@bp.route("/velociraptor/remotecommand", methods=["POST"])
124 +def run_remote_command():
125 + """
126 + Endpoint to run a remote command.
127 + It collects the command and client name from the request body and returns the results.
128 +
129 + Returns:
130 + json: A JSON response containing the result of the PowerShell command execution.
131 + """
132 + req_data = request.get_json()
133 + command = req_data["command"]
134 + client_name = req_data["client_name"]
135 + artifact_name = req_data["artifact_name"]
136 + service = UniversalService()
137 + client_id = service.get_client_id(client_name=client_name)["results"][0]["client_id"]
138 + if client_id is None:
139 + return (
140 + jsonify(
141 + {
142 + "message": f"{client_name} has not been seen in the last 30 seconds and may not be online with the "
143 + "Velociraptor server.",
144 + "success": False,
145 + },
146 + ),
147 + 500,
148 + )
149 +
150 + artifact_service = ArtifactsService()
151 + artifact_results = artifact_service.run_remote_command(
152 + client_id=client_id,
153 + artifact=artifact_name,
154 + command=command,
155 + )
156 + return artifact_results
backend/app/services/Velociraptor/artifacts.py
+47 -2
@@ -24,18 +24,22 @@ class ArtifactsService:
24 """
25 return query
26
27 - def _get_artifact_key(self, client_id: str, artifact: str) -> str:
27 + def _get_artifact_key(self, client_id: str, artifact: str, command: str = None) -> str:
28 """
29 Construct the artifact key.
30
31 Args:
32 client_id (str): The ID of the client.
33 artifact (str): The name of the artifact.
34 + command (str): The command that was run, if applicable.
35
36 Returns:
37 str: The constructed artifact key.
38 """
38 - return f"collect_client(client_id='{client_id}', artifacts=['{artifact}'])"
39 + if command:
40 + return f"collect_client(client_id='{client_id}', urgent=true, artifacts=['{artifact}'], env=dict(Command='{command}'))"
41 + else:
42 + return f"collect_client(client_id='{client_id}', artifacts=['{artifact}'])"
43
44 def collect_artifacts(self) -> dict:
45 """
@@ -163,3 +167,44 @@ class ArtifactsService:
167 "message": "Failed to run artifact collection",
168 "success": False,
169 }
170 +
171 + def run_remote_command(self, client_id: str, artifact: str, command: str) -> dict:
172 + """
173 + Run a remote command on a specific client.
174 + Accepted artifact names are `Windows.System.PowerShell`, `Windows.System.CmdShell`.
175 +
176 + Args:
177 + client_id (str): The ID of the client.
178 + artifact (str): The name of the artifact.
179 + command (str): The command to be executed.
180 +
181 + Returns:
182 + dict: A dictionary with the success status, a message, and potentially the results.
183 + """
184 + try:
185 + query = self._create_query(
186 + f"SELECT collect_client(client_id='{client_id}', urgent=true, artifacts=['{artifact}'], env=dict(Command='{command}')) "
187 + "FROM scope()",
188 + )
189 + flow = self.universal_service.execute_query(query)
190 + logger.info(f"Successfully ran artifact collection on {flow}")
191 +
192 + artifact_key = self._get_artifact_key(client_id, artifact, command)
193 + flow_id = flow["results"][0][artifact_key]["flow_id"]
194 + logger.info(f"Successfully ran artifact collection on {flow_id}")
195 +
196 + completed = self.universal_service.watch_flow_completion(flow_id)
197 + logger.info(f"Successfully watched flow completion on {completed}")
198 +
199 + results = self.universal_service.read_collection_results(
200 + client_id,
201 + flow_id,
202 + artifact,
203 + )
204 + return results
205 + except Exception as err:
206 + logger.error(f"Failed to run artifact collection: {err}")
207 + return {
208 + "message": "Failed to run artifact collection",
209 + "success": False,
210 + }
backend/app/static/swagger.json
+65 -2
@@ -1734,9 +1734,9 @@
1734 "description": "Endpoint to get all artifacts for a hostname.",
1735 "parameters": [
1736 {
1737 - "name": "hostname",
1737 + "name": "client_name",
1738 "in": "path",
1739 - "description": "The hostname",
1739 + "description": "The client name",
1740 "required": true,
1741 "schema": {
1742 "type": "string"
@@ -1834,6 +1834,69 @@
1834 "tags": ["Velociraptor"]
1835 }
1836 },
1837 + "/velociraptor/remotecommand": {
1838 + "post": {
1839 + "summary": "Run a remote command",
1840 + "description": "Endpoint to run a remote command.",
1841 + "requestBody": {
1842 + "description": "Remote command details",
1843 + "content": {
1844 + "application/json": {
1845 + "schema": {
1846 + "type": "object",
1847 + "properties": {
1848 + "client_name": {
1849 + "type": "string",
1850 + "value": "WIN-39O01J5F7G5",
1851 + "description": "The hostname of the client to run the command on."
1852 + },
1853 + "artifact_name": {
1854 + "type": "string",
1855 + "value": "Windows.System.PowerShell",
1856 + "description": "The name of the artifact to run."
1857 + },
1858 + "command": {
1859 + "type": "string",
1860 + "value": "ping 8.8.8.8",
1861 + "description": "The powershell command to run."
1862 + }
1863 + }
1864 + }
1865 + }
1866 + }
1867 + },
1868 + "responses": {
1869 + "200": {
1870 + "description": "Successful operation",
1871 + "content": {
1872 + "application/json": {
1873 + "schema": {
1874 + "type": "object",
1875 + "properties": {
1876 + "output": {
1877 + "type": "string",
1878 + "description": "The output of the command."
1879 + }
1880 + }
1881 + }
1882 + }
1883 + }
1884 + },
1885 + "default": {
1886 + "description": "Unexpected error",
1887 + "content": {
1888 + "application/json": {
1889 + "schema": {
1890 + "$ref": "#/components/schemas/Error"
1891 + }
1892 + }
1893 + }
1894 + }
1895 + },
1896 + "operationId": "runPowershellCommand",
1897 + "tags": ["Velociraptor"]
1898 + }
1899 + },
1900 "/dfir_iris/cases": {
1901 "get": {
1902 "summary": "Get all cases",