하드웨어를 소프트웨어(파일)로 표현한 것이다.

Bridged: 가상 머신이 물리적 네트워크에 직접 연결되는 것처럼 설정한다. 이 옵션을 사용하면 가상 머신이 네트워크의 다른 장치들과 동등한 위치에서 통신할 수 있게 된다.
NAT (Network Address Translation): 가상 머신이 호스트 컴퓨터의 IP 주소를 공유해서 인터넷에 접속한다. 애플리케이션처럼 네트워크에 연결한다. 호스트 머신이 가상 머신으로부터 오는 트래픽을 인터넷으로 전달해주며, 인터넷으로부터 오는 트래픽을 가상 머신으로 전달해준다.
Host-only: 가상 머신이 호스트 컴퓨터와만 통신할 수 있는 개인 네트워크를 만든다. 이 옵션은 가상 머신이 외부 네트워크와 분리되어 있길 원할 때 유용하다.
Custom: 사용자가 정의한 특정 가상 네트워크에 가상 머신을 연결한다. 이를 통해 특정 네트워킹 시나리오를 구성할 수 있다.
작업관리자(Ctrl+Alt+Del 또는 상태바에서 마우스 오른쪽 클릭해서 선택)를 실행해서 MySQL이 있는 경우 작업 끝내기








이클립스에서 WebGoat > src > main > webapp 에서 오른쪽 클릭해서 New > HTML File을 선택해서 index.html 파일을 추가


index.html 파일의 위치를 확인







요청을 인터셉터해서 어떻게 처리할 건지를 물어봄

Forward를 클릭
Forward를 클릭
http//host.pc:8080/WebGoat 으로 요청했을 때 리다이렉터 응답(http://host.pc:8080/WebGoat/로 재요청)을 받음

http//host.pc:8080/WebGoat/ 으로 요청 ⇒ 디렉터리 리스팅 옵션 확인 후 기본 페이지를 검색 ⇒ 기본 페이지(index.html)를 응답으로 반환 ⇒ index.html 파일 내용에 attack 페이지로 재요청이 포함되어 있음

http://host.pc:8080/WebGoat/attack 페이지를 요청 ⇒ attack 파일의 내용(또는 실행 결과)을 응답으로 반환

프로그램 입력값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식지정, 일관되지 않은 언어셋 사용 등으로 인해 발생되는 보안약점으로 SQL 삽입, 크로스사이트 스크립트(XSS) 등의 공격을 유발할 수 있다.
입력값 검증은 정보 시스템의 안전하고 예상된 방식으로의 동작을 보장하기 위해 필수적입니다. 이 과정은 크게 세 단계로 이루어집니다: 입력 → 처리 → 출력.
어떤 처리가 있을 때,
입력값에 처리를 조작할 수 있는 문자열 포함 여부를 확인하지 않고 처리에 사용하는 경우
처리의 구조와 의미가 변형되어 원래 의도했던 처리와 다르게 처리되는 문제점
SQL Injection ⇐ 입력값이 SQL문을 만들고 실행하는데 사용
XPath Injection ⇐ 입력값이 XPath 구문을 만들고 실행하는데 사용
XQuery Injection ⇐ 입력값이 XQuery 구문을 만들고 실행하는데 사용
Command Injection ⇐ 입력값이 운영체제 명령어 또는 명령어의 일부로 사용
1) 입력값에 처리를 조작하는 문자열 포함 여부를 확인하고 사용 ⇒ 입력값 검증, 제한
입력값에 처리를 조작하는 문자열이 포함되어 있는 경우
2) 각 기능에서 제공하는 안전한 방법을 사용 ⇒ 구조를 정의하고 정의된 구조에 입력값을 검증된 기능을 통해서 대입하는 방식으로 구현 ⇒ 구조화된 쿼리 실행, 파라미터화된 쿼리 실행
외부 입력값에 쿼리 조작 문자열 포함 여부를 확인하지 않고, 쿼리문(SQL문)을 생성, 실행하는데 사용하는 경우
원래 의도했던 쿼리의 구조와 내용이 변경되어 실행되는 것
데이터베이스 내 권한이 없는 데이터에 접근 가능
쿼리 실행을 통해 기능을 비정상적으로 이용 가능
예시: 로그인 기능
사용자가 ID abc와 비밀번호 xyz를 입력
시스템은 select * from users where id = 'abc' and pw = 'xyz' 쿼리를 실행
일치하는 사용자가 있으면 로그인 성공, 없으면 로그인 실패
사용자가 ID abc와 비밀번호 xyz' or 'a' = 'a를 입력
시스템은 select * from users where id = 'abc' and pw = 'xyz' or 'a' = 'a' 쿼리를 실행
'a' = 'a'는 항상 참이므로, 조건과 상관없이 로그인 성공 처리
결과적으로, SQL Injection은 데이터베이스 쿼리의 구조를 변경하여 무단으로 데이터에 접근하거나 시스템 기능을 우회하는 위험한 보안 취약점이다.
데이터베이스 서버의 제어권을 탈취하여 원격 제어가 가능해질 수도 있다.

