본문 바로가기

시큐어코딩 강의

시큐어코딩 강의 - WebGoat 실습

다운로드 : https://code.google.com/p/webgoat/downloads/list

주소창 입력 : http://localhost/WebGoat/attack

ID/PWD : guest/guest

http://parkya.tistory.com/975


설치 및 실행

WebGoat.pdf




HTTP 응답분할


1단계는 http분할 공격이며 이를 토대로 하여 2단계는 http분할 공격을 이용한 캐시중독 공격을 배우게 될것입니다.

검색하려는 시스템 언어를 입력하세요. 그러면 응용 프로그램이 서버에 처리를 요청을 처리하기 위해 서버는 자원을 할당하게된다.당신은 CR(%0d) 와 LF(%0a) 이를 악용하여 문자공격을 사용할수있어야합니다. 당신의 목표는 서버로 부터 강제로 200 ok 신호를 받는 것입니다.만약에 공격 영향으로 스크린 바뀌게 되면 이전 페이지로 돌아가면 됩니다. 그리고  2단계 공격을 성공한다면 왼족메뉴에 초록색 체크가 생길것입니다. 

풀이
이번 문제는 캐리지 리턴 문자(%0D)와 라인추가 문자(%0A)를 이용한 CRLF공격이다.

이러한 Carrage Return,Line Feed문들을 이용하여 임의의 제약들을 깨고 현재 서버에서 다른 페이지를 불러 올수도있으며 그리고 임의의 포트에 연결해서 대부분의 명령을 보낼수있습니다.

아래 문제 페이지를 보면 국가별 검색이라는 입력란이 있습니다. 이 입력란을 통해서 CRLF공격을 할것입니다.

우선 먼저 입력란을 통해 전달할 값을 입력하고 아래와 같이 200 ok라는 응답문을 작성합니다.

Content-Length 는 메시지 바디 길이를 바이트 단위로 나타낸것입니다. 여기서는 0으로 주었습니다.

HTTP/1.1 200 OK

여기서 HTTP/1.1는 HTTP버전을 나타내며, 200은 요청에 대한 결과코드로서 200이 가장일반적인 코드이며 사용자의 요청이 성공적으로 이뤄졌으며 요청한 자료가 클라이언트에게 보내졌다는 것을 뜻합니다. 그리고 OK는 응답에 대한 상황을 설명해주는 문자로서 정상적인 페이지가 전달되면 OK라는 값을 보내게 됩니다.

Content-type 는 이 메시지 바디에 html문자가 있음을 알려 됩니다.
Content-Length 는 메시지 바디 길이를 바이트 단위로 나타낸것입니다.

이렇게 작성한 것을 위와 같이 URL Encoding하여 암호화된값을 아래와 같이 입력란에 입력합니다.

