yara stuff
This commit is contained in:
parent
5d05e59b42
commit
8de46a3682
10 changed files with 209 additions and 4 deletions
|
@ -3,7 +3,6 @@ package config
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
_ "github.com/joho/godotenv/autoload"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,7 +46,9 @@ func setDefaults() {
|
||||||
// Others
|
// Others
|
||||||
viper.SetDefault("processing.oleurl", "http://localhost:5000")
|
viper.SetDefault("processing.oleurl", "http://localhost:5000")
|
||||||
viper.SetDefault("processing.maxmimesize", "100MB")
|
viper.SetDefault("processing.maxmimesize", "100MB")
|
||||||
viper.SetDefault("store.path", "./storage/files/")
|
viper.SetDefault("processing.yararules", "./storage/rules")
|
||||||
|
viper.SetDefault("processing.yaracompiled", "./storage/output.yarc")
|
||||||
|
viper.SetDefault("store.path", "./storage/files")
|
||||||
viper.SetDefault("debug", false)
|
viper.SetDefault("debug", false)
|
||||||
// UI Interface info
|
// UI Interface info
|
||||||
viper.SetDefault("ui.name", "Scanfile")
|
viper.SetDefault("ui.name", "Scanfile")
|
||||||
|
|
14
server/internal/database/queries-yara.sql
Normal file
14
server/internal/database/queries-yara.sql
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
-- name: InsertYaraResults :one
|
||||||
|
INSERT INTO yara_results (
|
||||||
|
file_id, matched
|
||||||
|
) VALUES ($1, $2)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: GetYaraResults :one
|
||||||
|
SELECT * FROM yara_results
|
||||||
|
WHERE file_id = $1
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: DeleteYaraResults :exec
|
||||||
|
DELETE FROM yara_results
|
||||||
|
WHERE id = $1;
|
|
@ -22,7 +22,7 @@ CREATE TABLE IF NOT EXISTS processing_jobs (
|
||||||
status TEXT,
|
status TEXT,
|
||||||
job_type TEXT,
|
job_type TEXT,
|
||||||
error TEXT,
|
error TEXT,
|
||||||
messages JSONB DEFAULT '[]'::JSONB
|
messages TEXT[]
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS diec (
|
CREATE TABLE IF NOT EXISTS diec (
|
||||||
|
@ -77,6 +77,12 @@ CREATE TABLE IF NOT EXISTS file_properties (
|
||||||
libmagic_apple TEXT
|
libmagic_apple TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS yara_results (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
file_id UUID REFERENCES files (id) ON DELETE CASCADE,
|
||||||
|
matched TEXT[]
|
||||||
|
);
|
||||||
|
|
||||||
-- Indices
|
-- Indices
|
||||||
-- Since tables will be heavily accessed by file_id, there should be indices for them
|
-- Since tables will be heavily accessed by file_id, there should be indices for them
|
||||||
CREATE INDEX idx_diec_file_id ON diec (file_id);
|
CREATE INDEX idx_diec_file_id ON diec (file_id);
|
||||||
|
|
33
server/internal/database/yara.go
Normal file
33
server/internal/database/yara.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"git.jmbit.de/jmb/scanfile/server/internal/sqlc"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetYaraResults(fileID string) (sqlc.YaraResult, error) {
|
||||||
|
var pgUUID pgtype.UUID
|
||||||
|
err := pgUUID.Scan(fileID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Unable to convert string to UUID", "file-uuid", fileID, "error", err)
|
||||||
|
}
|
||||||
|
query := sqlc.New(pool)
|
||||||
|
data, err := query.GetYaraResults(context.Background(), pgUUID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error in GetMsofficeInfo", "file-uuid", fileID, "error", err)
|
||||||
|
}
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertYaraResults(params sqlc.InsertYaraResultsParams) error {
|
||||||
|
query := sqlc.New(pool)
|
||||||
|
slog.Debug("InsertYaraResults", "params", params)
|
||||||
|
_, err := query.InsertYaraResults(context.Background(), params)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error in InsertYaraResults", "file-uuid", params.FileID.String(), "error", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"git.jmbit.de/jmb/scanfile/server/internal/database"
|
"git.jmbit.de/jmb/scanfile/server/internal/database"
|
||||||
"git.jmbit.de/jmb/scanfile/server/internal/processing/basic"
|
"git.jmbit.de/jmb/scanfile/server/internal/processing/basic"
|
||||||
"git.jmbit.de/jmb/scanfile/server/internal/processing/msoffice"
|
"git.jmbit.de/jmb/scanfile/server/internal/processing/msoffice"
|
||||||
|
"git.jmbit.de/jmb/scanfile/server/internal/processing/yara"
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ var startup time.Time
|
||||||
|
|
||||||
func Setup(wg *sync.WaitGroup) {
|
func Setup(wg *sync.WaitGroup) {
|
||||||
startup = time.Now()
|
startup = time.Now()
|
||||||
|
yara.InitYara()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit() starts the analysis process for a file.
|
// Submit() starts the analysis process for a file.
|
||||||
|
|
56
server/internal/processing/yara/wrap.go
Normal file
56
server/internal/processing/yara/wrap.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package yara
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"git.jmbit.de/jmb/scanfile/server/internal/store"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compileSourcesFromFiles() error {
|
||||||
|
root, err := filepath.Abs(viper.GetString("processing.yararules"))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error getting absolute path for processing.yararules", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outputPath, err := filepath.Abs(viper.GetString("processing.yaracompiled"))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error getting absolute path for processing.yaracompiled", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("/usr/local/bin/yr", "compile","-path-as-namespace", "--relaxed-re-syntax", "--output", outputPath, root)
|
||||||
|
result, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error compiling yara rules", "error", err, "result", string(result))
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
slog.Info("Compiled yara rules", "result", string(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanFile(fileName string) ([]string, error) {
|
||||||
|
var matched []string
|
||||||
|
outputPath, err := filepath.Abs(viper.GetString("processing.yaracompiled"))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error getting absolute path for processing.yaracompiled", "error", err)
|
||||||
|
return matched, err
|
||||||
|
}
|
||||||
|
fullPath, err := store.AbsPath(fileName)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error in DiecScan", "file-uuid", fileName, "error", err)
|
||||||
|
return matched, err
|
||||||
|
}
|
||||||
|
cmd := exec.Command("/usr/local/bin/yr", "scan", "--output-format ndjson", "--print-namespace","--compiled-rules", outputPath, fullPath)
|
||||||
|
result, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Error scanning file with yara", "error", err, "file-uuid", fileName,"result", string(result))
|
||||||
|
return matched, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched, nil
|
||||||
|
}
|
32
server/internal/processing/yara/yara.go
Normal file
32
server/internal/processing/yara/yara.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package yara
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.jmbit.de/jmb/scanfile/server/internal/database"
|
||||||
|
"git.jmbit.de/jmb/scanfile/server/internal/sqlc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitYara() error{
|
||||||
|
return compileSourcesFromFiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
func YaraProcessing(job sqlc.ProcessingJob) error {
|
||||||
|
database.StartProcessingJob(job.ID)
|
||||||
|
results, err := scanFile(job.FileID.String())
|
||||||
|
if err != nil {
|
||||||
|
database.FailProcessingJob(job.ID, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
params := sqlc.InsertYaraResultsParams{
|
||||||
|
FileID: job.FileID,
|
||||||
|
Matched: results,
|
||||||
|
}
|
||||||
|
err = database.InsertYaraResults(params)
|
||||||
|
if err != nil {
|
||||||
|
database.FailProcessingJob(job.ID, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -79,5 +79,11 @@ type ProcessingJob struct {
|
||||||
Status pgtype.Text
|
Status pgtype.Text
|
||||||
JobType pgtype.Text
|
JobType pgtype.Text
|
||||||
Error pgtype.Text
|
Error pgtype.Text
|
||||||
Messages []byte
|
Messages []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type YaraResult struct {
|
||||||
|
ID int64
|
||||||
|
FileID pgtype.UUID
|
||||||
|
Matched []string
|
||||||
}
|
}
|
||||||
|
|
54
server/internal/sqlc/queries-yara.sql.go
Normal file
54
server/internal/sqlc/queries-yara.sql.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: queries-yara.sql
|
||||||
|
|
||||||
|
package sqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const deleteYaraResults = `-- name: DeleteYaraResults :exec
|
||||||
|
DELETE FROM yara_results
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteYaraResults(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.db.Exec(ctx, deleteYaraResults, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getYaraResults = `-- name: GetYaraResults :one
|
||||||
|
SELECT id, file_id, matched FROM yara_results
|
||||||
|
WHERE file_id = $1
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetYaraResults(ctx context.Context, fileID pgtype.UUID) (YaraResult, error) {
|
||||||
|
row := q.db.QueryRow(ctx, getYaraResults, fileID)
|
||||||
|
var i YaraResult
|
||||||
|
err := row.Scan(&i.ID, &i.FileID, &i.Matched)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertYaraResults = `-- name: InsertYaraResults :one
|
||||||
|
INSERT INTO yara_results (
|
||||||
|
file_id, matched
|
||||||
|
) VALUES ($1, $2)
|
||||||
|
RETURNING id, file_id, matched
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertYaraResultsParams struct {
|
||||||
|
FileID pgtype.UUID
|
||||||
|
Matched []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertYaraResults(ctx context.Context, arg InsertYaraResultsParams) (YaraResult, error) {
|
||||||
|
row := q.db.QueryRow(ctx, insertYaraResults, arg.FileID, arg.Matched)
|
||||||
|
var i YaraResult
|
||||||
|
err := row.Scan(&i.ID, &i.FileID, &i.Matched)
|
||||||
|
return i, err
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ sql:
|
||||||
- "server/internal/database/queries-file_properties.sql"
|
- "server/internal/database/queries-file_properties.sql"
|
||||||
- "server/internal/database/queries-processing_jobs.sql"
|
- "server/internal/database/queries-processing_jobs.sql"
|
||||||
- "server/internal/database/queries-msoffice.sql"
|
- "server/internal/database/queries-msoffice.sql"
|
||||||
|
- "server/internal/database/queries-yara.sql"
|
||||||
database:
|
database:
|
||||||
managed: false
|
managed: false
|
||||||
uri: "postgresql://scanfile:${PG_PASSWORD}@localhost:5432/scanfile"
|
uri: "postgresql://scanfile:${PG_PASSWORD}@localhost:5432/scanfile"
|
||||||
|
|
Loading…
Add table
Reference in a new issue