BugKuCTF-WEB超详细解题思路(1-10)

本文仅用于网络安全技术学习与授权测试交流。本文实验皆在靶场进行,任何未经授权使用文中技术的行为均与作者无关,请务必遵守法律法规,获得许可后方可进行渗透测试。

嗯...想来想去,打算以10道题一篇文章来进行做笔记,怕照片存不住,字数多了Typora也容易卡,就先这样。正在持续更新中!

目录

滑稽

计算器

alert

你必须让他停下

头等舱

GET

POST

source

矛盾

备份是个好习惯


滑稽

题目信息

一打开,什么阴,一大堆笑脸满天飞

好好好,flag在源代码里(按f12查看源代码)

计算器

题目信息

不愧是计算器,考我数学,让我用计算器算一下

哦,答案是165

输入试试,结果只能输入一个数,可恶,一看就是长度限制

点击f12查看元素,发现这小子果然给我玩阴的,改一下最大长度吧

改成50之后,可以看到能够输入多个数字了。点击提交,哇!出现野生flag

alert

题目信息

进入靶场发现老是弹弹窗

还让我来找找,哎呦,那本王来啦

点击ctrl+u查看源代码,发现下图有段编码,解一下

解码为ASCII,得到flag

用什么工具都行,下面分享这道题解码的python脚本

复制代码
import html
encoded = "flag{59da2380b6b4be4368d543a27e65aed5}"
print(html.unescape(encoded))

再分享个解码网站

ASCII文本,十六进制,二进制,十进制,Base64转换器

你必须让他停下

题目信息

这题,页面一直刷新,真是的,我得让他停下

这时候,想想,什么能让他停下,哦?bp,拦截抓包,试一试

抓包之后发到repeater,send几次就找到flag了,终于让他停了下来

头等舱

题目信息

嗯?头等舱...估计跟头有关

用bp抓包看一下吧

send之后果然有flag

GET

题目信息

看一下靶场,可以看到下面信息,这里表示的是用get传参,如果把what换为flag,那就会输出flag{}

复制代码
$what=$_GET['what'];
echo $what;
if($what=='flag')
echo 'flag{****}';

还等啥呢,传一下呗,搞定!找到flag!

POST

题目信息

这一题让用post传参,那就传!

直接搞定!

source

题目信息

看到元素有些乱码,解个码看看

啥也不是

看题目提示,可能需要linux环境,去kali扫描一下

发现是.git源码泄露,在浏览器尝试访问/.git,发现点开文件并不能看到源码

复制代码
用 wget -r http://160.202.254.160:16766/.git/下载源码

用ls查看下载的目录

进入之后再ls查看目录,接着使用git reflog 查看日志

接下来一个一个查看日志里的具体信息使用

复制代码
git show 40c6d51

找到flag!爽,爽,爽!

矛盾

题目信息

打开靶场发现,这段代码也很好理解,就是get方式传参num,如果num不是数字类 型,那么输出num的值,并且num=1时,输出flag的值。

复制代码
$num=$_GET['num'];
if(!is_numeric($num))
{
echo $num;
if($num==1)
echo 'flag{**********}';
}
​
​

知道方法了,传呗,我去,失败。

原来不能直接传num=1

  • 如果直接传 ?num=1,第一步 is_numeric(1) 会返回 True ,因为 1 是数字。导致 if(!is_numeric($num)) 条件不成立,直接跳过,无法输出 Flag。

  • 所以必须找一个 "表面不是数字,但和 1 比较时被 PHP 当成 1" 的东西。这就是利用 PHP 的**松散比较(==)**特性(当字符串和数字比较时,PHP 会强制把字符串转换成数字)

paylaod:

复制代码
?num=1a

或者

复制代码
?num=1abc

或者(利用 %00 截断):

复制代码
?num=1%00

原理推演(以 ?num=1a 为例):

  1. $num = "1a"(字符串)。

  2. is_numeric("1a") 检测到里面有字母 a,返回 Falseif(!False) 成立,进入大括号。

  3. 页面先输出 1a

  4. 执行 if("1a" == 1)。PHP 会把 "1a" 转换成数字,遇到非数字字符 a 就停止,转换结果为整数 1

  5. 1 == 1 成立,成功打印 flag{\**\**\**\**\*}

搞定!找到flag!

备份是个好习惯

题目信息

进入靶场,看见一些乱码,其他之外啥也没有

根据题目信息,我怀疑跟备份有关,用御剑扫描扫一下,看看能否扫出来点东西

欸!不孬,果然有备份文件

把备份文件下载一下,打开发现下面内容

代码解释

