web刷题

刷题记录是根据小迪课程的顺序做
ctfshow
补充知识 bp爆破(部分)的使用 web21

随便输点什么,抓包后发送到



看着像base64
解码之后是我们输入的账密
接下来设置爆破
设置狙击手模式(单点爆破)因为是将账号:密码合在一起加密的

设置为自定义爆破模式

由于是测试,也没有字典,已知账密,添加一些字符串做为字典

接着设置第二段

第二段只有一个冒号

第三段

接着是设置编码模式


接着把URL 编码取消掉

然后开始爆破

下面这个是因为选错了爆破位置(多选了或者少选了空格之类的,我后来才发现)

这个是正确的

得到正确的账密解密之后输入


php特性
web98

1 | $_GET ? $_GET = &$_POST : 'flag' ;判断$_GET是否为空为空则返回flag不为空则$_GRT=&$_POST(不合法) |
那大致思路应该是让$_GET为空但是其中的HTTP_FLAG要等于flag
gpt说不合法,但是看了wp这个似乎合法,思路变为,GET传参会被POST传参覆盖,用GET传参任意值,POST传参HTTP_FLAG=flag,通过POST覆盖GET。

web99

1 | highlight_file(__FILE__); |
能理解,可以写一个文件
之后就不会了,wp中是创建一个1.php,向其中写入
1 | <?php system($_POST['a'])?> |
再访问新写的文件1.php,通过传参执行要执行的命令
先查看目录下文件结构,找flag文件的名字,再抓取该文件获取内容(tac反向读取文件内容)

多按几次,因为数组里是随机的数字,有可能就没有这个数字(弱比较强转类型,1.php被视为1)

通配符也可

web100

1 | highlight_file(__FILE__); |
is_numeric函数是用于检测值是否是数字,但是对于数字开头的字符串也会被当成数字
preg_match(“/;/“, $v2)过滤分号,但是不能处理数组
eval执行代码
思路是v2传的时候用数组绕,然后构造一个可以查看当前目录文件的指令,但是没成功
wp
1 | 对于 |
所以在给$v0赋值的时候只要让v1是数字就能绕过
v2里也不用加分号,不需要用数组绕
想要去除多余部分可以通过?>闭合php代码实现
ReflectionClass 是 PHP 中用于反射类的内置类,它允许获取关于类的信息
可以这样构造:
eval(“echo new ReflectionClass(‘ctfshow’);”);
1 | v1=1&v2=echo new ReflectionClass&v3=; |

这种方法读出来的flag需要将0x2d换成-
还有一种用反引号可以直接命令执行
1 | v1=1&v2=echo `ls`?>&v3=; |

之后读取文件信息发现flag不在flag36d.php里

在ctfshow.php里面

web101

和上一题差别不大,但是过滤了很多东西,$和反引号被禁了,只能用反射类的方式

另外提示里说flag末尾少一位,需要尝试16个数字
不知道出了什么原因,火狐上登不上去ctfshow的账号,爆破先放一放
web102

substr是截取字符串的函数,第一个参数是一个字符串,第二个参数是截取长度,第三个参数(可选)截取开始位置
这是call_user_func函数的介绍,这个函数可以动态调用想要调用的函数,返回值:返回调用函数的结果,或FALSE。


