webwp
攻防世界wp
一、攻防世界 - get_post- 简单
拿到题目,要求使用get方式提交变量
直接?a=1即可
但是地址栏无法直接post请求
此时切换火狐浏览器,使用hackbar插件
post b=2 直接获得flag
二、攻防世界 - view_source - 简单
根据问题描述,应该要查看网页的源代码,但是鼠标右键被禁用了,左键也不行
但是我们有键盘
使用F12快捷键即可
三、攻防世界 - disabled_button - 简单
进来发现一个奇怪的按钮,审阅html代码,发现有个表单
但是无法点击,按了没反应
看到里面有个”disabled”,我在想,直接去掉就行了
将disabled删除,这时候发现按钮可以点了
按一下得到flag
四、攻防世界 - cookie - 简单
使用火狐找到cookie,发现php源码泄露,访问
访问php文件,得到这个界面,说看response
前面一开始以为说的是http status,就是那个状态码404,
但是不是,网上查询发现其实就是响应头
刷新一下网页,在network里面,选择cookie.php访问响应头
拿到flag
五、搭建图床的过程
首先下载picgo
然后在github上搭建一个仓库来作为图床
记录token
在picgo里面配置
但注意要关掉steam++,否则会上传失败
】
1 | assert m < p |
六、easy SQL
进入网站后要求输入账号密码,随便输入一下,发现使用了get请求,并且泄露了php文件
访问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 | City = 1 |
为了区分,我们可以试着加入一个单引号
此时报错,说我们有SQL语法的错误,看后面报错信息,是多加了一个引号变成了’‘12‘’‘
所以这显然是字符串型
然后我们再看看闭合方式
**
显然是单引号闭合,但是不知道为什么后面password是双引号
查了网上博客才知道实现方式
1 | 0) { |
尝试使用万能密码
此处#将后面的部分注释掉
所以sql中的代码是
1 | username = ‘’or 1 =1 # password = ‘2’ |
由于1=1为true,因此直接执行,而不检查用户名和密码
12.9 web
1.2019极客大挑战havefun
打开看源码,发现是get请求,简单的php审计
只要cat=dog,就能拿到flag
2. warm up
打开查看源码,发现php文件名泄露
访问拿到代码,开始审计
1 | "source.php","hint"=>"hint.php"]; |
1 | if (! isset($page) || !is_string($page)) { |
这一段逻辑有点绕,但我们不希望执行if,可以使用数字逻辑知识
也就是与非门,只要两个条件同时成立,就不会执行if
换而言之,需要page设置,并且设置为字符串
1 | if (in_array($page, $whitelist)) { |
PHP 5中 in_array函数功能 — 检查数组中是否存在某个值。
所以大致我们就知道这个代码功能,就是检查用户是否输入了正确的文件名称
也就是检查page是否在whilelist中,而”source.php”,”hint.php”就是whilelist中的值
但是我对这个whilelist数组的形式有些奇怪,查询了一下
在PHP中,箭头(=>)是定义数组的键值对分隔符。你可以使用它来定义数组中的元素。
1 | $array = array("key1" => "value1", "key2" => "value2"); |
所以其实就是类似python的字典
首先先访问一下hint.php,看看提示
换而言之,我们要访问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 | $_page = urldecode($page); |
这里对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
不过有一个疑惑,为什么hint.php后面加了?不会把后面的认为是query
二、SQL注入
个人的理解:
SQL是一种结构化查询语言,用于在数据库中查询信息
用户在与网页交互时,需要使用get,post请求来提交表单到后台的SQl服务器,如果用户在其中加入了一些SQL语言代码,就可能获得数据库查询的权限,原因在于后端没有对输入进行过滤,于是就产生了SQL注入漏洞
一些术语:
回显:常常指程序开发中执行命令的结果,就是返回的显示,你输入一个命令,然后给你返回一个值,显示在屏幕上
当用户提交表单时,服务器返回到前端html页面的内容可以称为回显
字段:数据库表格中的列
我们把表中的每一行叫做一个“记录”,每一个记录包含这行中的所有信息,就像在通讯录数据库中某个人全部的信息,但记录在数据库中并没有专门的记录名,常常用它所在的行数表示这是第几个记录。字段是比记录更小的单位,字段集合组成记录,每个字段描述文献的某一特征,即数据项,并有唯一的供计算机识别的[字段标识符]
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 | select 'Hello, World!'; |
联合查询
1 | SELECT name, position FROM employees UNION SELECT name, position FROM contractors; |
比如说我们有两个表格,emplyees和contractors,他们都有同样的列,那么使用union select就可以同时查询
联合查询要求每个 `SELECT` 语句中的列数必须相同,并且对应列的数据类型应该是兼容的。
再结合前面没有from的select,就能探测列数或者专业来说是字段数
比如,ctfhub技能树的整型注入
一、CTFHUB:整型注入
拿到题目,说输个1试试,输入1,得到如下回显
回显把SQL语句泄露出来了,也就是
1 | select * from news where id=1 |
仔细研读,是从news这个表里,选择满足id=1的所有列,并返回
可以看出只有两列,两个字段,不过,也无法保证这个源码没有骗我们,可能不是*,而是只是输出了id,data?
所以可以用联合查询探测
1 | select * from news where id=1 union select 1 |
这个没有回显,说明列数没有匹配
输入
1 | select * from news where id=1 union select 1,2 |
之后就有回显了,说明确实是2列
这里
1 | select 1,2 |
这条查询没有指定表,而是直接返回两个常量值:1
和 2
。它相当于返回了一行包含两列的数据。
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 |
奇怪的是,为什么后面没有回显?
这或许是网站显示问题,不能完全显示联合查询的内容,我们把前面id换成-1,或者-10,这样就只显示后面的内容
这样就查到数据库名了,但是只有一个
怎么把全部数据显示出来呢?
使用语法
1 | select * from news where id=-10 union select 1,group_concat(schema_name) from information_schema.schemata |
就获得了所有库名
前四个库都是自带的,那么显然最后一个sqli应该就是flag藏得地方
接着我们要了解这个库里的表名
和上面类比就行,换成table
1 | select * from news where id=-10 union select 1,group_concat(table_name) from information_schema.tables |
能查是能查,但是太长了,需要筛选
那显然就在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' |
所以就准确定位了flag位置
sqli库,flag表,flag字段
使用
1 | select * from news where id=-1 union select 1,flag from sqli.flag |