第 1 行: include_once "flag.php"; 把 flag 文件包含进来,此时内存里已经有了 $flag(真正的 flag 字符)。

第 2 行: ini_set("display_errors", 0); 关掉错误显示。如果代码有报错,用户看不到,这是一道盲注式的判定题,只能根据输出结果是否出现 Flag 来判断。

第 3 行: $str = strstr($_SERVER['REQUEST_URI'], '?'); $_SERVER['REQUEST_URI'] 是用户访问的完整地址栏内容:/?kekeyy1=QNKCDZO&kekeyy2=240610708strstr(..., '?') 截取"问号"及其后面的所有字符。 此时 $str = "?kekeyy1=QNKCDZO&kekeyy2=240610708"

第 4 行: $str = substr($str,1); substr 从第 2 个字符(索引为 1)开始截取,把最前面的 ? 扔掉。 此时 $str = "kekeyy1=QNKCDZO&kekeyy2=240610708"

第 5 行: $str = str_replace('key','',$str); 这是整个题目的核心坑点str_replace 会把字符串里所有匹配 "key" 的部分都替换为 空字符串。 因为我们的参数名是 kekeyy1,字符串里夹在中间的 key 被匹配并删除,成功变成了 key1! 同理,kekeyy2 变成了 key2。 此时 $str = "key1=QNKCDZO&key2=240610708"

第 6 行: parse_str($str); 这个函数会把刚才生成的字符串直接解析成当前代码中的变量。 执行完后,当前环境里成功被动态生成了 两个变量: $key1 = "QNKCDZO" $key2 = "240610708"

第 7、8 行: echo md5($key1); echo md5($key2); 这两行会在页面上打印它们的 MD5 值(通常是给攻击者看的提示,确认 payload 生效)。

  • QNKCDZO 的 MD5 是 0e830400451993494058024219903391

  • 240610708 的 MD5 是 0e462097431906509019562988736854 页面会输出两串乱码。

第 9 行: if(md5($key1) == md5($key2) && $key1 !== $key2) 进入最后的判断。

  • 前半段(重点) :PHP 用 ==(松散比较)对比两个 MD5 字符串。因为这两个字符串都以 0e 开头且后面全是数字,PHP 在比较时会将它们都当做科学计数法的 0 。所以 0 == 0,结果判定为 True

  • 后半段$key1 !== $key2 是严格的类型和值对比。因为一个是字符串 QNKCDZO,另一个是 240610708,它们确实不完全相等

  • 结果if(True && True) 条件成立,代码执行 echo $flag."取得flag";,成功拿到 Flag。

好,知道原理了,咱们进行md5绕过,构造payload!

Payload 1:利用 MD5 0e 科学计数法(最常用)

URL 传参: ?kekeyy1=QNKCDZO&kekeyy2=240610708

原理:

  1. 避开 str_replace 过滤: 代码会把 "key" 替换成空。我们传入 kekeyy1,中间正好包裹了一个 key。替换后,kekeyy1 变成了 key1。同理 kekeyy2 变成了 key2parse_str 成功生成 $key1$key2

  2. 欺骗 if(md5($key1) == md5($key2))

    • QNKCDZO 的 MD5 值为:0e830400451993494058024219903391

    • 240610708 的 MD5 值为:0e462097431906509019562988736854 重点 :这两个字符串都是以 0e 开头且后面全是数字。在 PHP 的 == 弱比较中,PHP 会把这种字符串当成 科学计数法 (即 0)。所以 0 == 0,结果为 True

  3. 满足 $key1 !== $key2 因为一个是 "QNKCDZO",另一个是 "240610708",它们在严格比较 !== 下肯定是不相等 的。 结果True && True,成功输出 Flag。

Payload 2:利用数组绕过(适应度最高,不受 PHP 版本限制)

URL 传参: ?kekeyy1[]=1&kekeyy2[]=2

原理:

  1. 同样绕过了关键字清洗: kekeyy1[] 经过替换变成 key1[]parse_str 解析后,$key1$key2 变成了数组 (而不是字符串)。即 $key1 = [1], $key2 = [2]

  2. 欺骗 md5($key1) == md5($key2) PHP 的 md5() 函数只接受字符串 ,如果你传进去一个数组 (如 $key1),PHP 会直接报错并返回 NULL。 这就变成了比较 NULL == NULL。在 == 弱比较下,NULL == NULL 的结果自然是 True

  3. 满足 $key1 !== $key2 数组 [1] 和数组 [2] 的内容不同,它们用 !== 比较时确实不相等结果 :依旧能成功 True && True,拿到 Flag。

搞,搞,搞,搞定!找到flag!