web_security/web info

[WebHacking] 파일업로드 취약점(File Upload Vulnerability)이란?(New)

HawordFREAKEK 2022. 6. 1. 18:33

네 안녕하세요. Godhaword 입니다.
원래 주말에 이번 글을 쓰려했는데 공휴일이기도 하고, 갑자기 삘 받아서 써봅니다.

개인적으로 가장 좋아하는 취약점이기도 하고, Web Shell 을 통한 높은 등급의 공격을 자유롭게 할 수 있는 장점이 있는 취약점이라고 생각합니다.

하지만 본인이 올린 Web Shell 은 타인도 사용할 수 있다는 점 꼭 알아두시길 바랍니다.
만약 본인이 힘들게 우회란 우회는 다 해가면서 CTF에 Web Shell 을 올렸다고 생각해봅시다. 만약 유추하기 쉬운 경로, Web Shell 이름이라면 다른 참가자가 본인이 올린 Web Shell 을 그냥 공짜로 쓰고 flag 까지 따가는 상황이 나올 수도 있습니다. 실무로 나아가게 된다면 다른 참가자가 아닌 악성 해커가 저희가 점검, 진단하기 위해 올린 Web Shell로 운영 중인 서비스에 침투하여 모든 권한을 갖고 움직일 수 있다는 것을 뜻합니다.

그러므로 Web Shell에 암호기능을 넣어두시거나 최소한 유추하기 쉬운 이름으로 Shell 을 업로드하는건 피하셔야합니다.(ex : shell.php, test.php)

글은 거의 대부분 php 위주로 설명이 될 것 같으며, 확장자만 바꾸면 jsp, asp 다 적용됩니다.

한 번 끝까지 다 읽어보시고 나중에 필요한 부분은 목차 따라 읽어보시는 것 추천드립니다.
초보, 중수 분들은 여러 번 정독 해보시는 것 추천드립니다.(다른 글도 다회 정독은 필수 입니다.)

 

목차는 

1. 파일업로드 취약점(File Upload Vulnerability)이란?
2. 파일업로드를 위한 준비물과 준비과정
3. 공격시연
4. 파일업로드 취약점(File Upload Vulnerability) 조치 방법

순으로 진행하겠습니다.

 

 


 

1. 파일업로드 취약점(File Upload Vulnerability)이란?

웹 셸(web shell)은 업로드 취약점을 통하여 시스템에 명령을 내릴 수 있는 코드를 말한다. webshell은 간단한 서버 스크립트 (jsp,php,asp ..)로 만드는 방법이 널리 사용되며 이 스크립트들은 웹서버의 취약점을 통해 업로드 된다. 웹셀 설치시 해커들은 보안 시스템을 피하여 별도의 인증없이 시스템에 쉽게 접속 가능하다.
(웹이 서버에서 구동되고 있다 하여도 취약점이 존재하지 않으면, 수행되지 않으며 만약 업로드되었다 하더라도 실행 권한이 없으면, 실행이 되지 않는다. 하지만 취약점과 실행권한이 존재할 때는 서버 내부에 명령을 수행할 수 있으므로 침해 범위가 넓어 질 수 있다.)
사용자로부터 입력된 시스템 명령어를 셸에 전달하는 기능을 가지고 있다.
(위키피디아)

 

SQL Injection 은 악의적인 Query를 DB에 날려 공격자가 원하고자하는 값을 보는게 목적이라면 파일 업로드 취약점은 악의적인 파일을 올려 서버에 원하고자 하는 값을 보는게 목적이라고 보입니다.

물론 DB와 서버 중에 더 중요하고 덜 중요한 것은 없지만, 공격 자체로 접할 수 있는 범위를 보면 SQL Injection이 조금 더 넓다라고 볼 수 도 있습니다. SQL Injection이 가능하다면 저번 글에서 말씀드린것과 같이 경로 파악 후 Shell upload를 할 수도 있지만, 파일업로드 같은 경우 개발자가 꼼꼼한 성격이라 부가적인 정보에 대한 파일을 서버 경로에 저장해두지 않는다면 그냥 서버 장악 이후 공격이 끝날 수도 있습니다.

하지만 만약 sqlite, postgre, sqlplus 처럼 cmd 창에서 Database 명령어를 접하기 쉽게 되어있다면 간단히 .bat(batch)파일 이나 .sh 파일 만들어서 SQL Injection 과 같이 DB 장악도 할 수 있기 때문에 업로드 된 Shell 을 이용하여 공격을 전개하는건 공격자 기량에 따라 다릅니다.