https://www.hahwul.com/cullinan/history-of-owasp-top-10/
1) 입력값에 쿼리 조작 문자열 포함 여부를 확인하고 사용
2) PreparedStatement(Query Parameters)와 같은 구조화된 쿼리 실행(파라미터화된 쿼리 실행)을 보장하는 것을 사용
3) 오류 메시지에 상세한 내용(데이터베이스 및 쿼리 구조, 쿼리 실행과 관련한 프로그램 구조 등)이 포함되지 않도록 처리
4) 어플리케이션에서 사용하는 DB 사용자의 권한을 필요한 만큼의 최소한으로 부여
3) 4)은 SQL Injection 공격을 완화시키기 위해서 필요한 방어 기법
파이썬에서 SQL Injection을 방어하는 방법 ⇒ https://realpython.com/prevent-python-sql-injection/

Enter your last name: Smith
attack?Screen=34&menu=1100&account_name=Smith&SUBMIT=Go!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
POST 방식으로 해당 내용은 요청 본문을 통해서 전달되나,
여기에서는 편의를 위해서 GET 방식(주소를 통해서 전달)으로 묘사
F12 클릭

요청 파라미터로 전달된 값이 서버에서 어떻게 사용되는지를 유추 ⇒ 아마도 특정 테이블에 데이터를 조회하는 쿼리를 만들고 실행하는데 사용
SELECT * FROM user_data WHERE last_name = 'Smith'
SELECT * FROM user_data WHERE last_name = 'Smith' or 'a' = 'a' ⇐ 항상 참이 되는 조건을 추가
| |
+------------------+
last_name 컬럼의 데이터 타입이 문자열인 것을 확인
Enter your last name: Smith' or 'a' = 'a