这里的想法是创建一个文件写一个木马
v2写木马,v1写一个打印的函数,因为$str获得的是call_user_func($v1,$s);的返回值,v3写文件名
v1=echo(post传) v2=11system($_POST[‘a’])&v3=1.php
但是过不去第一个if,就离谱
wp内容附加相关知识点
什么是伪协议?
PHP伪协议是一种特殊的字符串,像URL一样,但它实际上不是一个真正的网络协议,而是PHP中用于访问特定资源或功能的一种方式。它让你可以操作文件、数据流或其他资源,就像访问网络资源一样。
常见的PHP伪协议包括:
php://filter
php://filter
是 PHP 中一个特殊的流包装器(stream wrapper)。它允许你在读取或写入文件的过程中对数据进行过滤。你可以将过滤器应用到文件流(例如读取文件、写入文件)时,来处理数据,比如编码、解码、压缩等。
file://
访问本地文件系统。例如:1
$content = file_get_contents("file:///path/to/file.txt");
http://
和https://
通过HTTP或HTTPS访问网络资源。php://
提供访问PHP流,比如标准输入、输出、错误等。例如:php://input
:获取原始的HTTP请求数据。php://output
:写入PHP的输出缓冲。
data://
直接嵌入原始数据为流。例如:1
$content = file_get_contents("data://text/plain;base64,SGVsbG8gd29ybGQ=");
zip://
用于访问ZIP文件的内容。glob://
用于通过通配符模式匹配文件。
这些伪协议的好处是,能以统一的方式访问不同的资源,而不需要复杂的代码。
因为第一个if没绕过去,所以需要对v2进行处理,看wp说十六进制数不行必须是纯数字
v2是木马,因is_numeric长度过长也不行且要求全数字,指令改为<?=cat *
;(<? 是短标签,可以理解为<?php,<?=可以理解为<?php echo,这里cat *是被反引号包裹的(这里被当成语法使用了),被反引号包裹的php代码会被当作shell指令执行,这个经过一系列变化得到的是纯数字)进行base64加密(base64加密的结果是ascii字符串)(后面用伪协议base64解码方式写入文件)
再bin2hex将ascii字符串转为十六进制数(v1的作用是十六进制转ASCII也就是调用hex2bin)

暂时没找到终端执行php代码的方式,先用网页对付一下

得到5044383959474e6864434171594473
因为有截断,在前面加上两位数字,v2=115044383959474e6864434171594473
因为在base64中,=是用来补位的,可以省略不会影响解码
接着是v3,v3=php://filter/write=convert.base64-decode/resource=1.php
php://filter在上面有
write=convert.base64-decode
这部分是指定要应用于流的过滤器。convert.base64-decode
是一个预定义的过滤器,用于对数据进行 Base64 解码。具体来说,write=convert.base64-decode
表示 PHP 会在写入数据时进行 Base64 解码操作,即将 Base64 编码的数据转换回原始的二进制数据或文本。
resource=1.php
这部分指定了要操作的资源文件。在这个例子中,1.php
是一个文件,表示要对该文件的内容进行 Base64 解码处理。php://filter
会将 1.php
文件中的内容读取出来,并通过 Base64 解码后再处理。
连起来就是把传进去的参数base64解码之后写入文件1.php里

写入之后,需要访问1.php,再检查源代码就能看到flag了
因为之前的cat *是用反引号包着的,会被执行,执行结果会被嵌入到代码中,因此查看源代码能够看到flag

web103
和web102一样的,应该是web102里不需要缩写php代码片段


web104
sha1()函数计算字符串的SHA-1散列
SHA-1散列是一种由美国国家安全局(NSA)设计的密码散列函数,由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个160位的散列值,通常以40个十六进制数表示。
SHA-1的工作原理
SHA-1算法将输入的数据(字符串或二进制流)分成若干个512位的块进行处理。首先,对输入的消息进行填充和扩展,以确保其长度是512位的倍数。然后,对每个512位的块进行一系列复杂的数学运算,包括位操作、逻辑运算和循环压缩函数等,最终生成一个160位的散列值。

post和get传参传一样的就可以
web105

1 | foreach($_GET as $key => $value)将$_GET中的键和值对应取出来 |
1 | $$key=$$value; |
$$key = $$value;
是 PHP 中的 可变变量(Variable Variables)的用法。它有点复杂但很灵活,允许你动态创建或访问变量名。
普通变量
在 PHP 中,
1
$key
和
1
$value
是普通变量,分别存储某些值。 例如:
1
2$key = "name";
$value = "Alice";
可变变量
可变变量
$$key
的含义是:变量的值是另一个变量的名字。如果
1
$key = "name"
那么
1
$$key
相当于
1
$name
例如:
1
2$key = "name";
$$key = "Alice"; // 等价于 $name = "Alice";
1 | #再看这句 |
回到题目,想要获取flag,可以通过可变变量把flag放到error里,但是get和post每一个都禁用了一部分
所以想到传递的方式,先将flag存储在一个不受约束的变量中,再用这个变量给error赋值
get传参:v1=flag
post传参:error=v1

