forked from by2waysprojects/shellcode-db
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ef56e03
commit ee28cb9
Showing
11 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
NEO4J_DB=neo4j://localhost:7687 | ||
NEO4J_USER=neo4j | ||
NEO4J_PASSWORD=password | ||
SERVER_PORT=8080 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"os" | ||
"shellcode-db/controllers" | ||
"shellcode-db/routes" | ||
"shellcode-db/services" | ||
|
||
"github.com/joho/godotenv" | ||
) | ||
|
||
func main() { | ||
err := godotenv.Load() | ||
if err != nil { | ||
log.Fatalf("error loading file .env: %v", err) | ||
} | ||
|
||
port := os.Getenv("SERVER_PORT") | ||
databaseURL := os.Getenv("NEO4J_DB") | ||
user := os.Getenv("NEO4J_USER") | ||
password := os.Getenv("NEO4J_PASSWORD") | ||
|
||
neo4jService := services.NewNeo4jService(databaseURL, user, password) | ||
defer neo4jService.Close() | ||
|
||
apiService := services.NewExploitDbService() | ||
dataLoaderService := services.NewDataLoaderService(apiService, neo4jService) | ||
shellCodeController := controllers.NewShellCodeController(neo4jService, dataLoaderService) | ||
|
||
router := routes.SetupRoutes(shellCodeController) | ||
|
||
log.Println("Server running on http://localhost:" + port) | ||
log.Fatal(http.ListenAndServe(":"+port, router)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package controllers | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"shellcode-db/services" | ||
|
||
"github.com/gorilla/mux" | ||
) | ||
|
||
type ShellCodeController struct { | ||
DBService *services.Neo4jService | ||
DataLoaderService *services.DataLoaderService | ||
} | ||
|
||
func NewShellCodeController(dbService *services.Neo4jService, dataLoaderService *services.DataLoaderService) *ShellCodeController { | ||
return &ShellCodeController{DBService: dbService, DataLoaderService: dataLoaderService} | ||
} | ||
|
||
func (sc *ShellCodeController) GetAllArchitectures(w http.ResponseWriter, r *http.Request) { | ||
archiectures, err := sc.DBService.GetAllArchitectures() | ||
if err != nil { | ||
http.Error(w, "Failed to fetch architectures", http.StatusInternalServerError) | ||
return | ||
} | ||
json.NewEncoder(w).Encode(archiectures) | ||
} | ||
|
||
func (sc *ShellCodeController) GetShellcodesByArchitectureID(w http.ResponseWriter, r *http.Request) { | ||
vars := mux.Vars(r) | ||
architectureID := vars["id"] | ||
|
||
shellcodes, err := sc.DBService.GetShellcodesByArchitectureID(architectureID) | ||
if err != nil { | ||
http.Error(w, "Failed to fetch shellcodes", http.StatusInternalServerError) | ||
return | ||
} | ||
json.NewEncoder(w).Encode(shellcodes) | ||
} | ||
|
||
func (sc *ShellCodeController) LoadData(w http.ResponseWriter, r *http.Request) { | ||
err := sc.DataLoaderService.LoadData() | ||
if err != nil { | ||
http.Error(w, "Failed to load data", http.StatusInternalServerError) | ||
return | ||
} | ||
w.WriteHeader(http.StatusOK) | ||
w.Write([]byte("Data successfully loaded")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module shellcode-db | ||
|
||
go 1.22.4 | ||
|
||
require ( | ||
github.com/gorilla/mux v1.8.1 | ||
github.com/neo4j/neo4j-go-driver/v5 v5.26.0 | ||
) | ||
|
||
require ( | ||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 // indirect | ||
github.com/joho/godotenv v1.5.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= | ||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= | ||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= | ||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= | ||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= | ||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= | ||
github.com/neo4j/neo4j-go-driver/v5 v5.26.0 h1:GB3o4VtIGsvU+RmfgvF7L6nt1IpbPZaGtPMtPSOKmvc= | ||
github.com/neo4j/neo4j-go-driver/v5 v5.26.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package model | ||
|
||
type Architecture struct { | ||
ID string `json:"id"` | ||
Name string `json:"name"` | ||
Shellcodes []Shellcode `json:"shellcodes"` | ||
} | ||
|
||
type Shellcode struct { | ||
ID string `json:"id"` | ||
Name string `json:"name"` | ||
DatePublished string `json:"date_published"` | ||
Data string `json:"data"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package routes | ||
|
||
import ( | ||
"shellcode-db/controllers" | ||
|
||
"github.com/gorilla/mux" | ||
) | ||
|
||
func SetupRoutes( | ||
shellCodeController *controllers.ShellCodeController, | ||
) *mux.Router { | ||
router := mux.NewRouter() | ||
|
||
router.HandleFunc("/architectures", shellCodeController.GetAllArchitectures).Methods("GET") | ||
router.HandleFunc("/architectures/{id}/shellcodes", shellCodeController.GetShellcodesByArchitectureID).Methods("GET") | ||
router.HandleFunc("/load-data", shellCodeController.LoadData).Methods("POST") | ||
|
||
return router | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package services | ||
|
||
import ( | ||
"log" | ||
) | ||
|
||
type DataLoaderService struct { | ||
APIService *APIService | ||
Neo4jService *Neo4jService | ||
} | ||
|
||
func NewDataLoaderService(apiService *APIService, neo4jService *Neo4jService) *DataLoaderService { | ||
return &DataLoaderService{ | ||
APIService: apiService, | ||
Neo4jService: neo4jService, | ||
} | ||
} | ||
|
||
func (dl *DataLoaderService) LoadData() error { | ||
// Fetch Architectures from API | ||
architectures, err := dl.APIService.FetchArchitectures() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Insert Architectures into Neo4j | ||
for _, architecture := range architectures { | ||
err := dl.Neo4jService.CreateArchitecture(architecture) | ||
if err != nil { | ||
log.Printf("Failed to insert architecture %s: %v", architecture.ID, err) | ||
continue | ||
} | ||
|
||
for _, shellcode := range architecture.Shellcodes { | ||
if err := dl.Neo4jService.CreateShellcodeWithArchitecture(architecture.ID, shellcode); err != nil { | ||
log.Printf("Failed to insert shellcode %s: %v", shellcode.ID, err) | ||
} | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package services | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"shellcode-db/model" | ||
services "shellcode-db/services/model" | ||
|
||
"github.com/gocarina/gocsv" | ||
) | ||
|
||
type APIService struct{} | ||
|
||
func NewExploitDbService() *APIService { | ||
return &APIService{} | ||
} | ||
|
||
func (api *APIService) FetchArchitectures() ([]model.Architecture, error) { | ||
url := "https://gitlab.com/exploit-database/exploitdb/-/raw/main/files_shellcodes.csv" | ||
response, err := http.Get(url) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer response.Body.Close() | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode) | ||
} | ||
|
||
var shellcodesExploitDB []services.Shellcode | ||
body, _ := io.ReadAll(response.Body) | ||
|
||
if err := gocsv.UnmarshalBytes(body, &shellcodesExploitDB); err != nil { | ||
return nil, err | ||
} | ||
|
||
var shellcodes []model.Architecture | ||
mapArchitectureShell := map[string][]model.Shellcode{} | ||
|
||
for _, shell := range shellcodesExploitDB { | ||
fileUrl := fmt.Sprintf("https://gitlab.com/exploit-database/exploitdb/-/raw/main/%s", shell.File) | ||
response, err := http.Get(fileUrl) | ||
if err != nil { | ||
continue | ||
} | ||
|
||
if response.StatusCode != http.StatusOK { | ||
continue | ||
} | ||
|
||
body, _ := io.ReadAll(response.Body) | ||
response.Body.Close() | ||
|
||
mapArchitectureShell[shell.Platform] = append(mapArchitectureShell[shell.Platform], | ||
model.Shellcode{ID: shell.Id, Name: shell.Description, DatePublished: shell.DatePublished, Data: string(body)}) | ||
} | ||
|
||
for key, value := range mapArchitectureShell { | ||
shellcodes = append(shellcodes, model.Architecture{ID: key, Name: key, Shellcodes: value}) | ||
} | ||
|
||
return shellcodes, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package services | ||
|
||
type Shellcode struct { | ||
Id string `csv:"id"` | ||
Platform string `csv:"platform"` | ||
SourceURL string `csv:"source_url"` | ||
DatePublished string `csv:"date_published"` | ||
Description string `csv:"description"` | ||
File string `csv:"file"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package services | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"shellcode-db/model" | ||
|
||
"github.com/neo4j/neo4j-go-driver/v5/neo4j" | ||
) | ||
|
||
type Neo4jService struct { | ||
Driver neo4j.DriverWithContext | ||
} | ||
|
||
func NewNeo4jService(uri, username, password string) *Neo4jService { | ||
driver, err := neo4j.NewDriverWithContext(uri, neo4j.BasicAuth(username, password, "")) | ||
if err != nil { | ||
log.Fatalf("Failed to create Neo4j driver: %v", err) | ||
} | ||
return &Neo4jService{Driver: driver} | ||
} | ||
|
||
func (s *Neo4jService) Close() { | ||
s.Driver.Close(context.Background()) | ||
} | ||
|
||
func (s *Neo4jService) GetAllArchitectures() ([]model.Architecture, error) { | ||
ctx := context.Background() | ||
session := s.Driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) | ||
defer session.Close(ctx) | ||
|
||
architectures := []model.Architecture{} | ||
_, err := session.ExecuteRead(ctx, func(tx neo4j.ManagedTransaction) (interface{}, error) { | ||
result, err := tx.Run(ctx, "MATCH (p:Architecture) RETURN p.id AS id, p.name AS name", nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for result.Next(ctx) { | ||
record := result.Record() | ||
architecture := model.Architecture{ | ||
ID: record.Values[0].(string), | ||
Name: record.Values[1].(string), | ||
} | ||
architectures = append(architectures, architecture) | ||
} | ||
return nil, result.Err() | ||
}) | ||
|
||
return architectures, err | ||
} | ||
|
||
func (s *Neo4jService) GetShellcodesByArchitectureID(architectureID string) ([]model.Shellcode, error) { | ||
ctx := context.Background() | ||
session := s.Driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) | ||
defer session.Close(ctx) | ||
|
||
shellcodes := []model.Shellcode{} | ||
_, err := session.ExecuteRead(ctx, func(tx neo4j.ManagedTransaction) (interface{}, error) { | ||
query := ` | ||
MATCH (p:Architecture {id: $architectureID})-[:HAS_CHILD]->(c:Shellcode) | ||
RETURN c.id AS id, c.name AS name, c.datePublished as datePublished, c.data as data | ||
` | ||
params := map[string]interface{}{"architectureID": architectureID} | ||
result, err := tx.Run(ctx, query, params) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for result.Next(ctx) { | ||
record := result.Record() | ||
shellcode := model.Shellcode{ | ||
ID: record.Values[0].(string), | ||
Name: record.Values[1].(string), | ||
DatePublished: record.Values[2].(string), | ||
Data: record.Values[3].(string), | ||
} | ||
shellcodes = append(shellcodes, shellcode) | ||
} | ||
return nil, result.Err() | ||
}) | ||
|
||
return shellcodes, err | ||
} | ||
|
||
func (s *Neo4jService) CreateArchitecture(architecture model.Architecture) error { | ||
ctx := context.Background() | ||
session := s.Driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) | ||
defer session.Close(ctx) | ||
|
||
_, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (interface{}, error) { | ||
query := ` | ||
MERGE (p:Architecture {id: $id}) | ||
SET p.name = $name | ||
` | ||
params := map[string]interface{}{"id": architecture.ID, "name": architecture.Name} | ||
_, err := tx.Run(ctx, query, params) | ||
return nil, err | ||
}) | ||
return err | ||
} | ||
|
||
func (s *Neo4jService) CreateShellcodeWithArchitecture(architectureID string, shellcode model.Shellcode) error { | ||
ctx := context.Background() | ||
session := s.Driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) | ||
defer session.Close(ctx) | ||
|
||
_, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (interface{}, error) { | ||
query := ` | ||
MERGE (c:Shellcode {id: $shellcodeID}) | ||
SET c.name = $shellcodeName, c.datePublished = $datePublished, c.data = $data | ||
WITH c | ||
MATCH (p:Architecture {id: $architectureID}) | ||
MERGE (p)-[:HAS_CHILD]->(c) | ||
` | ||
params := map[string]interface{}{ | ||
"architectureID": architectureID, | ||
"shellcodeID": shellcode.ID, | ||
"shellcodeName": shellcode.Name, | ||
"datePublished": shellcode.DatePublished, | ||
"data": shellcode.Data, | ||
} | ||
_, err := tx.Run(ctx, query, params) | ||
return nil, err | ||
}) | ||
return err | ||
} |