⇒ 외부 입력값을 쿼리 조작 문자열(' = or) 포함 여부를 확인하지 않고 그대로 쿼리 생성 및 실행에 사용해서
쿼리의 원래 의미(이름이 일치하는 데이터를 조회해서 반환)를 변경(모든 데이터를 조회)해서 실행
선택한 지역의 날씨 정보를 제공하는 웹 페이지에서 모든 지역의 날씨 정보가 출력되도록 해 보세요.

Select your local weather station: Columbia 를 선택하면 101이 station 파라미터 값으로 전달
<form accept-charset="UNKNOWN" method="POST" name="form" action="attack?Screen=44&menu=1100" enctype=""><p>Select your local weather station: <select name="station"><option value="101">Columbia</option><option value="102">Seattle</option><option value="103">New York</option><option value="104">Houston</option></select></p><p><input name="SUBMIT" type="SUBMIT" value="Go!"></p><pre>SELECT * FROM weather_data WHERE station = 102</pre><table cellpadding="1" border="1"><tbody><tr><td><b>STATION</b></td><td><b>NAME</b></td><td><b>STATE</b></td><td><b>MIN_TEMP</b></td><td><b>MAX_TEMP</b></td></tr><tr><td>102</td><td>Seattle</td><td>WA</td><td>-15</td><td>90</td></tr></tbody></table></form>
attack?Screen=44&menu=1100&station=101&SUBMIT=Go!
SELECT * FROM weather_data WHERE station = 101
항상 참이 되는 조건을 추가 (원래 쿼리의 형태를 고려해서 추가해야 함)
SELECT * FROM weather_data WHERE station = 101 or 1 = 1
방법1. 개발자 도구를 이용해서 선택되었을 때 서버로 전달되는 값을 조작
<form accept-charset="UNKNOWN" method="POST" name="form" action="attack?Screen=44&menu=1100" enctype=""><p>Select your local weather station: <select name="station"><option value="101 or 1 = 1">Columbia</option><option value="102">Seattle</option><option value="103">New York</option><option value="104">Houston</option></select></p><p><input name="SUBMIT" type="SUBMIT" value="Go!"></p><pre>SELECT * FROM weather_data WHERE station = 102</pre><table cellpadding="1" border="1"><tbody><tr><td><b>STATION</b></td><td><b>NAME</b></td><td><b>STATE</b></td><td><b>MIN_TEMP</b></td><td><b>MAX_TEMP</b></td></tr><tr><td>102</td><td>Seattle</td><td>WA</td><td>-15</td><td>90</td></tr></tbody></table></form>```





모든 지역의 날씨 데이터가 조회되는 것을 확인


Error Based SQL Injection
사용자 입력에 의해 에러를 유발시켜 에러 메시지로부터 정보를 수집
예시: 홑따옴표 ' 사용하여 데이터 타입 오류 또는 쿼리 구문 오류 유발
Always True SQL Injection
쿼리 조건식을 항상 참으로 만들어 권한 밖 데이터 접근 가능
예시: or 1=1을 추가하여 쿼리가 항상 참이 되도록 조작
Union Based SQL Injection
원래 쿼리에 공격자의 쿼리를 UNION을 이용해 추가하여 실행
두 쿼리의 결과를 결합하여 원하는 정보를 함께 출력
예시: 정상 쿼리에 and 1=2 UNION select ...를 추가하여 공격자가 원하는 정보 조회
Stored Procedure Injection
데이터베이스의 저장 프로시저를 호출하는 구문을 입력하여 실행
데이터베이스 제어권 탈취 가능
예시: ; exec xp_cmdshell 'cmd.exe /c dir'로 시스템 명령어 실행
Blind SQL Injection
쿼리의 결과에 따른 서버 반응을 통해 정보 수집
예시: 존재하는 id에 대해 and 1=1과 and 1=2 조건을 추가하여 결과 변화를 관찰하며 정보 수집
사용자가 입력한 계좌 번호(Account Number)의 유효성(있다, 없다)를 확인해 주는 웹 페이지
해당 계좌가 존재하는 경우, Account number is valid.를 출력하고,
해당 계좌가 존재하지 않는 경우, Invalid account number.를 출력

문제는 pins 테이블에서 cc_number 컬럼의 값이 1111222233334444와 일치하는 pin 컬럼의 값을 찾으시오.
The goal is to find the value of the field pin in table pins for the row with the cc_number of 1111222233334444. The field is of type int, which is an integer.

⇒ 공격자가 찾고자 하는 pin 값인 2364 임
pins 테이블에서 cc_number 컬럼의 값이 4321432143214321와 일치하는 name 컬럼의 값을 찾으시오.
(문자열 타입의 데이터를 저장하는 컬럼)

아스키 코드 추출을 이용


실행된 eclipse에서 Ctrl + Shift + R (Open Resource, 열려 있는 프로젝트에서 특정 패턴의 파일을 검색해서 열어주는 도구)

protected Element createContent(WebSession s)
{
ElementContainer ec = new ElementContainer();
try
{
Connection connection = DatabaseUtilities.getConnection(s);
ec.addElement(new P().addElement("Enter your Account Number: "));
"account_number"를 값으로 가지는 상수
~~~~~~~~
String accountNumber = s.getParser().getRawParameter(ACCT_NUM, "101"); ----+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
요청 파라미터 중 ACCT_NUM 파라미터의 값을 가져와서 반환 |
만약 파라미터 또는 파라미터의 값이 없는 경우 101을 반환 |
Input input = new Input(Input.TEXT, ACCT_NUM, accountNumber.toString()); |
ec.addElement(input); |
외부 입력값에 쿼리 조작 문자열 포함 여부를 확인하지 않고
Element b = ECSFactory.makeButton("Go!"); 문자열 결합 방식의 쿼리문 생성하고 있음
ec.addElement(b); → 외부 입력값에 의해 쿼리의 구조와 의미가 변형될 수 있음
|
String query = "SELECT * FROM user_data WHERE userid = " + accountNumber; -----+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~
문자열 결합 방식으로 쿼리를 생성
String answer_query;
// if (runningOnWindows())
// {
// answer_query = "SELECT TOP 1 first_name FROM user_data WHERE userid = "
// + TARGET_CC_NUM;
// } else
// {
answer_query = "SELECT name FROM pins WHERE cc_number = '" + TARGET_CC_NUM +"'";
// }
try
{
Statement answer_statement = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet answer_results = answer_statement.executeQuery(answer_query);
answer_results.first();
System.out.println("Account: " + accountNumber );
System.out.println("Answer : " + answer_results.getString(1));
if (accountNumber.toString().equals(answer_results.getString(1)))
{
makeSuccess(s);
} else
{
Statement statement = connection.createStatement( ⇐ Statement 구문을 통해서
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query); ⇐ 만들어진 쿼리를 그대로 실행
if ((results != null) && (results.first() == true))
{
ec.addElement(new P().addElement("Account number is valid"));
} else
{
ec.addElement(new P().addElement("Invalid account number"));
}
}
}
catch (SQLException sqle)
{
ec.addElement(new P().addElement("An error occurred, please try again."));
// comment out two lines below
ec.addElement(new P().addElement(sqle.getMessage()));
sqle.printStackTrace();
}
}
catch (Exception e)
{
s.setMessage("Error generating " + this.getClass().getName());
e.printStackTrace();
}
return (ec);
}
Java의 Statement 객체
Statement ⇒ 만들어진 문자열 형태의 쿼리를 그대로 전달해서 실행
~~~~~~~~~~~~~~~~~~~~~~~~~~~
쿼리 생성 책임이 개발자에게 있음
PreparedStatement ⇒ 미리 정의한 쿼리 구조에 맞춰서 쿼리를 생성해서 DB로 전달해서 실행
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
쿼리 구조 정의는 개발자가 하고, 쿼리 생성은 해당 객체가 책임지고 수행
CallableStatement ⇒ DB에 정의되어 있는 Stored Procedure를 호출할 때 사용