{
"$type": "site.standard.document",
"content": "Not all security is made equal. One might think that the following code is secure.\n\n```c\n#include <stdio.h>\n#include <string.h>\nint main() {\n char input[100];\n const char *secretCode = \"OpenSesame\"; // Expected input\n printf(\"Enter the vault code: \");\n scanf(\"%99s\", input); // Read user input, limit to 99 characters\n // Check if input matches the expected code\n if (strcmp(input, secretCode) == 0) {\n printf(\"Vault Opened\\n\");\n } else {\n printf(\"Incorrect code. Access Denied.\\n\");\n }\n return 0;\n}\n```\n\nThe proverbial vault being protected would only ever open when the correct passcode was provided. When the program is compiled and ran, it behaves as expected.\n\n\n\nThis method of protecting the vault is what I like to call \"Implicit Security\". There are no lines of code dedicated to making the system impenetrable (No, \"if\" statements do not count).\n\n::Hashiyya{title=\"Hashiyya\"}\nThis is a great example of policy versus mechanism. The policy says \"only the correct passcode opens the vault\", but the mechanism is still just mutable branch logic in a local binary.\n::\n\nBreaking this system is trivial, from inspecting strings within the binary to decompiling and inspecting the machine code.\n\nBut there is an even easier and permanent solution to this, but first we'd need to look at something.\n\n### Machine Code Instructions\n\nMachine code is the most low-level representation of a program, they are usually represented as bytes. These bytes are used by the computer's Instruction Set Architecture (ISA) to actually \"execute\" code via a complex set of physical electrical signals on the actual silicon.\n\n*I won't be going into details on these topics but I encourage anyone interested in Reverse Engineering to look into them.*\n\nThere are many Machine code instructions but the important one today is the machine code for branch statements. Branch statements are instructions that control the flow of execution based on the result of comparisons, a.k.a The low-level representation of \"if\" statements.\n\nHere are some that are relevant to this article.\n\n.png)\n\nThe one we are interested in is the \"je\" instruction which would be the low-level representation of what was written in the code.\n\n```c\n// ...\nif (strcmp(input, secretCode) == 0) {\n// ...\n```\n\nTo bypass this check, we will need to change the \"je\" to a \"jne\" which would turn the above code into\n\n```c\n// ...\nif (strcmp(input, secretCode) != 0) {\n// ...\n```\n\nWhich effectively means, if the password is incorrect, open the vault. With this information we can get into the next step.\n\n### Directly Editing Machine Code\n\nThe machine code can be edited with any hex editor but it'll be a lot easier to do so with reverse engineering programs like [Cutter](https://cutter.re/).\n\nThe following disassembly shows the machine code of the relevant section where the passcode comparison is done.\n\n*The \"jne\" below is the equality sign, gcc/clang seems to have made a few optimisations so in this case flipping from a \"jne\" to a \"je\" would be the way to do it*\n\n.png)\n\nTo make the program do our bidding, we change the \"jne\"at 0x100003eeb to a \"je\" which makes the program \"open the vault\".\n\n.png)\n\nAfter this change, the program is successfully broken.\n\n.png)\n\nDon't worry, there's an easy way to fix this.\n\n### Cryptographic Security\n\nThis is where cryptographic security comes in, the best way to secure such a system is to use cryptography in a pseudo-trustless system.\n\nInstead of checking whether the passcode is correct, we could encrypt our data using a key and embed it into the application. This way, if someone enters the wrong key, the data is garbled and even if they edit the code, the data that is embedded is would still be garbled.\n\n::Hashiyya{title=\"Hashiyya\"}\nThis shift is the core security move: make tampering less useful by coupling access to actual data transformation, not only to a UI branch condition.\n::\n\nLet's get started on our function, it'll be a header file so we can include our encryption function in a more secure version of our application and we could also create a separate program to encrypt the data that would be embedded into out new application.\n\nHere's our encryption function.\n\n```c\nchar* xor_encrypt_decrypt(const char *plain_text, const char *key) {\n int text_length = strlen(plain_text);\n int key_length = strlen(key);\n \n // Allocate memory for the output\n char *output = (char*)malloc(text_length + 1);\n if (output == NULL) {\n return NULL; // Handle memory allocation failure\n }\n // Iterate and perform XOR while ensuring printable output\n for (int i = 0; i < text_length; i++) {\n char encrypted_char = plain_text[i] ^ key[i % key_length]; // Perform XOR\n output[i] = (encrypted_char % 95) + 32; // Map to printable range (32-126)\n }\n output[text_length] = '\\0'; // Null-terminate the output string\n return output;\n}\n```\n\nIt takes input data and a key then performs performs an xor operation on every character in the input text.\n\nWhen this is used to generate embeddable data, the resulting program could be made more secure.\n\n.png)\n\nAfter embedding the encrypted data in our original application and only presenting the data based on xor calculations, we manage to get rid of the original problem of someone tampering with our program to get information out. Unless they provide the actual passcode.\n\n.png)\n\n### Conclusion\n\nAlthough the examples in this article are very rudimentary, the overall concept is the same. Securing applications does not just happen, it takes effort and deliberation to find what works best for your system/application/infrastructure.\n\n### Afterword\n\nThanks for going through my article, these take a long time to conceptualise and present in a manner that effectively gets a point across. Please consider giving me a follow as I plan to make more of these in the future.",
"description": "A look at a common security misconception regarding application distribution and how it to avoid it",
"path": "/posts/explicit-security-better-than-implicit-security",
"publishedAt": "2024-09-17T15:40:21.799Z",
"site": "https://blog.mainasara.dev",
"tags": [
"reverseengineering",
"cysec",
"security",
"machinecode",
"analysis",
"reverse engineering",
"x86"
],
"textContent": "Not all security is made equal. One might think that the following code is secure.\n\n```c\n#include <stdio.h>\n#include <string.h>\nint main() {\n char input[100];\n const char *secretCode = \"OpenSesame\"; // Expected input\n printf(\"Enter the vault code: \");\n scanf(\"%99s\", input); // Read user input, limit to 99 characters\n // Check if input matches the expected code\n if (strcmp(input, secretCode) == 0) {\n printf(\"Vault Opened\\n\");\n } else {\n printf(\"Incorrect code. Access Denied.\\n\");\n }\n return 0;\n}\n```\n\nThe proverbial vault being protected would only ever open when the correct passcode was provided. When the program is compiled and ran, it behaves as expected.\n\n\n\nThis method of protecting the vault is what I like to call \"Implicit Security\". There are no lines of code dedicated to making the system impenetrable (No, \"if\" statements do not count).\n\n::Hashiyya{title=\"Hashiyya\"}\nThis is a great example of policy versus mechanism. The policy says \"only the correct passcode opens the vault\", but the mechanism is still just mutable branch logic in a local binary.\n::\n\nBreaking this system is trivial, from inspecting strings within the binary to decompiling and inspecting the machine code.\n\nBut there is an even easier and permanent solution to this, but first we'd need to look at something.\n\n### Machine Code Instructions\n\nMachine code is the most low-level representation of a program, they are usually represented as bytes. These bytes are used by the computer's Instruction Set Architecture (ISA) to actually \"execute\" code via a complex set of physical electrical signals on the actual silicon.\n\n*I won't be going into details on these topics but I encourage anyone interested in Reverse Engineering to look into them.*\n\nThere are many Machine code instructions but the important one today is the machine code for branch statements. Branch statements are instructions that control the flow of execution based on the result of comparisons, a.k.a The low-level representation of \"if\" statements.\n\nHere are some that are relevant to this article.\n\n.png)\n\nThe one we are interested in is the \"je\" instruction which would be the low-level representation of what was written in the code.\n\n```c\n// ...\nif (strcmp(input, secretCode) == 0) {\n// ...\n```\n\nTo bypass this check, we will need to change the \"je\" to a \"jne\" which would turn the above code into\n\n```c\n// ...\nif (strcmp(input, secretCode) != 0) {\n// ...\n```\n\nWhich effectively means, if the password is incorrect, open the vault. With this information we can get into the next step.\n\n### Directly Editing Machine Code\n\nThe machine code can be edited with any hex editor but it'll be a lot easier to do so with reverse engineering programs like [Cutter](https://cutter.re/).\n\nThe following disassembly shows the machine code of the relevant section where the passcode comparison is done.\n\n*The \"jne\" below is the equality sign, gcc/clang seems to have made a few optimisations so in this case flipping from a \"jne\" to a \"je\" would be the way to do it*\n\n.png)\n\nTo make the program do our bidding, we change the \"jne\"at 0x100003eeb to a \"je\" which makes the program \"open the vault\".\n\n.png)\n\nAfter this change, the program is successfully broken.\n\n.png)\n\nDon't worry, there's an easy way to fix this.\n\n### Cryptographic Security\n\nThis is where cryptographic security comes in, the best way to secure such a system is to use cryptography in a pseudo-trustless system.\n\nInstead of checking whether the passcode is correct, we could encrypt our data using a key and embed it into the application. This way, if someone enters the wrong key, the data is garbled and even if they edit the code, the data that is embedded is would still be garbled.\n\n::Hashiyya{title=\"Hashiyya\"}\nThis shift is the core security move: make tampering less useful by coupling access to actual data transformation, not only to a UI branch condition.\n::\n\nLet's get started on our function, it'll be a header file so we can include our encryption function in a more secure version of our application and we could also create a separate program to encrypt the data that would be embedded into out new application.\n\nHere's our encryption function.\n\n```c\nchar* xor_encrypt_decrypt(const char *plain_text, const char *key) {\n int text_length = strlen(plain_text);\n int key_length = strlen(key);\n \n // Allocate memory for the output\n char *output = (char*)malloc(text_length + 1);\n if (output == NULL) {\n return NULL; // Handle memory allocation failure\n }\n // Iterate and perform XOR while ensuring printable output\n for (int i = 0; i < text_length; i++) {\n char encrypted_char = plain_text[i] ^ key[i % key_length]; // Perform XOR\n output[i] = (encrypted_char % 95) + 32; // Map to printable range (32-126)\n }\n output[text_length] = '\\0'; // Null-terminate the output string\n return output;\n}\n```\n\nIt takes input data and a key then performs performs an xor operation on every character in the input text.\n\nWhen this is used to generate embeddable data, the resulting program could be made more secure.\n\n.png)\n\nAfter embedding the encrypted data in our original application and only presenting the data based on xor calculations, we manage to get rid of the original problem of someone tampering with our program to get information out. Unless they provide the actual passcode.\n\n.png)\n\n### Conclusion\n\nAlthough the examples in this article are very rudimentary, the overall concept is the same. Securing applications does not just happen, it takes effort and deliberation to find what works best for your system/application/infrastructure.\n\n### Afterword\n\nThanks for going through my article, these take a long time to conceptualise and present in a manner that effectively gets a point across. Please consider giving me a follow as I plan to make more of these in the future.",
"title": "Explicit Security Is Always Better Than Implicit Security"
}