Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Feature] Gophish with QR code #2897

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

HLOverflow
Copy link

Hi @jordan-wright

I am sharing the same sentiment on having QR code generated for phishing URL from this issue

I would like to propose my implementation where users can generate QR image with <img src="{{ .QrURL }}" /> in the email template with this pull request.
Screenshot 2023-06-21 174805

Screenshot 2023-06-21 175124

I have also included a way for users to compile the binary via docker if they do not have Golang in their environment.

@Strong-IT-IBK
Copy link

Hi @HLOverflow! I did like your pull request allowing native QR code integration instead of classic links for phishing into gophish. However, while testing your code I found that some newer mail clients (new Outlook, gmail) did not show the base64 embedded .png image for some reason. I looked at other images which were showing correctly in the client and found that they were all referenced trough content-id (img src="cid:...."). Using this method instead of inline base64 embedding with gophish worked for me. Below you can find my slightly different implementation. You can then use the variable {{.RId}} to refernce the generated .png image as an attachment with content-id.

index 8e9afcb..a059695 100644
--- a/go.mod
+++ b/go.mod
@@ -25,6 +25,7 @@ require (
        github.com/mattn/go-sqlite3 v2.0.3+incompatible
        github.com/oschwald/maxminddb-golang v1.6.0
        github.com/sirupsen/logrus v1.4.2
+       github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
        github.com/ziutek/mymysql v1.5.4 // indirect
        golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d
        golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
diff --git a/go.sum b/go.sum
index a7a6e54..7af7b52 100644
--- a/go.sum
+++ b/go.sum
@@ -74,6 +74,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
diff --git a/models/maillog.go b/models/maillog.go
index 7ab3a2e..593dc06 100644
--- a/models/maillog.go
+++ b/models/maillog.go
@@ -12,11 +12,12 @@ import (
        "path/filepath"
        "strings"
        "time"
-
+       "encoding/base64"
        "github.com/gophish/gomail"
        "github.com/gophish/gophish/config"
        log "github.com/gophish/gophish/logger"
        "github.com/gophish/gophish/mailer"
+       qrcode "github.com/skip2/go-qrcode"    //library for generating qrcode
 )

 // MaxSendAttempts set to 8 since we exponentially backoff after each failed send
@@ -164,6 +165,25 @@ func (m *MailLog) GetSmtpFrom() (string, error) {
        return f.Address, err
 }

+//Generate QR code dataurl
+func generateQRCodeData(websiteURL string) string {
+
+       // imageSize = 256 x 256 pixels
+ 
+       imageSize := 256
+       qrCodeImageData, taskError := qrcode.Encode(websiteURL, qrcode.High, imageSize)
+ 
+       if taskError != nil {
+          log.Errorf("Error generating QR code. %s",taskError)
+       }
+ 
+       // Encode raw QR code data to base 64
+       encodedData := base64.StdEncoding.EncodeToString(qrCodeImageData)
+       log.Infof("QR encodedData = %s", encodedData)
+ 
+       return encodedData
+ }
+
 // Generate fills in the details of a gomail.Message instance with
 // the correct headers and body from the campaign and recipient listed in
 // the maillog. We accept the gomail.Message as an argument so that the caller
@@ -260,6 +280,15 @@ func (m *MailLog) Generate(msg *gomail.Message) error {
                addAttachment(msg, a, ptx)
        }

+       // generate QR code png image and embed attachment (reference it with img src="cid:{{.RId}}.png")
+       qrData := generateQRCodeData(ptx.URL)
+       a := Attachment{
+               Content: qrData,
+               Name:    (m.RId+".png"),
+               Type:   "image/png",
+       }
+       addAttachment(msg, a, ptx)
+
        return nil
 }

@FLX-0x00
Copy link
Contributor

FLX-0x00 commented Feb 2, 2024

@Strong-IT-IBK is right: Modern clients, especially web-based ones, do not render inline encoded data for security reasons. Instead, any image must be part of an attachment. Another approach that comes to my mind is to "encode" the qr code with some special characters like U+2588 or "#" to display a qr code as text. e.g. https://github.com/Jojodicus/qr2eascii

@FLX-0x00
Copy link
Contributor

FLX-0x00 commented Feb 2, 2024

Or use a simple html table as output with some background colors on specific cells: https://metacpan.org/pod/HTML::Barcode::QRCode

that would be more stable and flexible on phishing campaigns

https://jsfiddle.net/2rc5yven/

import qrcode

# Generate QR Code
url = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
qr = qrcode.QRCode(
    version=1,
    error_correction=qrcode.constants.ERROR_CORRECT_L,
    box_size=10,
    border=4,
)
qr.add_data(url)
qr.make(fit=True)

# Convert to matrix
img = qr.make_image(fill_color="black", back_color="white")
matrix = qr.get_matrix()

# Convert matrix to HTML table
html_code = '<table style="border-collapse: collapse; border: none;">\n'
for row in matrix:
    html_code += '<tr>\n'
    for cell in row:
        color = 'black' if cell else 'white'
        html_code += f'    <td style="width: 10px; height: 10px; background-color: {color}; border: none;"></td>\n'
    html_code += '</tr>\n'
html_code += '</table>'

# Save HTML code to a file
file_path = 'qr_code_table.html'
with open(file_path, 'w') as file:
    file.write(html_code)

file_path

@vanosg vanosg mentioned this pull request Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants