Skip to content

Commit

Permalink
Fixed Bugs with False Postivies
Browse files Browse the repository at this point in the history
Fixed Bugs with False Postivies
  • Loading branch information
amrudesh1 authored Dec 6, 2023
2 parents 376f4b0 + 58cb712 commit ecf09c8
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 12 deletions.
44 changes: 36 additions & 8 deletions apk/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ limitations under the License.

import (
"encoding/json"
"fmt"
"io/ioutil"
database "morf/db"
"morf/models"
Expand Down Expand Up @@ -56,29 +55,60 @@ func StartCliExtraction(apkPath string, db *gorm.DB) {
log.Error(json_error)
}

//Check if backup folder exists
_, err_ := os.Stat(vip.GetString("backup_path"))

if os.IsNotExist(err_) {
os.Mkdir(vip.GetString("backup_path"), 0755)
}

//Move the APK Data to backup folder
err := ioutil.WriteFile(vip.GetString("backup_path")+"/"+apkPath+"_"+secret.APKVersion+".json", json_data, 0644)
if err != nil {
log.Error(err)
}

// Print File Path to the apk file.json
log.Info("APK Data saved to: " + vip.GetString("backup_path") + "/" + apkPath + "_" + secret.APKVersion + ".json")
}

func StartJiraProcess(jiramodel models.JiraModel, db *gorm.DB, c *gin.Context) {
apk_path := util.DownloadFileUsingSlack(jiramodel, c)
if apk_path == "" {
return
}

apkFound, json_data := util.CheckDuplicateInDB(db, apk_path)

if apkFound {
log.Info("APK already exists in the database")
var secrets models.Secrets
apk_data := json.Unmarshal([]byte(json_data), &secrets)
if apk_data != nil {
log.Error(apk_data)
}
util.CookJiraComment(jiramodel, secrets, c)
return
}

packageModel := ExtractPackageData(apk_path)
metadata := StartMetaDataCollection(apk_path)
scanner_data := StartSecScan("temp/input/" + apk_path)
secret_data, secret_error := json.Marshal(scanner_data)

if secret_error != nil {
log.Error(secret_error)
}
secret := util.CreateSecretModel(apk_path, packageModel, metadata, scanner_data, secret_data)
database.InsertSecrets(secret, db)

// Comment the data to JIRA ticket
util.CookJiraComment(jiramodel, secret, c)
}

