本文仅用于网络安全技术学习与授权测试交流。本文实验皆在靶场进行,任何未经授权使用文中技术的行为均与作者无关,请务必遵守法律法规,获得许可后方可进行渗透测试。
嗯...想来想去,打算以10道题一篇文章来进行做笔记,怕照片存不住,字数多了Typora也容易卡,就先这样。正在持续更新中!

目录
滑稽
题目信息

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

好好好,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 为例):
-
$num = "1a"(字符串)。 -
is_numeric("1a")检测到里面有字母a,返回 False 。if(!False)成立,进入大括号。 -
页面先输出
1a。 -
执行
if("1a" == 1)。PHP 会把"1a"转换成数字,遇到非数字字符a就停止,转换结果为整数1。 -
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=240610708。 strstr(..., '?') 截取"问号"及其后面的所有字符。 此时 $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
原理:
-
避开
str_replace过滤: 代码会把"key"替换成空。我们传入kekeyy1,中间正好包裹了一个key。替换后,kekeyy1变成了key1。同理kekeyy2变成了key2。parse_str成功生成$key1和$key2。 -
欺骗
if(md5($key1) == md5($key2)):-
QNKCDZO的 MD5 值为:0e830400451993494058024219903391 -
240610708的 MD5 值为:0e462097431906509019562988736854重点 :这两个字符串都是以0e开头且后面全是数字。在 PHP 的==弱比较中,PHP 会把这种字符串当成 科学计数法 (即0)。所以0 == 0,结果为 True。
-
-
满足
$key1 !== $key2: 因为一个是"QNKCDZO",另一个是"240610708",它们在严格比较!==下肯定是不相等 的。 结果 :True && True,成功输出 Flag。
Payload 2:利用数组绕过(适应度最高,不受 PHP 版本限制)
URL 传参:
?kekeyy1[]=1&kekeyy2[]=2
原理:
-
同样绕过了关键字清洗:
kekeyy1[]经过替换变成key1[],parse_str解析后,$key1和$key2变成了数组 (而不是字符串)。即$key1 = [1],$key2 = [2]。 -
欺骗
md5($key1) == md5($key2): PHP 的md5()函数只接受字符串 ,如果你传进去一个数组 (如$key1),PHP 会直接报错并返回NULL。 这就变成了比较NULL == NULL。在==弱比较下,NULL == NULL的结果自然是 True! -
满足
$key1 !== $key2: 数组[1]和数组[2]的内容不同,它们用!==比较时确实不相等 。 结果 :依旧能成功True && True,拿到 Flag。
搞,搞,搞,搞定!找到flag!
