docker-compose 構建postgres的ssrf

2020-08-09 12:22:46

前言

最近ssrf神器Gopherus更新了支援postgres的攻擊。在ubuntu上搭建了環境試了一下發現效果還不錯。想了一下如果別人也想復現或者我想再次復現類似環境,還要重新搭建一遍。雖然搭建並不複雜,但還是想需要一鍵啓動的環境。於是就想到了docker。之前用過docker的基本命令和別人搭建的基礎映象,但還沒自己編寫過Dockerfile,定製自己的映象。藉此機會學習一下Dockerfile的基本編寫。

快速寫一個Dockerfile

  1. 首先新建一個資料夾postgres-ssrf

  2. 進入資料夾新建Dockerfile編輯如下

    ## Dockerfile
    FROM ubuntu # 拉取一個ubuntu基礎映象
    
    ENV DEBIAN_FRONTEND=noninteractive # 不互動模式,防止在apt安裝一些軟體包是發生互動導致構建卡死。
    
    RUN  sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list # 更新軟體源增加構建速度
    RUN  apt-get clean
    RUN  apt-get update
    RUN  apt-get install apt-utils -y
    RUN  apt-get install  php apache2 php-curl -y  # 安裝php,apache,以及php-curl,這裏php-curl版本要和php版本一致
    
    RUN echo "ServerName localhost:80" >> /etc/apache2/apache2.conf 
    RUN rm /var/www/html/index.html
    ADD start.sh /start.sh
    RUN chmod 755 /start.sh
    ADD index.php /var/www/html/index.php
    EXPOSE 80 # 開放80埠
    
    CMD /start.sh # 映象入口 
    
    # start.sh
    apachectl -D FOREGROUND
    

    這裏的一個坑點就是CMD之前的使用RUN執行的命令只會在構建時執行,構建完成後就失效了。因此想要執行如

    RUN service apache2 start
    

    使得在映象啓動時啓動apache服務是行不通的。docker提供CMDENTRYPOINT來解決這一問題,使用CMD執行的命令會在容器啓動後自動執行。但apache服務使用CMD執行service apache2 start還是無法啓動。需要使用

    apachectl -D FOREGROUND
    

    參考
    How to start apache2 automatically in a ubuntu docker container?

    ok,一個Dockerfile的大致結構就是如此。包括使用的基礎映象,容器內執行的命令,以及容器入口點。

    更多編寫dockerfile請參考Dockerfile reference

    但我們發現在Dockerfile中我並沒有安裝postgres服務。這也是我踩的一個大坑。開始時我嘗試在ubuntu內安裝postgres,並且進行設定,唯一重要的設定就是在pg_hba.conf設定本地無需密碼進行登陸。(因爲Gopherus要求攻擊不能進行互動,至於爲什麼。抓包看一下postgres的認證流程就懂了,包括mysql的ssrf攻擊也是。)設定完成後需要插入一些測試數據。或者說是flag。如下

    CREATE DATABASE "Flag";
        WITH OWNER = "postgres"
            ENCODING = 'UTF8';
    \c Flag postgres;
    CREATE TABLE flag (
            flag text
    );
    INSERT INTO Flag (flag) values ('flag{abc569d9e7ac742b9bc8a8}');
    

    但在構建的過程中會因爲postgres沒有啓動而無法匯入數據。因此只能想辦法使得在postgres容器啓動後匯入數據,還要先自動啓動postgres…,額有點麻煩。搜尋的過程中發現postgres官方映象在建立容器的時候自動匯入特定目錄的sql語句。那麼可以把web服務和db服務分開,db使用postgres官方映象。現在問題就是如何管理兩個映象。這就要引出docker-compose

編寫docker-compose.yml

  1. 在與Dockerfile同一目錄新建docker-compose.yml檔案,編輯如下

    version: '2'
    
    services:
        webapp:
            build: 
                context: .
                dockerfile: Dockerfile  #  此處會自動構建目錄下的Dockerfile並執行容器
            depends_on:                 #  聲名依賴
                - db
            ports:
                - "80:80"              # 開放埠
    
        db:
            image: postgres:12          # 指定依賴的基礎映象
            volumes:                    # 將當前的./initdb 對映到容器內/docker-entrypoint-initdb.d,根據文件這裏的sql檔案會被自動執行
                - ./initdb/:/docker-entrypoint-initdb.d
            environment:
                POSTGRES_HOST_AUTH_METHOD: trust # 環境變數可在官方文件查閱,這裏代表無認證登陸
            ports:
                - "5432:5432"
    

    使用yaml編寫邏輯已經很清晰了。docker-compose使用services來指定管理的多個映象,有依賴的容器docker-compose會構建網路保證容器間通訊。更多請參考Overview of Docker Compose

  2. 構建

    經典兩條命令

    docker-compose build
    docker-compose up -d
    
  3. 測試一下