("아니 그래서 SQLI랑 파일 업로드 중에 뭐가 더 높은 수준의 공격이냐" 라고 물으시면 강도가 뒤에서 총 겨누기 전까진 파일업로드라 할 것 같습니다.)

 

2. 파일업로드를 위한 준비물과 준비과정

일단 해커라면 그냥 Web Shell 딱 업로드 하고 되나 안되나 보고 안되면 나오면 그만입니다.

그런데 저희는 깨끗한 마음을 가지고 순수히 점검, 진단 목적으로 Shell 파일을 업로드 하는 입장이기에 개인적으로 몇가지 지켜야하는 절차가 있다고 생각합니다.

1. 일반 이미지 파일
2. 내용이 없는 서버 페이지 파일
3. Hello world 와 같은 간단한 문구가 출력되는 페이지 파일
4. 한줄 쉘 파일 (One line Webshell File)
5. 브라우저 웹쉘 파일 (Browser WebShell File)

CTF나 Wargame 까지도 그냥 5단계로 건너띄어도 괜찮다고 생각하지만 진단, 점검 목적에선 저 1~5번 절차를 다 지키시는 것을 추천드립니다.
해당 번호에 맞춰 이유를 하나씩 말씀드리자면

1.  업로드 기능이 정상적으로 들어있는지 부터 확인해야 합니다.
 그리고 게시글이나 그 다른 방법으로 올렸던 파일이 해당 과정을 지웠을 때 올렸던 이미지 파일이 지워지나도 함께 확인해봅니다.
1번 과정을 통하여 저희는 Web Shell 이 올라갈 경로를 유추할 수 있고, 해당 경로로 저희가 역으로 접근할 시 해당 이미지 파일을 조회할 수 있나 확인해봅니다.

2. 일단 확장자 검증을 하나 확인을 해보아야 합니다.
주로 하는 방식은 1번파일을 업로드 할 때 패킷을 Burp suite 와 같은 proxy tool 로 잡고, 파일 이름만 abc.jpg 에서 abc.php, abc.jsp, abc.asp로 변경하여 올려봅니다.
해당 과정을 통하여 서버가 무슨 언어로 되어있는 지와 서버페이지 확장자를 필터링 하는지, 어떤 방식으로 필터링 하는지를 확인합니다.
(솔직히 모든 공격전에 서버페이지가 무슨 언어로 되어있는지는 기본적으로 알고 시작해야 합니다.)

3. 서버페이지 파일이 업로드 된다해도, 해당 파일에 실행 권한이 없거나 그냥 text파일로 읽혀진다거나 하는 이유로 함수들이 실행이 안될 수도 있습니다.
그 와중에 저희가 system 이나 exec 같은 서버에 위협을 끼치는 함수가 들어있는 파일을 업로드 할 시, 방화벽이나 기타 관제 프로그램이 이를 확인하여 저희의 공격을 사이트 주인에게 들킬 수도 있습니다.
악성 해커라면 당연히 일어나선 안될 일이고, 진단 점검 관점에서도 서비스 제공자가 "아니 기분도 안좋은데 무슨 악성파일 올리고 있어" 라고 할 수도 있습니다.
물론 WebShell 까지 올라가 서버장악까지 한다면 말이 달라지겠지만 만약 그 이상 나아가지 못한다면 그냥 위험감수, 기분만 안 좋게 하고 아무일도 안 일어나게 된 꼴이 됩니다.

4. 일단 Browser Shell 같은 경우엔 거의 대부분이 Github 에 있는 Shell 코드 복붙해가지고 Shell 하나 만든 다음에 그 파일을 올리게 됩니다. 아니면 전에 아는 지인이 쓰던 파일을 올리거나 코드의 원작자는 극히 소수인데 그를 인용해서 올리는 사람이 대부분입니다.
이렇게 되면 해당 파일에 무슨 함수가 있는지, 어떤 구조로 돌아가는지, 이 Webshell에 악성 코드는 없는지, 만약 어떤 문제가 생기면 어떻게 대처해야하는지 모르는 상황이 대부분입니다.
Browser Webshell 은 Oneline Webshell 보다 더 많은 함수가 쓰이게 됩니다. Browser Webshell에 A, B, C 3가지에 실행함수가 쓰인다고 가정 했을때 만약 B만 검열되어도 해당 Browser Shell은 작동이 안되며 공격자 입장에선 "아 여긴 파일업로드 취약점이 터지질 않는구나" 라고 판단할 수 있습니다. 하지만 Oneline Shell 같은 경우 A 한 번, B 한 번, C 한 번 넣어서 공격을 해볼 수 있으므로 필터에 걸리지 않는 함수를 확인 후 그 함수를 이용하여 공격을 할 수 있다는 장점이 있습니다.
솔직히 4번까지만 와도 공격자의 기량이 높다면 웬만한 공격은 다 해볼 수 있습니다.