web106

有点像md5加密算法的套路
经过查找得知该函数同样不能直接处理数组
所以有

web107

parse_str 函数。它用于将 get 请求查询字符串转换为可用变量
parse_str(string,array)
参数 | 描述 |
---|---|
string | 必需。规定要解析的字符串。 |
array | 可选。规定存储变量的数组名称。该参数指示变量存储到数组中。 |
parse_str 有两个参数。第一个参数是输入字符串,它应该是查询字符串格式,例如名称=威尔逊&颜色=blue。
第二个参数是一个数组,它将由查询字符串中解析的变量填充。需要注意的是,parse_str 函数不会返回任何内容,因此需使用第二个参数来初始化该函数的结果。
回到本题,v2是不能通过get或者post传参的,通过后面的反应,只能理解为他是存在的。
两种解法
1、 传入v3传一个值,v1=flag=v3的md5值


2、 利用md5不能处理数组,使其返回值为null,v1则不传flag的值,达成null==null

web108

ereg函数类似preg_match函数,用于匹配正则表达式,第一个参数放表达式,第二个参数放字符串
intval函数之前有说过,返回变量整数,第二个参数设置为0的时候可以根据不同的进制处理
strrev函数将字符串反转
思路有但是不成功:第一个if应该输入不是纯字母的东西就能绕(可是只有输入纯字母的时候才能过),第二个36d转十进制是877,那传进去778就能过
后来发现是我想错了,目的是if不通过,而不是让if判断为true
所以第一个if应该是输入纯字母才能不成立,但是那样就不能满足下一个if的需求,所以
看wp
原来这个函数读取字符出时候也是%00截断(字符串末尾都会有的,这个在pwn里的printf函数也会用到)
所以结合两个if,需要传入的是字母+%00778

jwt
web345

抓包发现符合jwt特征的字符串


只有两段,可能是空加密模式
查看源代码发现

一开始猜还以为直接访问就行,但是不可以,也没注意到sub是user,把sub改成admin之后不能加密出jwt字符串,后来看wp,需要把Node改成随意一个算法才能加密出

改包放包

web346

抓包

拿到网站解码

这次有加密算法还有签名
需要爆破签名
这里用到脚本

爆破出签名密钥是123456
改包放包之后发现没有成功,看wp
原来是需要访问/admin,这里确实疏忽了,页面源代码里给了提示的

web347
和前两题一样,密钥还是123456
一摸一样
web348
这些题刷着好像没啥用,爆不出密钥就解不出来,爆出来密钥就能解
这题的密钥是aaab,我没爆出来,看的wp
web349
除了和前几题一样之外还给了部分源码

这里看到公钥私钥地址都有
但是访问之后没反应
看wp之后是直接访问private.key和public.key(这俩就在当前目录,这个是扫目录发现的)

这里需要post发送
获取密钥之后网页那里生成不了jwt
使用脚本生成



web350
题目给了附件,是这道题的源码,打开之后发现了公钥

因为是看着答案做题,我们知道他是jwt的题,所以抓包了

拿到解码的网站

这是一个rs256加密方式,这个加密记得是私钥加密(生成),公钥解密(生成)
我们没有私钥,只有公钥,之前的学习中有一篇文章中有写

这里没有使用文章中的算法,选择的是hs256,有脚本如下

得到token

改包后放包发现失败了

wp
需要post的方式发包,源码中有如下
正常是要看源码才能知道的,但是我是全局搜索才看到这个,通过连续两个题都是post,我觉得接收返回包的方式应该都是post

修改后得到

node.js
web334
下载附件,解压之后有两个js文件,并且user.js里有用户名密码

代码审计

这一行,第一个比较,不能让name输入大写,第二个比较,name转大写和item.username比较,user.js中的username是大写的ctfshow,所以输入不全为大写的ctfshow即可
一开始我还意为要改返回包,tmd,试了半天不行然后去看wp,结果这简单
web355

查看源代码

