1. admin 계정으로 로그인하기
doldol의 계정으로 로그인을 하니 loginProc.php를 GET으로 입력한 데이터와 함께 userId=doldol & userPw=dol1234 요청을 보내는 것 같습니다. 그런데 응답에서 result: "ok" 가 보이는데 이것으로 왠지 로그인 성공 여부를 결정할 것 같습니다.
그럼 admin으로 로그인하면 어떤 결과가 나오는지도 확인해보겠습니다.
역시나!! result값이 fail로 나옵니다. 그럼 응답을 ok로 바꿔주면 로그인이 될 것 같습니다.
보통 기본적으로 버프 스위트는 요청만 잡기때문에 응답을 잡기위해서는 원하는 응답의 요청을 오른쪽 클릭하면 Do intercept에서 이 request의 respons를 잡겠다는 것을 클릭하고 Forward로 요청을 보내주면 응답을 intercept할 수 있습니다.
응답을 버프스위트에서 잡고 있습니다. 이제 result값을 ok로 바꿔서 요청을 보내면 인증 우회를 할 수 있을 것입니다.
바꿔주고 intercept is off로 해주며 잡고있는 것을 모두 풀어주고 브라우저에 돌아와보니 admin으로 로그인을 성공했습니다.
이번 챌린지는 response도 활용을 해보라고 만들어 놓은 것 같습니다.
2. 사이트의 PIN번호를 크랙해보자.
pin code 숫자 4자리를 입력하라고 되어있네요... 1234를 입력해보겠습니다.
역시 실패라고 뜨면서 다시 로그인 페이지로 넘어가네요.. 바로 버프스위트로 어떤 데이터를 주고 받았는지 확인하겠습니다.
보니까... 우리가 입력한 숫자를 otpNum에 넣어 checkOTP.php페이지 GET요청을 보냅니다. 결과로 Login Fail 경고와 함께 location.href 로 다시 로그인 페이지로 이동하네요!!
이렇게 푸는 게 맞는 지는 모르겠지만 0000부터 9999까지 넣어 페이지에 요청을 보내보겠습니다. (오래걸리지만 않으면 확실한 방법이죠 ㅎㅎ)
import requests # requests 패키지 사용
# 만번 반복
for i in range(10000):
num = str(i) # 앞에 0을 채워주기 위해 정수를 문자로 바꿈
num = num.zfill(4) # 앞에 0채워주며 4자리를 맞춰줌
print(num)
# 요청을 보낼 URL 입력 (포맷팅을 통해 num부분만 변경하면서)
url = f"http://ctf.segfaulthub.com:1129/6/checkOTP.php?otpNum={num}"
# get으로 해당 url로 요청을 보낸 후 결과를 response에 저장
response = requests.get(url)
# respnse.text를 하면 응답의 body를 확인할 수 있다.
# Fail 이 없을 경우 중단시킴
if ('Fail' not in response.text):
print(num)
break
버프스위트에서 intruder 기능을 통해 optNum부분만 바꿔서 만번 요청을 보내도 되지만!! 무료버전 intruder 기능은 조금만 여러번 반복해도 오래걸리기 때문에 파이썬을 사용하여 요청을 보냈습니다.
파이썬의 requests 패키지를 사용하면 파이썬으로 요청을 보낼 수 있습니다. 내장 패키지가 아니므로 따로 다운로드 해야됩니다...
그래서 결론적으로 우리가 원하는 url에 만 번 요청을 보내면서 실패한 경우인 Fail이 뜨면 무시하고 Fail이 없는 경우 요청을 멈추며 해당 번호를 출력하게 코드를 짜봤습니다.
크랙 결과 나온 번호를 입력해주니 로그인 성공!!! (플래그에 브루트포스라는 단어가 포함되어있는 것 보니 이렇게 푸는 걸 원했던 것 같습니다.)
3. normaltic3 계정으로 로그인하기
doldol계정으로 로그인해보니 userId와 Password에 입력한 아이디와 비밀번호를 넣어 post요청을 통해 성공하면 index.php로 리디렉트하는 것 같습니다.
SQL Injection이 가능한 지 먼저 알아보겠습니다.
' and '1'='1를 넣었는데 로그인 되는 걸보니 SQL Injection이 가능한 것 같습니다.
하지만 아이디에 normaltic3' #, normaltic3' or '1'='1 은 안되네요... (따로 해보았습니다.)
주석이 막혔나 생각해서 doldol' #을 해보았는데 이것은 정상적으로 로그인이 가능합니다.
만약 주석이 필터링 되었다면 id='doldol'' and password ~ 이렇게 ' 가 두 개가 되어 SQL 문법 에러로 정상적으로 로그인 되지 않았을 것입니다.
오..?? 아이디에 주석처리 같이해줌으로써 뒤에 패스워드를 무시하여 doldol계정의 정보를 가져왔지만 비밀번호가 틀리니 로그인이 되지 않습니다.
그럼 비밀번호를 따로 검사하는 식별과 인증을 분리하는 로그인 로직인것 같습니다.
select * from [users] where id='userId';
if (비밀번호 비교)
우리는 doldol' # 을 아이디에 입력했는데 doldol이 로그인 되었습니다. 그럼 입력한 값으로 로그인이 결정되는 것이 아니라 SQL 문으로 찾은 계정의 아이디로 로그인을 시켜줍니다.
SQL로 찾은 데이터의 아이디와 비밀번호를 우리가 같게 만들어 주면 될 것 같습니다.
이때 알아야하는 것이 SQL의 union입니다.
union은 select한 결과값을 합쳐줍니다. (select한 결과값의 컬럼 개수가 같아야함.)
이렇게 안의 값이 전혀 달라도 컬럼 개수만 맞춰준다면 두 결과값을 합쳐 가져올 수 있습니다.
또한, select 문자열을 하면 해당 문자열로 데이터를 만들어 출력해줍니다. (저장은 되지 않음.)
그림과 같이 어느 테이블을 검색하는 것이 아닌 select 문자열을 쓰면 해당 문자열을 검색한 것처럼 출력해준다.
union과 이 두 기능을 합치면 아래와 같이 출력할 수 있다. 이때도 컬럼 개수는 맞추어 주어야합니다.
id='' 빈 문자열인 데이터는 없으며 두 컬럼(id, password)에 select 한 값이 두 개 들어가게 됩니다.
이것을 적용해보면...
// 추측 서버측 로그인 코드
select id, password from [users] id='userId';
// userId = ' union select 'normaltic3', '1234
select id, password from [users] id='' union select 'normaltic3', '1234';
우리가 select한 값을 union을 사용하여 조작할 수 있습니다.
즉, 아이디는 normaltic3이며 비밀번호는 1234 인 데이터를 가져와 비밀번호를 검사할 것입니다.
간단하게 설명하면 서버측에서는 SQL 쿼리를 통해 아이디와 비밀번호를 찾았는데 우리가 그것을 조작하여 아이디는 normaltic3 비밀번호는 1234로 서버는 생각하게 될 것입니다.
때문에 비밀번호에 1234를 입력하여주면 서버는 오?? 아이디가 normaltic3인 비밀번호는 1234? 비밀번호가 맞네? 하면서 로그인을 시켜줄 것입니다.
남은 챌린지는 다음에 계속하겠습니다.
'웹 해킹' 카테고리의 다른 글
웹 해킹 공부 일기장 2 - 과제 (0) | 2023.12.01 |
---|---|
웹 해킹 공부 일기장 2 - 1 (SQL Injection 데이터 추출) (0) | 2023.11.30 |
웹 해킹 공부 일기장 1 - 과제 (챌린지) (0) | 2023.11.27 |
웹 해킹 공부 일기장 1 - 2 (인증 우회) (4) | 2023.11.24 |
웹 해킹 공부 일기장 1 -1 (SQL Injection) (0) | 2023.11.23 |