5. Oneline Webshell 이 그냥 커피라면 Browser Shell은.. TOP?
일단 초보, 중수라고 생각되시는 분은 가급적이면 Browser Shell 을 안쓰시는 것을 추천드립니다. 처음부터 Browser Shell 로 접하시게 되면 아 이건 원래 이런거구나 라고 그냥 대충 사용하실 수도 있습니다. Oneline Webshell을 쓰시면서 ls, dir 과 같은 명령어와 친해지시면서 뭔가 모르게 Oneline Shell에 답답함을 느끼시게 된다면 그 이후 Browser Shell로 넘어오시는 것을 추천드립니다. Browser Shell을 쓰면 고수같아 보이고 편하고 그렇긴 하지만 제 입장에선 아무것도 모르는 사람한테 최상급 참치 뱃살을 줬는데 그 사람이 그 참치를 라면에 넣어먹는 것 보는거 같은 답답함을 느끼게 됩니다. SQLMAP이나 Browser Shell이나 끝 단계로 편한 방법이긴 하지만 그 이전 과정을 이해하지 못하고 쓰시면 해당 기능의 90%는 커녕 20~30프로도 못 뽑는다고 생각합니다.

 

이렇게 길고도 긴 준비물과 해당 준비물을 챙겨야 하는 이유를 말씀 드렸습니다. 상황이나 개인차에 따라 뭐 1번을 건너 뛸수도 있고 2번을 건너 뛸수도 있고 하긴 하지만 1번과 3번은 꼭 챙겨가시는 것을 추천드립니다.

 

3. 공격시연 

