{"id":546,"date":"2018-03-14T10:11:43","date_gmt":"2018-03-14T10:11:43","guid":{"rendered":"http:\/\/imalogic.com\/blog\/?p=546"},"modified":"2020-10-15T14:00:18","modified_gmt":"2020-10-15T14:00:18","slug":"fortify-static-code-analyzer","status":"publish","type":"post","link":"https:\/\/imalogic.com\/blog\/2018\/03\/14\/fortify-static-code-analyzer\/","title":{"rendered":"Fortify Static Code Analyzer"},"content":{"rendered":"<body><p><\/p>\n<p align=\"LEFT\">HP Fortify Static Code Analyzer (SCA) is a set of software security analyzers that search for violations of security-specific coding rules and guidelines in a variety of languages. The rich data provided by SCA language technology enables the analyzers to pinpoint and prioritize violations so that fixes can be fast and accurate. The analysis information produced by SCA helps you deliver more secure software, as well as making security code reviews more efficient, consistent, and complete. This is especially advantageous when large code bases are involved. The modular architecture of SCA allows you to quickly upload new third-party and customer-specific security rules.<\/p>\n<h3 align=\"LEFT\">The way of working<\/h3>\n<p align=\"LEFT\">Use fortify for a \u201cbig existing visual solution\u201d is not easy.\u00a0\u00a0And in my case, the visual solution\u00a0is\u00a0composed as more than\u00a0200 visual projects ! So, we have to manage\u00a0several points :<\/p>\n<h4>Project Type and Implications<\/h4>\n<p>We have three project types, each of them having their implications regarding fixing project issues:<\/p>\n<ul>\n<li>Application projects have probably the lesser implications, as their build does not affect other projects (their runtime might, of course).<\/li>\n<li>DLL projects could be released independently under the assumption that the interface doesn\u2019t change, and that proper unit testing is in place (to ensure that any modification doesn\u2019t break the interface contract).<\/li>\n<li>Static Library projects are the trickier ones, as fixing them will necessarily require the build.<\/li>\n<\/ul>\n<h4><a name=\"_Toc482799176\"><\/a>Dependency Analysis<\/h4>\n<p>The following analysis will be about the spread of issues across projects, while considering the dependency graph.<\/p>\n<p>This dependency analysis is done based on the dependency information as defined in the visual studio solution by the user. There are other dependencies that are not recorded (such as COM+ dependencies for our COM+ projects, or even P\/Invoked DLLs in C# code). The report still provides sufficient details in order to define some initial plans of action.<\/p>\n<p>The current results focus on the issues with Critical, High and Medium severities.<\/p>\n<h4><a name=\"_Toc482799177\"><\/a>Naming Used in the Analysis<\/h4>\n<p>There are some terms that will be used in the remainder of the documentation:<\/p>\n<ul>\n<li>\u201cRequires\u201d dependency: relationship between two projects where the subject depends on the object.<\/li>\n<li>\u201cUsed By\u201d dependency: relationship between two projects where the object depends on the object.<\/li>\n<li>Direct dependency: when the relationship between two projects is direct (as opposed to having an intermediate project that creates the dependency).<\/li>\n<li>Recursive dependencies: all direct dependencies of a project and all dependencies of those dependencies (recursively).<\/li>\n<\/ul>\n<h4><a name=\"_Toc482799178\"><\/a>Overview<\/h4>\n<p>We have found more than 16000 Critical issues and some specific issues detected are very hard to fix, need some change in architecture, way of working,\u2026 E.g. for the issues present in the DLLs, these projects could be released independently if done carefully:<\/p>\n<ul>\n<li>We would need to create careful unit testing before doing any changes, to make sure we can regress our fixes.<\/li>\n<li>We would have to still do end-to-end testing, although eventually in a lighter or less exhaustive activity.<\/li>\n<li>\u201cDeprecrate message\u201d should be inserted in the current DLLs entry point to notify the creation of the new DLL version and to make a progressive transition of usage of these new entries points.<\/li>\n<\/ul>\n<h4><a name=\"_Toc482799182\"><\/a>Possible Preliminary Actions<\/h4>\n<p>Any decided plan of action should take into account:<\/p>\n<ul>\n<li>The operational cost involved in fixing bugs (do the actual fixes, do the testing \u2013 unit and e2e): which projects should we proactively fix, which ones should we wait for an IM\/PM (and therefore leave it towards the end) to also fix the issues reported by Fortify.<\/li>\n<li>The operational cost of releasing common projects (DLLs in particular) in very early stage vs deferring them for a reasonable period, in case an IM\/PM shows that requires a functional fix (this might optimize testing\/releasing, since we avoid a release for fixing Fortify specifically).<\/li>\n<li>The functional impact of releasing each project: which other projects have a dependency in code or in the architecture.<\/li>\n<li>The security impact of each project: in terms of what issues represent bigger threats, what applications are more security-sensitive, whether it\u2019s better to fix one project with a big count of issues or many others with small count.<\/li>\n<\/ul>\n<h4>Deferring the Fixing of DLL Issues<\/h4>\n<ul>\n<li>A hard requirement that all DLL dependencies need to be fixed when an application is fixed will probably hinder the team. The reason for this is that such requirement will force to test (E2E) all other applications that also use the same dependency, which is a cost that we might not be able to afford without proper planning and time-boxing.There will be significant amount of unit test development to be done around DLLs, which we\u2019ll also need to plan for.<\/li>\n<\/ul>\n<h3>Fortify scan<\/h3>\n<p>We use a batch to launch the\u00a0fortify scan for a specific project or for all. Its separated from common build chain because\u00a0its take too much time to make a scan\u00a0every time. A security scan should be\u00a0done at the end of development after the testing and before releasing application.<\/p>\n<p>Launching Fortify can be done by using a specific menu installed in Visual Studio.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" data-attachment-id=\"606\" data-permalink=\"https:\/\/imalogic.com\/blog\/2018\/03\/14\/fortify-static-code-analyzer\/fortify3\/\" data-orig-file=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?fit=967%2C350&amp;ssl=1\" data-orig-size=\"967,350\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"fortify3\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?fit=810%2C293&amp;ssl=1\" class=\" wp-image-606 aligncenter\" src=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?resize=732%2C266&#038;ssl=1\" alt=\"\" width=\"732\" height=\"266\" loading=\"lazy\" srcset=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?resize=300%2C109&amp;ssl=1 300w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?resize=768%2C278&amp;ssl=1 768w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify3.png?w=967&amp;ssl=1 967w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a><\/p>\n<p>Or via a specific command line using several parameters.<\/p>\n<blockquote>\n<pre>sourceanalyzer -b MyBuild -machine-output devenv All-projects.sln \/BUILD debug \/project \"..\\projects\\%$_MyProject%\\%$_MyProject%.vcxproj\" \/ProjectConfig %$_Bits%<\/pre>\n<\/blockquote>\n<p>The result files from the analyzer is a \u201c.fpr\u201d file type and can be opened using the audit workbench tools.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" data-attachment-id=\"600\" data-permalink=\"https:\/\/imalogic.com\/blog\/2018\/03\/14\/fortify-static-code-analyzer\/fortify\/\" data-orig-file=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?fit=2064%2C1159&amp;ssl=1\" data-orig-size=\"2064,1159\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"fortify\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?fit=810%2C455&amp;ssl=1\" class=\"wp-image-600 aligncenter\" src=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?resize=726%2C407&#038;ssl=1\" alt=\"\" width=\"726\" height=\"407\" loading=\"lazy\" srcset=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?resize=300%2C168&amp;ssl=1 300w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?resize=768%2C431&amp;ssl=1 768w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?resize=1024%2C575&amp;ssl=1 1024w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/fortify.png?w=1620&amp;ssl=1 1620w\" sizes=\"auto, (max-width: 726px) 100vw, 726px\" \/><\/a><\/p>\n<p>With this audit tools, we can have a look at all security risk.<\/p>\n<p>For this huge \u201cproject\u201d (composed of many small\/medium projects), we have start with a two pass approach.<\/p>\n<ul>\n<li>First step called (QuickWins) is used to detect and fix the simple issues.<\/li>\n<li>Second step is used to fix more complex issues.<\/li>\n<\/ul>\n<p>To improve the way of working, we have done a fortify Library composed with fortify functions used to fix issues detected.<\/p>\n<p>Also, some security issues can be detected only in runtime, means that a specific functions can return some \u201calarm\u201d when secutiry issues are detected\u2026<\/p>\n<figure id=\"attachment_912\" aria-describedby=\"caption-attachment-912\" style=\"width: 810px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" data-attachment-id=\"912\" data-permalink=\"https:\/\/imalogic.com\/blog\/2018\/03\/14\/fortify-static-code-analyzer\/board\/\" data-orig-file=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?fit=1313%2C752&amp;ssl=1\" data-orig-size=\"1313,752\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"board\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?fit=810%2C464&amp;ssl=1\" class=\"wp-image-912 size-large\" src=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?resize=810%2C464&#038;ssl=1\" alt=\"\" width=\"810\" height=\"464\" loading=\"lazy\" srcset=\"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?resize=1024%2C586&amp;ssl=1 1024w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?resize=300%2C172&amp;ssl=1 300w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?resize=768%2C440&amp;ssl=1 768w, https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2018\/03\/board.png?w=1313&amp;ssl=1 1313w\" sizes=\"auto, (max-width: 810px) 100vw, 810px\" \/><\/a><figcaption id=\"caption-attachment-912\" class=\"wp-caption-text\">A Dashboard sample used during the project development, overview of all projects issues fixed, pending,\u2026<\/figcaption><\/figure>\n<h3>Sample of Fortify Library Helper<\/h3>\n<blockquote>\n<pre>FORTIFY_API\u00a0int fortifyPathManipulation(const char *originalPath, int size);\n\nFORTIFY_API int \u00a0fortifyReverseDnsCheck(struct hostent *resolvedHost);\n\nFORTIFY_API void fortifyEraseAndCleanMemory(void *ptr, int size);<\/pre>\n<\/blockquote>\n<h3>Typical Security Issues detected by Fortify Scan<\/h3>\n<h4>Potential command injection with Process.Start<\/h4>\n<p>The dynamic value passed to the command execution should be validated.<\/p>\n<h4>Vulnerable Code<\/h4>\n<pre>Process p = new Process();\n p.StartInfo.FileName = \"exportLegacy.exe\";\n p.StartInfo.Arguments = \" -user \" + input + \" -role user\";\n p.Start();<\/pre>\n<h4>Risk<\/h4>\n<p>If a malicious user is able to controlled either the command FileName or Arguments, he might be able to execute unwanted commands or add unwanted argument. This behavior would not be possible if input parameter are validate against a whitelist of characters.<\/p>\n<h4>Solution<\/h4>\n<pre>Regex rgx = new Regex(@\"^[a-zA-Z0-9]+$\");\nif(rgx.IsMatch(input)) {\n    Process p = new Process();\n    p.StartInfo.FileName = \"exportLegacy.exe\";\n    p.StartInfo.Arguments = \" -user \" + input + \" -role user\";\n    p.Start();\n}\n<\/pre>\n<h3 id=\"FortifyStaticCodeAnalyzer-BufferOverflowAttacks\">Buffer Overflow Attacks<\/h3>\n<p>It gets worse when an attacker comes to know about a buffer over flow in your program and he\/she exploits it.\u00a0Consider this example :<\/p>\n<blockquote>\n<pre>#include &lt;stdio.h&gt; #include &lt;string.h&gt;\n\nint main(void) {\n\nchar buff[15]; \u00a0\u00a0\u00a0 int pass = 0;\n\nprintf(\"\\n Enter the password : \\n\"); \u00a0\u00a0\u00a0 gets(buff);\n\nif (strcmp(buff, \"thegeekstuff\")) \u00a0\u00a0\u00a0 {\n\nprintf (\"\\n Wrong Password \\n\");\n\n} \u00a0\u00a0\u00a0 else \u00a0\u00a0\u00a0 {\n\nprintf (\"\\n Correct Password \\n\"); \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pass = 1;\n\n}\n\nif (pass) \u00a0\u00a0\u00a0 {\n\n\/* Now Give root or admin rights to user*\/\n\nprintf (\"\\n Root privileges given to the user \\n\");\n\n}\n\nreturn 0;\n\n}\n\n\n<\/pre>\n<\/blockquote>\n<p>The program above simulates scenario where a program expects a password from user and if the password is correct then it grants root privileges to the user.<\/p>\n<p>Let\u2019s the run the program with correct password ie \u2018thegeekstuff\u2019 :<\/p>\n<blockquote>\n<pre>$ .\/bfrovrflw\n\nEnter the password : thegeekstuff\n\nCorrect Password\n\nRoot privileges given to the user<\/pre>\n<\/blockquote>\n<p>This works as expected. The passwords match and root privileges are given.<\/p>\n<p>But do you know that there is a possibility of buffer overflow in this program. The gets() function does not check the array bounds and can even write string of length greater than the size of the buffer to which the string is written. Now, can you even imagine what can an attacker do with this kind of a loophole?<\/p>\n<p>Here is an example :<\/p>\n<blockquote>\n<pre style=\"width: 784px; height: 69px;\">$ .\/bfrovrflw<\/pre>\n<pre>Enter the password : hhhhhhhhhhhhhhhhhhhh<\/pre>\n<pre>Wrong Password<\/pre>\n<pre>Root privileges given to the user.<\/pre>\n<\/blockquote>\n<p>In the above example, even after entering a wrong password, the program worked as if you gave the correct password.<\/p>\n<p>There is a logic behind the output above. What attacker did was, he\/she supplied an input of length greater than what buffer can hold and at a particular length of input the buffer overflow so took place that it overwrote the memory of integer \u2018pass\u2019. So despite of a wrong password, the value of \u2018pass\u2019 became non zero and hence root privileges were granted to an attacker.<\/p>\n<p>There are several other advanced techniques (like code injection and execution) through which buffer over flow attacks can be done but it is always important to first know about the basics of buffer, it\u2019s overflow and why it is harmful.<\/p>\n<h2 id=\"FortifyStaticCodeAnalyzer-ReturnOrientedProgramming(ROP)\"><\/h2>\n<h1 id=\"FortifyStaticCodeAnalyzer-Commonvulnerabilitiesguide\">Common vulnerabilities guide<\/h1>\n<p>Most vulnerabilities in C are related to buffer overflows\u00a0and string manipulation. In most cases, this would result in a segmentation fault, but specially crafted malicious input values, adapted to the architecture and environment could yield to arbitrary code execution. You will find below a list of the most common errors and suggested fixes\/solutions.<\/p>\n<h2 id=\"FortifyStaticCodeAnalyzer-gets\">gets<\/h2>\n<p>The stdio gets() function does not check for buffer length and always results in a vulnerability.<\/p>\n<h5 id=\"FortifyStaticCodeAnalyzer-Vulnerablecode\">Vulnerable code<\/h5>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n<span class=\"kw4\">int<\/span> main <span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw4\">char<\/span> username<span class=\"br0\">[<\/span>8<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw4\">int<\/span> allow <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span>\n<a class=\"external-link\" href=\"http:\/\/www.opengroup.org\/onlinepubs\/009695399\/functions\/printf.html\" rel=\"nofollow\"><span class=\"kw3\">printf<\/span><\/a> <span class=\"br0\">(<\/span><span class=\"st0\">\"Enter your username, please: \"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\ngets<span class=\"br0\">(<\/span>username<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span> <span class=\"co1\">\/\/ user inputs \"malicious\"<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>grantAccess<span class=\"br0\">(<\/span>username<span class=\"br0\">)<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\nallow <span class=\"sy0\">=<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>allow <span class=\"sy0\">!=<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span> <span class=\"co1\">\/\/ has been overwritten by the overflow of the username.<\/span>\nprivilegedAction<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n<span class=\"kw1\">return<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<p>Prefer using fgets (and dynamically allocated memory!):<\/p>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n<span class=\"co2\">#include &lt;stdlib.h&gt;<\/span>\n<span class=\"co2\">#define LENGTH 8<\/span>\n<span class=\"kw4\">int<\/span> main <span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw4\">char<\/span><span class=\"sy0\">*<\/span> username<span class=\"sy0\">,<\/span> <span class=\"sy0\">*<\/span>nlptr<span class=\"sy0\">;<\/span>\n<span class=\"kw4\">int<\/span> allow <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span>\n\nusername <span class=\"sy0\">=<\/span> malloc<span class=\"br0\">(<\/span>LENGTH <span class=\"sy0\">*<\/span> <span class=\"kw4\">sizeof<\/span><span class=\"br0\">(<\/span><span class=\"sy0\">*<\/span>username<span class=\"br0\">)<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span><span class=\"sy0\">!<\/span>username<span class=\"br0\">) r<\/span><span class=\"kw1\">eturn<\/span> EXIT_FAILURE<span class=\"sy0\">;<\/span>\n<u><span class=\"kw3\">printf<\/span><\/u> <span class=\"br0\">(<\/span><span class=\"st0\">\"Enter your username, please: \"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\nfgets<span class=\"br0\">(<\/span>username<span class=\"sy0\">,<\/span>LENGTH<span class=\"sy0\">,<\/span> stdin<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"co1\">\/\/ fgets stops after LENGTH-1 characters or at a newline character, which ever comes first.<\/span>\n<span class=\"co1\">\/\/ but it considers \\n a valid character, so you might want to remove it:<\/span>\nnlptr <span class=\"sy0\">=<\/span> strchr<span class=\"br0\">(<\/span>username<span class=\"sy0\">,<\/span> <span class=\"st0\">'<span class=\"es1\">\\n<\/span>'<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>nlptr<span class=\"br0\">)<\/span> <span class=\"sy0\">*<\/span>nlptr <span class=\"sy0\">=<\/span> <span class=\"st0\">'<span class=\"es5\">\\0<\/span>'<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>grantAccess<span class=\"br0\">(<\/span>username<span class=\"br0\">)<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\nallow <span class=\"sy0\">=<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>allow <span class=\"sy0\">!=<\/span> 0<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\npriviledgedAction<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n\nfree<span class=\"br0\">(<\/span>username<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw1\">return<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}\n<\/span><\/pre>\n<\/blockquote>\n<h2 id=\"FortifyStaticCodeAnalyzer-strcpy\">strcpy<\/h2>\n<p>The strcpy built-in function does not check buffer lengths and may very well overwrite memory zone contiguous to the intended destination. In fact, the whole family of functions is similarly vulnerable: strcpy, strcat and strcmp.<\/p>\n<p><strong>Vulnerable code<\/strong><\/p>\n<blockquote>\n<pre><span class=\"kw4\">char<\/span> str1<span class=\"br0\">[<\/span>10<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw4\">char<\/span> str2<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">\"abcdefghijklmn\"<\/span><span class=\"sy0\">;<\/span>\nstrcpy<span class=\"br0\">(<\/span>str1<span class=\"sy0\">,<\/span>str2<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/blockquote>\n<p>The best way to mitigate this issue is to use strlcpy if it is readily available (which is only the case on BSD systems). However, it is very simple to define it yourself, as shown below:<\/p>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n\n<span class=\"co2\">#ifndef strlcpy<\/span>\n<span class=\"co2\">#define strlcpy(dst,src,sz) snprintf((dst), (sz), \"%s\", (src))<\/span>\n<span class=\"co2\">#endif<\/span>\n\n<span class=\"kw2\">enum<\/span> <span class=\"br0\">{<\/span> BUFFER_SIZE <span class=\"sy0\">=<\/span> 10 <span class=\"br0\">}<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw4\">int<\/span> main<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw4\">char<\/span> dst<span class=\"br0\">[<\/span>BUFFER_SIZE<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw4\">char<\/span> src<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">\"abcdefghijk\"<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw4\">int<\/span> buffer_length <span class=\"sy0\">=<\/span> strlcpy<span class=\"br0\">(<\/span>dst<span class=\"sy0\">,<\/span> src<span class=\"sy0\">,<\/span> BUFFER_SIZE<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>buffer_length <span class=\"sy0\">&gt;=<\/span> BUFFER_SIZE<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw3\">printf<\/span> <span class=\"br0\">(<\/span><span class=\"st0\">\"String too long: %d (%d expected)<span class=\"es1\">\\n<\/span>\"<\/span><span class=\"sy0\">,<\/span>\nbuffer_length<span class=\"sy0\">,<\/span> BUFFER_SIZE<span class=\"sy0\">-<\/span>1<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n\n<u><span class=\"kw3\">printf<\/span><\/u> <span class=\"br0\">(<\/span><span class=\"st0\">\"String copied: %s<span class=\"es1\">\\n<\/span>\"<\/span><span class=\"sy0\">,<\/span> dst<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw1\">return<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<p>Another and may be slightly less convenient way is to use strncpy, which prevents buffer overflows, but does not guarantee \u2018\\0\u2019-termination.<\/p>\n<blockquote>\n<pre><span class=\"kw2\">enum<\/span> <span class=\"br0\">{<\/span> BUFFER_SIZE <span class=\"sy0\">=<\/span> 10 <span class=\"br0\">}<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw4\">char<\/span> str1<span class=\"br0\">[<\/span>BUFFER_SIZE<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw4\">char<\/span> str2<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">\"abcdefghijklmn\"<\/span><span class=\"sy0\">;<\/span>\n<span class=\"coMULTI\">\/* limit number of characters to be copied *\/<\/span>\nstrncpy<span class=\"br0\">(<\/span>str1<span class=\"sy0\">,<\/span>str2<span class=\"sy0\">,<\/span> BUFFER_SIZE<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"co1\">\/\/ We need to set the limit to BUFFER_SIZE, so that all characters in the buffer<\/span>\n<span class=\"co1\">\/\/ are set to '\\0'. If the source buffer is longer than BUFFER_SIZE, all the '\\0'<\/span>\n<span class=\"co1\">\/\/ characters will be overwritten and the copy will be truncated.<\/span>\n\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>str1<span class=\"br0\">[<\/span>BUFFER_SIZE<span class=\"sy0\">-<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">]<\/span> <span class=\"sy0\">!=<\/span> <span class=\"st0\">'<span class=\"es5\">\\0<\/span>'<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"coMULTI\">\/* buffer was truncated, handle error? *\/<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<p>For the other functions in the family, the *n* variants exist as well: strncpm and strncat<\/p>\n<h2 id=\"FortifyStaticCodeAnalyzer-sprintf\">sprintf<\/h2>\n<div class=\"level3\">\n<p>Just as the previous functions, sprintf does not check the buffer boundaries and is vulnerable to overflows.<\/p>\n<h5 id=\"FortifyStaticCodeAnalyzer-Vulnerablecode.1\">Vulnerable code<\/h5>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n<span class=\"co2\">#include &lt;stdlib.h&gt;<\/span>\n\n<span class=\"kw2\">enum<\/span> <span class=\"br0\">{<\/span> BUFFER_SIZE <span class=\"sy0\">=<\/span> 10 <span class=\"br0\">}<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw4\">int<\/span> main<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw4\">char<\/span> buffer<span class=\"br0\">[<\/span>BUFFER_SIZE<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw4\">int<\/span> check <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span>\n\nsprintf<span class=\"br0\">(<\/span>buffer<span class=\"sy0\">,<\/span> <span class=\"st0\">\"%s\"<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">\"This string is too long!\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<u><span class=\"kw3\">printf<\/span><\/u> <span class=\"br0\">(<\/span><span class=\"st0\">\"check: %d\"<\/span><span class=\"sy0\">,<\/span> check<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span> <span class=\"coMULTI\">\/* This will not print 0! *\/<\/span>\n\n<span class=\"kw1\">return<\/span> EXIT_SUCCESS<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<p><span class=\"br0\">Prefer using snprintf, which has the double advantage of preventing buffers overflows and returning the minimal size of buffer needed to fit the whole formatted string. <\/span><\/p>\n<\/div>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n<span class=\"co2\">#include &lt;stdlib.h&gt;<\/span>\n\n<span class=\"kw2\">enum<\/span> <span class=\"br0\">{<\/span> BUFFER_SIZE <span class=\"sy0\">=<\/span> 10 <span class=\"br0\">}<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw4\">int<\/span> main<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw4\">char<\/span> buffer<span class=\"br0\">[<\/span>BUFFER_SIZE<span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw4\">int<\/span> length <span class=\"sy0\">=<\/span> snprintf<span class=\"br0\">(<\/span>buffer<span class=\"sy0\">,<\/span> BUFFER_SIZE<span class=\"sy0\">,<\/span> <span class=\"st0\">\"%s%s\"<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">\"long-name\"<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">\"suffix\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>length <span class=\"sy0\">&gt;=<\/span> BUFFER_SIZE<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"coMULTI\">\/* handle string truncation! *\/<\/span>\n<span class=\"br0\">}<\/span>\n\n<span class=\"kw1\">return<\/span> EXIT_SUCCESS<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<h2 id=\"FortifyStaticCodeAnalyzer-printfandfriends\">printf and friends<\/h2>\n<div class=\"level3\">\n<p>One other vulnerability category is concerned with string formatting attacks , those can cause information leakage, overwriting of memory, \u2026 This error can be exploited in any of the following functions: printf, fprintf, sprintf and snprintf, <em>i.e.<\/em> all functions that take a \u201cformat string\u201d as argument.<\/p>\n<p>It\u2019s really simple: <strong>always<\/strong> hardcode the format string. At least, <strong>never<\/strong> let it come directly from any user\u2019s input.<\/p>\n<\/div>\n<h2 id=\"FortifyStaticCodeAnalyzer-Fileopening\">File opening<\/h2>\n<p>Much care must be taken when opening files, as many issues can arise. This is covered in much detail by Kupsch and Miller in <a class=\"external-link\" title=\"http:\/\/www.cs.wisc.edu\/mist\/presentations\/kupsch_miller_secse08.pdf\" href=\"http:\/\/www.cs.wisc.edu\/mist\/presentations\/kupsch_miller_secse08.pdf\" rel=\"nofollow\">this tutorial<\/a>. They also provide libraries implementing their approach. Out of the many ways file handling can be attacked, we will only present two brief examples below.<\/p>\n<p>Some of the basic pitfalls are described below.<\/p>\n<h2 id=\"FortifyStaticCodeAnalyzer-Symboliclinkattack\">Symbolic link attack<\/h2>\n<div class=\"level4\">\n<p>It is a good idea to check whether a file exists or not before creating it. However, a malicious user might create a file (or worse, a symbolic link to a critical system file) between your check and the moment you actually use the file.<\/p>\n<h5 id=\"FortifyStaticCodeAnalyzer-Vulnerablecode.2\">Vulnerable code<\/h5>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n<span class=\"co2\">#include &lt;stdlib.h&gt;<\/span>\n<span class=\"co2\">#include &lt;unistd.h&gt;<\/span>\n\n<span class=\"co2\">#define MY_TMP_FILE \"\/tmp\/file.tmp\"<\/span>\n\n<span class=\"kw4\">int<\/span> main<span class=\"br0\">(<\/span><span class=\"kw4\">int<\/span> argc<span class=\"sy0\">,<\/span> <span class=\"kw4\">char<\/span><span class=\"sy0\">*<\/span> argv<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">{<\/span>\nFILE <span class=\"sy0\">*<\/span> f<span class=\"sy0\">;<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span><span class=\"sy0\">!<\/span>access<span class=\"br0\">(<\/span>MY_TMP_FILE<span class=\"sy0\">,<\/span> F_OK<span class=\"br0\">)<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw3\"><u>printf<\/u><\/span> <span class=\"br0\">(<\/span><span class=\"st0\">\"File exists!<span class=\"es1\">\\n<\/span>\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">return<\/span> EXIT_FAILURE<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n<span class=\"coMULTI\">\/* At this point the attacker creates a symlink from \/tmp\/file.tmp to \/etc\/passwd *\/<\/span>\ntmpFile <span class=\"sy0\">=<\/span> fopen<span class=\"br0\">(<\/span>MY_TMP_FILE<span class=\"sy0\">,<\/span> <span class=\"st0\">\"w\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>tmpFile <span class=\"sy0\">==<\/span> NULL<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n<span class=\"kw1\">return<\/span> EXIT_FAILURE<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n\nfputs<span class=\"br0\">(<\/span><span class=\"st0\">\"Some text...<span class=\"es1\">\\n<\/span>\"<\/span><span class=\"sy0\">,<\/span> tmpFile<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\nfclose<span class=\"br0\">(<\/span>tmpFile<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"coMULTI\">\/* You successfully overwrote \/etc\/passwd (at least if you ran this as root) *\/<\/span>\n\n<span class=\"kw1\">return<\/span> EXIT_SUCCESS<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<p>Avoid the race condition by accessing directly the file, and don\u2019t overwrite it if it already exists. So,<\/p>\n<\/div>\n<blockquote>\n<pre><span class=\"co2\">#include &lt;unistd.h&gt;<\/span>\n<span class=\"co2\">#include &lt;stdio.h&gt;<\/span>\n<span class=\"co2\">#include &lt;fcntl.h&gt;<\/span>\n<span class=\"co2\">#include &lt;stdlib.h&gt;<\/span>\n\n<span class=\"co2\">#define MY_TMP_FILE \"\/tmp\/file.tmp\"<\/span>\n\n<span class=\"kw2\">enum<\/span> <span class=\"br0\">{<\/span> FILE_MODE <span class=\"sy0\">=<\/span> 0600 <span class=\"br0\">}<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"kw4\">int<\/span> main<span class=\"br0\">(<\/span><span class=\"kw4\">int<\/span> argc<span class=\"sy0\">,<\/span> <span class=\"kw4\">char<\/span><span class=\"sy0\">*<\/span> argv<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span><span class=\"br0\">)<\/span>\n<span class=\"br0\">{<\/span>\n<span class=\"kw4\">int<\/span> fd<span class=\"sy0\">;<\/span>\nFILE<span class=\"sy0\">*<\/span> f<span class=\"sy0\">;<\/span>\n\n<span class=\"coMULTI\">\/* Remove possible symlinks *\/<\/span>\nunlink<span class=\"br0\">(<\/span>MY_TMP_FILE<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"coMULTI\">\/* Open, but fail if someone raced us and restored the symlink (secure version of fopen(path, \"w\") *\/<\/span>\nfd <span class=\"sy0\">=<\/span> open<span class=\"br0\">(<\/span>MY_TMP_FILE<span class=\"sy0\">,<\/span> O_WRONLY<span class=\"sy0\">|<\/span>O_CREAT<span class=\"sy0\">|<\/span>O_EXCL<span class=\"sy0\">,<\/span> FILE_MODE<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>fd <span class=\"sy0\">==<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\nperror<span class=\"br0\">(<\/span><span class=\"st0\">\"Failed to open the file\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">return<\/span> EXIT_FAILURE<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n\n<span class=\"coMULTI\">\/* Get a FILE*, as they are easier and more efficient than plan file descriptors *\/<\/span>\nf <span class=\"sy0\">=<\/span> fdopen<span class=\"br0\">(<\/span>fd<span class=\"sy0\">,<\/span> <span class=\"st0\">\"w\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>f <span class=\"sy0\">==<\/span> NULL<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\nperror<span class=\"br0\">(<\/span><span class=\"st0\">\"Failed to associate file descriptor with a stream\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">return<\/span> EXIT_FAILURE<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\nfprintf<span class=\"br0\">(<\/span>f<span class=\"sy0\">,<\/span> <span class=\"st0\">\"Hello, world<span class=\"es1\">\\n<\/span>\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\nfclose<span class=\"br0\">(<\/span>f<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\n<span class=\"coMULTI\">\/* fd is already closed by fclose()!!! *\/<\/span>\n<span class=\"kw1\">return<\/span> EXIT_SUCCESS<span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><\/pre>\n<\/blockquote>\n<h3>References<\/h3>\n<p><a href=\"https:\/\/www.owasp.org\/index.php\/Command_Injection\">OWASP: Command Injection<\/a><br>\n<a href=\"https:\/\/www.owasp.org\/index.php\/Top_10_2013-A1-Injection\">OWASP: Top 10 2013-A1-Injection<\/a><br>\n<a href=\"http:\/\/cwe.mitre.org\/data\/definitions\/78.html\">CWE-78: Improper Neutralization of Special Elements used in an OS Command (\u2018OS Command Injection\u2019)<\/a><\/p>\n<\/body>","protected":false},"excerpt":{"rendered":"<p>HP Fortify Static Code Analyzer (SCA) is a set of software security analyzers that search for violations of security-specific coding<\/p>\n","protected":false},"author":1,"featured_media":551,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[65,7,76],"tags":[24,82,80,83,81],"class_list":["post-546","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analyse","category-coding","category-security","tag-c","tag-coding-secure","tag-fortify","tag-hack","tag-security"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/imalogic.com\/blog\/wp-content\/uploads\/2017\/11\/Fortify_logo.jpg?fit=144%2C53&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8J21V-8O","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/posts\/546","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/comments?post=546"}],"version-history":[{"count":1,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/posts\/546\/revisions"}],"predecessor-version":[{"id":913,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/posts\/546\/revisions\/913"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/media\/551"}],"wp:attachment":[{"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/media?parent=546"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/categories?post=546"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/imalogic.com\/blog\/wp-json\/wp\/v2\/tags?post=546"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}