(http://www.url-encode-decode.com/)

그러면 아래 그림과 같이 임의로 작성한 html페이지가 열린 것을 확인 할수있습니다.

이렇게 1단계는 끝이 나고 다시 문제페이지로 돌아와 2단계문제를 푸실수있습니다.
2단계 문제는 Restart시 전송되는 헤더를 찾아 포함하여 전송하면 됩니다.

헤더를 찾으려면 프록시를 이용하여 Restart시 요청문들을 분석하면 이전에 요청문들에 추가된 헤더를 확인할수있습니다.

Restart시 응답문들에 추가되는 Last-Modified에 값을 추가하여 아래와 같은 요청문을 작성합니다.

앞에서와 같이 url encodin하고  그값에서 %0A를 찾아 CRLF로 변환해줍니다.



이렇게 작성한 코드를 입력란에 입력하게 되면 다음과 같이 이번 문제가 끝에 나게 됩니다.

이러한 CRLF공격이 가능한 이유는 요청 매개 변수의 값이 나타나는 각 응답 헤더에 대해 어플리케이션이 URL인코딩된  Carrage Return,Line Feed 를 필터링되지 않기 때문에 발생하게 된다.

이를 막기위해서 어플리케이션이 개행문자를 포함입력값을 막아놓아야하며 응답부분에 필터링이 효과적을 작성돼어있어야한다.

--------------------------------------------------------------------------------------------------------------------------------------------

* General


1. Thread Safety


이 부분은 jsp로 코딩했을 때, 클래스에서 공유되는 변수에 synchronized로 적절히 동

기화를 해주지 않는 경우에 발생하는 문제점을 다루고 있습니다. 서블릿의 경우에는 

클래스의 인스턴스 변수, jsp의 경우에는 <%! 로 선언한 변수에는 synchronized를 사

용한 동기화를 반드시 해야합니다.


문제를 푸는 방법은, 브라우저를 두개 열고 미리 jeff와 dave를 입력한다음 거의 동시

에 Submit을 누르면 됩니다.



* Code Quality


1. HTML Clues


HTML 소스를 보면 

113 <!-- 

114 FIXME admin:adminpw

115 --><!-- 

116 Use Admin to regenerate database

117 --><

가 있습니다. 



* Unvalidated Parameters


1. Hidden Field Tampering


Price가 hidden 필드로 넘어오고 있습니다.


소스를 보시면, 

161 </table><input name='Price' type='HIDDEN' value='4999.99'><br>

가 있죠. 따라서, http://.../WebGoat/attack?Screen=2269&Price=100 를 통해서 변수

를 고칠 수 있습니다.



2. Unchecked Email 


이 문제는 폼에서 넘어온 데이터를 서버에서 확인하지 않는데서 발생하는 경우를 다루

고 있습니다. 폼안에 html을 넣을 수도 있고, 수신자를 바꿀 수도 있습니다.


http://.../WebGoat/attack?Screen=2272&msg=<font%20color=red>hi</font>

&to=friend@owasp.org



3. JavaScript Validation


자바스크립트를 사용해서 사용자가 입력한 값을 검사합니다. 하지만 자바스크립트가 

동작하지 않으면 이런 validation 은 무용지물이 되죠. 예를들어,

http://211.196.25.147/WebGoat/attack?Screen=2262&field1=abc*

와 같이 field1에 abc*을 넣을 수 있습니다.



* Broken Access Control


1. Remote Admin Access


원격지에서 접속하는 관리자 화면을 띄워보는 문제입니다. 주소를 마구 추측하다가 

http://211.196.25.147/WebGoat/attack?Screen=2264&admin=true

를 했더니 왼쪽에 Admin Functions 라는게 뜨긴하는데 이게 문제를 제대로 푼건지는 

잘 모르겠습니다. Complete라고 안떠서요..



2. Path Based Access Control 


images 폴더 밑만 접근할 수 있습니다. 하지만 파일명을 

\..\..\..\..\..\..\..\..\config.sys

와 같이 주면 c:\config.sys 가 뚫리는 문제입니다.



3. Role Based Access Control 


어느 사용자가 'Account Manager' 의 권한을 가지고 있는지 보는 문제입니다. 그냥 하

나씩 확인해보면 답이 나옵니다.



* Broken Authentication and Session Management 


1. Predictable Session Identifier 


음. 하다가 관둬버렸는데요. 아마도 시간을 가지고 WEAKID 를 만들어 내는 것 같습니

다. 이 경우에는 brute force로 마구 WEAKID를 잘 추측하게 하면서 코드를 짜서 풀면 

되지 않을까 생각됩니다. 예전에 해커스랩 아니면 와우해커에 비슷한 문제가 있었던 

듯.. 도저히 귀찮아서 못하겠습니다 ㅋㅋ



2. Weak Authentication Cookie 


Show Cookies 체크하시고 aspect/aspect로 로그인한다음에 보시면 AuthCookie -> 

65432udfqtb 가 있습니다. 그리고 글을 잘 보면 처음에는 'You have been 

authenticated with PARAMETERS' 라고 나오지만 refresh후에는 'You have been 

authenticated with COOKIE'라고 나오죠.


따라서 로그아웃 상태에서 쿠키를 바로 보내면 로그인 할 수 있습니다.



3. Basic Authentication


http에서 basic authentication 할때의 헤더 내용입니다. 현재 로그인 할 때, 

guest:guest를 써서 들어왔으니까 헤더에는 Authorization: 뒤에 guest:guest의 

base64 encoding값이 들어있습니다.


풀고나면 이번에는 basic:basic으로 로그인하라고 나오는데 역시 base64 로 

basic:basic을 인코딩한다음에 헤더에 Authorization: 뒤에 적어서 보내면 됩니다.



* Cross-Site Scripting (XSS) 


1. Stored XSS 


입력 필드에 HTML 코드가 함부로 들어가게 놔두면 안된다는 내용입니다.

<script>alert(document.cookie);</script>

를 적으면 쿠키가 노출되는 것을 볼 수 있습니다.



2. Reflected XSS 


입력 필드중에 "Enter your three digit access code" 부분에 

111<script>alert(document.cookie);</script>

를 적어보시면 스크립트가 동작하는 것을 볼 수 있습니다.


그리고 credit card 정보도 빼낼 수 있는지 해봐라.. 라는 부분이 있는데요. 이 정보

는 나오지 않습니다. 이 부분은 아마도 httpOnly 에 대한 부분 같습니다. httpOnly 로 

지정된 쿠키는 스크립트에 의해서는 노출되지 않고, http 요청에 의해서만 빼낼 수 있

습니다.


이걸 또 우회하는 방법이 힌트를 누르다보면 나오는 XST(Cross Site Trace)인데요. 기

본적인 아이디어는 웹 서버의 TRACE 명령을 사용하는 것입니다. TRACE명령은 사용자가 

전송한 정보를 그대로 echo 해주는데요. 이걸 악용하는 XST 공격은 자바스크립트에서 

XMLHttpRequest 객체로 웹 서버에 request를 한번 보낸다음에 그 응답을 가져옵니다.



* Injection Flaws


1. Command Injection


ShowParameters 해보시면 

HelpFile -> BasicAuthentication.help 

가 있죠.


그러면 

http://...?Screen=2270&HelpFile=BasicAuthentication.help%26%26dir%20/b

를 하면 dir이 됩니다. (여기서 %26는 &에 해당)


그리고 실행 결과를 잘 보면, 

ExecResults for 'cmd.exe /c type "C:\Documents and 

Settings\Administrator\?? ??\Windows_WebGoat-

3.7_Release\tomcat\webapps\WebGoat\lesson_plans\"BasicAuthentication.html&&dir 

/b' Output...

라고 나옵니다.


그래서 http://.../WebGoat 가 deface 될 수 밖에 없었습니다. 음 그런데, deface 

중에 1234 포트를 열고 들어가려고 하는데 잘 안되었습니다. 운영체제가 XP 이므로 당

연히 방화벽에 걸릴 것을 알면서도 귀찮아서;; 다시 reverse telnet 해서 들어갔지

만, 아무튼 실수 였습니다. 너무 간단한 디페이스라서 죄송한 마음이... ^^;;;



2. Numeric SQL Injection 


"SELECT * FROM user_data WHERE userid =" + 문자열

이런형태이므로 단순히 101 or 1=1 넣으면 됩니다.


뚫고나면 parametric query 도 뚫어보라고 하지만, parameteric query는 안되는 거 맞

죠?



3. Blind SQL Injection 


음 이건 너무 고생시키는 문제입니다. 어카운트가 valid 인지 아닌지의 정보를 바탕으 

로 

101 or first_name >='a'

101 or first_name >='g'

101 or first_name >='i'

이렇게 띄엄띄엄 가면서 첫글자를 찾은다음에


101 or first_name >='ja'

101 or first_name >='jg'

101 or first_name >='ji'

101 or first_name >='ji'

이런식으로 두번째 글자를 찾으면서 계속 valid 여부를 잘 체크하면 문자열을 알아낼 

수 있습니다. 좀 삽질하다가 눈치로 Joseph 인거 알았습니다. (Joseph 맞죠? 기억이 

가물가물;;)



4. String SQL Injection 


"SELECT * FROM user_data WHERE last_name ='" + 변수 + "'"

와 같이 query가 만들어집니다. 따라서,


' or '1'='1 이라고 주면 

SELECT * FROM user_data WHERE last_name = '' or '1'='1'

가 되서 해결 됩니다.



* Improper Error Handling 


1. Fail Open Authentication 


정답부터 얘기드리면 

http://211.196.25.147/WebGoat/attack?Screen=2256&Username=a

를 하면 뚫립니다.


이게 왜 그런가 하면,

String Username = request.getParameter("Username");

String Password = request.getParameter("Password");


를 해서 아이디와 비번을 얻은 뒤,


try {

    if (Username.equals("아이디") == false ||

        Password.equals("비밀번호") == false)

    {

        // 다시 로그인 시키자

    }

}

catch(..) { .. }


welcome();


이런 식의 코드가 있다고 할때, 우리는 비밀번호를 주지 않았으므로 Password 변수는 

null입니다. 그러면, if 문에서 Password.equals에서 NullPointerException이 뜨게 되

고, 따라서 if 문 안이 수행이 안되고 catch로 뜁니다. 그 뒤, catch가 끝나고 나서 

wecome(); 이 수행되는 것이죠.


정말 주의해야겠다고 느끼게 만드는 문제였습니다.



* Denial of Service 


1. DOS Multiple Login


로그인 창에서 아이디와 비번을 잘 넣으면 질의를 SELECT * FROM user_system_data 

WHERE user_name = 'a' and password = '' or '1'='1' 로 만들 수 있을 겁니다. 그러

면 창 몇개 열어서 화면에 나온 아이디와 비번으로 로그인을 해주면 됩니다.



* Hackable Admin


이거 참 어떻게 푼건지 저도 잘;; 그냥 admin=true라고 하면 되던데요.


http://.../WebGoat/attack?Screen=2980&admin=true&sql=select%20*%20from%20user_data

http://.../WebGoat/attack?Screen=2982&admin=true

http://.../WebGoat/attack?Screen=2983&admin=true



* Challenge


1. Stage 1: 로그인 하기


하다하다 못해서 google에서 webgoat challenge 로 검색해보니, webgoat 제작자가 "소스를 

받아내도록 해야한다"고 하더군요. 그래서 방법을 생각해봤습니다. 일단, 모든 문제에

Java Source를 볼 수 있게 하는 버튼이 문제마다 있는데 그 주소는 http://.../WebGoat/source

입니다.


하지만 요청을 가로채서 보더라도 어떤 파라미터도 넘기지 않죠. 곰곰히 생각해보니

http://.../WebGoat/attack?Screen=nnn 에서 nnn을 세션에 저장하고 있다는 생각이

들었습니다. 그리고 http://.../WebGoat/source는 그 세션에 저장된 Screen 번호를

활용하고요.


그래서 http://.../WebGoat/attack?Screen=38을 한 뒤, http://.../WebGoat/source를

해서 소스를 받을 수 있었습니다. (그냥 Start Challenge를 누른경우에는 attack?

Challenge=true&Screen=38이 넘어감) 받아낸 소스를 잘 보시면 stage1의 아이디(변수명 

user)와 비밀번호(변수명 pass)를 찾을 수 있습니다. 



2. Stage 2: 모든 credit card number 획득


이 부분은 소스가 일부러 삭제되어 있습니다. 처음에는 Credit이라는 변수를 마구 조작

하다가, 몇시간동안 가만히 보니 s=White라는 것이 눈에 들어왔습니다.


앞서의 Hackable Admin에서 user_data를 질의한 결과를 보면, last_name이 White라는 

사람의 credit card정보가 2건 있는데, 이 화면에서 바로 그 2건의 credit card정보가

나오고 있거든요. 그래서 s=' or '1'='1 을 보내서 모든 credit card 정보를 볼 수 

있었습니다. 원래는 그냥 s=White에서 바로 s에다가 sql injection을 했어야 하는데,

뭐 모로가도 서울만 가면 된다는 식으로 풀어서 좀 (-.-;;)



3. Stage 3: Deface the site 


메시지 입력창에 글을 몇개 넣고, 입력한 글을 클릭해보면

http://../WebGoat/attack?File=Message_2_guest.msg 와 같이 요청이 갑니다.


그래서 http://211.196.25.147/WebGoat/attack?File=../index.html 를 하면,

index.html을 볼 수 있죠. 마찬가지 방법을 써서 webapps/WebGoat/WEB-INF/web.xml과

tomcat/conf/tomcat-users.xml을 열 수 있습니다. 그리고 tomcat-users.xml을 사용해서

webgoat의 진짜 관리자 화면 까지 갔습니다. (그런데 막상 갔는데 디페이스를 어떻게 하는지는

몰라서 디페이스 체크는 못했습니다.)


어쩄든, 이 문제의 답을 먼저 말씀드리겠습니다. 이 사이트를 디페이스 하려면 Message를 

조작해야합니다.


http://.../attack?Message=<!--#exec cmd="echo hello from the challenge of h4q0 > .\tomcat\webapps\WebGoat\index_guest.html" -->


라고 요청을 보냅니다. 물론 그냥 보내면 안되고 Hex값으로 인코딩 해서요.

이렇게 하면 deface가 완료 됩니다.


이 과정에서 처음에는 File뒤에 SSI명령을 적기도 해봤고, Message뒤에 적기도 해봤는데

역시 힘들더군요. 수시간동안 계속 온갖 상상을 하면서 마구잡이로 시도했습니다. 결국 

Message뒤에 dir명령을 <!--#exec cmd="dir" -->로 보내니 '잘하고 있어, 명령어가 제한되었으니 

제한 되지 않은걸 써봐'라고 나오더군요.


그래서 echo hi > index.html 을 하니, index_guest.html 을 디페이스 해야한다고 나왔습니다.

이 단계에서 echo hi > index_guest.html과 echo hi > ..\index_guest.html을 해보았지만

계속 실패했습니다. 결국 포기하고, 상황을 파악하기 위해 앞서 Command Injection 문제를 

풀때 미리 올려두었던 nc.exe로 들어가봤습니다. 가 보니 희안한 곳에 제가 수행한

echo hi > index_guest.html 에 의한 결과 파일이 생성되어 있더군요. echo의 결과는

바로 tomcat이 있는 디렉토리 바로 위 (webgoat실행파일인 webgoat.bat가 있는 위치)에

저장되어 있었습니다. 그래서 디렉토리 위치를 잘 맞춰서 앞서 보여드린 것과

같이 request를 보내서 디페이스를 하게 되었습니다.


만약 제가 nc.exe를 미리 올릴 수 없었다면 어떻게 풀어야할지 모르겠네요.








 

[re] Remote Admin Access


Admin Functions 메뉴 한번 들어가셨다 나오면 completed this lesson 이 나옵니다.

메뉴 들어가실때도 &admin=true 넣어주세요.

좋은 정보 감사합니다.