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

Exploit - CSV Injection #354

Closed
iodn opened this issue Mar 5, 2024 · 3 comments
Closed

Exploit - CSV Injection #354

iodn opened this issue Mar 5, 2024 · 3 comments

Comments

@iodn
Copy link

iodn commented Mar 5, 2024

Summary

[CWE-1236] - CSV Injection

A CSV Injection vulnerability (CWE-1236) was identified in the canarytokens.org platform. This security flaw permits an attacker to inject a CSV payload into the user-agent header. By clicking on a canary token link, this payload is then logged in the canary token owner's dashboard. If the victim exports and opens these logs as a CSV file, the embedded payload is executed. This could lead to unauthorized code execution or other malicious activities.

Details

By changing our own user-agent by a CSV injection payload such as =10+20+cmd|' /C calc'!A0 and then clicking on a canary token link, the payload =10+20+cmd|' /C calc'!A0 gets recorded in the HTML table under the user-agent column.

unnamed

When the canary token owner downloads the logs as a CSV file and opens it on a Windows machine, it results in the execution of the payload (opening the calculator app in this case).

The vulnerability resides in the canarytokens/canarytokens/canarydrop.py file at line 444:

def get_csv_incident_list(self) -> str:
    csvOutput = io.StringIO()
    writer = csv.writer(csvOutput)

    if len(self.triggered_details.hits) > 0:
        hit_class_dict = dict(self.triggered_details.hits[0])
        headers = [
            (i)
            for i in hit_class_dict.keys()
            if i not in ["token_type", "time_of_hit"]
        ]
        writer.writerow(["Timestamp"] + headers)
        for hit in self.triggered_details.hits:
            timestamp = hit.time_of_hit
            hit_id = datetime.fromtimestamp(timestamp).strftime(
                "%Y-%m-%d %H:%M:%S.%f"
            )
            hit_dict = dict(hit)
            data = [hit_id]
            for key in headers:
                data.append(hit_dict.get(key, "N/A"))
            writer.writerow(data)
    else:
        writer.writerow("the token has not been triggered")

    return csvOutput.getvalue()

In this function, there is a lack of sanitization for the inputs that are added to the CSV file. This absence of proper input handling allows for the execution of arbitrary commands when the CSV file is opened, posing a significant security risk.

PoC

Video uploaded on YouTube: https://youtu.be/Bexli-DKbpE

Impact

The primary individuals impacted by this vulnerability are the owners of Canary Tokens. If they export the logs containing the malicious payload and open them on their systems, they could inadvertently execute unauthorized commands or code such as a reverse shell for example. This puts their system's security and data integrity at risk.

Recommendation Fixes / Remediation:

The main concern for CSV injection is data that starts with characters like =, +, -, @, or %. These can be interpreted as formulas or commands by spreadsheet software. A simple way to prevent this is to prepend a single quote (') to any string that begins with such characters. This can be done by modifying the loop where data is appended to the data list.

Here is an example:

for hit in self.triggered_details.hits:
    timestamp = hit.time_of_hit
    hit_id = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S.%f")
    hit_dict = dict(hit)
    data = [hit_id]
    for key in headers:
        cell_value = str(hit_dict.get(key, "N/A"))
        # Prepend a single quote to any cell that starts with a dangerous character
        if cell_value.startswith(('=', '+', '-', '@', '%')):
            cell_value = "'" + cell_value
        data.append(cell_value)
    writer.writerow(data)

This modification checks each cell value and, if it starts with a character that could lead to CSV injection, prepends a single quote to it. This way, when the CSV file is opened in a spreadsheet program, the program will treat the cell's contents as a string rather than a formula.

Reference:

https://medium.com/cryptogennepal/what-is-a-csv-injection-attack-9208b54b4598
https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CSV%20Injection/README.md

P.S.: I previously reached out via email to security@thinkst.com on January 31, but haven't yet received a reply. I'm posting here now to ensure visibility. Thank you.

@iodn iodn added the bug label Mar 5, 2024
@thinkst-marco
Copy link
Contributor

Thanks for the report, we're looking into it now. Unfortunately we've got no record of the mail to security@thinkst.com, hence this delay. We'll figure out why the mail didn't arrive once we've sorted this issue.

@iodn
Copy link
Author

iodn commented Mar 6, 2024

I just checked and I realized that it was actually sent on January 19.

image

@thinkst-marco
Copy link
Contributor

@iodn thanks again for the report. We've pushed fixes live to canarytokens.org, and published an advisory at GHSA-fqh6-v4qp-65fv. We've also requested a CVE, and the advisory will be updated when one is issued.

I'd like to send swag to say thanks, if you drop me a mail at marco [at] thinkst [dot] com, we'll get it sent through.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants