vayishu commited on
Commit
45692d2
·
verified ·
1 Parent(s): 15e4576

Upload 5 files

Browse files
Files changed (5) hide show
  1. app.py +66 -0
  2. cybersecurity_pipeline.py +199 -0
  3. packages.txt +2 -0
  4. requirements.txt +3 -2
  5. wordlist.txt +15 -0
app.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import html
3
+ from cybersecurity_pipeline import run_security_pipeline
4
+
5
+ st.set_page_config(page_title="AgenticCyberOps", layout="wide")
6
+
7
+ # Inject custom CSS for styling (make sure this string is not indented unexpectedly)
8
+ st.markdown(
9
+ """<style>
10
+ .big-title {
11
+ font-size: 36px;
12
+ font-weight: bold;
13
+ color: #FF4B4B;
14
+ text-align: center;
15
+ }
16
+ .sub-title {
17
+ font-size: 24px;
18
+ font-weight: bold;
19
+ color: #FFFFFF;
20
+ background-color: #333;
21
+ padding: 10px;
22
+ border-radius: 5px;
23
+ }
24
+ .report-box {
25
+ background-color: #F5F5F5;
26
+ padding: 10px;
27
+ border-radius: 5px;
28
+ border-left: 5px solid #FF4B4B;
29
+ color: #000000;
30
+ font-family: sans-serif;
31
+ }
32
+ </style>
33
+ """, unsafe_allow_html=True)
34
+
35
+ st.markdown('<p class="big-title">🔍 Cybersecurity Agent Dashboard</p>', unsafe_allow_html=True)
36
+
37
+ st.sidebar.header("Agent Configuration")
38
+ st.sidebar.markdown(
39
+ """
40
+ **Allowed Scope:**
41
+ The agent will only scan targets within its allowed scope.
42
+ Currently, the allowed scope is set to (Universal links or any link):
43
+ - **example.com**
44
+ - **192.168.1.0/24**
45
+ - **scanme.nmap.org**, etc...
46
+ """
47
+ )
48
+
49
+ target = st.sidebar.text_input("Enter Target (e.g., example.com):", value="example.com")
50
+
51
+ if st.sidebar.button("Run Security Scan"):
52
+ with st.spinner("Running security scan..."):
53
+ task_description = f"Scan {target} for open ports and directories"
54
+ final_state = run_security_pipeline(task_description)
55
+ final_report = final_state.get("final_report", "No report generated.")
56
+ logs = final_state.get("logs", [])
57
+
58
+ st.success("Security scan complete!")
59
+
60
+ st.markdown('<p class="sub-title">Final Security Audit Report</p>', unsafe_allow_html=True)
61
+ # Escape HTML to display it as plain text
62
+ escaped_report = html.escape(final_report)
63
+ st.markdown(f'<div class="report-box"><pre>{escaped_report}</pre></div>', unsafe_allow_html=True)
64
+
65
+ st.markdown('<p class="sub-title">Detailed Execution Logs</p>', unsafe_allow_html=True)
66
+ st.text_area("Logs", "\n".join(logs), height=300)
cybersecurity_pipeline.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # cybersecurity_pipeline.py
2
+
3
+ import os
4
+ from dotenv import load_dotenv
5
+ import subprocess
6
+ import shlex
7
+ from pydantic import BaseModel
8
+ from typing import List
9
+ import langgraph
10
+ from langgraph.graph import StateGraph
11
+ import google.generativeai as genai
12
+
13
+ # -----------------------------------------------------------------------------
14
+ # Step 1: Setup Environment & API Configuration
15
+ # -----------------------------------------------------------------------------
16
+ # Load environment variables from .env file
17
+ load_dotenv()
18
+
19
+ # Retrieve the API key from the .env file
20
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
21
+ if not GOOGLE_API_KEY:
22
+ raise ValueError("No GOOGLE_API_KEY found in environment variables.")
23
+
24
+ # Configure Gemini with the API key
25
+ genai.configure(api_key=GOOGLE_API_KEY)
26
+
27
+ # -----------------------------------------------------------------------------
28
+ # Step 2: Define Core Architecture (State Model & LangGraph Workflow)
29
+ # -----------------------------------------------------------------------------
30
+ class CyberSecurityState(BaseModel):
31
+ task: str
32
+ task_list: List[str] = []
33
+ results: List[str] = []
34
+ # Use a wildcard to allow any link
35
+ allowed_scope: List[str] = ["*"]
36
+ # If we want to allow any specific link then we need to write:
37
+ # allowed_scope: List[str] = ["example.com", "google.com", "facebook.com"] # Try this also if you have any specific links.
38
+ logs: List[str] = []
39
+ final_report: str = "" # Field for the final report
40
+
41
+ # -----------------------------------------------------------------------------
42
+ # Step 4: Helper Function for Task Execution & Retry Logic
43
+ # -----------------------------------------------------------------------------
44
+ def execute_command_with_retry(cmd: str, alternate_cmd: str = None, max_retries: int = 2) -> str:
45
+ attempt = 0
46
+ while attempt < max_retries:
47
+ try:
48
+ output = subprocess.check_output(
49
+ shlex.split(cmd),
50
+ stderr=subprocess.STDOUT,
51
+ timeout=60,
52
+ universal_newlines=True
53
+ )
54
+ return output
55
+ except Exception as e:
56
+ attempt += 1
57
+ if attempt >= max_retries:
58
+ if alternate_cmd:
59
+ try:
60
+ output = subprocess.check_output(
61
+ shlex.split(alternate_cmd),
62
+ stderr=subprocess.STDOUT,
63
+ timeout=60,
64
+ universal_newlines=True
65
+ )
66
+ return output
67
+ except Exception as e2:
68
+ return f"Command failed after retries: {str(e2)}"
69
+ else:
70
+ return f"Command failed after retries: {str(e)}"
71
+ if alternate_cmd:
72
+ cmd = alternate_cmd
73
+ return "Unknown error"
74
+
75
+ # -----------------------------------------------------------------------------
76
+ # Step 3: Implement the Agent Workflow
77
+ # -----------------------------------------------------------------------------
78
+ # 3.1 Build Task Decomposition
79
+ def task_decomposition(state: dict) -> dict:
80
+ state_obj = CyberSecurityState.model_validate(state)
81
+ # For simplicity, extract target from the task description (assumes target is the second word)
82
+ target = state_obj.task.split()[1]
83
+ state_obj.task_list = [
84
+ f"nmap scan on {target}",
85
+ f"gobuster scan on {target} directories"
86
+ ]
87
+ state_obj.logs.append(f"[Task Decomposition] Decomposed task into: {state_obj.task_list}")
88
+ return state_obj.model_dump()
89
+
90
+ # 3.3 Implement Scope Constraints
91
+ def apply_scope_constraints(state: dict) -> dict:
92
+ state_obj = CyberSecurityState.model_validate(state)
93
+ # If wildcard is present, allow all tasks without filtering.
94
+ if "*" in state_obj.allowed_scope:
95
+ state_obj.logs.append("[Scope Constraints] Wildcard detected. All targets allowed.")
96
+ return state_obj.model_dump()
97
+
98
+ filtered_tasks = []
99
+ for task in state_obj.task_list:
100
+ if any(scope in task for scope in state_obj.allowed_scope):
101
+ filtered_tasks.append(task)
102
+ else:
103
+ filtered_tasks.append(f"Task '{task}' skipped (outside allowed scope)")
104
+ state_obj.task_list = filtered_tasks
105
+ state_obj.logs.append(f"[Scope Constraints] Filtered tasks: {state_obj.task_list}")
106
+ return state_obj.model_dump()
107
+
108
+ # Step 4 (continued): Execute Tasks with Retry Logic
109
+ def execute_tasks_with_retry(state: dict) -> dict:
110
+ state_obj = CyberSecurityState.model_validate(state)
111
+ results = []
112
+ target = state_obj.task.split()[1]
113
+ for task in state_obj.task_list:
114
+ if "nmap" in task:
115
+ primary_cmd = f"nmap -p- {target}"
116
+ alternate_cmd = f"nmap -sV {target}"
117
+ output = execute_command_with_retry(primary_cmd, alternate_cmd, max_retries=2)
118
+ results.append(f"nmap result for {target}:\n{output}")
119
+ state_obj.logs.append(f"[Execute Tasks] nmap scan executed for {target}")
120
+ elif "gobuster" in task:
121
+ primary_cmd = f"gobuster dir -u https://{target} -w wordlist.txt"
122
+ alternate_cmd = f"gobuster dir -u http://{target} -w wordlist.txt"
123
+ output = execute_command_with_retry(primary_cmd, alternate_cmd, max_retries=2)
124
+ results.append(f"gobuster result for {target}:\n{output}")
125
+ state_obj.logs.append(f"[Execute Tasks] gobuster scan executed for {target}")
126
+ else:
127
+ results.append(f"Unknown task: {task}")
128
+ state_obj.logs.append(f"[Execute Tasks] Unknown task encountered: {task}")
129
+ state_obj.results = results
130
+ return state_obj.model_dump()
131
+
132
+ # Optional: Dynamic Task Updates (Based on intermediate results)
133
+ def dynamic_task_update(state: dict) -> dict:
134
+ state_obj = CyberSecurityState.model_validate(state)
135
+ # Example: if nmap output contains "80/tcp open", add a new task for HTTP scan.
136
+ for result in state_obj.results:
137
+ if "80/tcp open" in result and not any("HTTP scan on" in task for task in state_obj.task_list):
138
+ new_task = f"HTTP scan on {state_obj.task.split()[1]}"
139
+ state_obj.task_list.append(new_task)
140
+ state_obj.logs.append(f"[Dynamic Update] Added new task: {new_task}")
141
+ return state_obj.model_dump()
142
+
143
+ # Step 5: Implement Logging & Reporting
144
+ def generate_report(state: dict) -> dict:
145
+ state_obj = CyberSecurityState.model_validate(state)
146
+ report_lines = ["=== Security Audit Report ==="]
147
+ report_lines.extend(state_obj.results)
148
+ report_lines.append("\n=== Execution Logs ===")
149
+ report_lines.extend(state_obj.logs)
150
+ final_report = "\n".join(report_lines)
151
+ state_obj.logs.append("[Generate Report] Final report generated.")
152
+ state_obj.final_report = final_report
153
+ return state_obj.model_dump()
154
+
155
+ # -----------------------------------------------------------------------------
156
+ # Build the LangGraph Workflow (Integrating Steps 2–5)
157
+ # -----------------------------------------------------------------------------
158
+ workflow = StateGraph(CyberSecurityState)
159
+ workflow.add_node("Task Decomposition", task_decomposition)
160
+ workflow.add_node("Apply Scope Constraints", apply_scope_constraints)
161
+ workflow.add_node("Execute Tasks with Retry", execute_tasks_with_retry)
162
+ workflow.add_node("Dynamic Task Update", dynamic_task_update)
163
+ workflow.add_node("Generate Report", generate_report)
164
+ workflow.set_entry_point("Task Decomposition")
165
+ workflow.add_edge("Task Decomposition", "Apply Scope Constraints")
166
+ workflow.add_edge("Apply Scope Constraints", "Execute Tasks with Retry")
167
+ # Route through the dynamic update node before generating the final report
168
+ workflow.add_edge("Execute Tasks with Retry", "Dynamic Task Update")
169
+ workflow.add_edge("Dynamic Task Update", "Generate Report")
170
+
171
+ agent = workflow.compile()
172
+
173
+ # -----------------------------------------------------------------------------
174
+ # Public Function to Run the Security Pipeline
175
+ # -----------------------------------------------------------------------------
176
+ def run_security_pipeline(task_description: str) -> dict:
177
+ """
178
+ Initializes the state with the provided high-level task, forces allowed_scope to ["*"],
179
+ runs the workflow, and returns the final state (including the final report and logs).
180
+ """
181
+ # Force allowed_scope to be a wildcard to allow scanning any link
182
+ initial_state = CyberSecurityState(task=task_description, allowed_scope=["*"])
183
+ final_state = agent.invoke(initial_state.model_dump())
184
+ return final_state
185
+
186
+ """
187
+ Scanning on domains:
188
+
189
+ 1. example.com = 41.12 seconds, report is generated without any errors except for the other addresses of this domain.
190
+ 2. en.wikipedia.org = 35.41 seconds, report is generated successfully. Its not shown on the port of 989 (I need to check the dynamic task function of ports).
191
+ 3. scanme.nmap.org = 29.95 seconds, report is generated successfully.
192
+ 4. google.com = 60 seconds, its timeout didn't generate the report as expected same for the logs.
193
+ 5. facebook.com = 40.52 seconds, it has generated the audit report however the important part is that it generated weird things in the report.
194
+ 6. The report is generated successfully.
195
+ 6. 192.168.1.0/24 = 60 seconds, runned successfully however the report isn't generated same as 'google.com'.
196
+ 7. x.com = 60 seconds, Same as the 'google.com'
197
+
198
+ Runned on 7 domains and go some successfull results. However it needs to be optimised.
199
+ """
packages.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ nmap
2
+ gobuster
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
- altair
2
- pandas
 
3
  streamlit
 
1
+ langgraph
2
+ google-generativeai
3
+ pydantic
4
  streamlit
wordlist.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ admin
2
+ login
3
+ dashboard
4
+ api
5
+ user
6
+ users
7
+ test
8
+ dev
9
+ prod
10
+ staging
11
+ backup
12
+ wp-admin
13
+ wp-login
14
+ admin.php
15
+ login.php