Web

HTTP

题目基本信息

基础镜像:https://github.com/qsnctf/base_nginx_php_72
考察点:代码审计、HTTP请求头伪造。


www>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
<?php
header('Content-type:text/html;charset=utf-8');
setcookie('admin','0');

function getip() {
if(getenv('HTTP_CLIENT_IP') && strcmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') && strcmp(getenv('REMOTE_ADDR'), 'unknown')) {
$ip = getenv('REMOTE_ADDR');
} elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}

$ip = getip();

if(preg_match('/(127\.\0.\.0\.1\.[^:]{15})/', $ip)) {
exit('不允许来自外地的人访问呦!!!');
}

if($_COOKIE['admin'] !== '1') {
exit('请登录后访问呀');
}

exit(file_get_contents('/flag'));
?>

flag.sh:

1
2
3
4
5
6
#!/bin/sh

echo $FLAG > /flag


rm -f /flag.sh

setcookie('admin','0'); 与随后用 $_COOKIE['admin'] 判断的顺序是错误/被滥用的:

  • setcookie() 是向客户端发送 Set-Cookie 响应头 —— 它只会在响应后让浏览器更新 cookie。
  • $_COOKIE 代表的是“请求中已经带来的 cookie”,不会被 setcookie() 立即修改。也就是说,攻击者在请求里发送 Cookie: admin=1,服务器仍会在响应中给客户端 Set-Cookie: admin=0(下一次请求才生效),但本次执行里 $_COOKIE['admin'] 仍为 '1' —— 检查会通过,从而绕过登录检查。

    IP 获取与正则(潜在混淆/学习点)

  • getip() 非常不可信(它优先使用 HTTP_CLIENT_IPHTTP_X_FORWARDED_FOR 等可由客户端控制的头)。这是常见的“信任头部导致伪造源地址”的问题。
  • 正则 preg_match('/(127\.\0.\.0\.1\.[^:]{15})/', $ip) 很怪:模式中有 \0(NUL)和 [^:]{15}。这看起来像是在搞“null 字符/编码”的考查或是故意混淆。对普通的 IP(例如 127.0.0.11.2.3.4)通常不会匹配到这个模式,所以大多数真实请求不会被 exit('不允许来自外地的人访问呦!!!') 阻断。
  • 因此,IP 检查在题目中并不能阻止攻击者(除非服务器的 $ip 恰好匹配那个非常规模式)。这部分更像是迷惑/教学点(展示对 header 的盲信任和对正则转义/\0 的细节)。

    直接读取文件 /flag

    如果通过了前两项检查,代码会直接 file_get_contents('/flag') 输出 flag。典型的 CTF “拿 flag”点就在这里。

    利用(解题)思路与步骤

    思路一句话: 直接在请求中把 admin cookie 设为 1,同时不要触发那条奇怪的 preg_match(用默认 IP 即可),然后访问该脚本,服务器会因为 $_COOKIE['admin']=='1' 而把 /flag 的内容输出给你。

    URL

    基础镜像:https://github.com/qsnctf/base_nginx_php_72
    考察点:代码审计、代码逻辑判断绕过

www>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
<?php
header("Content-type:text/html;charset=utf-8");
include 'flag.php';
highlight_file(__FILE__);

if(isset($_POST['url'])) {
$url = $_POST['url'];
if (filter_var($url, FILTER_VALIDATE_URL)) {

$r = parse_url($url);
print_r($r);
if (preg_match('/getflag\.com$/', $r['host'])) {

if(file_get_contents($url)=='pentest'){
echo $flag;
} else {
echo "error: 文件内容不是 pentest";
}
} else {
echo "error: host 不正确呢";
}
} else {
echo "error: url 不正确呀";
}
} else {
echo "error: 需要url呐";
}
?>

www>flag.php
1
2
3
<?php
$flag = file_get_contents('/flag');
?>

flag.sh
1
2
3
4
5
6
7
8
#!/bin/sh

echo $FLAG > /flag

export FLAG=not_flag
FLAG=not_flag

rm -f /flag.sh

关键逻辑

  • 接收 url 参数,先通过 filter_var(..., FILTER_VALIDATE_URL) 验证是否为 URL。
  • parse_url 解析出 $r['host'],要求 host getflag.com 结尾preg_match('/getflag\.com$/', $r['host']))。
  • 若通过,则 file_get_contents($url),判断返回内容是否精确为字符串 'pentest',若是则输出 flag。

    Misc

    坚强的压缩包

    原题是压缩包的已知明文攻击(Known-plaintext attack),已知明文攻击并不是魔法,也不是黑箱里的秘密武器。它源于加密系统的“可预测性”和“信息泄露”——当攻击者既有密文又知道其中一部分的明文时,能从两者的关系中反推出对解密有用的东西。想象把一段文字放进一个上锁的箱子。密文是被锁起来的箱子,明文是箱子里的物品。已知明文攻击就像攻击者手里同时有:
  • 一个看起来一模一样的空箱子(密文);
  • 与箱内物品相同的一件物品(已知明文)。
    如果箱子锁的结构很简单(内部机械零件少、规律明显),那攻击者就能通过研究“某件已知物品是如何放进箱子并被锁上的”来反推锁的内部机制,从而打开其它同样类型的箱子。

为什么“已知明文”会帮忙破解?

因为加密算法/实现并非完美随机,它们把明文和密文联系在一起,泄露了可被利用的结构或状态

很多旧的 ZIP 实现使用的 ZipCrypto 就是经典例子:它内部状态小、基于线性CRC运算生成 keystream,且文件头是可预测的。攻击者用已知的文件头就能推导出 keystream,继而恢复内部状态并解密其它文件。现代 AES-based ZIP 通过更强的 KDF 与认证解决了这些问题。

首先,准备一个docx文档,存储flag,一个png,作为单独的文件。

先将这两个文件,打包一个有密码的压缩包:

随后将png文件(也就是不是flag的文件),单独用同样的压缩方法、加密算法打包成单独的压缩包。

使用ARCHPR工具,选择明文攻击(Plain-text),左上角选择包含密码的压缩包,明文文件选择没有密码的压缩包,点击开始即可。