ctfshow
1,web21
Basic认证采用Base64加密方式,Base64解码字符串发现是 用户名:密码 的格式进行Base64编码。
密码shark63
2,web22
用 子域名扫描器 扫出flag.ctf.show拿到flag,但这个域名已经没了所以就直接交的官方提供的flag。
3,web23
这段PHP代码是一个简单的Web挑战,通常用于CTF(Capture The Flag)竞赛中,旨在测试参与者对Web安全、PHP代码审计和哈希函数的理解。下面是对这段代码的逐行解释:
- 注释部分:这部分提供了代码的元数据,包括作者信息、修改时间和联系方式等。这对于理解代码的上下文和背景很有帮助。
- error_reporting(0);:这行代码关闭了PHP的错误报告。在CTF挑战中,关闭错误报告是一种常见的做法,以防止泄露不必要的信息给攻击者。
- include('flag.php');:这行代码包含了一个名为 flag.php 的文件,该文件很可能包含了一个名为 $flag 的变量,该变量存储了挑战的“flag”。在CTF竞赛中,flag是一个秘密字符串,参赛者需要找到它来完成挑战。
- if(isset($_GET['token'])){:这行代码检查是否通过GET请求传递了一个名为 token 的参数。如果是,代码将继续执行;如果不是,将高亮显示当前文件的内容。
- $token = md5($_GET['token']);:这行代码将GET请求中的 token 参数的值进行MD5哈希处理,并将结果存储在变量 $token 中。MD5是一种广泛使用的哈希函数,但已知存在碰撞(即不同的输入产生相同的输出),并且不再被认为是安全的加密哈希函数。
- 接下来的条件判断是一个复杂的逻辑表达式,用于检查 $token 的值是否满足特定的条件:
-
- substr($token, 1,1)===substr($token, 14,1):检查MD5哈希值的第二个字符是否与第15个字符相同。
- substr($token, 14,1) ===substr($token, 17,1):检查MD5哈希值的第15个字符是否与第18个字符相同。
- (intval(substr($token, 1,1))+intval(substr($token, 14,1))+substr($token, 17,1))/substr($token, 1,1)===intval(substr($token, 31,1)):这个条件稍微复杂一些。它首先将MD5哈希值的第二个字符和第15个字符转换为整数,加上第18个字符(这里未转换为整数),然后将这个和除以第二个字符(作为除数),最后检查这个结果是否等于MD5哈希值的第32个字符(转换为整数)。
- 如果 $token 满足上述所有条件,那么将输出 $flag 变量的值。
- }else{:如果GET请求中没有 token 参数,则执行 highlight_file(__FILE__);,这将高亮显示当前PHP文件的内容。
关键点:
- 这个挑战的核心在于找到一个特定的输入( token),其MD5哈希值满足上述复杂的条件。
- 由于MD5的碰撞性,理论上可以通过暴力搜索或字典攻击找到满足条件的哈希值,但这种方法可能非常耗时。
- 另一种方法可能是利用MD5哈希值的某些已知特性或弱点来找到满足条件的输入。
这种类型的挑战强调了理解哈希函数、字符串操作和PHP编程的重要性。
import hashlib
import string
all = string.digits + string.ascii_letters
better_set = set(string.ascii_letters)
for a in all:
for b in all:
c = a + b
t = hashlib.md5(c.encode(encoding='utf-8')).hexdigest()
if t[1] == t[14] and t[14] == t[17]:
t_set = {t[1],t[14],t[17],t[31]}
if t_set.isdisjoint(better_set) and t[31] != '0':
if (int(t[1])+int(t[14])+int(t[17]))/int(t[1]) == int(t[31]):
print(c)
print(t)
这段Python代码是一个暴力破解尝试,旨在找到一个字符串 c,该字符串由两个字符组成(来自 string.digits + string.ascii_letters,即数字和小写及大写英文字母),其MD5哈希值满足特定的条件。这些条件与先前解释的PHP代码中的条件相同。下面是代码的逐行解释:
- import hashlib:导入Python的 hashlib 模块,该模块提供了常见的哈希算法,包括MD5。
- import string:导入Python的 string 模块,该模块包含一系列字符串常量,如数字、字母等。
- all = string.digits + string.ascii_letters:创建一个字符串 all,包含所有数字( string.digits)和小写及大写英文字母( string.ascii_letters)。
- better_set = set(string.ascii_letters):创建一个集合 better_set,包含所有小写和大写英文字母。这个集合将用于后续检查MD5哈希值的特定字符是否不在字母范围内。
- 接下来的两个嵌套的for循环遍历 all 字符串中的每个字符对 (a, b),生成一个两字符长的字符串 c。
- t = hashlib.md5(c.encode(encoding='utf-8')).hexdigest():将字符串 c 编码为UTF-8字节串,计算其MD5哈希值,并将哈希值转换为十六进制字符串表示。
- if t[1] == t[14] and t[14] == t[17]::检查MD5哈希值的第二个字符(索引1,因为索引从0开始)是否与第15个字符和第18个字符相同。
- t_set = {t[1],t[14],t[17],t[31]}:创建一个集合 t_set,包含MD5哈希值的第2、15、18和32个字符。
- if t_set.isdisjoint(better_set) and t[31] != '0'::检查 t_set 中的字符是否与 better_set(包含所有字母)没有交集,并且MD5哈希值的第32个字符不是'0'。 isdisjoint 方法如果两个集合没有共同元素则返回True。
- if (int(t[1])+int(t[14])+int(t[17]))/int(t[1]) == int(t[31])::将MD5哈希值的第2、15和18个字符转换为整数,求和,然后除以第2个字符(转换为整数),检查这个结果是否等于第32个字符(转换为整数)。
- 如果所有条件都满足,则打印出原始字符串 c 和它的MD5哈希值 t。
注意:
- 这段代码是一个暴力破解的示例,它尝试所有可能的两个字符组合来找到满足条件的字符串。由于 all 字符串包含62个字符(10个数字+26个小写字母+26个大写字母),因此总共有3,844种可能的组合。对于每个组合,都需要计算MD5哈希值并进行一系列检查。
- 尽管这段代码在理论上可以工作,但由于MD5哈希的碰撞性和计算量,它可能非常慢,特别是当输入空间更大时。在实际应用中,寻找满足特定哈希条件的输入通常是一个具有挑战性的问题,可能需要更高级的技术或优化方法。
4.web24
发现会通过 mt_srand() 生成伪随机数,php伪随机数漏洞
mt_srand() //播种 Mersenne Twister 随机数生成器。 mt_rand() //生成随机数
简单来说mt_srand()通过分发seed种子,然后种子有了后,靠mt_rand()生成随机数
5,web27
点击录取名单里面有,部分信息,然后进行查询
进行爆破
621022199002015237
6,web28
爆破目录/0-100/0-100/
7,web29
error_reporting(0);这行代码关闭了PHP的错误报告功能。这意味着如果代码执行过程中发生错误,用户不会看到任何错误信息。
if(isset($_GET['c'])){这行代码检查URL的查询字符串中是否存在名为 c 的参数。
if(!preg_match("/flag/i", $c)){这行代码使用 preg_match 函数检查变量 $c 的内容是否包含字符串"flag"(不区分大小写,由 /i 修饰符指定)。如果 $c 不包含"flag",条件为真。
如果上面的条件为真(即 $c 不包含"flag"),则执行 eval($c);。 eval 是一个PHP函数,它会将传递给它的字符串当作PHP代码执行。这是非常危险的,因为它允许执行任意代码,只要攻击者能够控制 $c 的值。
highlight_file(__FILE__);这行代码将当前文件的源代码以高亮形式输出。 __FILE__ 是一个魔术常量,它返回当前文件的完整路径和文件名。这通常用于调试目的,但在生产环境中暴露源代码可能是一个安全风险。
8,web30
和上面的非常像不过过滤了flag,system,php,知到了过滤就换函数
system:执行系统命令,有回显
passthru():执行系统命令并且显示原始输出
cat被过滤了,换成tac
9,web31
使用""双引号ls
空格被过滤了
审计源码发现system被过滤可以用 passthru 函数绕过,cat被过滤可以用 more、less、nl 绕过
空格被过滤可以用 ${IFS}、 %09 绕过
10,web32
php伪协议:
在实战中php伪协议配合文件包含漏洞可以发挥重大作用,比如读取文件源码,任意命令执行,或者开启后门获取webshell。常见的伪协议有
- php://filter 读取文件源码
- php://input 任意代码执行
- data://text/plain 任意代码执行
- zip:// 配合文件上传开启后门
php://filter:
php://filter 协议可以对打开的数据流进行筛选和过滤,常用于读取文件源码。
使用文件包含函数包含文件时,文件中的代码会被执行,如果想要读取文件源码,可以使用base64对文件内容进行编码,编码后的文件内容不会被执行,而是展示在页面中,我们将页面中的内容使用base64解码,就可以获取文件的源码了。
php://input:
可以访问请求的原始数据,配合文件包含漏洞可以将post请求体中的内容当做文件内容执行,从而实现任意代码执行,需要注意的是,当enctype=multipart/form-data时,php:/input将会无效。
data://text/plain:
写法:data://text/plain, 或 data://text/plain;base64,
协议格式: data:资源类型;编码,内容
data://协议通过执行资源类型,使后面的内容当做文件内容来执行,从而造成任意代码执行.
include (或 require)语句会获取指定文件中存在的所有文本/代码/标记,并复制到使用 include 语句的文件中。 伪协议中的 data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
zip://:
ziip://协议用来读取压缩包中的文件,可以配合文件上传开启后门,获取webshell
将shell.txt压缩成zip,再将后缀名改为jpg上传至服务器,再通过zip伪协议访问压缩包里的文件,从而链接木马
过滤了;分号
这⾥可以使⽤php短标签来闭合执⾏命令。这⾥可以⽤? c=include$_GET[a]?>
include 语句通常用于包含并执行一个文件的内容。 然后因为include不能直接包含出flag,所以使⽤php伪协议来读取flag的base64内容
php://filter 是一个元封装器,它允许你读取原始数据流,并对其进行过滤处理。在这个例子中,攻击者试图使用 convert.base64-encode 过滤器来读取 flag.php 文件的内容,并将其编码为Base64。
php://filter
php://filter 是一个元封装器,它允许你对一个打开的文件流应用一系列的过滤器。这些过滤器可以在读取文件内容之前或写入文件内容之后对数据进行转换。 php://filter 通常用于读取或写入文件时对数据进行预处理。
read=convert.base64-encode
这部分指定了要应用的过滤器。在这个例子中, read=convert.base64-encode 表示在读取文件内容之前,将其转换为Base64编码。 convert.base64-encode 是PHP内置的一个过滤器,用于将数据编码为Base64格式。
resource=flag.php
resource= 后面跟的是要读取或写入的文件的路径。在这个例子中, flag.php 是目标文件的名称。这意味着 php://filter 将尝试打开 flag.php 文件,应用Base64编码过滤器,然后返回编码后的内容。
11,web33
还是用上面的包含
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
12,web34
还是和上面的一样,通过php://filter/读取flag.php
13,web35
对上面的没有影响
也可以用
- data: 是数据URI的协议标识,告诉浏览器接下来的内容是一个数据URI。
- text/plain 是MIME类型,指明了嵌入内容的媒体类型。在这个例子中,它表明内容是纯文本。MIME类型用于告诉浏览器或其他客户端如何解释数据。
data://协议通过执行资源类型,使后面的内容当做文件内容来执行,从而造成任意代码执行.
14,web36
还是没影响,只是多过滤了数字
15,web37
想⽐于之前,这⼀次给的就不是eval直接来执⾏命令,⽽是使⽤的include来进⾏命令执⾏。
include 语句通常用于包含并执行一个文件的内容。 然后因为include会包含输入的语句,并执行,导致前面的php://filter/read=convert.base64-encode/resource=fla g.php,这个语句就不可以用了
16,web38
这⾥把php给过滤了,所以我们换个php的短标签,可以把php换成等号
<?php echo 1; ?> 正常写法
<? echo 1; ?> 短标签写法,5.4 起 <?= 'hello'; === <? echo 'hello';
<?= phpinfo();?>
<% echo 1; %> asp 风格写法
<script language="php"> echo 1; </script> 长标签写法<?php echo 1; ?> 正常写法
<? echo 1; ?> 短标签写法,5.4 起 <?= 'hello'; === <? echo 'hello';
<?= phpinfo();?>
<% echo 1; %> asp 风格写法
<script language="php"> echo 1; </script> 长标签写法
第 1 种是正常写法,没什么可说的。
第 2 种,需要 php.ini 配置文件中的指令 short_open_tag 打开后才可用,或者在 PHP 编译时加入了 --enable-short-tags 选项。自 PHP5.4 起,短格式的 echo 标记 <?= 总会被识别并且合法,而不管 short_open_tag 的设置是什么。
第 3 种,不需要修改参数开关,但是只能在7.0以下可用。
第 4 种,不推荐写法,为了 asp 程序员学习 php 所添加的语法糖写法。需要通过 php.ini 配置文件中的指令 asp_tags 打开后才可用。
第 5 种,在 php7.0 后已经不解析了。
17,web39
这⾥是把$c."php"拼接了起来,但是还是可以⽤命令执⾏,因为在短标签⾥⾯进⾏了⼀个 已经闭合了所以不会受到php的影响
18,web40
getallheaders():返回所有的HTTP头信息,返回的是数组⽽eval要求为字符串,所以要⽤impl ode()函数将数组转换为字符串 get_defined_vars():该函数的作⽤是获取所有的已定义变量,返回值也是数组,不过是⼆维数 组,⽤var_dump()输出可以看⻅输出的内容,看⻅在第⼏位之后,可以⽤current()函数来获取其 值,详细可以看官⽅函数。payload:var_dump(current(get_defined_vars())); session_id():session_id()可以⽤来获取/设置当前会话 ID,可以⽤这个函数来获取cookie 中的phpsessionid,并且这个值我们是可控的。 如可以在cookie中设置 PHPSESSID=706870696e666f28293b,然后⽤hex2bin()函数, 即传⼊?exp=eval(hex2bin(session_id(session_start()))); 并设置cookie:PHP
SESSID=706870696e666f28293b session_start 函数是为了开启session 配合使⽤的函数: print_r(scandir(‘.’)); 查看当前⽬录下的所有⽂件名 var_dump() localeconv() 函数返回⼀包含本地数字及货币格式信息的数组。 current() 函数返回数组中的当前元素(单元),默认取第⼀个值,pos是current的别名 each() 返回数组中当前的键/值对并将数组指针向前移动⼀步 end() 将数组的内部指针指向最后⼀个单元 next() 将数组中的内部指针向前移动⼀位 prev() 将数组中的内部指针倒回⼀位 array_reverse() 以相反的元素顺序返回数组
因为过滤了特殊符号所以上⾯print_r(scandir(‘.’));不 能直接⽤ 要配合localeconv()和current()来使⽤
19,web151
从这里可以看到提示说明是前端校验
20,web152
21,web153
大小写绕过失败
使用.user.ini 来构造后⻔
php.ini是php的⼀个全局配置⽂件,对整个web服务起作⽤;⽽.user.ini和.htaccess⼀样是⽬录的配置⽂件,.user.ini就是⽤户⾃定义的⼀个php.ini,我们可以利⽤这个⽂件来构造后⻔和隐藏后⻔。.htaccess是Apache的,.user.ini是Nginx的
php 配置项中有两个配置可以起到一些作用
auto_prepend_file = <filename> //包含在文件头
auto_append_file = <filename> //包含在文件尾
这两个配置项的作用相当于一个文件包含,比如
// .user.ini
auto_prepend_file = 1.jpg
// 1.jpg
<?php phpinfo();?>
// 1.php(任意php文件)
利用.user.ini的前提是服务器开启了CGI或者FastCGI,并且上传文件的存储路径下有index.php可执行文件。
另一条配置包含在文件尾,如果遇到了 exit 语句的话就会失效。
.user.ini使用范围很广,不仅限于 Apache 服务器,同样适用于 Nginx 服务器,只要服务器启用了 fastcgi 模式 (通常非线程安全模式使用的就是 fastcgi 模式)。 局限
在.user.ini中使用这条配置也说了是在同目录下的其他.php 文件中包含配置中所指定的文件,也就是说需要该目录下存在.php 文件,通常在文件上传中,一般是专门有一个目录用来存在图片,可能小概率会存在.php 文件。
先上传木马图片,再上传ini文件
先改成png,绕过前端