Bugku——web6

又是一道编程题,正好给自己练手

# coding:utf-8
import requests
from base64 import b64decode
s=requests.Session()
a=s.get('http://120.24.86.145:8002/web6/').headers['flag']
flag=b64decode(a)
uflag=str(flag,encoding="utf-8")
key=b64decode(uflag.split(': ')[1])
payload={'margin':key}
r=s.post('http://120.24.86.145:8002/web6/',data=payload)
print(r.text)
<think>首先,用户询问的是Bugku CTF web题目“备份是个好习惯”的解题方法。参考引用[1]列出了该题目在Web部分,引用[2]提供了题目的PHP代码片段。 从引用[2]中,我得到了题目的关键PHP代码: ```php include_once "flag.php"; ini_set("display_errors", 0); $str = strstr($_SERVER['REQUEST_URI'], '?'); $str = substr($str,1); $str = str_replace('key','',$str); parse_str($str); echo md5($key1); echo md5($key2); if(md5($key1) == md5($key2) && $key1 !== $key2){ echo $flag."取得flag"; } ``` 解题的关键在于满足条件:`md5($key1) == md5($key2)` 且 `$key1 !== $key2`。这涉及到MD5哈希碰撞或弱点利用。 在PHP中,`==` 操作符用于松散比较,它可能会在类型转换时导致漏洞。例如,如果两个不同的字符串的MD5哈希都以"0e"开头,且后面全是数字,PHP可能会将它们解释为科学计数法的0,从而导致比较为真。 因此,解题思路是找到两个不同的字符串 `key1` 和 `key2`,使得 `md5($key1)` 和 `md5($key2)` 都以 "0e" 开头,后面全是数字。 常见的例子包括: - `key1 = "240610708"`,MD5: "0e462097431906509019562988736854" - `key2 = "QNKCDZO"`,MD5: "0e830400451993494058024219903391" 这些字符串的MD5哈希都以 "0e" 开头,后面是数字,所以在松散比较时等于0。 在代码中,参数是通过URL传递的。代码处理URL查询字符串:提取问号后的部分,移除"key"字符串,然后解析查询字符串。 具体步骤: 1. `$str = strstr($_SERVER['REQUEST_URI'], '?');` – 获取问号后的部分。 2. `$str = substr($str,1);` – 移除问号,所以剩余的是查询字符串如 "key1=value1&key2=value2"。 3. `$str = str_replace('key','',$str);` – 移除所有 "key" 子串。这可能会改变参数名。 例如,如果原始查询是 "key1=a&key2=b",移除 "key" 后变成 "1=a&2=b"。 然后,`parse_str($str);` 会解析这个字符串并创建变量。移除 "key" 后,原来的 "key1" 变成 "1","key2" 变成 "2",所以变量 `$key1` 和 `$key2` 可能不会被正确设置。 用户需要设置变量 `$key1` 和 `$key2`,但由于移除了 "key",应该使用参数名如 "1" 和 "2" 来设置值。 例如,如果查询字符串是 "1=value1&2=value2",那么 `parse_str` 会创建 `$1` 和 `$2`,但代码中用的是 `$key1` 和 `$key2`。 代码中直接使用 `$key1` 和 `$key2`,但参数名被修改了。所以,可能需要使用不同的参数名。 在移除 "key" 后,原本的 "key1" 变成 "1",所以变量名是 `$1`,但代码中检查 `$key1`,这会导致未定义的变量。 PHP中,如果变量未定义,使用它会引发警告,但由于 `display_errors=0`,不会显示错误,但 `$key1` 和 `$key2` 可能为 null。 但条件 `$key1 !== $key2` 可能为真如果它们都未定义,但 `md5(null)` 是固定的,`md5(null)` 是 "d41d8cd98f00b204e9800998ecf8427e",不等于另一个 null 的 MD5,但它们相同,所以 `md5($key1) == md5($key2)` 可能为真,但 `$key1 !== $key2` 对于 null 可能为假,因为 `null !== null` 是假的?等号比较:`null === null` 为真,`null == null` 为真,但 `!==` 严格不相等。 `$key1` 和 `$key2` 如果未定义,都是 null,所以 `$key1 !== $key2` 是 false,因为 `null !== null` 是 false。 所以,需要正确设置变量。 在移除 "key" 后,参数名改变了。例如,如果原始查询有 "key1" 和 "key2",移除 "key" 后变成 "1" 和 "2",然后 `parse_str` 会设置变量 `$1` 和 `$2`,但不是 `$key1` 和 `$key2`。 所以,代码中 `$key1` 和 `$key2` 可能未定义。 但代码中直接使用 `$key1` 和 `$key2`,它们没有被设置。 或许用户需要使用参数名 "ey1" 或类似来绕过移除。 `str_replace('key','',$str)` 移除所有出现的 "key" 子串。 例如: - "key1" 移除 "key" 后变成 "1" - "akey1" 移除 "key" 后变成 "a1" - "kkeyey1" 变成 "1" 因为移除所有 "key" 要设置 `$key1`,但 "key" 被移除,所以变量名无效。 但代码中,`parse_str` 后,使用的变量是 `$key1` 和 `$key2`,但参数名被修改,所以 `$key1` 可能不存在。 除非参数名中包含 "key",但移除后剩下部分被用作变量名。 例如,如果参数名是 "kkeyey1",移除 "key" 后:先移除所有 "key",所以 "kkeyey1" -> 移除 "key" 两次? "kkeyey1" 有 "kkey" 其中 "key" 被移除,剩下 "k",然后 "ey1" 没有 "key",所以变成 "key"? 移除所有出现的子串 "key"。 在字符串中,移除所有连续或非连续的 "key" 子串? `str_replace` 移除所有出现的子串。 例如 "keykey1" 移除所有 "key" 后变成 "1"。 "akeybkeyc" 移除后变成 "abc"。 对于参数名,假设原始查询是 "key1=value1&key2=value2",移除 "key" 后变成 "1=value1&2=value2",然后 `parse_str($str)` 会设置 `$1 = value1` 和 `$2 = value2`,但代码中用的是 `$key1` 和 `$key2`,这些变量未被设置,所以可能为 null。 然后 `md5($key1)` 和 `md5($key2)` 都是 `md5(null)`,即 "d41d8cd98f00b204e9800998ecf8427e",所以 `md5($key1) == md5($key2)` 为 true(因为哈希相同),但 `$key1 !== $key2`:由于两者都为 null,`$key1 !== $key2` 是 false,因为 null 与 null 在严格比较下是相等的? 等等,不对。 PHP 中的比较: - `$key1 == $key2`:如果都是 null,则为 true。 - `$key1 === $key2`:如果都是 null,则为 true,因为类型和值都相同。 - `$key1 !== $key2` 是 `!($key1 === $key2)`,所以如果都是 null,就是 false。 但条件要求 `$key1 !== $key2`,如果都是 null,这就为 false。 所以条件不成立。 需要 `$key1` 和 `$key2` 被设置且不同。 所以,参数命名的方式必须保证移除 "key" 后,变量名被设置为 `$key1` 和 `$key2`,但原始名称中有 "key",移除后,名称发生了变化。 例如,如果参数名为 "xkey1",移除 "key" 后变成 "x1",所以变量是 `$x1`,而不是 `$key1`。 无法直接设置 `$key1`,因为名称中包含 "key" 会被移除。 但变量名 `$key1` 是硬编码的,所以可能无法设置。 除非使用其他方法。 或许 `parse_str` 会设置变量,但名称是修改后的字符串。 在代码中,echo md5($key1) 和 echo md5($key2) 之后,如果变量未定义,md5 的参数是 null,但代码可能出错,不过 display_errors=0,所以没有输出,但逻辑继续。 但在 if 条件中,如果 $key1 和 $key2 未定义,$key1 !== $key2 是 false。 但我们需要它们被定义且不同。 解决方案:使用在移除 "key" 后的参数名来设置值。 例如,在移除 "key" 后的字符串中,如果有 "1" 和 "2",那么变量 $1 和 $2 将被设置,但代码使用的是 $key1 和 $key2,而不是这些变量。 所以,代码中可能有一个错误,或者需要特定的方式。 回顾代码: $str = strstr($_SERVER['REQUEST_URI'], '?'); // 例如,对于 /path/script.php?key1=val&key2=val,$str 是 "?key1=val&key2=val" $str = substr($str,1); // 去掉 '?',所以是 "key1=val&key2=val" $str = str_replace('key','',$str); // 移除所有 'key',所以如果输入是 "key1=val&key2=val",输出是 "1=val&2=val" 然后 parse_str($str); // 解析查询字符串 "1=val&2=val",所以它设置了变量 $1 和 $2,值为 val。 但在PHP中,变量名不能以数字开头,所以 $1 是无效变量名。parse_str 可能会忽略它或产生警告,但 display_errors=0,所以没有错误,但 $1 和 $2 不会被定义。 在 PHP 中,变量名不能以数字开头,所以 parse_str 对于像 "1=val" 这样的键无法创建变量,因此这些值不会被设置。 因此,$key1 和 $key2 没有被定义。 但是,在代码中,有 echo md5($key1); 和 echo md5($key2);,所以如果未定义,md5(null) 会被计算,但if条件不起作用。 我们需要一种方法来设置 $key1 和 $key2。 关键是原始参数名中包含 'key',所以移除后,名称发生变化,但我们需要参数名在移除 'key' 后,能够被解析为变量。 例如,如果参数名中没有 'key',但名字是 $key1,而 'key' 被移除,所以如果我们使用参数名 'key1',就变成了 '1',无效。 所以,解决方案是使用在移除 'key' 后有效且能设置所需变量的参数名。 但所需变量是 $key1 和 $key2,它们不是由 parse_str 设置的,因为键被修改了。 除非代码使用不同的变量名,但代码中写的是 $key1 和 $key2。 也许在移除之后,字符串可以被解析,使得变量名是 'key1',但原始字符串中有 'key',所以被移除了。 另一个想法:使用像 'kkeyey1' 这样的参数名,在移除 'key' 之后,会变成 'key1' 或类似的东西。 例如,'kkeyey1':'kkeyey1' 包含 'key' 吗?'kkeyey1' - 移除 'key':位置,'kkey' 有 'key' 子串,移除后剩下 'k',但 'kkey' 是 'k' + 'key',移除 'key' 后剩下 'k',然后 'ey1',没有 'key',所以是 'key'?我们来正确使用 str_replace。 str_replace('key', '', $str) 会替换所有出现的 'key'。 对于 'kkeyey1':它包含两个 'key' 吗?'kkey' 可以视为 'k-key',但 'key' 是一个子串,所以 'kk ey' 不行,'kkeyey1' 这个字符串,子串:从索引 0 开始,'kke' 不是 'key',索引 1 'key' 是 'key'? 字符:索引 0:'k', 1:'k', 2:'e', 3:'y', 4:'1',所以子串从索引 1 开始是 'ke y' 不行,在 'kkeyey1' 中,如果它是 'kk' + 'ey',就没有 'key' 子串,除非是 'k-key',但它是连续的。 'key' 子串必须是连续的字符。 所以对于 'kkeyey1',它没有 'key' 子串,因为 'k' 然后 'k' 然后 'e' 然后 'y',所以没有 "k" 后接 "e" 后接 "y" 的连续序列。 例如,'key1' 有 'key'。 'akey1' 有 'key'。 'kkey' 有 'key'(位置1-3:k, k, e, y,索引1-3是 k,e,y?索引1是第二个k,索引2是e,索引3是y,所以索引1-3是 "key" 如果我们考虑索引1,2,3:但索引0是k, 索引1是k, 索引2是e, 索引3是y,所以索引1-3是 "key" 如果我们取索引1,2,3:字符索引1是k, 索引2是e, 索引3是y,所以 "key" 子串存在。 在 "kkey" 中,从索引1开始的子串是 "key",所以 str_replace 会移除它。移除后,剩下索引0的 'k',然后索引4及之后的内容。 对于 "kkeyey1",我们分解一下:假设字符串是 "kkeyey1"。 字符:索引0:'k', 1:'k', 2:'e', 3:'y', 4:'e', 5:'y', 6:'1' 子串 "key" 出现在索引1-3:字符1:'k',2:'e',3:'y' -> "key",移除后移除字符1,2,3。 移除后,剩下索引0: 'k', 然后索引4:'e', 5:'y', 6:'1',所以是 "key1"?索引4是 'e', 5是 'y', 6是 '1',所以 "ey1"。 所以移除后,字符串是 "k" + "ey1" = "key1"。 "k" 和 "ey1" 所以是 "key1"。 类似地,对于 "kkeyey2",移除后变成 "key2"。 然后,在查询字符串中使用这些参数名。 例如,在URL中使用参数名 kkeyey1 和 kkeyey2。 所以,对于原始查询:?kkeyey1=value1&kkeyey2=value2 然后 $str = strstr(..., '?') 是 "?kkeyey1=value1&kkeyey2=value2" substr($str,1) 后是 "kkeyey1=value1&kkeyey2=value2" str_replace('key','',$str) 后:对于 "kkeyey1",如上所述,移除 "key" 子串,变成 "key1"。 类似地,"kkeyey2" 变成 "key2"。 所以字符串变为 "key1=value1&key2=value2" 然后 parse_str($str) 设置 $key1 = value1 和 $key2 = value2。 完美。 然后,我们需要 $key1 和 $key2 的值不同,但 md5 值在弱比较中相等。 所以,使用像 "240610708" 和 "QNKCDZO" 这样的值。 所以,解题方法是构造一个类似如下的URL: http://xxx/?kkeyey1=240610708&kkeyey2=QNKCDZO 然后,代码会设置 $key1 = "240610708", $key2 = "QNKCDZO" md5($key1) = md5("240610708") = "0e462097431906509019562988736854" md5($key2) = md5("QNKCDZO") = "0e830400451993494058024219903391" 在松散比较中,md5($key1) == md5($key2) 为 true,因为两者都以 "0e" 开头,后面是数字,表示在科学记数法中为 0。 而 $key1 !== $key2 为 true,因为字符串不同。 因此,条件满足,将回显标志。 在代码中,在判断之前有 echo md5($key1); 和 echo md5($key2);,因此输出哈希值,但判断后会输出 $flag。 对于 CTF,用户需要访问带有这些参数的 URL。 现在,在响应中,应该包含标志。 根据引用 [2],标题是“备份是个好习惯”,我假设这是一个 Web 题目,用户需要利用这个漏洞。 所以,解题方法是: 1. 访问带有特定参数的 URL。 2. 使用参数名称,在移除 'key' 后变为 'key1' 和 'key2',例如 'kkeyey1' 和 'kkeyey2'。 3. 设置值以实现 MD5 冲突,例如 '240610708' 和 'QNKCDZO'。 4. 提交请求,响应中将包含标志。 在原始代码中,在移除之后,它将设置 $key1 和 $key2,然后进行检查。 在响应中,如果条件满足,将输出 $flag。 所以,对于答案,我应该用简单的语言解释步骤。 另外,根据系统指令,使用中文回答,在 LaTeX 中使用行内数学格式,但对于这个答案,可能没有数学内容,但如果有变量,要使用 $...$。 在这个上下文中,主要是讨论代码和字符串,所以可能不需要 LaTeX。 但例如,在解释时,如果有类似变量的内容,可以使用 $...$。 另外,生成相关问题。 在回答末尾添加引用标识。 引用来自用户的消息,所以我可以在末尾添加 [^1] 和 [^2],但用户说“上述引用仅供参考”,所以我应该基于引用内容进行回答。 最后,将答案结构清晰地呈现。 </think>### Bugku CTF "备份是个好习惯" 题目解题方法 在 Bugku CTF 的 Web 题目 "备份是个好习惯" 中,解题的关键在于分析提供的 PHP 代码,并利用其逻辑漏洞来触发条件获取 flag。以下是基于引用 [2] 中代码的详细解题步骤。代码的核心逻辑是:通过 URL 参数传入两个值 `$key1` 和 `$key2`,满足条件 `md5($key1) == md5($key2)` 且 `$key1 !== $key2` 时,输出 flag[^2]。 #### 解题步骤 1. **理解代码漏洞**: - 代码从 URL 查询字符串中提取参数,并移除所有 "key" 子串:`$str = str_replace('key','',$str);`。 - 移除 "key" 后,参数名会被修改,然后将字符串解析为变量:`parse_str($str);`。 - 目标是通过巧妙构造参数名,使解析后变量 `$key1` 和 `$key2` 被正确设置,且满足: - `md5($key1) == md5($key2)`:PHP 的 `==` 是松散比较,可利用 MD5 哈希的 "0e" 开头漏洞(即哈希值以 "0e" 开头后跟数字,比较时被当作科学计数法的 0)。 - `$key1 !== $key2`:严格比较,确保两个值不同。 - 推荐的漏洞利用值: - `$key1 = "240610708"`:MD5 哈希为 `0e462097431906509019562988736854`。 - `$key2 = "QNKCDZO"`:MD5 哈希为 `0e830400451993494058024219903391`。 - 松散比较时,两个哈希都等于 0,因此 `md5($key1) == md5($key2)` 为真,但字符串值不同,满足 `$key1 !== $key2`。 2. **绕过参数名修改**: - 代码移除所有 "key" 子串后解析参数。直接使用 `key1` 和 `key2` 会被修改(例如 `key1` 变成 `1`),导致变量无法正确设置。 - 解决方案:使用参数名 `kkeyey1` 和 `kkeyey2`。移除 "key" 子串后: - `kkeyey1` → 移除 "key"(在索引位置)后变为 `key1`。 - `kkeyey2` → 移除 "key" 后变为 `key2`。 - 这样,`parse_str` 会正确设置变量 `$key1` 和 `$key2`。 3. **构造攻击 URL**: - 访问题目 URL,并附加查询参数: - 完整 URL 格式:`http://题目域名/路径?kkeyey1=240610708&kkeyey2=QNKCDZO` - 示例(实际域名需替换):`http://example.com/challenge?kkeyey1=240610708&kkeyey2=QNKCDZO` - 参数解释: - `kkeyey1=240610708`:设置 `$key1` 的值。 - `kkeyey2=QNKCDZO`:设置 `$key2` 的值。 4. **触发 flag 输出**: - 发送 HTTP 请求(使用浏览器或工具如 curl)后,代码会: - 移除 "key" 子串,解析出 `$key1` 和 `$key2`。 - 计算并输出 MD5 哈希(调试信息,可忽略)。 - 检查条件:满足时输出 `$flag` 和 "取得flag"。 - 如果条件正确,响应中将包含 flag,格式类似:`flag{...}取得flag`。 #### 注意事项 - **测试工具**:可以使用 curl 命令测试: ```bash curl "http://example.com/challenge?kkeyey1=240610708&kkeyey2=QNKCDZO" ``` - **环境依赖**:题目可能部署在 Bugku CTF 平台,确保访问正确的 URL(参考引用 [1] 中的题目列表)[^1]。 - **原理总结**:本题利用 PHP 松散比较的漏洞和字符串处理缺陷,通过巧妙参数名和 MD5 碰撞值绕过检查。 #### 相关问题 1. 如何防御 PHP 中的 MD5 松散比较漏洞? 2. CTF Web 题目中还有哪些常见的哈希碰撞利用方法? 3. PHP 的 `parse_str` 函数可能导致哪些安全问题? [^1]: BugkuCTF练习题解——Web一。 [^2]: 备份是个好习惯题目源码。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值