提示eval
直觉是传参,但是怎么传不知道
wp
1 | ?eval=require('child_process').spawnSync('ls',['.']).stdout.toString() |
require(‘child_process’)使用node.js的child_process模块。该模块允许你创建和管理子进程,类似于执行系统命令,类似于执行系统命令或脚本。
spawnSync(‘ls’,[‘.’])
spawnSync是child_process模块中的一个方法,意味着它是同步执行的。它创建一个新的子进程,并执行指定的命令。具体来说:ls
是一个Linux。Unix系统中的命令,用于列出当前目录下的文件和文件夹。
[‘.’]传递给ls命令的参数.
代表当前目录。.stdout
spawnSync返回一个包含子进程输出的对象。stdout是该对象的一个属性,表示子进程的标准输出流(即ls命令的输出)
stdout是一个Buffer对象,包含了命令输出的二进制数据。.toString()
stdout.toString()将输出的Buffer数据转换为字符串。最终,这个字符串就是当前目录下的文件和文件夹列表。
整体意思就是执行ls查看当前目录的文件

找到flag应是存在fl00g.txt里
修改命令,cat就行
1 | ?eval=require('child_process').spawnSync('cat',['fl00g.txt']).stdout.toString() |

web336
和上题一样
看wp区别是
检查发现过滤了exec
web337

题目的提示信息
1 | var express = require('express'); |
最开始我传的参数是a[]=1&b[]=2这是不成功的
看wp之后要传a[]=1&b[]=1,去问gpt的解释
在 JavaScript 中,数组和对象是引用类型。当你比较两个数组(或者两个对象)时,比较的是它们在内存中的引用,而不是它们的内容。
那之前为啥不能过呢,因为
在 md5(a + flag) === md5(b + flag)
中,a
和 b
是数组。因此,a + flag
和 b + flag
会被 JavaScript 转换为字符串,并且这个字符串是基于数组的 toString()
方法生成的。数组的 toString()
方法会将数组元素连接为一个字符串,并用逗号分隔。所以:
a = ['1']
的字符串表示为'1'
,因此a + flag
变成了'1xxxxxxx'
。b = ['2']
的字符串表示也为'1'
,因此b + flag
变成了'2xxxxxxx'
。
那是不一样的

web338
原型链污染
对于JavaScript来讲只有一种结构,也就是对象[Object],每一个对象都有一个私有属性,这个私有属性我们称之为
1 | __proto__ |
它指向构造函数的原型对象(prototype),这个prototype可以理解为父类。然后每个对象都有这样的特性,层层向上直到一个对象的原型对象为null,根据定义,null是没有原型的。作为这个原型链的最后一个环节。
几乎所有JavaScript中的对象都是位于原型链顶端的Object的实例。
需要知道的一个特点:当我们去访问一个对象的属性时,它不仅仅会在当前对象中寻找该属性,他还会在它的原型对象中找,以及该原型对象的原型对象,一直往上找。直到达到原型链的末尾为止。
这个写的能看懂,直接抄(嘿嘿
1 | const o = { |
merge操作导致原型链污染
1 | function merge(target, source) { |
JavaScript没有的变量会自动创建
有时候merge是copy
回到题目
给了源码,下载下来
找到了两个类似cookie的东西,所以我以为要伪造cookie,但是尝试多次失败了


wp
很巧妙(我做的题少目前是这样觉得的
利用的是叫做原型链污染方式
在代码中有


满足原型链污染的条件,使用到mereg(这里是copy),并且比较的对象属性(这俩我自己归拢出来的
思路:

让secert.ctfshow等于36dboy(遇到好几个这字符串了,作者是不是有
获得flag,往上找,secret没有东西,他和user有共同的原型,Object.prototype
在copy那里,user复制了req.body
req.body
是一个在 Express 中存储 HTTP 请求体数据的对象。它通常用于 POST
或 PUT
请求,包含了客户端发送给服务器的数据。在不同的请求中,req.body
的内容会根据请求的类型和客户端发送的数据格式而有所不同。
结合之前的知识点,可以借助copy将user的原型覆盖(不知道这么说对不对)带有secert.ctfshow===’36dboy’
创建一个
1 | {"__proto__":{"ctfshow":"36dboy"}} |
用post方式
