{"id":284,"date":"2021-04-22T10:58:18","date_gmt":"2021-04-22T10:58:18","guid":{"rendered":"https:\/\/reversea.me\/?p=284"},"modified":"2021-04-22T12:58:20","modified_gmt":"2021-04-22T12:58:20","slug":"reverse-engineering-the-string-decryption-algorithm-of-mekotio","status":"publish","type":"post","link":"https:\/\/reversea.me\/index.php\/reverse-engineering-the-string-decryption-algorithm-of-mekotio\/","title":{"rendered":"Reverse-Engineering the   String Decryption Algorithm  of Mekotio"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 8<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span>\n<p><strong>TL;DR<\/strong> We study the algorithm used by Mekotio (also known as BestaFera), a banking Trojan that started targeting Brazilian users and now targets Spanish and LATAM users, to decrypt the strings contained within the program file. This post is motivated by a current publication of the <a href=\"https:\/\/www.incibe.es\/\">Spanish National Institute of Cybersecurity (INCIBE)<\/a>, in which they analyze a sample of this family in detail. <a href=\"https:\/\/www.incibe-cert.es\/sites\/default\/files\/contenidos\/estudios\/doc\/incibe-cert_mekotio_analysis_study_2021_v1.pdf\">See the full report here<\/a>. We first reverse-engineer the algorithm and then implement a solution in Python to brute-force the decryption key. <em>Here we go!<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p>Mekotio is an advanced banking Trojan malware that incorporates interesting features, such as clipboard hijacking to steal money from bitcoin wallets. In addition, it watches the user activity in common web browsers (Firefox, Edge, and Opera, among others), overlaying HTML in the browser window of the bank website to steal the user&#8217;s credentials. It also relies on AutoHotKey to evade detection and make the analysis harder. You can read more details on this malware family <a href=\"https:\/\/www.bleepingcomputer.com\/news\/security\/mekotio-banking-trojan-imitates-update-alerts-to-steal-bitcoin\/\">here<\/a>, <a href=\"https:\/\/cofense.com\/blog\/autohotkey-banking-trojan\/\">here<\/a>, and <a href=\"https:\/\/socprime.com\/blog\/detection-content-mekotio-banking-trojan\/\">here<\/a>.<\/p>\n\n\n\n<p>In this post, we have considered the malware sample with the SHA-256 hash:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">9572a6e0d50bd67c35cb70653661719c6c8034254f55e4693cfbfafb2768c59c<\/code><\/pre>\n\n\n\n<p>which is a PE32+ DLL. This file needs to be loaded with the AutoHotKey interpreter and an AutoHotKey script. More details in the content of this script can be read in <a href=\"https:\/\/www.incibe-cert.es\/sites\/default\/files\/contenidos\/estudios\/doc\/incibe-cert_mekotio_analysis_study_2021_v1.pdf\">the full report of INCIBE<\/a> (basically, the script loads a small 32\/64-bit assembly code into the memory to dynamically resolve certain Windows APIs and change the permissions of the allocated memory with <code>PAGE_EXECUTE_READWRITE<\/code> to enable later execution).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The algorithm<\/h2>\n\n\n\n<p>If you check for the strings in the file, you will rapidly see that there are very few &#8220;normal&#8221; strings. If you look closer, you will find out that there are <strong>A LOT<\/strong> of strings codified in hexadecimal:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">$ strings 9572a6e0d50bd67c35cb70653661719c6c8034254f55e4693cfbfafb2768c59c |  grep -E \"^[0-9A-F]*$\"\n 56789\n 34934\n FDA9\n FDD9\n C0A9\n 67889C4D8B88D91FD1769A3337D9133E\n 71F1022AC15088A791B866E1\n EE669E47E11149EA5D8CBB1B\n 7CF03237D263EC072AC276F53EE61BC667E3\n 92DD15C67EB228D87EA14587F120D4B24691A73FFF5CC7CCAF\n [ ... redacted ... ]\n 96DC1AC178B92FF21C35C1182DDA0B38F5648BD560FA24B174DD06303B83A52FD2053DAA448F528AC9718C963AFD30D57DA929B0A04BF9097AA15288A7E619C877A5509D429545BB69E11EB74A\n 589D46F4120D45\n 81E11CC06399CC72A04F8BD1163F\n 19BA66D5042AAA\n 1F6EBC51F439AA74F6\n 45B467ED12DE7C8EB66BA4D1\n 33BA48F62DD87FAB988B4388AA\n 8ACC6EDD1CC203\n 8ACC6EDD1CC203\n [ ... redacted ... ]\n 33333\n 3333\n 3333\n 33333\n 333333\n 3333333\n 333333333333333333<\/code><\/pre>\n\n\n\n<p>As introduced in the report of INCIBE, the algorithm that decrypts the strings is the function located at <code>0x94E2D0<\/code>. The explanation given in the report about this function is a little\u2026 cryptic (yeah, that&#8217;s a good adjective). So, let us explain it again. (<strong>First things first! <\/strong>To be able to reverse engineer the function, we need to fully understand it!).<\/p>\n\n\n\n<p>We will use <a href=\"https:\/\/ghidra-sre.org\/\">the Ghidra tool<\/a> to disassemble it. The first basic block of this function is this one:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"607\" src=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_init-1024x607.png\" alt=\"\" class=\"wp-image-292\" srcset=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_init-1024x607.png 1024w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_init-300x178.png 300w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_init-768x455.png 768w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_init.png 1118w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><strong>Start of the decryption function.<\/strong><\/figcaption><\/figure>\n\n\n\n<p>As shown, the function defines 9 local variables and receives two parameters, which are stored in <code>[rbp + 0x78]<\/code> and <code>[rbp + 0x10]<\/code> (passed on the <code>rcx<\/code> and <code>rdx<\/code> registers, respectively). These parameters are indeed pointers to strings. Recall that the calling convention on x64 <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/build\/x64-software-conventions?view=msvc-160\">follows the Microsoft ABI<\/a>: the first four integer (or pointer parameters) are passed in the <code>rcx<\/code>, <code>rdx<\/code>, <code>r8<\/code>, and <code>r9<\/code> registers, while additional arguments are passed on the stack. After the initialization of these variables to zero, it checks if the cipher string is null. If so, it will finish the function. Otherwise, the decryption algorithm begins:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"831\" src=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/first_blocks-1024x831.png\" alt=\"\" class=\"wp-image-293\" srcset=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/first_blocks-1024x831.png 1024w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/first_blocks-300x243.png 300w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/first_blocks-768x623.png 768w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/first_blocks.png 1050w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><strong>First blocks of the decryption function after initialization.<\/strong><\/figcaption><\/figure>\n\n\n\n<p>After clearing the content of <code>[rbp + 0x58]<\/code>, it sets a zero in the <code>ebx<\/code> register and loads in <code>rax<\/code> the pointer to the decryption key. In case it is not zero, it sets in <code>ebx<\/code> the length of the decryption key (after studying this, we came to the conclusion that a string pointer contains in its previous byte its length). The block <code>0x94e35c<\/code> then begins, clearing the <code>esi<\/code> register and loading in <code>dst_buffer1<\/code> the first two chars of the cipher string. Recall that the strings are encoded in hexadecimal, and thus every two chars represents in fact one byte. These two chars are moved to another local buffer to finally convert them to from the ASCII representation to their corresponding integer value. The result is finally stored in the <code>edi<\/code> register (recall that by the calling convention, <code>eax<\/code> contains the return value of the function). This block ends storing in <code>r13<\/code> a value of 3. This register will be used as an index for the deciphering loop, as you will see now.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"604\" src=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/second_blocks-1024x604.png\" alt=\"\" class=\"wp-image-294\" srcset=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/second_blocks-1024x604.png 1024w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/second_blocks-300x177.png 300w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/second_blocks-768x453.png 768w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/second_blocks.png 1153w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><strong>Begin of the loop body.<\/strong><\/figcaption><\/figure>\n\n\n\n<p>The block <code>0x94e35c<\/code> that we have explained is the loop header block. The loop body starts in the <code>0x94e39f<\/code>. The first instructions of this block perform a similar behavior as the loop header: it gets two chars of the cipher string, indicated by <code>r13<\/code>, moves them to a temporal buffer, and converts them to ther corresponding integer value. The result in this case is moved to the <code>r14<\/code> register. Finally, it checks if <code>esi<\/code> (cleared in the loop header block, hence in the first iteration its value is zero) is greater than or equal to <code>ebx<\/code> (which contains the length of the decryption key, read again the previous paragraph!). If so, it resets the value of <code>esi<\/code> to one (block <code>0x94e3e1<\/code>). Otherwise, it increments the value of <code>esi<\/code> in one unit (block <code>0x94e3dc<\/code>). This register is being used to index the cipher key, as you will see now.<\/p>\n\n\n\n<p>The next block (<code>0x94e3e6<\/code>) performs the decryption. It gets the pointer of the decryption key and, through indirect access, gets the two bytes pointed by the <code>rcx<\/code> register (which is previously loaded with <code>esi<\/code>) and stores them in <code>eax<\/code>, zeroing the upper 16 bits of the register. It then gets the value of <code>r14<\/code> in <code>ecx<\/code> and XORes it with <code>eax<\/code>. The result is then moved to <code>eax<\/code> again and then compared with the <code>edi<\/code> register. The latter register was previously set to the integer representation of the first two bytes of the cipher string (see explanation of the previous block <code>0x94e35c<\/code>). A weird thing is that it is getting two bytes from the decryption key, while only one byte was considered from the cipher string. We guess the decryption key must be UNICODE encoded, and thus there is a null byte after every byte with content which does not affect the XOR operation. This block ends comparing <code>eax<\/code> with <code>edi<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"577\" src=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/third_blocks-1024x577.png\" alt=\"\" class=\"wp-image-295\" srcset=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/third_blocks-1024x577.png 1024w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/third_blocks-300x169.png 300w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/third_blocks-768x432.png 768w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/third_blocks.png 1252w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><strong>Final loop body.<\/strong><\/figcaption><\/figure>\n\n\n\n<p>It then subtracts <code>edi<\/code> to <code>eax<\/code>, and adds to <code>eax<\/code> the value <code>0xff<\/code> when <code>eax<\/code> is greater than <code>edi<\/code> , which guarantees a positive value in <code>eax<\/code> after the subtraction. Then, the final block of the loop begins. The result is first stored in a temporal buffer and then concatenated to <code>dst_buffer6<\/code>, which will contain the decrypted string within the loop. Finally, <code>edi<\/code> is updated with the value of <code>r14<\/code> and <code>r13<\/code> (the index used to access the cipher string in the first block of the loop body) is incremented by two units. This block ends checking whether the cipher string has been fully processed. When some chars are still unprocessed, the loop body starts again. Otherwise, the last two blocks of the function are executed.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"442\" src=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_end-1024x442.png\" alt=\"\" class=\"wp-image-296\" srcset=\"https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_end-1024x442.png 1024w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_end-300x130.png 300w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_end-768x332.png 768w, https:\/\/reversea.me\/wp-content\/uploads\/2021\/04\/func_end.png 1262w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><strong>End of the decryption function.<\/strong><\/figcaption><\/figure>\n\n\n\n<p>The <code>dst_buffer6<\/code> is copied to <code>[rbp + 0x78]<\/code>, which is then returned in <code>rax<\/code> to the caller. And that&#8217;s all from the function used by this sample of Mekotio to decrypt strings!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Python implementation to brute-force the decryption key<\/h2>\n\n\n\n<p><em>Ok, now let&#8217;s try to brute-force the decryption key<\/em>. We know how the algorithm works and have seen that it is similar to a decryption algorithm with feedback, as in each step the value of <code>edi<\/code> is updated, which is used in the next iteration for checking the positivity of the subtraction operation performed after the block <code>0x94e3e6<\/code>.<\/p>\n\n\n\n<p>We can build a quick-and-dirty function in Python to brute-force the decryption key. As input, the function will accept two parameters: the cipher string and the deciphered string. As output, it will return a list containing the bytes that conform the decryption key. An implementation of this function can be as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"python\" class=\"language-python\">def bruteforce_key(enc_str: str, dec_str: str) -&gt; list: \n    idx = 0\n    # first iteration\n    edi = int(enc_str[idx:idx + 2], base= 16) # convert to int\n\n    key_list = []\n    dec_idx = 0\n    guess_key = 0\n    while guess_key &lt; 256:\n\n        var2 = int(enc_str[idx + 2:idx + 4], base= 16) # convert to int\n        xor_val = guess_key ^ var2 # xored it\n\n        sub = xor_val - edi\n        if (sub &lt; 0): # check if negative\n            sub += 0xff \n\n        if (sub == ord(dec_str[dec_idx])): # match?\n            key_list.append(guess_key)\n            dec_idx += 1\n            edi = var2\n            idx += 2\n            guess_key = 0 # reset for the next byte of guess key\n        else:\n            guess_key += 1 # try next key\n\n        if dec_idx == len(dec_str):\n            return key_list<\/code><\/pre>\n\n\n\n<p>Now we can use one of the (long) strings given in <a href=\"https:\/\/www.incibe-cert.es\/sites\/default\/files\/contenidos\/estudios\/doc\/incibe-cert_mekotio_analysis_study_2021_v1.pdf\">the report of INCIBE of this sample<\/a> to get the decryption key. Let&#8217;s try it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"python\" class=\"language-python\">ciphered_str = \"48A543EE1E1C081EC87298CA6E984D2BF2592ABF62F51240FA2DC7659A39094BF224DD7380DA15B5147DA041549F48E36791C71ED70021D9CD6D8AB15043EF14C16D83DC1C0ECAD90050EB79BC7EA43DE77EB692428EFA669E23A35A8CB2122CF82265\"\ndec_str = \"Hola, Enviamos un c\u00f3digo como simulaci\u00f3n de transacci\u00f3n para validar y sincronizar su dispositivo.\"\n\nkey_str = bruteforce_key(ciphered_str, dec_str)\nprint(key_str)\nprint(\"\".join([chr(x) for x in key_str]))<\/code><\/pre>\n\n\n\n<p>The output will be as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">[53, 86, 65, 78, 86, 52, 83, 68, 77, 67, 51, 86, 69, 65, 70, 82, 56, 83, 50, 209, 51, 77, 57, 85, 54, 87, 82, 72, 51, 80, 55, 70, 68, 68, 57, 84, 57, 81, 188, 48, 73, 65, 71, 53, 87, 90, 74, 53, 75, 53, 53, 86, 65, 210, 86, 52, 83, 68, 77, 67, 51, 86, 69, 65, 70, 82, 56, 83, 50, 77, 51, 77, 57, 85, 54, 87, 82, 72, 51, 80, 55, 70, 68, 68, 57, 84, 57, 81, 49, 48, 73, 65, 71, 53, 87, 90, 74, 53]\n5VANV4SDMC3VEAFR8S2\u00d13M9U6WRH3P7FDD9T9Q\u00bc0IAG5WZJ5K55VA\u00d2V4SDMC3VEAFR8S2M3M9U6WRH3P7FDD9T9Q10IAG5WZJ5<\/code><\/pre>\n\n\n\n<p>Once we have this decryption key, you can code the decryption function (it is very easy, you just need to adapt a little bit the code of <code>bruteforce_key<\/code>). For instance:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"python\" class=\"language-python\">def decipher(key_str, enc_str): \n    idx = 0\n    # first iteration\n    edi = int(enc_str[idx:idx + 2], base = 16)\n    idx += 2\n\n    deciphered_str = []\n    key_idx = 0 \n    while True: # is ugly, but it works :)\n        var2 = int(enc_str[idx: idx + 2], base = 16)\n        xor_val = key_str[key_idx] ^ var2\n        sub = xor_val - edi\n        if (sub &lt; 0): # check if negative\n            sub += 255 \n\n        deciphered_str.append(sub)\n        key_idx += 1\n        edi = var2\n        idx += 2\n        if idx &gt;= len(enc_str):\n            return deciphered_str<\/code><\/pre>\n\n\n\n<p>And then decrypt the strings of the banks provided in <a href=\"https:\/\/www.incibe-cert.es\/sites\/default\/files\/contenidos\/estudios\/doc\/incibe-cert_mekotio_analysis_study_2021_v1.pdf\">the report of INCIBE<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">bbvaes\nbankiaes\ncajamares\ncaixabankes\nbancsabadellcom\nunicajabancoes\npibankes\ncetelemes\ncaixaenginyerscom\ningingdirectes\nibercajaes\ncecabankes\nbankingtriodoses\nbancaadistancialibe\u00debankes\nbancosantanderes\ngruposantanderes\nbancaelectronicaaba\u00e2cacom\nlaboralkutxacomes\nbancomediolanumeses\u00f0s\nbmedonlinees\nbankintercombancaen\u00f3ome\ngrupocajaruraleses\nbancochilecl\nsantandercl\nbancoestadocl\nbancosecuritycl\nscotiabankchilecl\nbcicl\nbancoitaucl\nbancobrasilcombr\ninternetbankingcaix\u00edgovbr\nbancobradesco\nsicoobcombr\nsicredicombr\nitaucombr\nbanquepopulairefr\nmabanquebnpparibas\ncaisseepargnefr\ncreditagricolefr\ncreditmutuelfr\nlabanquepostalefr\nmonespacelclfr\nparticulierssocieteeneralefr\nbankinterpt\nnovobancopt\nindmillenniumbcppt\nsantanderpt\nbancomontepiopt\nabancapt\nbancobpipt\ncgdpt<\/code><\/pre>\n\n\n\n<p>As you can see, there are strings regarding (a large set of) banks of several countries, such as Spain, Chile, Brazil, France, and Portugal. We warn the users of these banks to be suspicious if abnormal behavior is shown when visiting your bank websites (for instance, a closing of the browser window or unusual petitions of credentials).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Indicators of Compromise (IOCs)<\/h2>\n\n\n\n<p>You can easily detect if your machine is compromised with this malware by looking at the Registry. The malware makes persistence setting itself in the following Run key:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\<\/code><\/pre>\n\n\n\n<p>This kind of persistence is widely used by malware, and corresponds to the <em>System persistence mechanisms &#8212; Run keys (HKCU root key)<\/em> category of our proposed taxonomy for ASEPs (which was introduced in our paper <a href=\"https:\/\/www.sciencedirect.com\/science\/article\/pii\/S1742287619300362\">&#8220;Characteristics and detectability of Windows auto-start extensibility points in memory forensics&#8221;<\/a>).<\/p>\n\n\n\n<p>To work, the malware will create a named pipe that starts with AHK, followed by an arbitrary string of eight chars (apparently, always capital letters). If your system also has any object with this name, it is also an indicative of infection.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p><em>And that\u2019s all, folks! In this post we have statically analyzed a piece of x64 assembly code to reverse engineer it, relying on program binary analysis tools such as <a href=\"https:\/\/ghidra-sre.org\/\">Ghidra<\/a>. Other disassembly frameworks, such as <a href=\"https:\/\/rada.re\/n\/\">radare2<\/a>, could be also used for this purpose. We then implemented a Python algorithm to get the decryption key, using the insights given by INCIBE, and found the banks affected by this sample of Mekotio. Let me finish this post expressing my gratitude to INCIBE for releasing such an interesting and detailed report of this piece of malware (but please, the next time, do not hide important information for final users!).<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 8<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span>TL;DR We study the algorithm used by Mekotio (also known as BestaFera), a banking Trojan that started targeting Brazilian users and now targets Spanish and LATAM users, to decrypt the strings contained within the program file. This post is motivated by a current publication of the Spanish National Institute of Cybersecurity (INCIBE), in which they [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,27],"tags":[29,31,28,30,14],"class_list":["post-284","post","type-post","status-publish","format-standard","hentry","category-malware","category-reverse-engineering","tag-encryption-algorithms","tag-ghidra","tag-malware","tag-reverse-engineering","tag-windows","no-featured-image"],"_links":{"self":[{"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/posts\/284","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/comments?post=284"}],"version-history":[{"count":26,"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/posts\/284\/revisions"}],"predecessor-version":[{"id":323,"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/posts\/284\/revisions\/323"}],"wp:attachment":[{"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/media?parent=284"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/categories?post=284"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/reversea.me\/index.php\/wp-json\/wp\/v2\/tags?post=284"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}