공격 시연 이전에 파일업로드 취약점의 가장 기초가 되는 우회 방법은

  1. null byte, 주석으로 2중 확장자 넘기기(shell.php%00.png, shell.php#.png)
  2. 대소문자 변경하기(shell.Php)
  3. html(url) encoding 하여 확장자 넘기기(shell.ph%70)
  4. 보조 확장자 사용하기
    .asp -> .cer .cdx .asa
    .php -> .php3 .html .htm
    .jsp -> .war, jspx, jsv, jsw
  5. content-type 우회하기(image)
  6. Shell file 맨 앞에 이미지 파일 시그니쳐 추가하기(89 50 4E 47 0D 0A)
  7. .htaccess 사용하기(임의의 확장자에 실행권한 추가하기)

등등이 있습니다. 자세한 방법은 아래 글에서 추가적으로 설명하겠습니다.

1

root me 의 문제입니다.
파일업로드 취약점이긴 하지만 해당 취약점을 찾기 전에 일단 모든 기능 파악을 하시는 것을 추천드립니다.
1.기본 사진
2. 파일 업로드 하기
3. 해적 관련 사진
이렇게 메뉴가 있네요.

2

2번 메뉴에서 이미지를 업로드하게 되면 저렇게 패킷이 떨어지는 것을 보실 수 있습니다.
업로드 할 때마다 메뉴가서 이미지 고르고 파일 업로드 할꺼 귀찮으니까 Repeater에 패킷 옮겨주고 다음 작업 실행하도록 하겠습니다.

3

제가 올렸던 파일이 이렇게 있네요. 해당 파일을 조회하여 어느 경로에 파일이 떨어지는지 확인해봅니다.

4

전 항상 1x1 크기의 파일을 올리기에 우측 하단에 아주 자그마한 흰색 점이 보이는 것을 볼 수 있습니다. 업로드 경로는 복잡하나 저희가 따로 수고를 안해도 자동적으로 경로가 따라오는 것을 확인하실 수 있습니다.

5

사이트가 php로 구성되었다고 판단 후 php파일을 올리면 확장자가 image 파일이 아니라 Wrong file type 이라고 뜨는 것을 보실 수 있습니다. 그러면 화이트리스트 관련 필터링을 한다면 몇가지 우회 방법을 저희가 생각해볼 수 있는게

1. 이중 확장자

2. Content type 변경

등이 있습니다.

 

1번 2중 확장자로 테스트를 해보면

6

위와 같이 .jpg.php 처럼 확장자를 2중으로 써줍니다. 옛날 버전 아파치나 몇몇 서버에선 확장자 확인 시 왼쪽부터 읽기 시작하여 가장 첫 번째 확장자로 파일을 판단해서 이미지로 확인 후 파일을 올리겠지만 업로드 후에는 맨 마지막에 있는 확장자 기준으로 파일이 정해져서 php 파일로 실행되게 됩니다.

7

어.. 안되네요;;
그러면 Content Type 만 한번 바꿔줘봅시다.

8

위와 같이 이번엔 확장자는 그냥 php로 두고, Content Type 만 image/jpeg로 바꿔보겠습니다.

9

정상적으로 업로드 된 것을 확인하실 수 있으며

해당 경로에서 passwd 파일을 확인 해당 파일을 확인 시, 안에 flag 값이 있는 것을 확인 하실 수 있습니다.
구조에서 보시는 것과 같이 저는 항상 외부 WebShell 을 쓸 때, 한 번 Source 코드를 보고 외부 하이퍼링크가 있거나 쓸모 없는 코드, 필요 없는 값들은 다 지우고 다시 짜서 사용합니다.(wargame이라 바로바로 브라우저 쉘을 올렸습니다.)

 

Dreamhack 문제로 다시 한번 보여드리자면

1

이렇게 업로드 폼이 있네요.

2

마찬가지로 1번 준비물인 1x1 파일을 올려 파일이 어떤식으로 어느 위치에 올라가는지 확인해봅니다. 대부분의 사이트가 upload, uploads 경로에 파일이 올라가더라구요.
업로드한 파일에 이름은 그대로 올라가며 뒤에 확장자 까지 붙어 날라가는 것을 보실 수 있습니다.

 

3
5

해당 정보를 배경으로 몇가지 사전작업을 해주고 파일을 업로드하면 flag라는 파일에 이런 값이 있는 것을 확인하실 수 있습니다.(자세한 풀이는.. 나중에 올리던가 하겠습니다.)
오히려 파일에 대한 필터링은 없어서 풀기 쉬웠던 문제 같습니다.

 

(사실 이 문제는 빨리 푼거 자랑하려고 올렸습니다. 푸는데는 얼마 안 걸렸는데 문제 보자마자 6분이 푸셔놨더라구요)

 

 

※ 주의

웹쉘에은 전쟁에서의 총이라고 보시면 편할 것 같습니다. 들고 다니면 가장 강력한 무기이지만 그게 제 손에만 있다는 보장도 없고, 그게 악의적인 누군가에게 쥐어진다면 저희와 똑같은 파급력을 누군가가 행할 수 있게 된다는 것 입니다. 만약 webshell.php, backdoor.php 이런 이름으로 해놨다가 악성 해커가 웹 스캔이라도 때려보면 해당 Shell은 바로 노출될 것이고, 해당 Shell을 통하여 반대로 서버가 장악될 수도 있다는점 알아두셔야 합니다.
SQL Injection은 본인만 조심하면 사고는 안 나지만, WebShell은 본인이 조심 안하면 사고나기 아주 좋은 매개체 입니다.
그러므로 자신이 해당 서비스에 올린 Shell 파일들은 모두 어디에 뭐가 몇개 있는지 까지 다 알고 있어야하며, 그 수고를 최소화하기 위하여 최소한의 단계로 서버를 장악해야 한다는 것 말씀 드립니다.

 

4. 파일업로드 취약점(File Upload Vulnerability) 조치 방법

일단 조치방법의 정석은 kisa나 주요정보통신 기반시설 pdf 확인해보시면 거기 있습니다. 보고서나 오피셜한 작업하실 땐 앞서 말해드린 조치방법 참고하시고 제가 말씀드리는 방법은 최소한 이건 꼭 해줘라 하는 내용만 담겨있는 점 참고 부탁드립니다.

  1. 업로드 된 파일이 저장되는 위치를 서버 경로 밖으로 빼두시는 것을 추천드립니다.

www.test.com/bbs/upload/shell.php
www.test.com/upload/shell.php
www.test.com/shell.php

위와 같이 WebShell 경로가 서버 경로 이후에 있는 것이 가장 큰 문제입니다.
그러므로 서버 경로 밖으로 저장 디렉토리를 만든다면 별다른 조치를 안해도 해당 Shell 파일에 접근하기 어려워집니다.

(winzip 뒷광고 아님)

위 처럼 서버경로 바로 옆에 다 두셔도 되고 훨씬 뒤에 두시거나 C에서 D 처럼 다른 드라이브에 저장해두셔도 됩니다.

  2. 실행 권한 제거

서버파일이 올라갔다 하더라도 실행권한이 없으면 그냥 txt파일처럼 읽혀집니다. ubuntu 기반의 서버면 umask나 chmod로 -x 로 execute 기능은 빼두시길 바랍니다.

  3. 업로드 시 확장자 필터링

1,2 번이 근본적인 조치 방법이라면 3번부터는 뚫릴수도 있기에 필수보다는 보조 느낌으로 알아두시면 좋을 것 같습니다.

jsp 기반 사이트라해서 jsp만 필터링 걸어두시지 마시고 jspx, jsw나 php3,php5 와 같은 보조 확장자도 모두 필터링 해주어야합니다. httpd.conf 관련 파일에 모두 정리되어있으니 보조 확장자는 모두 기능을 지우시고, 메인 확장자로만 편하게 필터링 해두시기 바랍니다.

  4. id 값과 sequence 값으로 정리

파일업로드 취약점의 단서가 되는 두 가지가 upload 되는 파일명 유추와 경로 유추가 있습니다.

www.test.com/main/service/filedownload?id=1124af1k3l&seq=31&type=7


위와 같이 id값과 sequence 값으로 파일을 관리한다면 파일의 직접적인 이름은 은닉하면서도 업로드 되어있는 파일의 경로를 완벽하게 숨길 수 있습니다. 하지만 개발 단계에서 그냥 경로만 띄우면 페이지에 띄우거나 다운로드 가능했었던 기능을 굳이 파일 업로드 시 id 값 부여하고 seq 값 부여하고 때에 따라 type 값도 재정립하고 다운 받거나 페이지에 띄울 때도 정립했던 정보들 다시 한 번 불러와서 띄워야 함으로 개발자의 수고가 늘어나는 단점이 있습니다.

하지만 여기서도 서비스 경로 위에 업로드 경로가 있는 서비스에다가 WebShell 업로드 이후 웹 스캔을 돌려서 운이 좋으면 WebShell 을 찾을 수도 있습니다. 
그러므로 업로드 경로를 1번처럼 밖으로 빼두거나 파일 저장 시 id 값을 주는 대신 파일명을 난수화, 암호화 시켜 저장하면 앞서 말씀드린 위험은 줄일 수 있습니다.

  5. 파일명 암호화

파일명 필터링 우회 방법 중에 주석으로 뒷 부분을 날려버리는 방법도 있습니다.
1. shell.php#.jpg
2. shell.php%00.jpg
3. shell.php%80.jpg
4. shell.php--.jpg

등과 같이 주석이나 널바이트로 뒤를 날려버리게 되면 온전한 shell.php 파일을 업로드 할 수 있게 됩니다.
하지만 먼저 우측 마지막 확장자 이전 파일명 부분을 암호화 시키고 확장자를 검사한다는 개념으로 들어가게 되면
(암호문).jpg 꼴로 더 안정적인 파일 업로드를 받을 수 있습니다.
(주석이나 널바이트까지 암호화를 시켜 원형을 없앤다는 느낌)
그 외에도 파일명을 암호화하여 저장할 시, 대체로 안정성이 올라간다는 장점이 있지만 user가 업로드한 파일의 원본명을 잃어버리기에 상황에 따라 사용해야하는 단점이 있습니다.

  6. 보안프로그램 활성화

WebShell의 실행함수들은 대부분 악성코드로 판단되어 V3 만 켜놔도 대부분 서버에 저장 시 자동 삭제합니다.
공격자 입장에서도 WebShell 만들었다가 그냥 본인 컴퓨터에 저장하면 V3나 Window Defender가 잡아서 파일이 사라지는 경험 자주 해보셨을 것이라 생각합니다.
하지만 이 기능만 믿고 앞서 말씀드린 조치 안하시면 백신이 업데이트 된다거나, 딱 백신 한바퀴 돌기 전에 어쩌다 한 번 뚫릴 수도 있다는 점 알려드립니다.


제가 좋아하는 취약점이다보니 좀더 자세하게 글을 쓴 것 같네요.

 

파일 업로드 같은 경우 공격 방법보다 제가 주의하라고 말씀 드린 부분 꼭 다시 챙겨보시기 바라며, 웹린이 분들은 파일 업로드 관해서 이 글 만큼은 다회 정독하는 것 추천드립니다.

 

혹시나 더 궁금하신 부분은 댓글로 남겨주시기 바랍니다.