func StartExtractProcess(apkPath string, db *gorm.DB, c *gin.Context, isSlack bool, slackData models.SlackData) {

apkFound, json_data := util.CheckDuplicateInDB(db, apkPath)
if apkFound {
if isSlack {
util.RespondToSlack(slackData, c, string(json_data))
util.RespondSecretsToSlack(slackData, c, string(json_data))
} else {

c.JSON(http.StatusOK, gin.H{
Expand All @@ -92,8 +122,6 @@ func StartExtractProcess(apkPath string, db *gorm.DB, c *gin.Context, isSlack bo

packageModel := ExtractPackageData(apkPath)
metadata := StartMetaDataCollection(apkPath)
fmt.Println("Metadata: ", metadata)
fmt.Println("Package Model: ", packageModel)
scanner_data := StartSecScan("temp/input/" + apkPath)
secret_data, secret_error := json.Marshal(scanner_data)

Expand Down Expand Up @@ -138,7 +166,7 @@ func StartExtractProcess(apkPath string, db *gorm.DB, c *gin.Context, isSlack bo
}

if isSlack {
util.RespondToSlack(slackData, c, string(json_data))
util.RespondSecretsToSlack(slackData, c, string(json_data))
}

}
3 changes: 2 additions & 1 deletion apk/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,14 @@ func StartScan(apkPath string) []models.SecretModel {
patternFound = contentParts[1]
}

// Split Secret String between double quotes
if err == nil {
secret := models.SecretModel{
Type: pattern.Pattern.Name,
LineNo: lineNumber,
FileLocation: fileName,
SecretType: typeName,
SecretString: patternFound,
SecretString: strings.Split(patternFound, "\"")[1],
}

resultsChan <- secret
Expand Down
2 changes: 2 additions & 0 deletions db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ limitations under the License.
*/package db

import (
"fmt"
"morf/models"
"os"

Expand All @@ -27,6 +28,7 @@ var DB *gorm.DB
func InitDB() {
// Connect to PHPMyAdmin database
db, err := gorm.Open(mysql.Open(os.Getenv("DATABASE_URL")), &gorm.Config{})
fmt.Println("Database URL:", os.Getenv("DATABASE_URL"))

if err != nil {
panic("failed to connect database")
Expand Down
8 changes: 8 additions & 0 deletions models/JiraModel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package models

type JiraModel struct {
FileUrl string `json:"fileUrl"`
SlackToken string `json:"slackToken"`
Ticket_id string `json:"ticket_id"`
JiraToken string `json:"jiraToken"`
}
23 changes: 22 additions & 1 deletion router/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/package router
*/

package router

import (
"fmt"
Expand All @@ -29,9 +31,11 @@ import (
func InitRouters(router *gin.RouterGroup) *gin.RouterGroup {

router.GET("/health", func(c *gin.Context) {

c.JSON(200, gin.H{
"message": "ok",
})

})

router.POST("/upload", func(c *gin.Context) {
Expand All @@ -46,6 +50,23 @@ func InitRouters(router *gin.RouterGroup) *gin.RouterGroup {

})

router.POST("/jira", func(ctx *gin.Context) {
requestBody := models.JiraModel{}
if err := ctx.ShouldBindBodyWith(&requestBody, binding.JSON); err != nil {
fmt.Println("Error binding request body:", err)
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{"message": "Sit Back and Relax! We are working on it!"})
go func() {
apk.StartJiraProcess(requestBody, db.DB, ctx)
}()
})

router.POST("/release", func(ctx *gin.Context) {

})

router.POST("/slackscan", func(ctx *gin.Context) {
requestBody := models.SlackData{}
if err := ctx.ShouldBindBodyWith(&requestBody, binding.JSON); err != nil {
Expand Down
159 changes: 157 additions & 2 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"os"
"os/exec"
"strconv"
"strings"
"syscall"

log "github.com/sirupsen/logrus"
Expand All @@ -36,6 +37,112 @@ import (
"gorm.io/gorm"
)

func CookJiraComment(jiraModel models.JiraModel, secret models.Secrets, ctx *gin.Context) string {
if len(parseJiraMessage(secret)) == 0 {
return ""
} else {
for _, message := range parseJiraMessage(secret) {
commentToJira(jiraModel, message)
}
}

return "Commented on Jira ticket"
}

func SlackRespond(jiraModel models.JiraModel, slackData models.SlackData) {
slack_app := slack.New(slackData.SlackToken)
_, err := slack_app.AuthTest()
if err != nil {
log.Error(err)
}
_, _, err = slack_app.PostMessage("***REMOVED***", slack.MsgOptionText("```"+"MORF Scan has been completed successfully"+"```", false))
}

func commentToJira(jiraModel models.JiraModel, message string) string {
jira_url := "***REMOVED***" + "/rest/api/2/issue/" + jiraModel.Ticket_id + "/comment"
final_body := map[string]string{"body": message}
final_body_json, _ := json.Marshal(final_body)
log.Info(final_body)
req, err := http.NewRequest("POST", jira_url, bytes.NewBuffer([]byte(final_body_json)))

log.Print(jiraModel.JiraToken)

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Basic "+jiraModel.JiraToken)

if err != nil {
log.Error(err)
}

client := &http.Client{}
resp, err := client.Do(req)

if err != nil {
log.Error(err)
}

defer resp.Body.Close()

log.Info("response Status:", resp.Status)
log.Info("response Headers:", resp.Header)

if resp.StatusCode == 201 {
log.Info("Commented on Jira ticket")
SlackRespond(jiraModel, models.SlackData{SlackToken: jiraModel.SlackToken, SlackChannel: ""})
}

return resp.Status

}

func DownloadFileUsingSlack(jiraModel models.JiraModel, ctx *gin.Context) string {

slack_app := slack.New(jiraModel.SlackToken)
_, err := slack_app.AuthTest()

if err != nil {
log.Error(err)
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return ""
}

// Split URL and get the last part of the URL
url := jiraModel.FileUrl
url_split := strings.Split(url, "/")
file_name := url_split[len(url_split)-1]

file, err := os.Create(file_name)
if err != nil {
log.Error(err)
return ""
}

defer file.Close()

suc := slack_app.GetFile(jiraModel.FileUrl, file)
if suc != nil {
return ""
}

if file_name[len(file_name)-4:] != ".apk" {
log.Error("File is not an APK")
ctx.JSON(http.StatusBadRequest, gin.H{
"status": http.StatusBadRequest,
"message": "File is not an APK",
})
return ""
} else {
log.Info("File is an APK")
ctx.JSON(http.StatusOK, gin.H{
"status": http.StatusOK,
"message": "Downloading of APK successful",
})
}

return file_name

}

func GetDownloadUrlFromSlack(slackData models.SlackData, ctx *gin.Context) string {
slack_app := slack.New(slackData.SlackToken)

Expand Down Expand Up @@ -68,6 +175,7 @@ func GetDownloadUrlFromSlack(slackData models.SlackData, ctx *gin.Context) strin
}
}

fmt.Println(file_url)
file, err := os.Create(file_name)
if err != nil {
log.Error(err)
Expand All @@ -76,6 +184,7 @@ func GetDownloadUrlFromSlack(slackData models.SlackData, ctx *gin.Context) strin

defer file.Close()

log.Print(file_url)
suc := slack_app.GetFile(file_url, file)
if suc != nil {
log.Error(suc)
Expand Down Expand Up @@ -111,7 +220,7 @@ func CheckDuplicateInDB(startDB *gorm.DB, apkPath string) (bool, []byte) {
return false, nil
}

func RespondToSlack(slackData models.SlackData, ctx *gin.Context, data string) {
func RespondSecretsToSlack(slackData models.SlackData, ctx *gin.Context, data string) {
data_string := parseSlackData(data)
slack_app := slack.New(slackData.SlackToken)
for _, message := range data_string {
Expand Down Expand Up @@ -160,7 +269,7 @@ func parseSecretModel(secrets models.Secrets) []string {
"----------------\n"

for _, value := range secretModel {
secretEntry := "Secret Type: " + value.SecretType + "\n" +
secretEntry := "Secret Type: " + value.Type + "\n" +
"Secret Value: " + value.SecretString + "\n" +
"Secret Type: " + value.SecretType + "\n" +
"Line No: " + strconv.Itoa(value.LineNo) + "\n" +
Expand All @@ -182,6 +291,52 @@ func parseSecretModel(secrets models.Secrets) []string {
return messages
}

func parseJiraMessage(secrets models.Secrets) []string {
var secretModel []models.SecretModel

err := json.Unmarshal([]byte(secrets.SecretModel), &secretModel)

if err != nil {
log.Error(err)
}

var messages []string
var currentMessage string

currentMessage = "h2. MORF - Mobile Reconnisance Framework\n" +
"h4. APK Name: " + secrets.FileName + "\n" +
"h4. App Version: " + secrets.APKVersion + "\n" +
"h4. Package Name: " + secrets.PackageDataModel.PackageName + "\n" +
"h4. SHA1: " + secrets.APKHash + "\n" +
"h4. Secrets in APK:\n" +
"----------------\n" +
strconv.Itoa(len(secretModel)) + " secrets found\n" +
"----------------\n"

for _, value := range secretModel {
heading := value.Type
headingMarkup := fmt.Sprintf("\n=== %s ===\n", heading)
secretEntry := headingMarkup +
"{noformat}" + "Secret Value: " + value.SecretString + "\n" +
"Line No: " + strconv.Itoa(value.LineNo) + "\n" +
"File Location: " + value.FileLocation + "\n" +
"{noformat}"

if len(currentMessage)+len(secretEntry) > 32767 { // Jira has a 32,767 character limit per comment
messages = append(messages, currentMessage)
currentMessage = secretEntry
} else {
currentMessage += secretEntry
}
}

if currentMessage != "{noformat}" {
messages = append(messages, currentMessage)
}

return messages
}

func ExtractHash(apkPath string) string {
file, err := os.Open(apkPath)
if err != nil {
Expand Down

0 comments on commit ecf09c8

Please sign in to comment.